6.19.7-rc1 review
Subsystems (10)
Sasha Levin
maintainercover 6.19.7-rc1 review
This is the start of the stable review cycle for the 6.19.7 release. There are 311 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 Thu Mar 12 11:04:16 AM UTC 2026. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/rawdiff/?id=linux-6.19.y&id2=v6.19.6
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.19.y
and the diffstat can be found below.
Thanks,
Sasha
-------------
Pseudo-Shortlog of commits:
Aaron Ma (1):
ice: recap the VSI and QoS info after rebuild
Alain Volmat (1):
spi: stm32: fix missing pointer assignment in case of dma chaining
Alban Bedel (1):
can: mcp251x: fix deadlock in error path of mcp251x_open
Alex Hung (2):
drm/amd/display: Use mpc.preblend flag to indicate 3D LUT drm/amd/display: Enable DEGAMMA and reject COLOR_PIPELINE+DEGAMMA_LUT
Alexandre Courbot (1):
rust: kunit: fix warning when !CONFIG_PRINTK
Alexey Charkov (1):
scsi: ufs: core: Fix RPMB region size detection for UFS 2.2
Allison Henderson (1):
net/rds: Fix circular locking dependency in rds_tcp_tune
Alper Ak (1):
crypto: ccp - Fix use-after-free on error path
Andrew Cooper (1):
x86/fred: Correct speculative safety in fred_extint()
Andrew Lunn (1):
net: phy: register phy led_triggers during probe to avoid AB-BA
deadlock
Ankit Garg (1):
gve: fix incorrect buffer cleanup in gve_tx_clean_pending_packets for
QPL
Ariel Silver (1):
wifi: mac80211: bounds-check link_id in ieee80211_ml_reconfiguration
Bart Van Assche (5):
drm/amdgpu: Unlock a mutex before destroying it drm/amdgpu: Fix locking bugs in error paths
hwmon: (it87) Check the it87_lock() return value
wifi: cw1200: Fix locking in error paths
wifi: wlcore: Fix a locking bug
Bjorn Helgaas (1):
PCI: Correct PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value
Bobby Eshleman (1):
net: devmem: use READ_ONCE/WRITE_ONCE on binding->dev
Boris Faure (1):
ASoC: sdca: Fix missing regmap dependencies in Kconfig
Brad Spengler (1):
drm/vmwgfx: Fix invalid kref_put callback in vmw_bo_dirty_release
Brian Vazquez (1):
idpf: change IRQ naming to match netdev and ethtool queue numbering
Catalin Marinas (1):
arm64: gcs: Do not set PTE_SHARED on GCS mappings if FEAT_LPA2 is
enabled
Chaitanya Kulkarni (1):
blktrace: fix __this_cpu_read/write in preemptible context
Charles Haithcock (1):
i2c: i801: Revert "i2c: i801: replace acpi_lock with I2C bus lock"
Charles Keepax (1):
ASoC: SDCA: Add allocation failure check for Entity name
Chen Ni (2):
drm/imx: parallel-display: check return value of devm_drm_bridge_add()
in imx_pd_probe()
drm/bridge: synopsys: dw-dp: Check return value of
devm_drm_bridge_add() in dw_dp_bind()
Chintan Vankar (1):
net: ethernet: ti: am65-cpsw-nuss/cpsw-ale: Fix multicast entry
handling in ALE table
Christian Brauner (1):
namespace: fix proc mount iteration
Christoph Böhmwalder (1):
drbd: fix null-pointer dereference on local read error
Christoph Hellwig (2):
zloop: advertise a volatile write cache
zloop: check for spurious options passed to remove
Conor Dooley (1):
pinctrl: generic: move function to amlogic-am4 driver
Corey Minyard (1):
ipmi: Fix use-after-free and list corruption on sender error
Dan Carpenter (1):
accel: ethosu: Fix shift overflow in cmd_to_addr()
Daniel Hodges (1):
wifi: libertas: fix use-after-free in lbs_free_adapter()
Daniel J Blueman (1):
gpio: shared: fix memory leaks
Danielle Ratson (1):
bridge: Check relevant per-VLAN options in VLAN range grouping
Daniil Dulov (1):
wifi: cfg80211: cancel rfkill_block work in wiphy_unregister()
Danilo Krummrich (1):
clk: scu/imx8qxp: do not register driver in probe()
Darrick J. Wong (1):
xfs: fix xfs_group release bug in xfs_dax_notify_dev_failure
Dave Jiang (2):
cxl: Move devm_cxl_add_nvdimm_bridge() to cxl_pmem.ko
cxl: Fix race of nvdimm_bus object when creating nvdimm objects
David Carlier (1):
sched_ext: Fix SCX_EFLAG_INITIALIZED being a no-op flag
David Howells (1):
netfs: Fix unbuffered/DIO writes to dispatch subrequests in strict
sequence
David Laight (1):
uaccess: Fix scoped_user_read_access() for 'pointer to const'
David Thomson (1):
xen/acpi-processor: fix _CST detection using undersized evaluation
buffer
Davide Caratti (1):
net/sched: ets: fix divide by zero in the offload path
Davidlohr Bueso (1):
cxl/mbox: validate payload size before accessing contents in
cxl_payload_from_user_allowed()
Deepanshu Kartikey (1):
mm: thp: deny THP for files on anonymous inodes
Eduard Zingerman (1):
bpf: collect only live registers in linked regs
Eric Biggers (1):
ksmbd: Compare MACs in constant time
Eric Dumazet (5):
net: annotate data-races around sk->sk_{data_ready,write_space}
inet: annotate data-races around isk->inet_num
indirect_call_wrapper: do not reevaluate function pointer
tcp: secure_seq: add back ports to TS offset
net_sched: sch_fq: clear q->band_pkt_count[] in fq_reset()
Ethan Tidmore (2):
drm/tiny: sharp-memory: fix pointer error dereference
xfs: Fix error pointer dereference
Felix Gu (7):
drm/logicvc: Fix device node reference leak in
logicvc_drm_config_parse()
regulator: fp9931: Fix PM runtime reference leak in
fp9931_hwmon_read()
regulator: bq257xx: Fix device node reference leak in
bq257xx_reg_dt_parse_gpio()
pinctrl: pinconf-generic: Fix memory leak in
pinconf_generic_parse_dt_config()
pinctrl: meson: amlogic-a4: Fix device node reference leak in
aml_dt_node_to_map_pinmux() pinctrl: cirrus: cs42l43: Fix double-put in cs42l43_pin_probe()
regulator: mt6363: Fix incorrect and redundant IRQ disposal in probe
Fernando Fernandez Mancera (2):
net: bridge: fix nd_tbl NULL dereference when IPv6 is disabled
net: vxlan: fix nd_tbl NULL dereference when IPv6 is disabled
Florian Eckert (2):
pinctrl: equilibrium: rename irq_chip function callbacks
pinctrl: equilibrium: fix warning trace on load
Florian Westphal (1):
netfilter: nft_set_pipapo: split gc into unlink and reclaim phase
Francesco Lavra (1):
drm/solomon: Fix page start when updating rectangle in page addressing
mode
Fuad Tabba (3):
KVM: arm64: Hide S1POE from guests when not supported by the host
KVM: arm64: Fix ID register initialization for non-protected pKVM
guests
bpf, arm64: Force 8-byte alignment for JIT buffer to prevent atomic
tearing
Geoffrey D. Bennett (3):
ALSA: scarlett2: Fix DSP filter control array handling
ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP
Gerd Rausch (1):
time/jiffies: Fix sysctl file error on configurations where USER_HZ <
HZ
Greg Kroah-Hartman (12):
nfc: pn533: properly drop the usb interface reference on disconnect
net: usb: kaweth: validate USB endpoints
net: usb: kalmia: validate USB endpoints
net: usb: pegasus: validate USB endpoints
can: ems_usb: ems_usb_read_bulk_callback(): check the proper length of
a message
can: usb: f81604: correctly anchor the urb in the read bulk callback
can: ucan: Fix infinite loop from zero-length messages
can: usb: etas_es58x: correctly anchor the urb in the read bulk
callback
can: usb: f81604: handle short interrupt urb messages properly
can: usb: f81604: handle bulk write errors properly
HID: Add HID_CLAIMED_INPUT guards in raw_event callbacks missing them Revert "netfilter: nft_set_rbtree: validate open interval overlap"
Guenter Roeck (5):
hwmon: (macsmc) Fix regressions in Apple Silicon SMC hwmon driver
hwmon: (macsmc) Fix overflows, underflows, and sign extension
dpaa2-switch: Fix interrupt storm after receiving bad if_id in IRQ
handler
ata: libata-eh: Fix detection of deferred qc timeouts
tracing: Add NULL pointer check to trigger_data_free()
Hao Yu (1):
hwmon: (aht10) Fix initialization commands for AHT20
Haocheng Yu (1):
perf/core: Fix refcount bug and potential UAF in perf_mmap
Harishankar Vishwanathan (1):
bpf: Introduce tnum_step to step through tnum's members
Harry Yoo (1):
mm/slab: pass __GFP_NOWARN to refill_sheaf() if fallback is available
Heiko Carstens (2):
s390/idle: Fix cpu idle exit cpu time accounting s390/vtime: Fix virtual timer forwarding
Heitor Alves de Siqueira (1):
Bluetooth: purge error queues in socket destructors
Henrique Carvalho (1):
smb: client: fix cifs_pick_channel when channels are equally loaded
Hou Wenlong (1):
x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
Ian Forbes (1):
drm/vmwgfx: Return the correct value in vmw_translate_ptr functions
Ian Ray (2):
HID: multitouch: new class MT_CLS_EGALAX_P80H84
net: nfc: nci: Fix zero-length proprietary notifications
Ingo Molnar (3):
sched/fair: Rename cfs_rq::avg_load to cfs_rq::sum_weight sched/fair: Rename cfs_rq::avg_vruntime to ::sum_w_vruntime, and
helper functions
sched/fair: Introduce and use the vruntime_cmp() and vruntime_op()
wrappers for wrapped-signed aritmetics
Ioana Ciornei (1):
irqchip/ls-extirq: Fix devm_of_iomap() error check
Jakub Kicinski (6):
tcp: give up on stronger sk_rcvbuf checks (for now)
ipv6: fix NULL pointer deref in ip6_rt_get_dev_rcu()
nfc: nci: free skb on nci_transceive early error paths
nfc: nci: complete pending data exchange on device close
nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
nfc: rawsock: cancel tx_work before socket teardown
Jamal Hadi Salim (1):
net/sched: act_ife: Fix metalist update behavior
Jan Stancek (1):
x86/boot: Handle relative CONFIG_EFI_SBAT_FILE file paths
Jann Horn (1):
eventpoll: Fix integer overflow in ep_loop_check_proc()
Jason Gunthorpe (3):
IB/mthca: Add missed mthca_unmap_user_db() for mthca_create_srq() RDMA/irdma: Fix kernel stack leak in irdma_create_user_ah() RDMA/ionic: Fix kernel stack leak in ionic_create_cq()
Jens Axboe (2):
io_uring/cmd_net: use READ_ONCE() for ->addr3 read
media: dvb-core: fix wrong reinitialization of ringbuffer on reopen
Jiayuan Chen (5):
bpf: Fix race in cpumap on PREEMPT_RT
bpf: Fix race in devmap on PREEMPT_RT
atm: lec: fix null-ptr-deref in lec_arp_clear_vccs bpf/bonding: reject vlan+srcmac xmit_hash_policy change when XDP is
loaded
net: ipv6: fix panic when IPv4 route references loopback IPv6 nexthop
Johannes Berg (1):
wifi: radiotap: reject radiotap with unknown bits
Jonathan Cavitt (1):
drm/client: Do not destroy NULL modes
Jonathan Teh (1):
platform/x86: thinkpad_acpi: Fix errors reading battery thresholds
Juhyung Park (2):
ALSA: hda/realtek: fix model name typo for Samsung Galaxy Book Flex
(NT950QCG-X716)
ALSA: hda/realtek: add quirk for Samsung Galaxy Book Flex
(NT950QCT-A38A)Julian Orth (1):
drm/syncobj: Fix handle <-> fd ioctls with dirty stack
Jun Seo (1):
ALSA: usb-audio: Use correct version for UAC3 header validation
Junxiao Bi (1):
scsi: core: Fix refcount leak for tagset_refcnt
Juri Lelli (1):
sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting
Justin Tee (1):
nvmet-fcloop: Check remoteport port_state before calling done callback
Keith Busch (1):
nvme-multipath: fix leak on try_module_get failure
Khushit Shah (1):
KVM: x86: Add x2APIC "features" to control EOI broadcast suppression
Kim Phillips (1):
x86/sev: Allow IBPB-on-Entry feature for SNP guests
Kohei Enju (2):
bpf: Fix stack-out-of-bounds write in devmap
iavf: fix netdev->max_mtu to respect actual hardware limit
Koichiro Den (1):
net: sched: avoid qdisc_reset_all_tx_gt() vs dequeue race for lockless
qdiscs
Kuen-Han Tsai (3):
usb: gadget: u_ether: add gether_opts for config caching
usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device
usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
Kuniyuki Iwashima (2):
nfsd: Fix cred ref leak in nfsd_nl_threads_set_doit().
udp: Unhash auto-bound connected sk from 4-tuple hash table when
disconnected.
Kurt Borja (2):
platform/x86: alienware-wmi-wmax: Add G-Mode support to m18 laptops platform/x86: dell-wmi: Add audio/mic mute key codes
Lang Xu (1):
bpf: Fix a UAF issue in bpf_trampoline_link_cgroup_shim
Lars Ellenberg (1):
drbd: fix "LOGIC BUG" in drbd_al_begin_io_nonblock()
Larysa Zaremba (9):
ice: fix adding AQ LLDP filter for VF
xdp: use modulo operation to calculate XDP frag tailroom
xsk: introduce helper to determine rxq->frag_size
ice: fix rxq info registering in mbuf packets
ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz
i40e: fix registering XDP RxQ info
i40e: use xdp.frame_sz as XDP RxQ info frag_size
net: enetc: use truesize as XDP RxQ info frag_size
xdp: produce a warning when calculated tailroom is negative
Li Li (1):
idpf: increment completion queue next_to_clean in sw marker wait
routine
Lijo Lazar (1):
drm/amdgpu: Fix error handling in slot reset
Lizhi Hou (11):
accel/amdxdna: Remove buffer size check when creating command BO accel/amdxdna: Switch to always use chained command accel/amdxdna: Fix crash when destroying a suspended hardware context accel/amdxdna: Fix dead lock for suspend and resume accel/amdxdna: Fix suspend failure after enabling turbo mode accel/amdxdna: Fix command hang on suspended hardware context accel/amdxdna: Fix out-of-bounds memset in command slot handling accel/amdxdna: Prevent ubuf size overflow
accel/amdxdna: Validate command buffer payload count accel/amdxdna: Fill invalid payload for failed command accel/amdxdna: Fix NULL pointer dereference of mgmt_chann
Lorenzo Bianconi (4):
wifi: mt76: mt7996: Fix possible oob access in
mt7996_mac_write_txwi_80211()
wifi: mt76: mt7925: Fix possible oob access in
mt7925_mac_write_txwi_80211()
wifi: mt76: Fix possible oob access in
mt76_connac2_mac_write_txwi_80211() net: ethernet: mtk_eth_soc: Reset prog ptr to old_prog in case of
error in mtk_xdp_setup()
MD Danish Anwar (1):
net: ti: icssg-prueth: Fix ping failure after offload mode setup when
link speed is not 1G
Mario Limonciello (2):
accel/amdxdna: Reduce log noise during process termination platform/x86: hp-bioscfg: Support allocations of larger data
Mariusz Skamra (1):
Bluetooth: Fix CIS host feature condition
Mark Harmstone (6):
btrfs: fix error message order of parameters in
btrfs_delete_delayed_dir_index()
btrfs: fix incorrect key offset in error message in
check_dev_extent_item()
btrfs: fix objectid value in error message in check_extent_data_ref()
btrfs: fix warning in scrub_verify_one_metadata()
btrfs: print correct subvol num if active swapfile prevents deletion
btrfs: fix compat mask in error messages in btrfs_check_features()
Mathias Krause (1):
scsi: lpfc: Properly set WC for DPP mapping
Mathieu Desnoyers (1):
rseq: Clarify rseq registration rseq_size bound check comment
Matt Roper (1):
drm/xe/wa: Steer RMW of MCR registers while building default LRC
Matthew Brost (1):
drm/xe: Do not preempt fence signaling CS instructions
Matthieu Baerts (NGI0) (4):
mptcp: pm: avoid sending RM_ADDR over same subflow
mptcp: pm: in-kernel: always mark signal+subflow endp as used
selftests: mptcp: join: check RM_ADDR not sent over same subflow
selftests: mptcp: join: check removing signal+subflow endp
Maulik Shah (1):
pinctrl: qcom: qcs615: Add missing dual edge GPIO IRQ errata flag
Michal Schmidt (1):
ice: fix crash in ethtool offline loopback test
Michal Swiatkowski (1):
libie: don't unroll if fwlog isn't supported
Mieczyslaw Nalewaj (1):
net: dsa: realtek: rtl8365mb: fix rtl8365mb_phy_ocp_write return value
Mike Rapoport (Microsoft) (1):
x86/efi: defer freeing of boot services memory
Ming Lei (2):
nvme: fix admin queue leak on controller reset
block: use trylock to avoid lockdep circular dependency in sysfs
Miquel Sabaté Solà (1):
btrfs: free pages on error in btrfs_uring_read_extent()
Miroslav Lichvar (1):
timekeeping: Fix timex status validation for auxiliary clocks
Nam Cao (1):
irqchip/sifive-plic: Fix frozen interrupt due to affinity setting
Namhyung Kim (1):
perf/core: Fix invalid wait context in ctx_sched_in()
Natalie Vock (1):
drm/amd/display: Use GFP_ATOMIC in dc_create_stream_for_sink
Nathan Chancellor (2):
kbuild: Split .modinfo out from ELF_DETAILS
kbuild: Leave objtool binary around with 'make clean'
Nikhil P. Rao (2):
xsk: Fix fragment node deletion to prevent buffer leak
xsk: Fix zero-copy AF_XDP fragment drop
Niklas Cassel (3):
PCI: dwc: ep: Refresh MSI Message Address cache on change
PCI: dwc: ep: Flush MSI-X write before unmapping its ATU entry
ata: libata: cancel pending work after clearing deferred_qc
Oliver Hartkopp (2):
can: bcm: fix locking for bcm_op runtime updates
can: dummy_can: dummy_can_init(): fix packet statistics
Olivier Sobrie (1):
hwmon: (max6639) fix inverted polarity
Ovidiu Panait (4):
net: stmmac: Fix error handling in VLAN add and delete paths
net: stmmac: Improve double VLAN handling
net: stmmac: Fix VLAN HW state restore
net: stmmac: Defer VLAN HW configuration when interface is down
Pablo Neira Ayuso (2):
netfilter: nf_tables: unconditionally bump set->nelems before
insertion
netfilter: nf_tables: clone set on flush only
Panagiotis Foliadis (2):
ALSA: hda/intel: increase default bdl_pos_adj for Nvidia controllers
ALSA: hda/realtek: Add quirk for Acer Aspire V3-572G
Paolo Abeni (1):
selftests: mptcp: more stable simult_flows tests
Paul Chaignon (1):
bpf: Improve bounds when tnum has a single possible value
Paulo Alcantara (2):
smb: client: fix broken multichannel with krb5+signing
smb: client: fix oops due to uninitialised var in smb2_unlink()
Peter Wang (1):
scsi: ufs: core: Move link recovery for hibern8 exit failure to
wl_resume
Peter Zijlstra (9):
x86/cfi: Fix CFI rewrite for odd alignments
sched/fair: Fix zero_vruntime tracking
sched/fair: Only set slice protection at pick time sched/fair: Fix lag clamp
perf: Fix __perf_event_overflow() vs perf_remove_from_context() race x86/numa: Store extra copy of numa_nodes_parsed
x86/topo: Add topology_num_nodes_per_package()
x86/topo: Replace x86_has_numa_in_package
x86/topo: Fix SNC topology mess
Petr Pavlu (1):
module: Remove duplicate freeing of lockdep classes
Phillip Lougher (1):
Squashfs: check metadata block offset is within range
Prithvi Tambewagh (1):
scsi: target: Fix recursive locking in __configfs_open_file()
Qing Wang (1):
tracing: Fix WARN_ON in tracing_buffers_mmap_close
Quentin Schulz (2):
accel/rocket: fix unwinding in error path in rocket_core_init accel/rocket: fix unwinding in error path in rocket_probe
Raju Rangoju (2):
amd-xgbe: fix MAC_TCR_SS register width for 2.5G and 10M speeds
amd-xgbe: fix sleep while atomic on suspend/resume
Richard Fitzgerald (1):
ALSA: hda: cs35l56: Fix signedness error in cs35l56_hda_posture_put()
Rob Herring (Arm) (2):
accel: ethosu: Fix job submit error clean-up refcount underflows
accel: ethosu: Fix NPU_OP_ELEMENTWISE validation with scalar
Rong Zhang (1):
ALSA: doc: usb-audio: Add doc for QUIRK_FLAG_SKIP_IFACE_SETUP
Russell King (Oracle) (1):
net: stmmac: remove support for lpi_intr_o
Salomon Dushimirimana (1):
scsi: pm8001: Fix use-after-free in pm8001_queue_command()
Sasha Levin (1):
Linux 6.19.7-rc1
Sebastian Andrzej Siewior (1):
net: Provide a PREEMPT_RT specific check for netdev_queue::_xmit_lock
Sebastian Krzyszkowiak (1):
wifi: rsi: Don't default to -EOPNOTSUPP in rsi_mac80211_config
Shuicheng Lin (2):
drm/xe/configfs: Free ctx_restore_mid_bb in release drm/xe/reg_sr: Fix leak on xa_store failure
Shuvam Pandey (1):
kunit: tool: copy caller args in run_kernel to prevent mutation
Simon Ser (1):
drm/fourcc: fix plane order for 10/12/16-bit YCbCr formats
Sreedevi Joshi (1):
idpf: Fix flow rule delete failure due to invalid validation
Srinivas Pandruvada (1):
cpufreq: intel_pstate: Fix crash during turbo disable
Sun Jian (1):
selftests/harness: order TEST_F and XFAIL_ADD constructors
Sungwoo Kim (1):
nvme: fix memory allocation in nvme_pr_read_keys()
T.J. Mercier (1):
selftests/bpf: Fix OOB read in dmabuf_collector
Takashi Iwai (4):
ALSA: usb-audio: Cap the packet size pre-calculations
ALSA: usb-audio: Use inclusive terms
ALSA: usb: qcom: Correct parameter comment for
uaudio_transfer_buffer_setup()
ASoC: SDCA: Fix comments for sdca_irq_request()
Thomas Gleixner (2):
debugobject: Make it work with deferred page initialization - again
i40e: Fix preempt count leak in napi poll tracepoint
Thomas Weißschuh (1):
ARM: clean up the memset64() C wrapper
Thorsten Blum (2):
platform/x86: dell-wmi-sysman: Don't hex dump plaintext password data
smb: client: Don't log plaintext credentials in cifs_set_cifscreds
Tianci Cao (1):
bpf: Add bitwise tracking for BPF_END
Tom Lendacky (1):
x86/boot/sev: Move SEV decompressor variables into the .data section
Tomasz Lis (1):
drm/xe/queue: Call fini on exec queue creation fail
Tomasz Pakuła (1):
HID: pidff: Fix condition effect bit clearing
Tvrtko Ursulin (1):
drm/amdgpu/userq: Do not allow userspace to trivially triger kernel
warnings
Vahagn Vardanian (1):
wifi: mac80211: fix NULL pointer dereference in mesh_rx_csa_frame()
Vasily Gorbik (1):
s390/kexec: Disable stack protector in s390_reset_system()
Vimlesh Kumar (4):
octeon_ep: Relocate counter updates before NAPI
octeon_ep: avoid compiler and IQ/OQ reordering
octeon_ep_vf: Relocate counter updates before NAPI
octeon_ep_vf: avoid compiler and IQ/OQ reordering
Vitaly Lifshits (1):
e1000e: clear DPG_EN after reset to avoid autonomous power-gating
Vivek Behera (2):
igb: Fix trigger of incorrect irq in igb_xsk_wakeup
igc: Fix trigger of incorrect irq in igc_xsk_wakeup function
Waiman Long (2):
cgroup/cpuset: Fix incorrect change to effective_xcpus in
partition_xcpus_del()
cgroup/cpuset: Fix incorrect use of cpuset_update_tasks_cpumask() in
update_cpumasks_hier()
Wang Tao (1):
sched/eevdf: Update se->vprot in reweight_entity()
Werner Sembach (1):
HID: multitouch: Keep latency normal on deactivate for reactivation
gesture
Will Deacon (2):
arm64: io: Rename ioremap_prot() to __ioremap_prot()
arm64: io: Extract user memory type in ioremap_prot()
Yifan Wu (1):
selftest/arm64: Fix sve2p1_sigill() to hwcap test
Yujie Liu (1):
drm/sched: Fix kernel-doc warning for drm_sched_job_done()
Yung Chih Su (1):
net: ipv4: fix ARM64 alignment fault in multipath hash seed
Zhang Heng (2):
ALSA: hda/realtek: Add quirk for HP Pavilion 15-eh1xxx to enable mute
LED
ALSA: hda/realtek: add quirk for Acer Nitro ANV15-51
ZhangGuoDong (2):
smb/client: fix buffer size for smb311_posix_qinfo in
smb2_compound_op()
smb/client: fix buffer size for smb311_posix_qinfo in
SMB311_posix_query_info()Zhanjun Dong (1):
drm/xe/gsc: Fix GSC proxy cleanup on early initialization failure
Zide Chen (1):
perf/x86/intel/uncore: Add per-scheduler IMC CAS count events
Zilin Guan (1):
ice: Fix memory leak in ice_set_ringparam()
Documentation/sound/alsa-configuration.rst | 4 + Documentation/virt/kvm/api.rst | 28 ++- Makefile | 12 +- arch/alpha/kernel/vmlinux.lds.S | 1 + arch/arc/kernel/vmlinux.lds.S | 1 + arch/arm/boot/compressed/vmlinux.lds.S | 1 + arch/arm/include/asm/string.h | 14 +- arch/arm/kernel/vmlinux-xip.lds.S | 1 + arch/arm/kernel/vmlinux.lds.S | 1 + arch/arm64/include/asm/io.h | 26 +- arch/arm64/include/asm/pgtable-prot.h | 3 - arch/arm64/kernel/acpi.c | 2 +- arch/arm64/kernel/vmlinux.lds.S | 1 + arch/arm64/kvm/hyp/nvhe/pkvm.c | 35 ++- arch/arm64/kvm/sys_regs.c | 3 + arch/arm64/mm/ioremap.c | 6 +- arch/arm64/mm/mmap.c | 8 +- arch/arm64/net/bpf_jit_comp.c | 2 +- arch/csky/kernel/vmlinux.lds.S | 1 + arch/hexagon/kernel/vmlinux.lds.S | 1 + arch/loongarch/kernel/vmlinux.lds.S | 1 + arch/m68k/kernel/vmlinux-nommu.lds | 1 + arch/m68k/kernel/vmlinux-std.lds | 1 + arch/m68k/kernel/vmlinux-sun3.lds | 1 + arch/mips/kernel/vmlinux.lds.S | 1 + arch/nios2/kernel/vmlinux.lds.S | 1 + arch/openrisc/kernel/vmlinux.lds.S | 1 + arch/parisc/boot/compressed/vmlinux.lds.S | 1 + arch/parisc/kernel/vmlinux.lds.S | 1 + arch/powerpc/kernel/vmlinux.lds.S | 1 + arch/riscv/kernel/vmlinux.lds.S | 1 + arch/s390/include/asm/idle.h | 1 + arch/s390/kernel/idle.c | 13 +- arch/s390/kernel/ipl.c | 2 +- arch/s390/kernel/irq.c | 10 +- arch/s390/kernel/vmlinux.lds.S | 1 + arch/s390/kernel/vtime.c | 18 +- arch/sh/kernel/vmlinux.lds.S | 1 + arch/sparc/kernel/vmlinux.lds.S | 1 + arch/um/kernel/dyn.lds.S | 1 + arch/um/kernel/uml.lds.S | 1 + arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/sev.c | 9 +- arch/x86/boot/compressed/vmlinux.lds.S | 2 +- arch/x86/boot/startup/sev-shared.c | 2 +- arch/x86/coco/sev/core.c | 1 + arch/x86/entry/entry_fred.c | 5 +- arch/x86/events/intel/uncore_snbep.c | 28 ++- arch/x86/include/asm/cfi.h | 12 +- arch/x86/include/asm/efi.h | 2 +- arch/x86/include/asm/kvm_host.h | 7 + arch/x86/include/asm/linkage.h | 4 +- arch/x86/include/asm/msr-index.h | 5 +- arch/x86/include/asm/numa.h | 6 + arch/x86/include/asm/topology.h | 6 + arch/x86/include/asm/traps.h | 2 + arch/x86/include/uapi/asm/kvm.h | 6 +- arch/x86/kernel/alternative.c | 29 ++- arch/x86/kernel/cpu/common.c | 3 + arch/x86/kernel/cpu/topology.c | 13 +- arch/x86/kernel/smpboot.c | 201 ++++++++++----- arch/x86/kernel/traps.c | 2 +- arch/x86/kernel/vmlinux.lds.S | 1 + arch/x86/kvm/ioapic.c | 2 +- arch/x86/kvm/lapic.c | 76 +++++- arch/x86/kvm/lapic.h | 2 + arch/x86/kvm/x86.c | 21 +- arch/x86/mm/extable.c | 7 +- arch/x86/mm/numa.c | 8 + arch/x86/mm/srat.c | 2 + arch/x86/net/bpf_jit_comp.c | 13 +- arch/x86/platform/efi/efi.c | 2 +- arch/x86/platform/efi/quirks.c | 55 +++- block/blk-sysfs.c | 8 +- block/elevator.c | 12 +- drivers/accel/amdxdna/aie2_ctx.c | 55 ++-- drivers/accel/amdxdna/aie2_message.c | 36 ++- drivers/accel/amdxdna/aie2_pci.c | 23 +- drivers/accel/amdxdna/aie2_pci.h | 1 + drivers/accel/amdxdna/aie2_pm.c | 2 +- drivers/accel/amdxdna/amdxdna_ctx.c | 51 +++- drivers/accel/amdxdna/amdxdna_ctx.h | 3 + drivers/accel/amdxdna/amdxdna_gem.c | 38 +-- drivers/accel/amdxdna/amdxdna_pm.c | 2 + drivers/accel/amdxdna/amdxdna_pm.h | 11 + drivers/accel/amdxdna/amdxdna_ubuf.c | 6 +- drivers/accel/ethosu/ethosu_gem.c | 7 +- drivers/accel/ethosu/ethosu_job.c | 26 +- drivers/accel/rocket/rocket_core.c | 7 +- drivers/accel/rocket/rocket_drv.c | 15 +- drivers/ata/libata-eh.c | 3 +- drivers/ata/libata-scsi.c | 1 + drivers/block/drbd/drbd_actlog.c | 53 ++-- drivers/block/drbd/drbd_interval.h | 5 +- drivers/block/drbd/drbd_req.c | 3 +- drivers/block/zloop.c | 31 ++- drivers/char/ipmi/ipmi_msghandler.c | 11 +- drivers/clk/imx/clk-imx8qxp.c | 24 +- drivers/clk/imx/clk-scu.c | 12 +- drivers/clk/imx/clk-scu.h | 2 + drivers/cpufreq/intel_pstate.c | 10 +- drivers/crypto/ccp/sev-dev-tsm.c | 2 +- drivers/cxl/core/mbox.c | 11 +- drivers/cxl/core/pmem.c | 42 +++- drivers/cxl/cxl.h | 7 + drivers/cxl/pmem.c | 22 +- drivers/firmware/efi/mokvar-table.c | 2 +- drivers/gpio/gpiolib-shared.c | 6 +- drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 17 +- drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c | 12 +- .../gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 8 +- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 6 +- .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 3 +- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 16 +- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 8 + .../gpu/drm/amd/display/dc/core/dc_stream.c | 2 +- drivers/gpu/drm/bridge/synopsys/dw-dp.c | 4 +- drivers/gpu/drm/drm_client_modeset.c | 3 +- drivers/gpu/drm/drm_syncobj.c | 4 +- drivers/gpu/drm/imx/ipuv3/parallel-display.c | 4 +- drivers/gpu/drm/logicvc/logicvc_drm.c | 4 +- drivers/gpu/drm/scheduler/sched_main.c | 1 + drivers/gpu/drm/solomon/ssd130x.c | 6 +- drivers/gpu/drm/tiny/sharp-memory.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 9 +- drivers/gpu/drm/xe/regs/xe_engine_regs.h | 6 + drivers/gpu/drm/xe/xe_configfs.c | 1 + drivers/gpu/drm/xe/xe_exec_queue.c | 23 +- drivers/gpu/drm/xe/xe_gsc_proxy.c | 43 +++- drivers/gpu/drm/xe/xe_gsc_types.h | 2 + drivers/gpu/drm/xe/xe_gt.c | 66 ++++- drivers/gpu/drm/xe/xe_lrc.h | 3 +- drivers/gpu/drm/xe/xe_reg_sr.c | 4 +- drivers/gpu/drm/xe/xe_ring_ops.c | 9 + drivers/hid/hid-cmedia.c | 2 +- drivers/hid/hid-creative-sb0540.c | 2 +- drivers/hid/hid-multitouch.c | 43 +++- drivers/hid/hid-zydacron.c | 2 +- drivers/hid/usbhid/hid-pidff.c | 11 +- drivers/hwmon/aht10.c | 6 +- drivers/hwmon/it87.c | 5 +- drivers/hwmon/macsmc-hwmon.c | 53 ++-- drivers/hwmon/max6639.c | 2 +- drivers/i2c/busses/i2c-i801.c | 14 +- .../infiniband/hw/ionic/ionic_controlpath.c | 2 +- drivers/infiniband/hw/irdma/verbs.c | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 5 +- drivers/irqchip/irq-ls-extirq.c | 6 +- drivers/irqchip/irq-sifive-plic.c | 7 +- drivers/media/dvb-core/dmxdev.c | 4 +- drivers/net/bonding/bond_main.c | 9 +- drivers/net/bonding/bond_options.c | 2 + drivers/net/can/dummy_can.c | 1 + drivers/net/can/spi/mcp251x.c | 15 +- drivers/net/can/usb/ems_usb.c | 7 +- drivers/net/can/usb/etas_es58x/es58x_core.c | 8 +- drivers/net/can/usb/f81604.c | 45 +++- drivers/net/can/usb/ucan.c | 2 +- drivers/net/dsa/realtek/rtl8365mb.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 10 - drivers/net/ethernet/amd/xgbe/xgbe-main.c | 1 - drivers/net/ethernet/amd/xgbe/xgbe.h | 3 - .../ethernet/freescale/dpaa2/dpaa2-switch.c | 3 +- drivers/net/ethernet/freescale/enetc/enetc.c | 2 +- drivers/net/ethernet/google/gve/gve_tx_dqo.c | 56 ++--- drivers/net/ethernet/intel/e1000e/defines.h | 1 + drivers/net/ethernet/intel/e1000e/ich8lan.c | 9 + drivers/net/ethernet/intel/i40e/i40e_main.c | 41 +-- drivers/net/ethernet/intel/i40e/i40e_trace.h | 2 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 5 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 17 +- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_base.c | 38 ++- drivers/net/ethernet/intel/ice/ice_common.c | 2 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 16 +- drivers/net/ethernet/intel/ice/ice_idc.c | 44 +++- drivers/net/ethernet/intel/ice/ice_lib.c | 15 +- drivers/net/ethernet/intel/ice/ice_main.c | 7 +- drivers/net/ethernet/intel/ice/ice_txrx.c | 4 +- drivers/net/ethernet/intel/ice/ice_xsk.c | 3 + .../net/ethernet/intel/idpf/idpf_ethtool.c | 3 - drivers/net/ethernet/intel/idpf/idpf_txrx.c | 8 +- drivers/net/ethernet/intel/igb/igb_xsk.c | 38 ++- drivers/net/ethernet/intel/igc/igc_main.c | 34 ++- drivers/net/ethernet/intel/igc/igc_ptp.c | 3 +- drivers/net/ethernet/intel/libie/fwlog.c | 4 + .../ethernet/marvell/octeon_ep/octep_main.c | 40 ++- .../net/ethernet/marvell/octeon_ep/octep_rx.c | 27 +- .../marvell/octeon_ep_vf/octep_vf_main.c | 38 ++- .../marvell/octeon_ep_vf/octep_vf_rx.c | 28 ++- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 15 +- drivers/net/ethernet/stmicro/stmmac/common.h | 1 - .../net/ethernet/stmicro/stmmac/dwmac-intel.c | 4 - .../ethernet/stmicro/stmmac/dwmac-loongson.c | 7 - drivers/net/ethernet/stmicro/stmmac/stmmac.h | 3 +- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 89 +++---- .../ethernet/stmicro/stmmac/stmmac_platform.c | 8 - .../net/ethernet/stmicro/stmmac/stmmac_vlan.c | 60 ++--- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 +- drivers/net/ethernet/ti/cpsw_ale.c | 9 +- drivers/net/ethernet/ti/icssg/icssg_prueth.c | 8 + drivers/net/phy/phy_device.c | 25 +- drivers/net/usb/kalmia.c | 7 + drivers/net/usb/kaweth.c | 13 + drivers/net/usb/pegasus.c | 13 +- drivers/net/vxlan/vxlan_core.c | 5 + drivers/net/wireless/marvell/libertas/main.c | 4 +- .../wireless/mediatek/mt76/mt76_connac_mac.c | 1 + .../net/wireless/mediatek/mt76/mt7925/mac.c | 1 + .../net/wireless/mediatek/mt76/mt7996/mac.c | 1 + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- drivers/net/wireless/st/cw1200/pm.c | 2 + drivers/net/wireless/ti/wlcore/main.c | 4 +- drivers/nfc/pn533/usb.c | 1 + drivers/nvme/host/core.c | 7 + drivers/nvme/host/multipath.c | 12 +- drivers/nvme/host/pr.c | 4 +- drivers/nvme/target/fcloop.c | 15 +- .../pci/controller/dwc/pcie-designware-ep.c | 25 +- drivers/pinctrl/cirrus/pinctrl-cs42l43.c | 5 +- drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 70 +++++- drivers/pinctrl/pinconf-generic.c | 73 +----- drivers/pinctrl/pinctrl-equilibrium.c | 31 ++- drivers/pinctrl/qcom/pinctrl-qcs615.c | 1 + .../platform/x86/dell/alienware-wmi-wmax.c | 2 +- drivers/platform/x86/dell/dell-wmi-base.c | 6 + .../dell-wmi-sysman/passwordattr-interface.c | 1 - .../x86/hp/hp-bioscfg/enum-attributes.c | 9 +- drivers/platform/x86/lenovo/thinkpad_acpi.c | 6 +- drivers/regulator/bq257xx-regulator.c | 3 +- drivers/regulator/fp9931.c | 7 +- drivers/regulator/mt6363-regulator.c | 4 +- drivers/scsi/lpfc/lpfc_init.c | 2 + drivers/scsi/lpfc/lpfc_sli.c | 36 ++- drivers/scsi/lpfc/lpfc_sli4.h | 3 + drivers/scsi/pm8001/pm8001_sas.c | 5 +- drivers/scsi/scsi_scan.c | 1 + drivers/spi/spi-stm32.c | 3 + drivers/target/target_core_configfs.c | 15 +- drivers/ufs/core/ufshcd.c | 38 ++- drivers/usb/gadget/function/f_ncm.c | 128 +++++----- drivers/usb/gadget/function/u_ether.c | 45 ++++ drivers/usb/gadget/function/u_ether.h | 30 +++ .../usb/gadget/function/u_ether_configfs.h | 176 +++++++++++++ drivers/usb/gadget/function/u_ncm.h | 4 +- drivers/xen/xen-acpi-processor.c | 7 +- fs/btrfs/delayed-inode.c | 2 +- fs/btrfs/disk-io.c | 6 +- fs/btrfs/inode.c | 2 +- fs/btrfs/ioctl.c | 7 +- fs/btrfs/scrub.c | 2 +- fs/btrfs/tree-checker.c | 4 +- fs/eventpoll.c | 5 +- fs/namespace.c | 20 +- fs/netfs/direct_write.c | 228 +++++++++++++++-- fs/netfs/internal.h | 4 +- fs/netfs/write_collect.c | 21 -- fs/netfs/write_issue.c | 41 +-- fs/nfsd/nfsctl.c | 2 +- fs/smb/client/connect.c | 1 - fs/smb/client/smb2inode.c | 8 +- fs/smb/client/smb2pdu.c | 24 +- fs/smb/client/transport.c | 21 +- fs/smb/server/Kconfig | 1 + fs/smb/server/auth.c | 4 +- fs/smb/server/smb2pdu.c | 5 +- fs/squashfs/cache.c | 3 + fs/xfs/scrub/orphanage.c | 7 +- fs/xfs/xfs_notify_failure.c | 4 +- include/asm-generic/vmlinux.lds.h | 4 +- include/linux/indirect_call_wrapper.h | 18 +- include/linux/netdevice.h | 27 +- include/linux/pinctrl/pinconf-generic.h | 5 - include/linux/ring_buffer.h | 1 + include/linux/sched.h | 1 + include/linux/stmmac.h | 1 - include/linux/tnum.h | 8 + include/linux/uaccess.h | 54 ++-- include/net/bonding.h | 1 + include/net/inet6_hashtables.h | 2 +- include/net/inet_hashtables.h | 2 +- include/net/ip.h | 2 +- include/net/ip_fib.h | 2 +- include/net/netfilter/nf_tables.h | 11 +- include/net/sch_generic.h | 10 + include/net/secure_seq.h | 45 +++- include/net/tc_act/tc_ife.h | 4 +- include/net/tcp.h | 6 +- include/net/xdp_sock_drv.h | 16 +- include/trace/events/netfs.h | 4 +- include/uapi/drm/drm_fourcc.h | 12 +- include/uapi/linux/pci_regs.h | 2 +- io_uring/cmd_net.c | 2 +- kernel/bpf/cpumap.c | 17 +- kernel/bpf/devmap.c | 47 +++- kernel/bpf/tnum.c | 72 ++++++ kernel/bpf/trampoline.c | 4 +- kernel/bpf/verifier.c | 103 +++++++- kernel/cgroup/cpuset.c | 4 +- kernel/events/core.c | 83 ++++-- kernel/module/main.c | 6 - kernel/rseq.c | 5 +- kernel/sched/ext_internal.h | 2 +- kernel/sched/fair.c | 238 +++++++++++++----- kernel/sched/sched.h | 4 +- kernel/sched/syscalls.c | 30 +++ kernel/time/jiffies.c | 2 - kernel/time/timekeeping.c | 6 +- kernel/trace/blktrace.c | 3 +- kernel/trace/ring_buffer.c | 21 ++ kernel/trace/trace.c | 13 + kernel/trace/trace_events_trigger.c | 3 + lib/Kconfig.debug | 1 + lib/debugobjects.c | 19 +- mm/huge_memory.c | 3 + mm/slub.c | 13 +- net/atm/lec.c | 26 +- net/bluetooth/hci_sock.c | 1 + net/bluetooth/hci_sync.c | 2 +- net/bluetooth/iso.c | 1 + net/bluetooth/l2cap_sock.c | 1 + net/bluetooth/sco.c | 1 + net/bridge/br_device.c | 2 +- net/bridge/br_input.c | 2 +- net/bridge/br_private.h | 10 + net/bridge/br_vlan_options.c | 26 +- net/can/bcm.c | 1 + net/core/dev.c | 7 +- net/core/devmem.c | 6 +- net/core/filter.c | 6 +- net/core/netpoll.c | 2 +- net/core/secure_seq.c | 80 +++--- net/core/skmsg.c | 14 +- net/ipv4/inet_hashtables.c | 8 +- net/ipv4/syncookies.c | 11 +- net/ipv4/sysctl_net_ipv4.c | 5 +- net/ipv4/tcp.c | 4 +- net/ipv4/tcp_bpf.c | 2 +- net/ipv4/tcp_diag.c | 2 +- net/ipv4/tcp_input.c | 38 ++- net/ipv4/tcp_ipv4.c | 37 ++- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/udp.c | 27 +- net/ipv4/udp_bpf.c | 2 +- net/ipv6/inet6_hashtables.c | 3 +- net/ipv6/route.c | 11 +- net/ipv6/syncookies.c | 11 +- net/ipv6/tcp_ipv6.c | 37 ++- net/mac80211/mesh.c | 3 + net/mac80211/mlme.c | 3 + net/mptcp/pm.c | 55 +++- net/mptcp/pm_kernel.c | 9 + net/netfilter/nf_tables_api.c | 66 +++-- net/netfilter/nft_set_hash.c | 1 + net/netfilter/nft_set_pipapo.c | 62 ++++- net/netfilter/nft_set_pipapo.h | 2 + net/netfilter/nft_set_rbtree.c | 79 ++---- net/nfc/nci/core.c | 30 ++- net/nfc/nci/data.c | 12 +- net/nfc/rawsock.c | 11 + net/rds/tcp.c | 14 +- net/sched/act_ife.c | 93 ++++--- net/sched/sch_ets.c | 12 +- net/sched/sch_fq.c | 1 + net/unix/af_unix.c | 8 +- net/wireless/core.c | 1 + net/wireless/radiotap.c | 4 +- net/xdp/xsk.c | 26 +- rust/kernel/kunit.rs | 8 + sound/hda/codecs/realtek/alc269.c | 13 +- sound/hda/codecs/side-codecs/cs35l56_hda.c | 2 +- sound/hda/controllers/intel.c | 2 + sound/soc/sdca/Kconfig | 2 + sound/soc/sdca/sdca_functions.c | 5 +- sound/soc/sdca/sdca_interrupts.c | 4 +- sound/usb/endpoint.c | 9 +- sound/usb/mixer_scarlett2.c | 10 +- sound/usb/qcom/qc_audio_offload.c | 2 +- sound/usb/quirks.c | 3 +- sound/usb/stream.c | 3 + sound/usb/usbaudio.h | 6 + sound/usb/validate.c | 2 +- tools/objtool/Makefile | 8 +- tools/testing/kunit/kunit_kernel.py | 6 +- tools/testing/kunit/kunit_tool_test.py | 26 ++ tools/testing/selftests/arm64/abi/hwcap.c | 4 +- .../testing/selftests/bpf/progs/dmabuf_iter.c | 2 +- .../selftests/bpf/progs/exceptions_assert.c | 34 +-- .../selftests/bpf/progs/verifier_scalar_ids.c | 56 +++-- .../testing/selftests/bpf/verifier/precise.c | 8 +- tools/testing/selftests/kselftest_harness.h | 7 +- .../testing/selftests/net/mptcp/mptcp_join.sh | 49 ++++ .../selftests/net/mptcp/simult_flows.sh | 11 +- 396 files changed, 4121 insertions(+), 1792 deletions(-)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 1/311 perf/core: Fix refcount bug and potential UAF in perf_mmap
From: Haocheng Yu <[email protected]>
commit 77de62ad3de3967818c3dbe656b7336ebee461d2 upstream.
Syzkaller reported a refcount_t: addition on 0; use-after-free warning in perf_mmap.
The issue is caused by a race condition between a failing mmap() setup and a concurrent mmap() on a dependent event (e.g., using output redirection).
In perf_mmap(), the ring_buffer (rb) is allocated and assigned to event->rb with the mmap_mutex held. The mutex is then released to perform map_range().
If map_range() fails, perf_mmap_close() is called to clean up. However, since the mutex was dropped, another thread attaching to this event (via inherited events or output redirection) can acquire the mutex, observe the valid event->rb pointer, and attempt to increment its reference count. If the cleanup path has already dropped the reference count to zero, this results in a use-after-free or refcount saturation warning.
Fix this by extending the scope of mmap_mutex to cover the map_range() call. This ensures that the ring buffer initialization and mapping (or cleanup on failure) happens atomically effectively, preventing other threads from accessing a half-initialized or dying ring buffer.
--- kernel/events/core.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-)
kernel/events/core.c +19 -19
@@ -7188,28 +7188,28 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ret =perf_mmap_aux (vma, event, nr_pages);if (ret)return ret; - } -/* -* Since pinned accounting is per vm we cannot allow fork() to copy our -* vma. -*/ -vm_flags_set (vma,VM_DONTCOPY |VM_DONTEXPAND |VM_DONTDUMP ); - vma->vm_ops = &perf_mmap_vmops; +/* +* Since pinned accounting is per vm we cannot allow fork() to copy our +* vma. +*/ +vm_flags_set (vma,VM_DONTCOPY |VM_DONTEXPAND |VM_DONTDUMP ); + vma->vm_ops = &perf_mmap_vmops; - mapped =get_mapped (event, event_mapped); -if (mapped) -mapped (event, vma->vm_mm); + mapped =get_mapped (event, event_mapped); +if (mapped) +mapped (event, vma->vm_mm); -/* -* Try to map it into the page table. On fail, invoke -* perf_mmap_close() to undo the above, as the callsite expects -* full cleanup in this case and therefore does not invoke -* vmops::close(). -*/ - ret =map_range (event->rb, vma); -if (ret) -perf_mmap_close (vma); +/* +* Try to map it into the page table. On fail, invoke +* perf_mmap_close() to undo the above, as the callsite expects +* full cleanup in this case and therefore does not invoke +* vmops::close(). +*/ + ret =map_range (event->rb, vma); +if (ret) +perf_mmap_close (vma); + }return ret; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/311 drm/vmwgfx: Fix invalid kref_put callback in vmw_bo_dirty_release
In reply to Sasha LevinFrom: Brad Spengler <[email protected]>
[ Upstream commit 211ecfaaef186ee5230a77d054cdec7fbfc6724a ]
The kref_put() call uses (void *)kvfree as the release callback, which is incorrect. kref_put() expects a function with signature void (*release)(struct kref *), but kvfree has signature void (*)(const void *). Calling through an incompatible function pointer is undefined behavior.
The code only worked by accident because ref_count is the first member of vmw_bo_dirty, making the kref pointer equal to the struct pointer.
Fix this by adding a proper release callback that uses container_of() to retrieve the containing structure before freeing.
--- drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c +8 -1
@@ -260,6 +260,13 @@ int vmw_bo_dirty_add(struct vmw_bo *vbo)return ret; } +static void vmw_bo_dirty_free (struct kref *kref) +{ + struct vmw_bo_dirty *dirty = container_of(kref, struct vmw_bo_dirty, ref_count); + +kvfree (dirty); +} +/** * vmw_bo_dirty_release - Release a dirty-tracking user from a buffer object * @vbo: The buffer object
@@ -274,7 +281,7 @@ void vmw_bo_dirty_release(struct vmw_bo *vbo) {struct vmw_bo_dirty *dirty = vbo->dirty; -if (dirty &&kref_put (&dirty->ref_count, (void *)kvfree)) +if (dirty &&kref_put (&dirty->ref_count, vmw_bo_dirty_free)) vbo->dirty =NULL ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 3/311 drm/vmwgfx: Return the correct value in vmw_translate_ptr functions
In reply to Sasha LevinFrom: Ian Forbes <[email protected]>
[ Upstream commit 5023ca80f9589295cb60735016e39fc5cc714243 ]
Before the referenced fixes these functions used a lookup function that returned a pointer. This was changed to another lookup function that returned an error code with the pointer becoming an out parameter.
The error path when the lookup failed was not changed to reflect this change and the code continued to return the PTR_ERR of the now uninitialized pointer. This could cause the vmw_translate_ptr functions to return success when they actually failed causing further uninitialized and OOB accesses.
--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +2 -2
@@ -1143,7 +1143,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, ret =vmw_user_bo_lookup (sw_context->filp, handle, &vmw_bo);if (ret !=0 ) {drm_dbg (&dev_priv->drm,"Could not find or use MOB buffer.\n" ); -return PTR_ERR (vmw_bo); +return ret; }vmw_bo_placement_set (vmw_bo,VMW_BO_DOMAIN_MOB ,VMW_BO_DOMAIN_MOB ); ret =vmw_validation_add_bo (sw_context->ctx, vmw_bo);
@@ -1199,7 +1199,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, ret =vmw_user_bo_lookup (sw_context->filp, handle, &vmw_bo);if (ret !=0 ) {drm_dbg (&dev_priv->drm,"Could not find or use GMR region.\n" ); -return PTR_ERR (vmw_bo); +return ret; }vmw_bo_placement_set (vmw_bo,VMW_BO_DOMAIN_GMR |VMW_BO_DOMAIN_VRAM ,VMW_BO_DOMAIN_GMR |VMW_BO_DOMAIN_VRAM );
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 4/311 debugobject: Make it work with deferred page initialization - again
In reply to Sasha LevinFrom: Thomas Gleixner <[email protected]>
[ Upstream commit fd3634312a04f336dcbfb481060219f0cd320738 ]
debugobjects uses __GFP_HIGH for allocations as it might be invoked within locked regions. That worked perfectly fine until v6.18. It still works correctly when deferred page initialization is disabled and works by chance when no page allocation is required before deferred page initialization has completed.
Since v6.18 allocations w/o a reclaim flag cause new_slab() to end up in alloc_frozen_pages_nolock_noprof(), which returns early when deferred page initialization has not yet completed. As the deferred page initialization takes quite a while the debugobject pool is depleted and debugobjects are disabled.
This can be worked around when PREEMPT_COUNT is enabled as that allows debugobjects to add __GFP_KSWAPD_RECLAIM to the GFP flags when the context is preemtible. When PREEMPT_COUNT is disabled the context is unknown and the reclaim bit can't be set because the caller might hold locks which might deadlock in the allocator.
In preemptible context the reclaim bit is harmless and not a performance issue as that's usually invoked from slow path initialization context.
That makes debugobjects depend on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT.
--- lib/Kconfig.debug | 1 + lib/debugobjects.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-)
lib/Kconfig.debug +1 -0
@@ -723,6 +723,7 @@ source "mm/Kconfig.debug" config DEBUG_OBJECTS bool "Debug object operations" + depends on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT depends on DEBUG_KERNEL help If you say Y here, additional code will be inserted into the
lib/debugobjects.c +18 -1
@@ -398,9 +398,26 @@ static void fill_pool(void)atomic_inc (&cpus_allocating);while (pool_should_refill (&pool_global)) { +gfp_t gfp = __GFP_HIGH | __GFP_NOWARN;HLIST_HEAD (head); -if (!kmem_alloc_batch (&head, obj_cache, __GFP_HIGH | __GFP_NOWARN)) +/* +* Allow reclaim only in preemptible context and during +* early boot. If not preemptible, the caller might hold +* locks causing a deadlock in the allocator. +* +* If the reclaim flag is not set during early boot then +* allocations, which happen before deferred page +* initialization has completed, will fail. +* +* In preemptible context the flag is harmless and not a +* performance issue as that's usually invoked from slow +* path initialization context. +*/ +if (preemptible () || system_state <SYSTEM_SCHEDULING ) + gfp |= __GFP_KSWAPD_RECLAIM; + +if (!kmem_alloc_batch (&head, obj_cache, gfp))break ;guard (raw_spinlock_irqsave)(&pool_lock);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 5/311 drm/logicvc: Fix device node reference leak in logicvc_drm_config_parse()
In reply to Sasha LevinFrom: Felix Gu <[email protected]>
[ Upstream commit fef0e649f8b42bdffe4a916dd46e1b1e9ad2f207 ]
The logicvc_drm_config_parse() function calls of_get_child_by_name() to find the "layers" node but fails to release the reference, leading to a device node reference leak.
Fix this by using the __free(device_node) cleanup attribute to automatic release the reference when the variable goes out of scope.
--- drivers/gpu/drm/logicvc/logicvc_drm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/logicvc/logicvc_drm.c +2 -2
@@ -92,7 +92,6 @@ static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)struct device *dev = drm_dev->dev;struct device_node *of_node = dev->of_node;struct logicvc_drm_config *config = &logicvc->config; -struct device_node *layers_node;int ret; logicvc_of_property_parse_bool(of_node, LOGICVC_OF_PROPERTY_DITHERING,
@@ -128,7 +127,8 @@ static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)if (ret)return ret; - layers_node =of_get_child_by_name (of_node,"layers" ); + struct device_node *layers_node __free(device_node) = +of_get_child_by_name (of_node,"layers" );if (!layers_node) {drm_err (drm_dev,"Missing non-optional layers node\n" );return -EINVAL ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 6/311 KVM: arm64: Hide S1POE from guests when not supported by the host
In reply to Sasha LevinFrom: Fuad Tabba <[email protected]>
[ Upstream commit f66857bafd4f151c5cc6856e47be2e12c1721e43 ]
When CONFIG_ARM64_POE is disabled, KVM does not save/restore POR_EL1. However, ID_AA64MMFR3_EL1 sanitisation currently exposes the feature to guests whenever the hardware supports it, ignoring the host kernel configuration.
If a guest detects this feature and attempts to use it, the host will fail to context-switch POR_EL1, potentially leading to state corruption.
Fix this by masking ID_AA64MMFR3_EL1.S1POE in the sanitised system registers, preventing KVM from advertising the feature when the host does not support it (i.e. system_supports_poe() is false).
--- arch/arm64/kvm/sys_regs.c | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kvm/sys_regs.c +3 -0
@@ -1816,6 +1816,9 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,ID_AA64MMFR3_EL1_SCTLRX |ID_AA64MMFR3_EL1_S1POE |ID_AA64MMFR3_EL1_S1PIE ; + +if (!system_supports_poe ()) + val &= ~ID_AA64MMFR3_EL1_S1POE ;break ;case SYS_ID_MMFR4_EL1 : val &= ~ID_MMFR4_EL1_CCIDX ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 7/311 KVM: arm64: Fix ID register initialization for non-protected pKVM guests
In reply to Sasha LevinFrom: Fuad Tabba <[email protected]>
[ Upstream commit 7e7c2cf0024d89443a7af52e09e47b1fe634ab17 ]
In protected mode, the hypervisor maintains a separate instance of the kvm structure for each VM. For non-protected VMs, this structure is initialized from the host's kvm state.
Currently, pkvm_init_features_from_host() copies the KVM_ARCH_FLAG_ID_REGS_INITIALIZED flag from the host without the underlying id_regs data being initialized. This results in the hypervisor seeing the flag as set while the ID registers remain zeroed.
Consequently, kvm_has_feat() checks at EL2 fail (return 0) for non-protected VMs. This breaks logic that relies on feature detection, such as ctxt_has_tcrx() for TCR2_EL1 support. As a result, certain system registers (e.g., TCR2_EL1, PIR_EL1, POR_EL1) are not saved/restored during the world switch, which could lead to state corruption.
Fix this by explicitly copying the ID registers from the host kvm to the hypervisor kvm for non-protected VMs during initialization, since we trust the host with its non-protected guests' features. Also ensure KVM_ARCH_FLAG_ID_REGS_INITIALIZED is cleared initially in pkvm_init_features_from_host so that vm_copy_id_regs can properly initialize them and set the flag once done.
--- arch/arm64/kvm/hyp/nvhe/pkvm.c | 35 ++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +33 -2
@@ -345,6 +345,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc/* No restrictions for non-protected VMs. */ if (!kvm_vm_is_protected (kvm)) { hyp_vm->kvm.arch.flags = host_arch_flags; + hyp_vm->kvm.arch.flags &= ~BIT_ULL (KVM_ARCH_FLAG_ID_REGS_INITIALIZED ); bitmap_copy(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
@@ -471,6 +472,35 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *hreturn ret; } +static int vm_copy_id_regs (struct pkvm_hyp_vcpu *hyp_vcpu) +{ +struct pkvm_hyp_vm *hyp_vm =pkvm_hyp_vcpu_to_hyp_vm (hyp_vcpu); +const struct kvm *host_kvm = hyp_vm->host_kvm; +struct kvm *kvm = &hyp_vm->kvm; + +if (!test_bit (KVM_ARCH_FLAG_ID_REGS_INITIALIZED , &host_kvm->arch.flags)) +return -EINVAL ; + +if (test_and_set_bit (KVM_ARCH_FLAG_ID_REGS_INITIALIZED , &kvm->arch.flags)) +return 0 ; + +memcpy (kvm->arch.id_regs, host_kvm->arch.id_regs,sizeof (kvm->arch.id_regs)); + +return 0 ; +} + +static int pkvm_vcpu_init_sysregs (struct pkvm_hyp_vcpu *hyp_vcpu) +{ +int ret =0 ; + +if (pkvm_hyp_vcpu_is_protected (hyp_vcpu)) +kvm_init_pvm_id_regs (&hyp_vcpu->vcpu); +else + ret =vm_copy_id_regs (hyp_vcpu); + +return ret; +} +static int init_pkvm_hyp_vcpu (struct pkvm_hyp_vcpu *hyp_vcpu,struct pkvm_hyp_vm *hyp_vm,struct kvm_vcpu *host_vcpu)
@@ -490,8 +520,9 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, hyp_vcpu->vcpu.arch.cflags =READ_ONCE (host_vcpu->arch.cflags); hyp_vcpu->vcpu.arch.mp_state.mp_state =KVM_MP_STATE_STOPPED ; -if (pkvm_hyp_vcpu_is_protected (hyp_vcpu)) -kvm_init_pvm_id_regs (&hyp_vcpu->vcpu); + ret =pkvm_vcpu_init_sysregs (hyp_vcpu); +if (ret) + goto done; ret =pkvm_vcpu_init_traps (hyp_vcpu);if (ret)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 8/311 drm/fourcc: fix plane order for 10/12/16-bit YCbCr formats
In reply to Sasha LevinFrom: Simon Ser <[email protected]>
[ Upstream commit e9e0b48cd15b46dcb2bbc165f6b0fee698b855d6 ]
The short comments had the correct order, but the long comments had the planes reversed.
--- include/uapi/drm/drm_fourcc.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
include/uapi/drm/drm_fourcc.h +6 -6
@@ -401,8 +401,8 @@ extern "C" {* implementation can multiply the values by 2^6=64. For that reason the padding * must only contain zeros. * index 0 = Y plane, [15:0] z:Y [6:10] little endian -* index 1 = Cr plane, [15:0] z:Cr [6:10] little endian -* index 2 = Cb plane, [15:0] z:Cb [6:10] little endian +* index 1 = Cb plane, [15:0] z:Cb [6:10] little endian +* index 2 = Cr plane, [15:0] z:Cr [6:10] little endian */ #define DRM_FORMAT_S010 fourcc_code('S', '0', '1', '0')/* 2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel */ #define DRM_FORMAT_S210 fourcc_code('S', '2', '1', '0')/* 2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel */
@@ -414,8 +414,8 @@ extern "C" {* implementation can multiply the values by 2^4=16. For that reason the padding * must only contain zeros. * index 0 = Y plane, [15:0] z:Y [4:12] little endian -* index 1 = Cr plane, [15:0] z:Cr [4:12] little endian -* index 2 = Cb plane, [15:0] z:Cb [4:12] little endian +* index 1 = Cb plane, [15:0] z:Cb [4:12] little endian +* index 2 = Cr plane, [15:0] z:Cr [4:12] little endian */ #define DRM_FORMAT_S012 fourcc_code('S', '0', '1', '2')/* 2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel */ #define DRM_FORMAT_S212 fourcc_code('S', '2', '1', '2')/* 2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel */
@@ -424,8 +424,8 @@ extern "C" {/* * 3 plane YCbCr * index 0 = Y plane, [15:0] Y little endian -* index 1 = Cr plane, [15:0] Cr little endian -* index 2 = Cb plane, [15:0] Cb little endian +* index 1 = Cb plane, [15:0] Cb little endian +* index 2 = Cr plane, [15:0] Cr little endian */ #define DRM_FORMAT_S016 fourcc_code('S', '0', '1', '6')/* 2x2 subsampled Cb (1) and Cr (2) planes 16 bits per channel */ #define DRM_FORMAT_S216 fourcc_code('S', '2', '1', '6')/* 2x1 subsampled Cb (1) and Cr (2) planes 16 bits per channel */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 9/311 drm/tiny: sharp-memory: fix pointer error dereference
In reply to Sasha LevinFrom: Ethan Tidmore <[email protected]>
[ Upstream commit 46120745bb4e7e1f09959624716b4c5d6e2c2e9e ]
The function devm_drm_dev_alloc() returns a pointer error upon failure not NULL. Change null check to pointer error check.
Detected by Smatch:drivers/gpu/drm/tiny/sharp-memory.c:549 sharp_memory_probe() error:
'smd' dereferencing possible ERR_PTR()
--- drivers/gpu/drm/tiny/sharp-memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/tiny/sharp-memory.c +2 -2
@@ -541,8 +541,8 @@ static int sharp_memory_probe(struct spi_device *spi) smd =devm_drm_dev_alloc (dev, &sharp_memory_drm_driver, struct sharp_memory_device, drm); -if (!smd) -return -ENOMEM ; +if (IS_ERR (smd)) +return PTR_ERR (smd);spi_set_drvdata (spi, smd);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 10/311 irqchip/sifive-plic: Fix frozen interrupt due to affinity setting
In reply to Sasha LevinFrom: Nam Cao <[email protected]>
[ Upstream commit 1072020685f4b81f6efad3b412cdae0bd62bb043 ]
PLIC ignores interrupt completion message for disabled interrupt, explained by the specification:
The PLIC signals it has completed executing an interrupt handler by writing the interrupt ID it received from the claim to the claim/complete register. The PLIC does not check whether the completion ID is the same as the last claim ID for that target. If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored.
This caused problems in the past, because an interrupt can be disabled while still being handled and plic_irq_eoi() had no effect. That was fixed by checking if the interrupt is disabled, and if so enable it, before sending the completion message. That check is done with irqd_irq_disabled().
However, that is not sufficient because the enable bit for the handling hart can be zero despite irqd_irq_disabled(d) being false. This can happen when affinity setting is changed while a hart is still handling the interrupt.
This problem is easily reproducible by dumping a large file to uart (which generates lots of interrupts) and at the same time keep changing the uart interrupt's affinity setting. The uart port becomes frozen almost instantaneously.
Fix this by checking PLIC's enable bit instead of irqd_irq_disabled().
--- drivers/irqchip/irq-sifive-plic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/irqchip/irq-sifive-plic.c +6 -1
@@ -172,8 +172,13 @@ static void plic_irq_disable(struct irq_data *d)static void plic_irq_eoi (struct irq_data *d) {struct plic_handler *handler =this_cpu_ptr (&plic_handlers); +u32 __iomem *reg; +bool enabled; + + reg = handler->enable_base + (d->hwirq /32 ) *sizeof (u32); + enabled =readl (reg) &BIT (d->hwirq %32 ); -if (unlikely (irqd_irq_disabled (d))) { +if (unlikely (!enabled)) {plic_toggle (handler, d->hwirq,1 );writel (d->hwirq, handler->hart_base +CONTEXT_CLAIM );plic_toggle (handler, d->hwirq,0 );
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 11/311 scsi: lpfc: Properly set WC for DPP mapping
In reply to Sasha LevinFrom: Mathias Krause <[email protected]>
[ Upstream commit bffda93a51b40afd67c11bf558dc5aae83ca0943 ]
Using set_memory_wc() to enable write-combining for the DPP portion of the MMIO mapping is wrong as set_memory_*() is meant to operate on RAM only, not MMIO mappings. In fact, as used currently triggers a BUG_ON() with enabled CONFIG_DEBUG_VIRTUAL.
Simply map the DPP region separately and in addition to the already existing mappings, avoiding any possible negative side effects for these.
--- drivers/scsi/lpfc/lpfc_init.c | 2 ++ drivers/scsi/lpfc/lpfc_sli.c | 36 +++++++++++++++++++++++++++++------ drivers/scsi/lpfc/lpfc_sli4.h | 3 +++ 3 files changed, 35 insertions(+), 6 deletions(-)
drivers/scsi/lpfc/lpfc_init.c +2 -0
@@ -12034,6 +12034,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)iounmap (phba->sli4_hba.conf_regs_memmap_p);if (phba->sli4_hba.dpp_regs_memmap_p)iounmap (phba->sli4_hba.dpp_regs_memmap_p); +if (phba->sli4_hba.dpp_regs_memmap_wc_p) +iounmap (phba->sli4_hba.dpp_regs_memmap_wc_p);break ;case LPFC_SLI_INTF_IF_TYPE_1 :break ;
drivers/scsi/lpfc/lpfc_sli.c +30 -6
@@ -15981,6 +15981,32 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)return NULL ; } +static __maybe_unused void __iomem * +lpfc_dpp_wc_map (struct lpfc_hba *phba,uint8_t dpp_barset) +{ + +/* DPP region is supposed to cover 64-bit BAR2 */ +if (dpp_barset !=WQ_PCI_BAR_4_AND_5 ) { +lpfc_log_msg (phba,KERN_WARNING ,LOG_INIT , +"3273 dpp_barset x%x != WQ_PCI_BAR_4_AND_5\n" , + dpp_barset); +return NULL ; + } + +if (!phba->sli4_hba.dpp_regs_memmap_wc_p) { +void __iomem *dpp_map; + + dpp_map =ioremap_wc (phba->pci_bar2_map, +pci_resource_len (phba->pcidev, +PCI_64BIT_BAR4 )); + +if (dpp_map) + phba->sli4_hba.dpp_regs_memmap_wc_p = dpp_map; + } + +return phba->sli4_hba.dpp_regs_memmap_wc_p; +} +/** * lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs * @phba: HBA structure that EQs are on.
@@ -16944,9 +16970,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,uint8_t dpp_barset;uint32_t dpp_offset;uint8_t wq_create_version; -#ifdef CONFIG_X86 -unsigned long pg_addr; -#endif /* sanity check on queue memory */ if (!wq || !cq)
@@ -17132,14 +17155,15 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,#ifdef CONFIG_X86 /* Enable combined writes for DPP aperture */ - pg_addr = (unsigned long )(wq->dpp_regaddr) &PAGE_MASK ; - rc =set_memory_wc (pg_addr,1 ); -if (rc) { + bar_memmap_p =lpfc_dpp_wc_map (phba, dpp_barset); +if (!bar_memmap_p) {lpfc_printf_log (phba,KERN_ERR ,LOG_INIT ,"3272 Cannot setup Combined " "Write on WQ[%d] - disable DPP\n" , wq->queue_id); phba->cfg_enable_dpp =0 ; + }else { + wq->dpp_regaddr = bar_memmap_p + dpp_offset; }#else phba->cfg_enable_dpp =0 ;
drivers/scsi/lpfc/lpfc_sli4.h +3 -0
@@ -785,6 +785,9 @@ struct lpfc_sli4_hba {void __iomem *dpp_regs_memmap_p;/* Kernel memory mapped address for * dpp registers */ +void __iomem *dpp_regs_memmap_wc_p;/* Kernel memory mapped address for +* dpp registers with write combining +*/ union { struct { /* IF Type 0, BAR 0 PCI cfg space reg mem map */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 12/311 scsi: pm8001: Fix use-after-free in pm8001_queue_command()
In reply to Sasha LevinFrom: Salomon Dushimirimana <[email protected]>
[ Upstream commit 38353c26db28efd984f51d426eac2396d299cca7 ]
Commit e29c47fe8946 ("scsi: pm8001: Simplify pm8001_task_exec()") refactors pm8001_queue_command(), however it introduces a potential cause of a double free scenario when it changes the function to return -ENODEV in case of phy down/device gone state.
In this path, pm8001_queue_command() updates task status and calls task_done to indicate to upper layer that the task has been handled. However, this also frees the underlying SAS task. A -ENODEV is then returned to the caller. When libsas sas_ata_qc_issue() receives this error value, it assumes the task wasn't handled/queued by LLDD and proceeds to clean up and free the task again, resulting in a double free.
Since pm8001_queue_command() handles the SAS task in this case, it should return 0 to the caller indicating that the task has been handled.
--- drivers/scsi/pm8001/pm8001_sas.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_sas.c +3 -2
@@ -525,8 +525,9 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) }else { task->task_done (task); } - rc = -ENODEV ; - goto err_out; +spin_unlock_irqrestore (&pm8001_ha->lock, flags); +pm8001_dbg (pm8001_ha,IO ,"pm8001_task_exec device gone\n" ); +return 0 ; } ccb =pm8001_ccb_alloc (pm8001_ha, pm8001_dev, task);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 13/311 accel: ethosu: Fix shift overflow in cmd_to_addr()
In reply to Sasha LevinFrom: Dan Carpenter <[email protected]>
[ Upstream commit 7be41fb00e2c2a823f271a8318b453ca11812f1e ]
The "((cmd[0] & 0xff0000) << 16)" shift is zero. This was intended to be (((u64)cmd[0] & 0xff0000) << 16). Move the cast to the correct location.
--- drivers/accel/ethosu/ethosu_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/accel/ethosu/ethosu_gem.c +1 -1
@@ -154,7 +154,7 @@ static void cmd_state_init(struct cmd_state *st)static u64 cmd_to_addr (u32 *cmd) { -return ((u64)((cmd[0 ] &0xff0000 ) <<16 )) | cmd[1 ]; +return (((u64 )cmd[0 ] &0xff0000 ) <<16 ) | cmd[1 ]; } static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 14/311 drm/imx: parallel-display: check return value of devm_drm_bridge_add() in imx_pd_probe()
In reply to Sasha LevinFrom: Chen Ni <[email protected]>
[ Upstream commit c5f8658f97ec392eeaf355d4e9775ae1f23ca1d3 ]
Return the value of devm_drm_bridge_add() in order to propagate the error properly, if it fails due to resource allocation failure or bridge registration failure.
This ensures that the probe function fails safely rather than proceeding with a potentially incomplete bridge setup.
--- drivers/gpu/drm/imx/ipuv3/parallel-display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/imx/ipuv3/parallel-display.c +3 -1
@@ -256,7 +256,9 @@ static int imx_pd_probe(struct platform_device *pdev)platform_set_drvdata (pdev, imxpd); -devm_drm_bridge_add (dev, &imxpd->bridge); + ret =devm_drm_bridge_add (dev, &imxpd->bridge); +if (ret) +return ret;return component_add (dev, &imx_pd_ops); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 15/311 drm/bridge: synopsys: dw-dp: Check return value of devm_drm_bridge_add() in dw_dp_bind()
In reply to Sasha LevinFrom: Chen Ni <[email protected]>
[ Upstream commit 496daa2759260374bb9c9b2196a849aa3bc513a8 ]
Return the value of devm_drm_bridge_add() in order to propagate the error properly, if it fails due to resource allocation failure or bridge registration failure.
This ensures that the bind function fails safely rather than proceeding with a potentially incomplete bridge setup.
--- drivers/gpu/drm/bridge/synopsys/dw-dp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/synopsys/dw-dp.c +3 -1
@@ -2049,7 +2049,9 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder, bridge->type = DRM_MODE_CONNECTOR_DisplayPort; bridge->ycbcr_420_allowed = true; -devm_drm_bridge_add (dev, bridge); + ret =devm_drm_bridge_add (dev, bridge); +if (ret) +return ERR_PTR (ret); dp->aux.dev = dev; dp->aux.drm_dev = encoder->dev;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 16/311 ALSA: scarlett2: Fix DSP filter control array handling
In reply to Sasha LevinFrom: "Geoffrey D. Bennett" <[email protected]>
[ Upstream commit 1d241483368f2fd87fbaba64d6aec6bad3a1e12e ]
scarlett2_add_dsp_ctls() was incorrectly storing the precomp and PEQ filter coefficient control pointers into the precomp_flt_switch_ctls and peq_flt_switch_ctls arrays instead of the intended targets precomp_flt_ctls and peq_flt_ctls. Pass NULL instead, as the filter coefficient control pointers are not used, and remove the unused precomp_flt_ctls and peq_flt_ctls arrays from struct scarlett2_data.
Additionally, scarlett2_update_filter_values() was reading dsp_input_count * peq_flt_count values for SCARLETT2_CONFIG_PEQ_FLT_SWITCH, but the peq_flt_switch array is indexed only by dsp_input_count (one switch per DSP input, not per filter). Fix the read count.
--- sound/usb/mixer_scarlett2.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
sound/usb/mixer_scarlett2.c +3 -7
@@ -1328,8 +1328,6 @@ struct scarlett2_data {struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX ];struct snd_kcontrol *mix_ctls[SCARLETT2_MIX_MAX ];struct snd_kcontrol *compressor_ctls[SCARLETT2_COMPRESSOR_CTLS_MAX ]; -struct snd_kcontrol *precomp_flt_ctls[SCARLETT2_PRECOMP_FLT_CTLS_MAX ]; -struct snd_kcontrol *peq_flt_ctls[SCARLETT2_PEQ_FLT_CTLS_MAX ];struct snd_kcontrol *precomp_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX ];struct snd_kcontrol *peq_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX ];struct snd_kcontrol *direct_monitor_ctl;
@@ -3447,7 +3445,6 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) private->autogain_status[i] = private->num_autogain_status_texts -1 ; -for (i =0 ; i <SCARLETT2_AG_TARGET_COUNT ; i++)if (scarlett2_has_config_item (private, scarlett2_ag_target_configs[i])) {
@@ -5372,8 +5369,7 @@ static int scarlett2_update_filter_values(struct usb_mixer_interface *mixer) err =scarlett2_usb_get_config ( mixer,SCARLETT2_CONFIG_PEQ_FLT_SWITCH , - info->dsp_input_count * info->peq_flt_count, - private->peq_flt_switch); + info->dsp_input_count, private->peq_flt_switch);if (err <0 )return err;
@@ -6546,7 +6542,7 @@ static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i) err =scarlett2_add_new_ctl ( mixer, &scarlett2_precomp_flt_ctl, i * info->precomp_flt_count + j, -1 , s, &private->precomp_flt_switch_ctls[j]); +1 , s,NULL );if (err <0 )return err; }
@@ -6556,7 +6552,7 @@ static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i) err =scarlett2_add_new_ctl ( mixer, &scarlett2_peq_flt_ctl, i * info->peq_flt_count + j, -1 , s, &private->peq_flt_switch_ctls[j]); +1 , s,NULL );if (err <0 )return err; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 17/311 ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
In reply to Sasha LevinFrom: "Geoffrey D. Bennett" <[email protected]>
[ Upstream commit a8cc55bf81a45772cad44c83ea7bb0e98431094a ]
Remove QUIRK_FLAG_VALIDATE_RATES for Focusrite. With the previous commit, focusrite_valid_sample_rate() produces correct rate tables without USB probing.
QUIRK_FLAG_VALIDATE_RATES sends SET_CUR requests for each rate (~25ms each) and leaves the device at 192kHz. This is a problem because that
rate: 1) disables the internal mixer, so outputs are silent until an application opens the PCM and sets a lower rate, and 2) the Air and Safe modes get disabled.
--- sound/usb/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/quirks.c +1 -1
@@ -2422,7 +2422,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {VENDOR_FLG (0x07fd ,/* MOTU */ QUIRK_FLAG_VALIDATE_RATES ),VENDOR_FLG (0x1235 ,/* Focusrite Novation */ -QUIRK_FLAG_VALIDATE_RATES ), +0 ),VENDOR_FLG (0x1511 ,/* AURALiC */ QUIRK_FLAG_DSD_RAW ), VENDOR_FLG(0x152a, /* Thesycon devices */
Signature · 1 line
2.51.0
Re: [PATCH 6.19 017/311] ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
Quoted 7 lines · Sasha Levin
From: "Geoffrey D. Bennett" <[email protected]>
[ Upstream commit
a8cc55bf81a45772cad44c83ea7bb0e98431094a]Remove
QUIRK_FLAG_VALIDATE_RATESfor Focusrite. With the previous commit,focusrite_valid_sample_rate()produces correct rate tables without USB probing.
[...]
Hi Sasha, Greg,
This commit depends on its predecessor 24d2d3c5f940 ("ALSA: usb-audio:
Improve Focusrite sample rate filtering") which was not picked up for stable because it didn't have a Fixes tag.
Without the rate filtering patch, the Focusrite Scarlett 18i8 3rd Gen gets all sample rates advertised on every altsetting instead of the correct per-altsetting subset. I've confirmed this on 6.19.7.
Could 24d2d3c5f940 be queued for stable please?
Thanks,
Geoffrey.
Sasha Levin
maintainerPATCH 18/311 ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP
In reply to Sasha LevinFrom: "Geoffrey D. Bennett" <[email protected]>
[ Upstream commit 38c322068a26a01d7ff64da92179e68cdde9860b ]
Add a quirk flag to skip the usb_set_interface(), snd_usb_init_pitch(), and snd_usb_init_sample_rate() calls in __snd_usb_parse_audio_interface(). These are redundant with snd_usb_endpoint_prepare() at stream-open time.
Enable the quirk for Focusrite devices, as init_sample_rate(rate_max) sets 192kHz during probing, which disables the internal mixer and Air and Safe modes.
--- sound/usb/quirks.c | 3 ++- sound/usb/stream.c | 3 +++ sound/usb/usbaudio.h | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-)
sound/usb/quirks.c +2 -1
@@ -2422,7 +2422,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {VENDOR_FLG (0x07fd ,/* MOTU */ QUIRK_FLAG_VALIDATE_RATES ),VENDOR_FLG (0x1235 ,/* Focusrite Novation */ -0 ), +QUIRK_FLAG_SKIP_IFACE_SETUP ),VENDOR_FLG (0x1511 ,/* AURALiC */ QUIRK_FLAG_DSD_RAW ), VENDOR_FLG(0x152a, /* Thesycon devices */
@@ -2504,6 +2504,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {QUIRK_STRING_ENTRY (MIC_RES_384 ),QUIRK_STRING_ENTRY (MIXER_PLAYBACK_MIN_MUTE ),QUIRK_STRING_ENTRY (MIXER_CAPTURE_MIN_MUTE ), +QUIRK_STRING_ENTRY (SKIP_IFACE_SETUP ), NULL };
sound/usb/stream.c +3 -0
@@ -1259,6 +1259,9 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, set_iface_first = true;/* try to set the interface... */ +if (chip->quirk_flags &QUIRK_FLAG_SKIP_IFACE_SETUP ) +continue ; +usb_set_interface (chip->dev, iface_no,0 );if (set_iface_first)usb_set_interface (chip->dev, iface_no, altno);
sound/usb/usbaudio.h +6 -0
@@ -224,6 +224,10 @@ extern bool snd_usb_skip_validation;* playback value represents muted state instead of minimum audible volume * QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE * Similar to QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE, but for capture streams +* QUIRK_FLAG_SKIP_IFACE_SETUP +* Skip the probe-time interface setup (usb_set_interface, +* init_pitch, init_sample_rate); redundant with +* snd_usb_endpoint_prepare() at stream-open time */ enum {
@@ -253,6 +257,7 @@ enum {QUIRK_TYPE_MIC_RES_384 =23 ,QUIRK_TYPE_MIXER_PLAYBACK_MIN_MUTE =24 ,QUIRK_TYPE_MIXER_CAPTURE_MIN_MUTE =25 , + QUIRK_TYPE_SKIP_IFACE_SETUP = 26, /* Please also edit snd_usb_audio_quirk_flag_names */ };
@@ -284,5 +289,6 @@ enum {#define QUIRK_FLAG_MIC_RES_384 QUIRK_FLAG(MIC_RES_384)#define QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE QUIRK_FLAG(MIXER_PLAYBACK_MIN_MUTE)#define QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE QUIRK_FLAG(MIXER_CAPTURE_MIN_MUTE) +#define QUIRK_FLAG_SKIP_IFACE_SETUP QUIRK_FLAG(SKIP_IFACE_SETUP)#endif /* __USBAUDIO_H */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 19/311 gpio: shared: fix memory leaks
In reply to Sasha LevinFrom: Daniel J Blueman <[email protected]>
[ Upstream commit 32e0a7ad9c841f46549ccac0f1cca347a40d8685 ]
On a Snapdragon X1 Elite laptop (Lenovo Yoga Slim 7x), kmemleak reports three sets of:
unreferenced object 0xffff00080187f400 (size 1024):
comm "swapper/0", pid 1, jiffies 4294667327 hex dump (first 32 bytes):
58 bd 70 01 08 00 ff ff 58 bd 70 01 08 00 ff ff X.p.....X.p.....
00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
backtrace (crc 1665d1f8):
kmemleak_alloc+0xf4/0x12c
__kmalloc_cache_noprof+0x370/0x49c
gpio_shared_make_ref+0x70/0x16c
gpio_shared_of_traverse+0x4e8/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_init+0x34/0x1c4
do_one_initcall+0x50/0x280
kernel_init_freeable+0x290/0x33c
kernel_init+0x28/0x14c
ret_from_fork+0x10/0x20unreferenced object 0xffff00080170c140 (size 8):
comm "swapper/0", pid 1, jiffies 4294667327
hex dump (first 8 bytes):
72 65 73 65 74 00 00 00 reset...
backtrace (crc fc24536):
kmemleak_alloc+0xf4/0x12c
__kmalloc_node_track_caller_noprof+0x3c4/0x584
kstrdup+0x4c/0xcc
gpio_shared_make_ref+0x8c/0x16c
gpio_shared_of_traverse+0x4e8/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_of_traverse+0x200/0x5f4
gpio_shared_init+0x34/0x1c4
do_one_initcall+0x50/0x280
kernel_init_freeable+0x290/0x33c
kernel_init+0x28/0x14c
ret_from_fork+0x10/0x20Fix this by decrementing the reference count of each list entry rather than only the first.
Fix verified on the same laptop.
--- drivers/gpio/gpiolib-shared.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-shared.c +3 -3
@@ -753,14 +753,14 @@ static bool gpio_shared_entry_is_really_shared(struct gpio_shared_entry *entry)static void gpio_shared_free_exclusive (void ) {struct gpio_shared_entry *entry, *epos; +struct gpio_shared_ref *ref, *rpos;list_for_each_entry_safe (entry, epos, &gpio_shared_list, list) {if (gpio_shared_entry_is_really_shared (entry))continue ; -gpio_shared_drop_ref (list_first_entry (&entry->refs, - struct gpio_shared_ref, - list)); +list_for_each_entry_safe (ref, rpos, &entry->refs, list) +gpio_shared_drop_ref (ref);gpio_shared_drop_entry (entry); } }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 20/311 x86/fred: Correct speculative safety in fred_extint()
In reply to Sasha LevinFrom: Andrew Cooper <[email protected]>
[ Upstream commit aa280a08e7d8fae58557acc345b36b3dc329d595 ]
array_index_nospec() is no use if the result gets spilled to the stack, as it makes the believed safe-under-speculation value subject to memory predictions.
For all practical purposes, this means array_index_nospec() must be used in the expression that accesses the array.
As the code currently stands, it's the wrong side of irqentry_enter(), and 'index' is put into %ebp across the function call.
Remove the index variable and reposition array_index_nospec(), so it's calculated immediately before the array access.
--- arch/x86/entry/entry_fred.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
arch/x86/entry/entry_fred.c +2 -3
@@ -159,8 +159,6 @@ void __init fred_complete_exception_setup(void) static noinstr void fred_extint(struct pt_regs *regs) {unsigned int vector = regs->fred_ss.vector; -unsigned int index =array_index_nospec (vector -FIRST_SYSTEM_VECTOR , -NR_SYSTEM_VECTORS );if (WARN_ON_ONCE (vector <FIRST_EXTERNAL_VECTOR ))return ;
@@ -169,7 +167,8 @@ static noinstr void fred_extint(struct pt_regs *regs)irqentry_state_t state =irqentry_enter (regs);instrumentation_begin (); - sysvec_table[index](regs); + sysvec_table[array_index_nospec (vector -FIRST_SYSTEM_VECTOR , +NR_SYSTEM_VECTORS )](regs);instrumentation_end ();irqentry_exit (regs, state); }else {
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 21/311 x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
In reply to Sasha LevinFrom: Hou Wenlong <[email protected]>
[ Upstream commit a0cb371b521dde44f32cfe954b6ef6f82b407393 ]
The commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()") implemented __WARN_printf(), which changed the mechanism to use UD1 instead of UD2. However, it only handles the trap in the runtime IDT handler, while the early booting IDT handler lacks this handling. As a result, the usage of WARN() before the runtime IDT setup can lead to kernel crashes. Since KMSAN is enabled after the runtime IDT setup, it is safe to use handle_bug() directly in early_fixup_exception() to address this issue.
--- arch/x86/include/asm/traps.h | 2 ++ arch/x86/kernel/traps.c | 2 +- arch/x86/mm/extable.c | 7 ++----- 3 files changed, 5 insertions(+), 6 deletions(-)
arch/x86/include/asm/traps.h +2 -0
@@ -25,6 +25,8 @@ extern int ibt_selftest_noendbr(void);void handle_invalid_op (struct pt_regs *regs);#endif +noinstr bool handle_bug(struct pt_regs *regs); +static inline int get_si_code (unsigned long condition) {if (condition &DR_STEP )
arch/x86/kernel/traps.c +1 -1
@@ -397,7 +397,7 @@ static inline void handle_invalid_op(struct pt_regs *regs) ILL_ILLOPN, error_get_trap_addr(regs)); } -static noinstr bool handle_bug(struct pt_regs *regs) +noinstr bool handle_bug(struct pt_regs *regs) {unsigned long addr = regs->ip;bool handled = false;
arch/x86/mm/extable.c +2 -5
@@ -411,14 +411,11 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)return ;if (trapnr ==X86_TRAP_UD ) { -if (report_bug (regs->ip, regs) ==BUG_TRAP_TYPE_WARN ) { -/* Skip the ud2. */ - regs->ip +=LEN_UD2 ; +if (handle_bug (regs))return ; - }/* -* If this was a BUG and report_bug returns or if this +* If this was a BUG and handle_bug returns or if this * was just a normal #UD, we want to continue onward and * crash. */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 22/311 x86/cfi: Fix CFI rewrite for odd alignments
In reply to Sasha LevinFrom: Peter Zijlstra <[email protected]>
[ Upstream commit 24c8147abb39618d74fcc36e325765e8fe7bdd7a ]
Rustam reported his clang builds did not boot properly; turns out his .config has: CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B=y set.
Fix up the FineIBT code to deal with this unusual alignment.
--- arch/x86/include/asm/cfi.h | 12 ++++++++---- arch/x86/include/asm/linkage.h | 4 ++-- arch/x86/kernel/alternative.c | 29 ++++++++++++++++++++++------- arch/x86/net/bpf_jit_comp.c | 13 ++----------- 4 files changed, 34 insertions(+), 24 deletions(-)
arch/x86/include/asm/cfi.h +8 -4
@@ -111,6 +111,12 @@ extern bhi_thunk __bhi_args_end[];struct pt_regs ; +#ifdef CONFIG_CALL_PADDING +#define CFI_OFFSET (CONFIG_FUNCTION_PADDING_CFI+5) +#else +#define CFI_OFFSET 5 +#endif +#ifdef CONFIG_CFI enum bug_trap_type handle_cfi_failure (struct pt_regs *regs);#define __bpfcall
@@ -119,11 +125,9 @@ static inline int cfi_get_offset(void) {switch (cfi_mode) {case CFI_FINEIBT : -return 16 ; +return /* fineibt_prefix_size */ 16 ;case CFI_KCFI : -if (IS_ENABLED (CONFIG_CALL_PADDING )) -return 16 ; -return 5 ; +return CFI_OFFSET ;default :return 0 ; }
arch/x86/include/asm/linkage.h +2 -2
@@ -68,7 +68,7 @@* Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_PADDING) the * CFI symbol layout changes. * -* Without CALL_THUNKS: +* Without CALL_PADDING: * * .align FUNCTION_ALIGNMENT * __cfi_##name:
@@ -77,7 +77,7 @@* .long __kcfi_typeid_##name * name: * -* With CALL_THUNKS: +* With CALL_PADDING: * * .align FUNCTION_ALIGNMENT * __cfi_##name:
arch/x86/kernel/alternative.c +22 -7
@@ -1147,7 +1147,7 @@ void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)poison_endbr (addr);if (IS_ENABLED (CONFIG_FINEIBT )) -poison_cfi (addr -16 ); +poison_cfi (addr -CFI_OFFSET ); } }
@@ -1354,6 +1354,8 @@ extern u8 fineibt_preamble_end[];#define fineibt_preamble_ud 0x13#define fineibt_preamble_hash 5 +#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) +/* * <fineibt_caller_start>: * 0: b8 78 56 34 12 mov $0x12345678, %eax
@@ -1599,7 +1601,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)* have determined there are no indirect calls to it and we * don't need no CFI either. */ -if (!is_endbr (addr +16 )) +if (!is_endbr (addr +CFI_OFFSET ))continue ; hash =decode_preamble_hash (addr, &arity);
@@ -1607,6 +1609,15 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end) addr, addr, 5, addr))return -EINVAL ; +/* +* FineIBT relies on being at func-16, so if the preamble is +* actually larger than that, place it the tail end. +* +* NOTE: this is possible with things like DEBUG_CALL_THUNKS +* and DEBUG_FORCE_FUNCTION_ALIGN_64B. +*/ + addr +=CFI_OFFSET - fineibt_prefix_size; +text_poke_early (addr, fineibt_preamble_start, fineibt_preamble_size);WARN_ON (*(u32 *)(addr + fineibt_preamble_hash) !=0x12345678 );text_poke_early (addr + fineibt_preamble_hash, &hash,4 );
@@ -1629,10 +1640,10 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end)for (s = start; s < end; s++) {void *addr = (void *)s + *s; -if (!exact_endbr (addr +16 )) +if (!exact_endbr (addr +CFI_OFFSET ))continue ; -poison_endbr (addr +16 ); +poison_endbr (addr +CFI_OFFSET ); } }
@@ -1737,7 +1748,8 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,if (FINEIBT_WARN (fineibt_preamble_size,20 ) ||FINEIBT_WARN (fineibt_preamble_bhi + fineibt_bhi1_size,20 ) ||FINEIBT_WARN (fineibt_caller_size,14 ) || -FINEIBT_WARN (fineibt_paranoid_size,20 )) +FINEIBT_WARN (fineibt_paranoid_size,20 ) || +WARN_ON_ONCE (CFI_OFFSET < fineibt_prefix_size))return ;if (cfi_mode ==CFI_AUTO ) {
@@ -1850,6 +1862,11 @@ static void poison_cfi(void *addr)*/ switch (cfi_mode) {case CFI_FINEIBT : +/* +* FineIBT preamble is at func-16. +*/ + addr +=CFI_OFFSET - fineibt_prefix_size; +/* * FineIBT prefix should start with an ENDBR. */
@@ -1888,8 +1905,6 @@ static void poison_cfi(void *addr) } } -#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) -/* * When regs->ip points to a 0xD6 byte in the FineIBT preamble, * return true and fill out target and type.
arch/x86/net/bpf_jit_comp.c +2 -11
@@ -438,17 +438,8 @@ static void emit_kcfi(u8 **pprog, u32 hash)EMIT1_off32 (0xb8 , hash);/* movl $hash, %eax */ #ifdef CONFIG_CALL_PADDING -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); -EMIT1 (0x90 ); +for (int i =0 ; i <CONFIG_FUNCTION_PADDING_CFI ; i++) +EMIT1 (0x90 );#endif EMIT_ENDBR ();
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 23/311 sched/fair: Rename cfs_rq::avg_load to cfs_rq::sum_weight
In reply to Sasha LevinFrom: Ingo Molnar <[email protected]>
[ Upstream commit 4ff674fa986c27ec8a0542479258c92d361a2566 ]
The ::avg_load field is a long-standing misnomer: it says it's an 'average load', but in reality it's the momentary sum of the load of all currently runnable tasks. We'd have to also perform a division by nr_running (or use time-decay) to arrive at any sort of average value.
This is clear from comments about the math of fair scheduling:
* \Sum w_i := cfs_rq->avg_load
The sum of all weights is ... the sum of all weights, not the average of all weights.
To make it doubly confusing, there's also an ::avg_load in the load-balancing struct sg_lb_stats, which *is* a true average.
The second part of the field's name is a minor misnomer as well: it says 'load', and it is indeed a load_weight structure as it shares code with the load-balancer - but it's only in an SMP load-balancing context where load = weight, in the fair scheduling context the primary purpose is the weighting of different nice levels.
So rename the field to ::sum_weight instead, which makes the terminology of the EEVDF math match up with our implementation of it:
* \Sum w_i := cfs_rq->sum_weight
Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")
--- kernel/sched/fair.c | 16 ++++++++-------- kernel/sched/sched.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-)
kernel/sched/fair.c +8 -8
@@ -608,7 +608,7 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)* * v0 := cfs_rq->zero_vruntime * \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime -* \Sum w_i := cfs_rq->avg_load +* \Sum w_i := cfs_rq->sum_weight * * Since zero_vruntime closely tracks the per-task service, these * deltas: (v_i - v), will be in the order of the maximal (virtual) lag
@@ -625,7 +625,7 @@ avg_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)s64 key =entity_key (cfs_rq, se); cfs_rq->avg_vruntime += key * weight; - cfs_rq->avg_load += weight; + cfs_rq->sum_weight += weight; } static void
@@ -635,16 +635,16 @@ avg_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)s64 key =entity_key (cfs_rq, se); cfs_rq->avg_vruntime -= key * weight; - cfs_rq->avg_load -= weight; + cfs_rq->sum_weight -= weight; }static inline void avg_vruntime_update (struct cfs_rq *cfs_rq,s64 delta) {/* -* v' = v + d ==> avg_vruntime' = avg_runtime - d*avg_load +* v' = v + d ==> avg_vruntime' = avg_runtime - d*sum_weight */ - cfs_rq->avg_vruntime -= cfs_rq->avg_load * delta; + cfs_rq->avg_vruntime -= cfs_rq->sum_weight * delta; }/*
@@ -655,7 +655,7 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq) {struct sched_entity *curr = cfs_rq->curr;s64 avg = cfs_rq->avg_vruntime; -long load = cfs_rq->avg_load; +long load = cfs_rq->sum_weight;if (curr && curr->on_rq) {unsigned long weight =scale_load_down (curr->load.weight);
@@ -723,7 +723,7 @@ static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime) {struct sched_entity *curr = cfs_rq->curr;s64 avg = cfs_rq->avg_vruntime; -long load = cfs_rq->avg_load; +long load = cfs_rq->sum_weight;if (curr && curr->on_rq) {unsigned long weight =scale_load_down (curr->load.weight);
@@ -5175,7 +5175,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)* * vl_i = (W + w_i)*vl'_i / W */ - load = cfs_rq->avg_load; + load = cfs_rq->sum_weight;if (curr && curr->on_rq) load +=scale_load_down (curr->load.weight);
kernel/sched/sched.h +1 -1
@@ -679,7 +679,7 @@ struct cfs_rq {unsigned int h_nr_idle;/* SCHED_IDLE */ s64 avg_vruntime; -u64 avg_load; +u64 sum_weight;u64 zero_vruntime;#ifdef CONFIG_SCHED_CORE
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 24/311 sched/fair: Rename cfs_rq::avg_vruntime to ::sum_w_vruntime, and helper functions
In reply to Sasha LevinFrom: Ingo Molnar <[email protected]>
[ Upstream commit dcbc9d3f0e594223275a18f7016001889ad35eff ]
The ::avg_vruntime field is a misnomer: it says it's an 'average vruntime', but in reality it's the momentary sum of the weighted vruntimes of all queued tasks, which is at least a division away from being an average.
This is clear from comments about the math of fair scheduling:
* \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime
This confusion is increased by the cfs_avg_vruntime() function, which does perform the division and returns a true average.
The sum of all weighted vruntimes should be named thusly, so rename the field to ::sum_w_vruntime. (As arguably ::sum_weighted_vruntime would be a bit of a mouthful.)
Understanding the scheduler is hard enough already, without extra layers of obfuscated naming. ;-)
Also rename related helper functions:
sum_vruntime_add() => sum_w_vruntime_add()
sum_vruntime_sub() => sum_w_vruntime_sub()
sum_vruntime_update() => sum_w_vruntime_update()
With the notable exception of cfs_avg_vruntime(), which was named accurately.
Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")
--- kernel/sched/fair.c | 26 +++++++++++++------------- kernel/sched/sched.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-)
kernel/sched/fair.c +13 -13
@@ -607,7 +607,7 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)* Which we track using: * * v0 := cfs_rq->zero_vruntime -* \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime +* \Sum (v_i - v0) * w_i := cfs_rq->sum_w_vruntime * \Sum w_i := cfs_rq->sum_weight * * Since zero_vruntime closely tracks the per-task service, these
@@ -619,32 +619,32 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)* As measured, the max (key * weight) value was ~44 bits for a kernel build. */ static void -avg_vruntime_add (struct cfs_rq *cfs_rq,struct sched_entity *se) +sum_w_vruntime_add (struct cfs_rq *cfs_rq,struct sched_entity *se) {unsigned long weight =scale_load_down (se->load.weight);s64 key =entity_key (cfs_rq, se); - cfs_rq->avg_vruntime += key * weight; + cfs_rq->sum_w_vruntime += key * weight; cfs_rq->sum_weight += weight; }static void -avg_vruntime_sub (struct cfs_rq *cfs_rq,struct sched_entity *se) +sum_w_vruntime_sub (struct cfs_rq *cfs_rq,struct sched_entity *se) {unsigned long weight =scale_load_down (se->load.weight);s64 key =entity_key (cfs_rq, se); - cfs_rq->avg_vruntime -= key * weight; + cfs_rq->sum_w_vruntime -= key * weight; cfs_rq->sum_weight -= weight; }static inline -void avg_vruntime_update (struct cfs_rq *cfs_rq,s64 delta) +void sum_w_vruntime_update (struct cfs_rq *cfs_rq,s64 delta) {/* -* v' = v + d ==> avg_vruntime' = avg_runtime - d*sum_weight +* v' = v + d ==> sum_w_vruntime' = sum_runtime - d*sum_weight */ - cfs_rq->avg_vruntime -= cfs_rq->sum_weight * delta; + cfs_rq->sum_w_vruntime -= cfs_rq->sum_weight * delta; }/*
@@ -654,7 +654,7 @@ void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)u64 avg_vruntime (struct cfs_rq *cfs_rq) {struct sched_entity *curr = cfs_rq->curr; -s64 avg = cfs_rq->avg_vruntime; +s64 avg = cfs_rq->sum_w_vruntime;long load = cfs_rq->sum_weight;if (curr && curr->on_rq) {
@@ -722,7 +722,7 @@ static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)static int vruntime_eligible (struct cfs_rq *cfs_rq,u64 vruntime) {struct sched_entity *curr = cfs_rq->curr; -s64 avg = cfs_rq->avg_vruntime; +s64 avg = cfs_rq->sum_w_vruntime;long load = cfs_rq->sum_weight;if (curr && curr->on_rq) {
@@ -745,7 +745,7 @@ static void update_zero_vruntime(struct cfs_rq *cfs_rq)u64 vruntime =avg_vruntime (cfs_rq);s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime); -avg_vruntime_update (cfs_rq, delta); +sum_w_vruntime_update (cfs_rq, delta); cfs_rq->zero_vruntime = vruntime; }
@@ -819,7 +819,7 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,*/ static void __enqueue_entity (struct cfs_rq *cfs_rq,struct sched_entity *se) { -avg_vruntime_add (cfs_rq, se); +sum_w_vruntime_add (cfs_rq, se);update_zero_vruntime (cfs_rq); se->min_vruntime = se->vruntime; se->min_slice = se->slice;
@@ -831,7 +831,7 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) {rb_erase_augmented_cached (&se->run_node, &cfs_rq->tasks_timeline, &min_vruntime_cb); -avg_vruntime_sub (cfs_rq, se); +sum_w_vruntime_sub (cfs_rq, se);update_zero_vruntime (cfs_rq); }
kernel/sched/sched.h +1 -1
@@ -678,7 +678,7 @@ struct cfs_rq {unsigned int h_nr_runnable;/* SCHED_{NORMAL,BATCH,IDLE} */ unsigned int h_nr_idle;/* SCHED_IDLE */ -s64 avg_vruntime; +s64 sum_w_vruntime;u64 sum_weight;u64 zero_vruntime;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 25/311 sched/fair: Introduce and use the vruntime_cmp() and vruntime_op() wrappers for wrapped-signed aritmetics
In reply to Sasha LevinFrom: Ingo Molnar <[email protected]>
[ Upstream commit 5758e48eefaf111d7764d8f1c8b666140fe5fa27 ]
We have to be careful with vruntime comparisons and subtraction, due to the possibility of wrapping, so we have macros like:
#define vruntime_gt(field, lse, rse) ({ (s64)((lse)->field - (rse)->field) > 0; })Which is used like this:
if (vruntime_gt(min_vruntime, se, rse)) se->min_vruntime = rse->min_vruntime;
Replace this with an easier to read pattern that uses the regular arithmetics operators:
if (vruntime_cmp(se->min_vruntime, ">", rse->min_vruntime)) se->min_vruntime = rse->min_vruntime;
Also replace vruntime subtractions with vruntime_op():
- delta = (s64)(sea->vruntime - seb->vruntime) +
- (s64)(cfs_rqb->zero_vruntime_fi - cfs_rqa->zero_vruntime_fi);
+ delta = vruntime_op(sea->vruntime, "-", seb->vruntime) +
+ vruntime_op(cfs_rqb->zero_vruntime_fi, "-", cfs_rqa->zero_vruntime_fi);
In the vruntime_cmp() and vruntime_op() macros use Use __builtin_strcmp(), because of __HAVE_ARCH_STRCMP might turn off the compiler optimizations we rely on here to catch usage bugs.
No change in functionality.
Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")
--- kernel/sched/fair.c | 66 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 15 deletions(-)
kernel/sched/fair.c +51 -15
@@ -524,10 +524,48 @@ void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec);* Scheduling class tree data structure manipulation methods: */ +extern void __BUILD_BUG_vruntime_cmp (void ); + +/* Use __builtin_strcmp() because of __HAVE_ARCH_STRCMP: */ + +#define vruntime_cmp (A ,CMP_STR ,B ) ({ \ + int __res = 0; \ + \ + if (!__builtin_strcmp(CMP_STR, "<")) { \ + __res = ((s64)((A)-(B)) < 0); \ + } else if (!__builtin_strcmp(CMP_STR, "<=")) { \ + __res = ((s64)((A)-(B)) <= 0); \ + } else if (!__builtin_strcmp(CMP_STR, ">")) { \ + __res = ((s64)((A)-(B)) > 0); \ + } else if (!__builtin_strcmp(CMP_STR, ">=")) { \ + __res = ((s64)((A)-(B)) >= 0); \ + } else { \ +/* Unknown operator throws linker error: */ \ +__BUILD_BUG_vruntime_cmp (); \ + } \ + \ + __res; \ +}) + +extern void __BUILD_BUG_vruntime_op (void ); + +#define vruntime_op (A ,OP_STR ,B ) ({ \ + s64 __res = 0; \ + \ + if (!__builtin_strcmp(OP_STR, "-")) { \ + __res = (s64)((A)-(B)); \ + } else { \ +/* Unknown operator throws linker error: */ \ +__BUILD_BUG_vruntime_op (); \ + } \ + \ + __res; \ +}) + +static inline __maybe_unused u64 max_vruntime (u64 max_vruntime,u64 vruntime) { -s64 delta = (s64)(vruntime - max_vruntime); -if (delta >0 ) +if (vruntime_cmp (vruntime,">" , max_vruntime)) max_vruntime = vruntime;return max_vruntime;
@@ -535,8 +573,7 @@ static inline __maybe_unused u64 max_vruntime(u64 max_vruntime, u64 vruntime)static inline __maybe_unused u64 min_vruntime (u64 min_vruntime,u64 vruntime) { -s64 delta = (s64)(vruntime - min_vruntime); -if (delta <0 ) +if (vruntime_cmp (vruntime,"<" , min_vruntime)) min_vruntime = vruntime;return min_vruntime;
@@ -549,12 +586,12 @@ static inline bool entity_before(const struct sched_entity *a,* Tiebreak on vruntime seems unnecessary since it can * hardly happen. */ -return (s64)(a->deadline - b->deadline) <0 ; +return vruntime_cmp (a->deadline,"<" , b->deadline); }static inline s64 entity_key (struct cfs_rq *cfs_rq,struct sched_entity *se) { -return (s64)(se->vruntime - cfs_rq->zero_vruntime); +return vruntime_op (se->vruntime,"-" , cfs_rq->zero_vruntime); }#define __node_2_se (node) \
@@ -732,7 +769,7 @@ static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime) load += weight; } -return avg >= (s64)(vruntime - cfs_rq->zero_vruntime) * load; +return avg >=vruntime_op (vruntime,"-" , cfs_rq->zero_vruntime) * load; }int entity_eligible (struct cfs_rq *cfs_rq,struct sched_entity *se)
@@ -743,7 +780,7 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)static void update_zero_vruntime (struct cfs_rq *cfs_rq) {u64 vruntime =avg_vruntime (cfs_rq); -s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime); +s64 delta =vruntime_op (vruntime,"-" , cfs_rq->zero_vruntime);sum_w_vruntime_update (cfs_rq, delta);
@@ -770,13 +807,12 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)return entity_before (__node_2_se (a),__node_2_se (b)); } -#define vruntime_gt (field, lse, rse) ({ (s64)((lse)->field - (rse)->field) > 0; }) -static inline void __min_vruntime_update (struct sched_entity *se,struct rb_node *node) {if (node) {struct sched_entity *rse =__node_2_se (node); -if (vruntime_gt (min_vruntime, se, rse)) + +if (vruntime_cmp (se->min_vruntime,">" , rse->min_vruntime)) se->min_vruntime = rse->min_vruntime; } }
@@ -887,7 +923,7 @@ static inline void update_protect_slice(struct cfs_rq *cfs_rq, struct sched_entistatic inline bool protect_slice (struct sched_entity *se) { -return ((s64)(se->vprot - se->vruntime) >0 ); +return vruntime_cmp (se->vruntime,"<" , se->vprot); }static inline void cancel_protect_slice (struct sched_entity *se)
@@ -1024,7 +1060,7 @@ static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se);*/ static bool update_deadline (struct cfs_rq *cfs_rq,struct sched_entity *se) { -if ((s64)(se->vruntime - se->deadline) <0 ) +if (vruntime_cmp (se->vruntime,"<" , se->deadline))return false;/*
@@ -13319,8 +13355,8 @@ bool cfs_prio_less(const struct task_struct *a, const struct task_struct *b,* zero_vruntime_fi, which would have been updated in prior calls * to se_fi_update(). */ - delta = (s64)(sea->vruntime - seb->vruntime) + - (s64)(cfs_rqb->zero_vruntime_fi - cfs_rqa->zero_vruntime_fi); + delta =vruntime_op (sea->vruntime,"-" , seb->vruntime) + +vruntime_op (cfs_rqb->zero_vruntime_fi,"-" , cfs_rqa->zero_vruntime_fi);return delta >0 ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 26/311 sched/fair: Fix zero_vruntime tracking
In reply to Sasha LevinFrom: Peter Zijlstra <[email protected]>
[ Upstream commit b3d99f43c72b56cf7a104a364e7fb34b0702828b ]
It turns out that zero_vruntime tracking is broken when there is but a single task running. Current update paths are through __{en,de}queue_entity(), and when there is but a single task, pick_next_task() will always return that one task, and put_prev_set_next_task() will end up in neither function.
This can cause entity_key() to grow indefinitely large and cause overflows, leading to much pain and suffering.
Furtermore, doing update_zero_vruntime() from __{de,en}queue_entity(), which are called from {set_next,put_prev}_entity() has problems because:
- set_next_entity() calls __dequeue_entity() before it does cfs_rq->curr = se. This means the avg_vruntime() will see the removal but not current, missing the entity for accounting.
- put_prev_entity() calls __enqueue_entity() before it does cfs_rq->curr = NULL. This means the avg_vruntime() will see the addition *and* current, leading to double accounting.
Both cases are incorrect/inconsistent.
Noting that avg_vruntime is already called on each {en,de}queue, remove the explicit avg_vruntime() calls (which removes an extra 64bit division for each {en,de}queue) and have avg_vruntime() update zero_vruntime itself.
Additionally, have the tick call avg_vruntime() -- discarding the result, but for the side-effect of updating zero_vruntime.
While there, optimize avg_vruntime() by noting that the average of one value is rather trivial to compute.
Test case:
# taskset -c -p 1 $$
# taskset -c 2 bash -c 'while :; do :; done&'
# cat /sys/kernel/debug/sched/debug | awk '/^cpu#/ {P=0} /^cpu#2,/ {P=1} {if (P) print $0}' | grep -e zero_vruntime -e "^>"PRE:
.zero_vruntime : 31316.407903
Quoted 1 line
R bash 487 50787.345112 E 50789.145972 2.800000 50780.298364 16 120 0.000000 0.000000 0.000000 /
.zero_vruntime : 382548.253179
Quoted 1 line
R bash 487 427275.204288 E 427276.003584 2.800000 427268.157540 23 120 0.000000 0.000000 0.000000 /
POST:
.zero_vruntime : 17259.709467
Quoted 1 line
R bash 526 17259.709467 E 17262.509467 2.800000 16915.031624 9 120 0.000000 0.000000 0.000000 /
.zero_vruntime : 18702.723356
Quoted 1 line
R bash 526 18702.723356 E 18705.523356 2.800000 18358.045513 9 120 0.000000 0.000000 0.000000 /
--- kernel/sched/fair.c | 84 ++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 27 deletions(-)
kernel/sched/fair.c +57 -27
@@ -589,6 +589,21 @@ static inline bool entity_before(const struct sched_entity *a,return vruntime_cmp (a->deadline,"<" , b->deadline); } +/* +* Per avg_vruntime() below, cfs_rq::zero_vruntime is only slightly stale +* and this value should be no more than two lag bounds. Which puts it in the +* general order of: +* +* (slice + TICK_NSEC) << NICE_0_LOAD_SHIFT +* +* which is around 44 bits in size (on 64bit); that is 20 for +* NICE_0_LOAD_SHIFT, another 20 for NSEC_PER_MSEC and then a handful for +* however many msec the actual slice+tick ends up begin. +* +* (disregarding the actual divide-by-weight part makes for the worst case +* weight of 2, which nicely cancels vs the fuzz in zero_vruntime not actually +* being the zero-lag point). +*/ static inline s64 entity_key (struct cfs_rq *cfs_rq,struct sched_entity *se) {return vruntime_op (se->vruntime,"-" , cfs_rq->zero_vruntime);
@@ -676,39 +691,61 @@ sum_w_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se) }static inline -void sum_w_vruntime_update (struct cfs_rq *cfs_rq,s64 delta) +void update_zero_vruntime (struct cfs_rq *cfs_rq,s64 delta) {/* -* v' = v + d ==> sum_w_vruntime' = sum_runtime - d*sum_weight +* v' = v + d ==> sum_w_vruntime' = sum_w_vruntime - d*sum_weight */ cfs_rq->sum_w_vruntime -= cfs_rq->sum_weight * delta; + cfs_rq->zero_vruntime += delta; }/* -* Specifically: avg_runtime() + 0 must result in entity_eligible() := true +* Specifically: avg_vruntime() + 0 must result in entity_eligible() := true * For this to be so, the result of this function must have a left bias. +* +* Called in: +* - place_entity() -- before enqueue +* - update_entity_lag() -- before dequeue +* - entity_tick() +* +* This means it is one entry 'behind' but that puts it close enough to where +* the bound on entity_key() is at most two lag bounds. */ u64 avg_vruntime (struct cfs_rq *cfs_rq) {struct sched_entity *curr = cfs_rq->curr; -s64 avg = cfs_rq->sum_w_vruntime; -long load = cfs_rq->sum_weight; +long weight = cfs_rq->sum_weight; +s64 delta =0 ; -if (curr && curr->on_rq) { -unsigned long weight =scale_load_down (curr->load.weight); +if (curr && !curr->on_rq) + curr =NULL ; - avg +=entity_key (cfs_rq, curr) * weight; - load += weight; - } +if (weight) { +s64 runtime = cfs_rq->sum_w_vruntime; + +if (curr) { +unsigned long w =scale_load_down (curr->load.weight); + + runtime +=entity_key (cfs_rq, curr) * w; + weight += w; + } -if (load) {/* sign flips effective floor / ceiling */ -if (avg <0 ) - avg -= (load -1 ); - avg =div_s64 (avg, load); +if (runtime <0 ) + runtime -= (weight -1 ); + + delta =div_s64 (runtime, weight); + }else if (curr) { +/* +* When there is but one element, it is the average. +*/ + delta = curr->vruntime - cfs_rq->zero_vruntime; } -return cfs_rq->zero_vruntime + avg; +update_zero_vruntime (cfs_rq, delta); + +return cfs_rq->zero_vruntime; }/*
@@ -777,16 +814,6 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)return vruntime_eligible (cfs_rq, se->vruntime); } -static void update_zero_vruntime (struct cfs_rq *cfs_rq) -{ -u64 vruntime =avg_vruntime (cfs_rq); -s64 delta =vruntime_op (vruntime,"-" , cfs_rq->zero_vruntime); - -sum_w_vruntime_update (cfs_rq, delta); - - cfs_rq->zero_vruntime = vruntime; -} -static inline u64 cfs_rq_min_slice (struct cfs_rq *cfs_rq) {struct sched_entity *root =__pick_root_entity (cfs_rq);
@@ -856,7 +883,6 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,static void __enqueue_entity (struct cfs_rq *cfs_rq,struct sched_entity *se) {sum_w_vruntime_add (cfs_rq, se); -update_zero_vruntime (cfs_rq); se->min_vruntime = se->vruntime; se->min_slice = se->slice; rb_add_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
@@ -868,7 +894,6 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)rb_erase_augmented_cached (&se->run_node, &cfs_rq->tasks_timeline, &min_vruntime_cb);sum_w_vruntime_sub (cfs_rq, se); -update_zero_vruntime (cfs_rq); }struct sched_entity *__pick_root_entity (struct cfs_rq *cfs_rq)
@@ -5567,6 +5592,11 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)update_load_avg (cfs_rq, curr,UPDATE_TG );update_cfs_group (curr); +/* +* Pulls along cfs_rq::zero_vruntime. +*/ +avg_vruntime (cfs_rq); +#ifdef CONFIG_SCHED_HRTICK /* * queued ticks are scheduled to match the slice, so don't bother
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 27/311 sched/fair: Only set slice protection at pick time
In reply to Sasha LevinFrom: Peter Zijlstra <[email protected]>
[ Upstream commit bcd74b2ffdd0a2233adbf26b65c62fc69a809c8e ]
We should not (re)set slice protection in the sched_change pattern which calls put_prev_task() / set_next_task().
--- kernel/sched/fair.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/sched/fair.c +6 -5
@@ -5488,7 +5488,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) }static void -set_next_entity (struct cfs_rq *cfs_rq,struct sched_entity *se) +set_next_entity (struct cfs_rq *cfs_rq,struct sched_entity *se,bool first) {clear_buddies (cfs_rq, se);
@@ -5503,7 +5503,8 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)__dequeue_entity (cfs_rq, se);update_load_avg (cfs_rq, se,UPDATE_TG ); -set_protect_slice (cfs_rq, se); +if (first) +set_protect_slice (cfs_rq, se); }update_stats_curr_start (cfs_rq, se);
@@ -9016,13 +9017,13 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf pse =parent_entity (pse); }if (se_depth >= pse_depth) { -set_next_entity (cfs_rq_of (se), se); +set_next_entity (cfs_rq_of (se), se, true); se =parent_entity (se); } }put_prev_entity (cfs_rq, pse); -set_next_entity (cfs_rq, se); +set_next_entity (cfs_rq, se, true);__set_next_task_fair (rq, p, true); }
@@ -13621,7 +13622,7 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)for_each_sched_entity (se) {struct cfs_rq *cfs_rq =cfs_rq_of (se); -set_next_entity (cfs_rq, se); +set_next_entity (cfs_rq, se, first);/* ensure bandwidth has been allocated on our new cfs_rq */ account_cfs_rq_runtime (cfs_rq,0 ); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 28/311 sched/eevdf: Update se->vprot in reweight_entity()
In reply to Sasha LevinFrom: Wang Tao <[email protected]>
[ Upstream commit ff38424030f98976150e42ca35f4b00e6ab8fa23 ]
In the EEVDF framework with Run-to-Parity protection, se->vprot is an independent variable defining the virtual protection timestamp.
When reweight_entity() is called (e.g., via nice/renice), it performs the following actions to preserve Lag consistency:
1. Scales se->vlag based on the new weight.
2. Calls place_entity(), which recalculates se->vruntime based on the new weight and scaled lag.
However, the current implementation fails to update se->vprot, leading to mismatches between the task's actual runtime and its expected duration.
--- kernel/sched/fair.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
kernel/sched/fair.c +12 -0
@@ -3816,6 +3816,8 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, unsigned long weight) {bool curr = cfs_rq->curr == se; +bool rel_vprot = false; +u64 vprot;if (se->on_rq) {/* commit outstanding execution time */
@@ -3823,6 +3825,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,update_entity_lag (cfs_rq, se); se->deadline -= se->vruntime; se->rel_deadline =1 ; +if (curr &&protect_slice (se)) { + vprot = se->vprot - se->vruntime; + rel_vprot = true; + } + cfs_rq->nr_queued--;if (!curr)__dequeue_entity (cfs_rq, se);
@@ -3838,6 +3845,9 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,if (se->rel_deadline) se->deadline =div_s64 (se->deadline * se->load.weight, weight); +if (rel_vprot) + vprot =div_s64 (vprot * se->load.weight, weight); +update_load_set (&se->load, weight); do {
@@ -3849,6 +3859,8 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,enqueue_load_avg (cfs_rq, se);if (se->on_rq) {place_entity (cfs_rq, se,0 ); +if (rel_vprot) + se->vprot = se->vruntime + vprot;update_load_add (&cfs_rq->load, se->load.weight);if (!curr)__enqueue_entity (cfs_rq, se);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 29/311 sched/fair: Fix lag clamp
In reply to Sasha LevinFrom: Peter Zijlstra <[email protected]>
[ Upstream commit 6e3c0a4e1ad1e0455b7880fad02b3ee179f56c09 ]
Vincent reported that he was seeing undue lag clamping in a mixed slice workload. Implement the max_slice tracking as per the todo comment.
--- include/linux/sched.h | 1 + kernel/sched/fair.c | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-)
include/linux/sched.h +1 -0
@@ -574,6 +574,7 @@ struct sched_entity {u64 deadline;u64 min_vruntime;u64 min_slice; +u64 max_slice;struct list_head group_node;unsigned char on_rq;
kernel/sched/fair.c +35 -4
@@ -748,6 +748,8 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)return cfs_rq->zero_vruntime; } +static inline u64 cfs_rq_max_slice (struct cfs_rq *cfs_rq); +/* * lag_i = S - s_i = w_i * (V - v_i) *
@@ -761,17 +763,16 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)* EEVDF gives the following limit for a steady state system: * * -r_max < lag < max(r_max, q) -* -* XXX could add max_slice to the augmented data to track this. */ static void update_entity_lag (struct cfs_rq *cfs_rq,struct sched_entity *se) { +u64 max_slice =cfs_rq_max_slice (cfs_rq) +TICK_NSEC ;s64 vlag, limit;WARN_ON_ONCE (!se->on_rq); vlag =avg_vruntime (cfs_rq) - se->vruntime; - limit =calc_delta_fair (max_t (u64,2 *se->slice,TICK_NSEC ), se); + limit =calc_delta_fair (max_slice, se); se->vlag =clamp (vlag, -limit, limit); }
@@ -829,6 +830,21 @@ static inline u64 cfs_rq_min_slice(struct cfs_rq *cfs_rq)return min_slice; } +static inline u64 cfs_rq_max_slice (struct cfs_rq *cfs_rq) +{ +struct sched_entity *root =__pick_root_entity (cfs_rq); +struct sched_entity *curr = cfs_rq->curr; +u64 max_slice =0ULL ; + +if (curr && curr->on_rq) + max_slice = curr->slice; + +if (root) + max_slice =max (max_slice, root->max_slice); + +return max_slice; +} +static inline bool __entity_less (struct rb_node *a,const struct rb_node *b) {return entity_before (__node_2_se (a),__node_2_se (b));
@@ -853,6 +869,15 @@ static inline void __min_slice_update(struct sched_entity *se, struct rb_node *n } } +static inline void __max_slice_update (struct sched_entity *se,struct rb_node *node) +{ +if (node) { +struct sched_entity *rse =__node_2_se (node); +if (rse->max_slice > se->max_slice) + se->max_slice = rse->max_slice; + } +} +/* * se->min_vruntime = min(se->vruntime, {left,right}->min_vruntime) */
@@ -860,6 +885,7 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit) {u64 old_min_vruntime = se->min_vruntime;u64 old_min_slice = se->min_slice; +u64 old_max_slice = se->max_slice;struct rb_node *node = &se->run_node; se->min_vruntime = se->vruntime;
@@ -870,8 +896,13 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit)__min_slice_update (se, node->rb_right);__min_slice_update (se, node->rb_left); + se->max_slice = se->slice; +__max_slice_update (se, node->rb_right); +__max_slice_update (se, node->rb_left); +return se->min_vruntime == old_min_vruntime && - se->min_slice == old_min_slice; + se->min_slice == old_min_slice && + se->max_slice == old_max_slice; } RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 30/311 rseq: Clarify rseq registration rseq_size bound check comment
In reply to Sasha LevinFrom: Mathieu Desnoyers <[email protected]>
[ Upstream commit 26d43a90be81fc90e26688a51d3ec83188602731 ]
The rseq registration validates that the rseq_size argument is greater or equal to 32 (the original rseq size), but the comment associated with this check does not clearly state this.
Clarify the comment to that effect.
--- kernel/rseq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/rseq.c +3 -2
@@ -428,8 +428,9 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32* auxiliary vector AT_RSEQ_ALIGN. If rseq_len is the original rseq * size, the required alignment is the original struct rseq alignment. * -* In order to be valid, rseq_len is either the original rseq size, or -* large enough to contain all supported fields, as communicated to +* The rseq_len is required to be greater or equal to the original rseq +* size. In order to be valid, rseq_len is either the original rseq size, +* or large enough to contain all supported fields, as communicated to * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE. */ if (rseq_len < ORIG_RSEQ_SIZE ||
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 31/311 perf/core: Fix invalid wait context in ctx_sched_in()
In reply to Sasha LevinFrom: Namhyung Kim <[email protected]>
[ Upstream commit 486ff5ad49bc50315bcaf6d45f04a33ef0a45ced ]
Lockdep found a bug in the event scheduling when a pinned event was failed and wakes up the threads in the ring buffer like below.
It seems it should not grab a wait-queue lock under perf-context lock. Let's do it with irq_work.
[ 39.913691] =============================
[ 39.914157] [ BUG: Invalid wait context ]
[ 39.914623] 6.15.0-next-20250530-next-2025053 #1 Not tainted
[ 39.915271] -----------------------------
[ 39.915731] repro/837 is trying to lock:
[ 39.916191] ffff88801acfabd8 (&event->waitq){....}-{3:3}, at: __wake_up+0x26/0x60
[ 39.917182] other info that might help us debug this:
[ 39.917761] context-{5:5}
[ 39.918079] 4 locks held by repro/837:
[ 39.918530] #0: ffffffff8725cd00 (rcu_read_lock){....}-{1:3}, at: __perf_event_task_sched_in+0xd1/0xbc0
[ 39.919612] #1: ffff88806ca3c6f8 (&cpuctx_lock){....}-{2:2}, at: __perf_event_task_sched_in+0x1a7/0xbc0
[ 39.920748] #2: ffff88800d91fc18 (&ctx->lock){....}-{2:2}, at: __perf_event_task_sched_in+0x1f9/0xbc0
[ 39.921819] #3: ffffffff8725cd00 (rcu_read_lock){....}-{1:3}, at: perf_event_wakeup+0x6c/0x470--- kernel/events/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/events/core.c +2 -1
@@ -4017,7 +4017,8 @@ static int merge_sched_in(struct perf_event *event, void *data)if (*perf_event_fasync (event)) event->pending_kill =POLL_ERR ; -perf_event_wakeup (event); + event->pending_wakeup =1 ; +irq_work_queue (&event->pending_irq); }else {struct perf_cpu_pmu_context *cpc =this_cpc (event->pmu_ctx->pmu);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 32/311 accel/amdxdna: Remove buffer size check when creating command BO
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 08fe1b5166fdc81b010d7bf39cd6440620e7931e ]
Large command buffers may be used, and they do not always need to be mapped or accessed by the driver. Performing a size check at command BO creation time unnecessarily rejects valid use cases.
Remove the buffer size check from command BO creation, and defer vmap and size validation to the paths where the driver actually needs to map and access the command buffer.
--- drivers/accel/amdxdna/amdxdna_gem.c | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-)
drivers/accel/amdxdna/amdxdna_gem.c +19 -19
@@ -21,8 +21,6 @@#include "amdxdna_pci_drv.h" #include "amdxdna_ubuf.h" -#define XDNA_MAX_CMD_BO_SIZE SZ_32K -MODULE_IMPORT_NS ("DMA_BUF" ); static int
@@ -746,12 +744,6 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev, {struct amdxdna_dev *xdna =to_xdna_dev (dev);struct amdxdna_gem_obj *abo; -int ret; - -if (args->size >XDNA_MAX_CMD_BO_SIZE ) { -XDNA_ERR (xdna,"Command bo size 0x%llx too large" , args->size); -return ERR_PTR (-EINVAL ); - }if (args->size <sizeof (struct amdxdna_cmd )) {XDNA_DBG (xdna,"Command BO size 0x%llx too small" , args->size);
@@ -765,17 +757,7 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev, abo->type =AMDXDNA_BO_CMD ; abo->client = filp->driver_priv; - ret =amdxdna_gem_obj_vmap (abo, &abo->mem.kva); -if (ret) { -XDNA_ERR (xdna,"Vmap cmd bo failed, ret %d" , ret); - goto release_obj; - } -return abo; - -release_obj: -drm_gem_object_put (to_gobj (abo)); -return ERR_PTR (ret); }int amdxdna_drm_create_bo_ioctl (struct drm_device *dev,void *data,struct drm_file *filp)
@@ -872,6 +854,7 @@ struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client,struct amdxdna_dev *xdna = client->xdna;struct amdxdna_gem_obj *abo;struct drm_gem_object *gobj; +int ret; gobj =drm_gem_object_lookup (client->filp, bo_hdl);if (!gobj) {
@@ -880,9 +863,26 @@ struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client, } abo =to_xdna_obj (gobj); -if (bo_type ==AMDXDNA_BO_INVALID || abo->type == bo_type) +if (bo_type !=AMDXDNA_BO_INVALID && abo->type != bo_type) + goto put_obj; + +if (bo_type !=AMDXDNA_BO_CMD || abo->mem.kva)return abo; +if (abo->mem.size >SZ_32K ) { +XDNA_ERR (xdna,"Cmd bo is too big %ld" , abo->mem.size); + goto put_obj; + } + + ret =amdxdna_gem_obj_vmap (abo, &abo->mem.kva); +if (ret) { +XDNA_ERR (xdna,"Vmap cmd bo failed, ret %d" , ret); + goto put_obj; + } + +return abo; + +put_obj:drm_gem_object_put (gobj);return NULL ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 33/311 accel/amdxdna: Switch to always use chained command
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit c68a6af400ca80596e8c37de0a1cb564aa9da8a4 ]
Preempt commands are only supported when submitted as chained commands. To ensure preempt support works consistently, always submit commands in chained command format.
Set force_cmdlist to true so that single commands are filled using the chained command layout, enabling correct handling of preempt commands.
--- drivers/accel/amdxdna/aie2_ctx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/accel/amdxdna/aie2_ctx.c +2 -2
@@ -23,9 +23,9 @@#include "amdxdna_pci_drv.h" #include "amdxdna_pm.h" -static bool force_cmdlist; +static bool force_cmdlist = true;module_param (force_cmdlist, bool,0600 ); -MODULE_PARM_DESC (force_cmdlist,"Force use command list (Default false)" ); +MODULE_PARM_DESC (force_cmdlist,"Force use command list (Default true)" );#define HWCTX_MAX_TIMEOUT 60000/* milliseconds */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 34/311 accel/amdxdna: Fix crash when destroying a suspended hardware context
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 8363c02863332992a1822688da41f881d88d1631 ]
If userspace issues an ioctl to destroy a hardware context that has already been automatically suspended, the driver may crash because the mailbox channel pointer is NULL for the suspended context.
Fix this by checking the mailbox channel pointer in aie2_destroy_context() before accessing it.
--- drivers/accel/amdxdna/aie2_message.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/accel/amdxdna/aie2_message.c +3 -0
@@ -274,6 +274,9 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwcstruct amdxdna_dev *xdna = ndev->xdna;int ret; +if (!hwctx->priv->mbox_chann) +return 0 ; +xdna_mailbox_stop_channel (hwctx->priv->mbox_chann); ret =aie2_destroy_context_req (ndev, hwctx->fw_ctx_id);xdna_mailbox_destroy_channel (hwctx->priv->mbox_chann);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 35/311 accel/amdxdna: Reduce log noise during process termination
In reply to Sasha LevinFrom: Mario Limonciello <[email protected]>
[ Upstream commit 57aa3917a3b3bd805a3679371f97a1ceda3c5510 ]
During process termination, several error messages are logged that are not actual errors but expected conditions when a process is killed or interrupted. This creates unnecessary noise in the kernel log.
The specific scenarios are:
1. HMM invalidation returns -ERESTARTSYS when the wait is interrupted by a signal during process cleanup. This is expected when a process is being terminated and should not be logged as an error.
2. Context destruction returns -ENODEV when the firmware or device has already stopped, which commonly occurs during cleanup if the device was already torn down. This is also an expected condition during orderly shutdown.
Downgrade these expected error conditions from error level to debug level to reduce log noise while still keeping genuine errors visible.
--- drivers/accel/amdxdna/aie2_ctx.c | 6 ++++-- drivers/accel/amdxdna/aie2_message.c | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-)
drivers/accel/amdxdna/aie2_ctx.c +4 -2
@@ -497,7 +497,7 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx)if (AIE2_FEATURE_ON (xdna->dev_handle,AIE2_TEMPORAL_ONLY )) { ret =aie2_destroy_context (xdna->dev_handle, hwctx); -if (ret) +if (ret && ret != -ENODEV )XDNA_ERR (xdna,"Destroy temporal only context failed, ret %d" , ret); }else { ret =xrs_release_resource (xdna->xrs_hdl, (uintptr_t )hwctx);
@@ -1070,6 +1070,8 @@ void aie2_hmm_invalidate(struct amdxdna_gem_obj *abo, ret =dma_resv_wait_timeout (gobj->resv,DMA_RESV_USAGE_BOOKKEEP , true,MAX_SCHEDULE_TIMEOUT ); -if (!ret || ret == -ERESTARTSYS ) +if (!ret)XDNA_ERR (xdna,"Failed to wait for bo, ret %ld" , ret); +else if (ret == -ERESTARTSYS ) +XDNA_DBG (xdna,"Wait for bo interrupted by signal" ); }
drivers/accel/amdxdna/aie2_message.c +3 -1
@@ -193,8 +193,10 @@ static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id) req.context_id = id; ret =aie2_send_mgmt_msg_wait (ndev, &msg); -if (ret) +if (ret && ret != -ENODEV )XDNA_WARN (xdna,"Destroy context failed, ret %d" , ret); +else if (ret == -ENODEV ) +XDNA_DBG (xdna,"Destroy context: device already stopped" );return ret; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 36/311 accel/amdxdna: Fix dead lock for suspend and resume
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 1aa82181a3c285c7351523d587f7981ae4c015c8 ]
When an application issues a query IOCTL while auto suspend is running, a deadlock can occur. The query path holds dev_lock and then calls pm_runtime_resume_and_get(), which waits for the ongoing suspend to complete. Meanwhile, the suspend callback attempts to acquire dev_lock and blocks, resulting in a deadlock.
Fix this by releasing dev_lock before calling pm_runtime_resume_and_get() and reacquiring it after the call completes. Also acquire dev_lock in the resume callback to keep the locking consistent.
--- drivers/accel/amdxdna/aie2_ctx.c | 4 ++-- drivers/accel/amdxdna/aie2_pci.c | 7 +++---- drivers/accel/amdxdna/aie2_pm.c | 2 +- drivers/accel/amdxdna/amdxdna_ctx.c | 19 +++++++------------ drivers/accel/amdxdna/amdxdna_pm.c | 2 ++ drivers/accel/amdxdna/amdxdna_pm.h | 11 +++++++++++ 6 files changed, 26 insertions(+), 19 deletions(-)
drivers/accel/amdxdna/aie2_ctx.c +2 -2
@@ -629,7 +629,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx) goto free_entity; } - ret =amdxdna_pm_resume_get (xdna); + ret =amdxdna_pm_resume_get_locked (xdna);if (ret) goto free_col_list;
@@ -760,7 +760,7 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 sizeif (!hwctx->cus)return -ENOMEM ; - ret =amdxdna_pm_resume_get (xdna); + ret =amdxdna_pm_resume_get_locked (xdna);if (ret) goto free_cus;
drivers/accel/amdxdna/aie2_pci.c +3 -4
@@ -469,7 +469,6 @@ static int aie2_hw_suspend(struct amdxdna_dev *xdna) {struct amdxdna_client *client; -guard (mutex)(&xdna->dev_lock);list_for_each_entry (client, &xdna->client_list, node)aie2_hwctx_suspend (client);
@@ -969,7 +968,7 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_iif (!drm_dev_enter (&xdna->ddev, &idx))return -ENODEV ; - ret =amdxdna_pm_resume_get (xdna); + ret =amdxdna_pm_resume_get_locked (xdna);if (ret) goto dev_exit;
@@ -1062,7 +1061,7 @@ static int aie2_get_array(struct amdxdna_client *client,if (!drm_dev_enter (&xdna->ddev, &idx))return -ENODEV ; - ret =amdxdna_pm_resume_get (xdna); + ret =amdxdna_pm_resume_get_locked (xdna);if (ret) goto dev_exit;
@@ -1152,7 +1151,7 @@ static int aie2_set_state(struct amdxdna_client *client,if (!drm_dev_enter (&xdna->ddev, &idx))return -ENODEV ; - ret =amdxdna_pm_resume_get (xdna); + ret =amdxdna_pm_resume_get_locked (xdna);if (ret) goto dev_exit;
drivers/accel/amdxdna/aie2_pm.c +1 -1
@@ -31,7 +31,7 @@ int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) {int ret; - ret =amdxdna_pm_resume_get (ndev->xdna); + ret =amdxdna_pm_resume_get_locked (ndev->xdna);if (ret)return ret;
drivers/accel/amdxdna/amdxdna_ctx.c +7 -12
@@ -266,9 +266,9 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drstruct amdxdna_drm_config_hwctx *args = data;struct amdxdna_dev *xdna =to_xdna_dev (dev);struct amdxdna_hwctx *hwctx; -int ret, idx;u32 buf_size;void *buf; +int ret;u64 val;if (XDNA_MBZ_DBG (xdna, &args->pad,sizeof (args->pad)))
@@ -310,20 +310,17 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drreturn -EINVAL ; } -mutex_lock (&xdna->dev_lock); - idx =srcu_read_lock (&client->hwctx_srcu); +guard (mutex)(&xdna->dev_lock); hwctx =xa_load (&client->hwctx_xa, args->handle);if (!hwctx) {XDNA_DBG (xdna,"PID %d failed to get hwctx %d" , client->pid, args->handle); ret = -EINVAL ; - goto unlock_srcu; + goto free_buf; } ret = xdna->dev_info->ops->hwctx_config (hwctx, args->param_type, val, buf, buf_size); -unlock_srcu: -srcu_read_unlock (&client->hwctx_srcu, idx); -mutex_unlock (&xdna->dev_lock); +free_buf:kfree (buf);return ret; }
@@ -334,7 +331,7 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)struct amdxdna_hwctx *hwctx;struct amdxdna_gem_obj *abo;struct drm_gem_object *gobj; -int ret, idx; +int ret;if (!xdna->dev_info->ops->hwctx_sync_debug_bo)return -EOPNOTSUPP ;
@@ -345,17 +342,15 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl) abo =to_xdna_obj (gobj);guard (mutex)(&xdna->dev_lock); - idx =srcu_read_lock (&client->hwctx_srcu); hwctx =xa_load (&client->hwctx_xa, abo->assigned_hwctx);if (!hwctx) { ret = -EINVAL ; - goto unlock_srcu; + goto put_obj; } ret = xdna->dev_info->ops->hwctx_sync_debug_bo (hwctx, debug_bo_hdl); -unlock_srcu: -srcu_read_unlock (&client->hwctx_srcu, idx); +put_obj:drm_gem_object_put (gobj);return ret; }
drivers/accel/amdxdna/amdxdna_pm.c +2 -0
@@ -16,6 +16,7 @@ int amdxdna_pm_suspend(struct device *dev)struct amdxdna_dev *xdna =to_xdna_dev (dev_get_drvdata (dev));int ret = -EOPNOTSUPP ; +guard (mutex)(&xdna->dev_lock);if (xdna->dev_info->ops->suspend) ret = xdna->dev_info->ops->suspend (xdna);
@@ -28,6 +29,7 @@ int amdxdna_pm_resume(struct device *dev)struct amdxdna_dev *xdna =to_xdna_dev (dev_get_drvdata (dev));int ret = -EOPNOTSUPP ; +guard (mutex)(&xdna->dev_lock);if (xdna->dev_info->ops->resume) ret = xdna->dev_info->ops->resume (xdna);
drivers/accel/amdxdna/amdxdna_pm.h +11 -0
@@ -15,4 +15,15 @@ void amdxdna_pm_suspend_put(struct amdxdna_dev *xdna);void amdxdna_pm_init (struct amdxdna_dev *xdna);void amdxdna_pm_fini (struct amdxdna_dev *xdna); +static inline int amdxdna_pm_resume_get_locked (struct amdxdna_dev *xdna) +{ +int ret; + +mutex_unlock (&xdna->dev_lock); + ret =amdxdna_pm_resume_get (xdna); +mutex_lock (&xdna->dev_lock); + +return ret; +} +#endif /* _AMDXDNA_PM_H_ */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 37/311 accel/amdxdna: Fix suspend failure after enabling turbo mode
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit fdb65acfe655f844ae1e88696b9656d3ef5bb8fb ]
Enabling turbo mode disables hardware clock gating. Suspend requires hardware clock gating to be re-enabled, otherwise suspend will fail. Fix this by calling aie2_runtime_cfg() from aie2_hw_stop() to re-enable clock gating during suspend. Also ensure that firmware is initialized in aie2_hw_start() before modifying clock-gating settings during resume.
--- drivers/accel/amdxdna/aie2_pci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/accel/amdxdna/aie2_pci.c +5 -4
@@ -341,6 +341,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna)return ; } +aie2_runtime_cfg (ndev,AIE2_RT_CFG_CLK_GATING ,NULL );aie2_mgmt_fw_fini (ndev);xdna_mailbox_stop_channel (ndev->mgmt_chann);xdna_mailbox_destroy_channel (ndev->mgmt_chann);
@@ -424,15 +425,15 @@ static int aie2_hw_start(struct amdxdna_dev *xdna) goto stop_psp; } - ret =aie2_pm_init (ndev); + ret =aie2_mgmt_fw_init (ndev);if (ret) { -XDNA_ERR (xdna,"failed to init pm, ret %d" , ret); +XDNA_ERR (xdna,"initial mgmt firmware failed, ret %d" , ret); goto destroy_mgmt_chann; } - ret =aie2_mgmt_fw_init (ndev); + ret =aie2_pm_init (ndev);if (ret) { -XDNA_ERR (xdna,"initial mgmt firmware failed, ret %d" , ret); +XDNA_ERR (xdna,"failed to init pm, ret %d" , ret); goto destroy_mgmt_chann; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 38/311 accel/amdxdna: Fix command hang on suspended hardware context
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 07efce5a6611af6714ea3ef65694e0c8dd7e44f5 ]
When a hardware context is suspended, the job scheduler is stopped. If a command is submitted while the context is suspended, the job is queued in the scheduler but aie2_sched_job_run() is never invoked to restart the hardware context. As a result, the command hangs.
Fix this by modifying the hardware context suspend routine to keep the job scheduler running so that queued jobs can trigger context restart properly.
--- drivers/accel/amdxdna/aie2_ctx.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
drivers/accel/amdxdna/aie2_ctx.c +11 -7
@@ -53,6 +53,7 @@ static void aie2_hwctx_stop(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwct {drm_sched_stop (&hwctx->priv->sched, bad_job);aie2_destroy_context (xdna->dev_handle, hwctx); +drm_sched_start (&hwctx->priv->sched,0 ); }static int aie2_hwctx_restart (struct amdxdna_dev *xdna,struct amdxdna_hwctx *hwctx)
@@ -80,7 +81,6 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw } out: -drm_sched_start (&hwctx->priv->sched,0 );XDNA_DBG (xdna,"%s restarted, ret %d" , hwctx->name, ret);return ret; }
@@ -297,19 +297,23 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)struct dma_fence *fence;int ret; -if (!hwctx->priv->mbox_chann) + ret =amdxdna_pm_resume_get (hwctx->client->xdna); +if (ret) +return NULL ; + +if (!hwctx->priv->mbox_chann) { +amdxdna_pm_suspend_put (hwctx->client->xdna);return NULL ; + } -if (!mmget_not_zero (job->mm)) +if (!mmget_not_zero (job->mm)) { +amdxdna_pm_suspend_put (hwctx->client->xdna);return ERR_PTR (-ESRCH ); + }kref_get (&job->refcnt); fence =dma_fence_get (job->fence); - ret =amdxdna_pm_resume_get (hwctx->client->xdna); -if (ret) - goto out; -if (job->drv_cmd) {switch (job->drv_cmd->opcode) {case SYNC_DEBUG_BO :
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 39/311 accel/amdxdna: Fix out-of-bounds memset in command slot handling
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 1110a949675ebd56b3f0286e664ea543f745801c ]
The remaining space in a command slot may be smaller than the size of the command header. Clearing the command header with memset() before verifying the available slot space can result in an out-of-bounds write and memory corruption.
Fix this by moving the memset() call after the size validation.
--- drivers/accel/amdxdna/aie2_message.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/accel/amdxdna/aie2_message.c +4 -4
@@ -656,11 +656,11 @@ aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *sizu32 cmd_len;void *cmd; -memset (npu_slot,0 ,sizeof (*npu_slot)); cmd =amdxdna_cmd_get_payload (cmd_bo, &cmd_len);if (*size <sizeof (*npu_slot) + cmd_len)return -EINVAL ; +memset (npu_slot,0 ,sizeof (*npu_slot)); npu_slot->cu_idx =amdxdna_cmd_get_cu_idx (cmd_bo);if (npu_slot->cu_idx ==INVALID_CU_IDX )return -EINVAL ;
@@ -681,7 +681,6 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siu32 cmd_len;u32 arg_sz; -memset (npu_slot,0 ,sizeof (*npu_slot)); sn =amdxdna_cmd_get_payload (cmd_bo, &cmd_len); arg_sz = cmd_len -sizeof (*sn);if (cmd_len <sizeof (*sn) || arg_sz >MAX_NPU_ARGS_SIZE )
@@ -690,6 +689,7 @@ aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siif (*size <sizeof (*npu_slot) + arg_sz)return -EINVAL ; +memset (npu_slot,0 ,sizeof (*npu_slot)); npu_slot->cu_idx =amdxdna_cmd_get_cu_idx (cmd_bo);if (npu_slot->cu_idx ==INVALID_CU_IDX )return -EINVAL ;
@@ -713,7 +713,6 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_tu32 cmd_len;u32 arg_sz; -memset (npu_slot,0 ,sizeof (*npu_slot)); pd =amdxdna_cmd_get_payload (cmd_bo, &cmd_len); arg_sz = cmd_len -sizeof (*pd);if (cmd_len <sizeof (*pd) || arg_sz >MAX_NPU_ARGS_SIZE )
@@ -722,6 +721,7 @@ aie2_cmdlist_fill_npu_preempt(struct amdxdna_gem_obj *cmd_bo, void *slot, size_tif (*size <sizeof (*npu_slot) + arg_sz)return -EINVAL ; +memset (npu_slot,0 ,sizeof (*npu_slot)); npu_slot->cu_idx =amdxdna_cmd_get_cu_idx (cmd_bo);if (npu_slot->cu_idx ==INVALID_CU_IDX )return -EINVAL ;
@@ -749,7 +749,6 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siu32 cmd_len;u32 arg_sz; -memset (npu_slot,0 ,sizeof (*npu_slot)); pd =amdxdna_cmd_get_payload (cmd_bo, &cmd_len); arg_sz = cmd_len -sizeof (*pd);if (cmd_len <sizeof (*pd) || arg_sz >MAX_NPU_ARGS_SIZE )
@@ -758,6 +757,7 @@ aie2_cmdlist_fill_npu_elf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *siif (*size <sizeof (*npu_slot) + arg_sz)return -EINVAL ; +memset (npu_slot,0 ,sizeof (*npu_slot)); npu_slot->type =EXEC_NPU_TYPE_ELF ; npu_slot->inst_buf_addr = pd->inst_buf; npu_slot->save_buf_addr = pd->save_buf;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 40/311 accel/amdxdna: Prevent ubuf size overflow
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 03808abb1d868aed7478a11a82e5bb4b3f1ca6d6 ]
The ubuf size calculation may overflow, resulting in an undersized allocation and possible memory corruption.
Use check_add_overflow() helpers to validate the size calculation before allocation.
--- drivers/accel/amdxdna/amdxdna_ubuf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/accel/amdxdna/amdxdna_ubuf.c +5 -1
@@ -7,6 +7,7 @@#include <drm/drm_device.h> #include <drm/drm_print.h> #include <linux/dma-buf.h> +#include <linux/overflow.h> #include <linux/pagemap.h> #include <linux/vmalloc.h>
@@ -176,7 +177,10 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev, goto free_ent; } - exp_info.size += va_ent[i].len; +if (check_add_overflow (exp_info.size, va_ent[i].len, &exp_info.size)) { + ret = -EINVAL ; + goto free_ent; + } } ubuf->nr_pages = exp_info.size >>PAGE_SHIFT ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 41/311 accel/amdxdna: Validate command buffer payload count
In reply to Sasha LevinFrom: Lizhi Hou <[email protected]>
[ Upstream commit 901ec3470994006bc8dd02399e16b675566c3416 ]
The count field in the command header is used to determine the valid payload size. Verify that the valid payload does not exceed the remaining buffer space.
--- drivers/accel/amdxdna/amdxdna_ctx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/accel/amdxdna/amdxdna_ctx.c +4 -1
@@ -104,7 +104,10 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size)if (size) { count =FIELD_GET (AMDXDNA_CMD_COUNT , cmd->header); -if (unlikely (count <= num_masks)) { +if (unlikely (count <= num_masks || + count *sizeof (u32) + + offsetof(struct amdxdna_cmd, data[0]) > + abo->mem.size)) { *size =0 ;return NULL ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 42/311 drm/xe/wa: Steer RMW of MCR registers while building default LRC
In reply to Sasha LevinFrom: Matt Roper <[email protected]>
[ Upstream commit 43d37df67f7770d8d261fdcb64ecc8c314e91303 ]
When generating the default LRC, if a register is not masked, we apply any save-restore programming necessary via a read-modify-write sequence that will ensure we only update the relevant bits/fields without clobbering the rest of the register. However some of the registers that need to be updated might be MCR registers which require steering to a non-terminated instance to ensure we can read back a valid, non-zero value. The steering of reads originating from a command streamer is controlled by register CS_MMIO_GROUP_INSTANCE_SELECT. Emit additional MI_LRI commands to update the steering before any RMW of an MCR register to ensure the reads are performed properly.
Note that needing to perform a RMW of an MCR register while building the default LRC is pretty rare. Most of the MCR registers that are part of an engine's LRCs are also masked registers, so no MCR is necessary.
--- drivers/gpu/drm/xe/regs/xe_engine_regs.h | 6 +++ drivers/gpu/drm/xe/xe_gt.c | 66 +++++++++++++++++++----- 2 files changed, 60 insertions(+), 12 deletions(-)
drivers/gpu/drm/xe/regs/xe_engine_regs.h +6 -0
@@ -96,6 +96,12 @@#define ENABLE_SEMAPHORE_POLL_BIT REG_BIT(13)#define RING_CMD_CCTL (base) XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED) + +#define CS_MMIO_GROUP_INSTANCE_SELECT (base) XE_REG((base) + 0xcc) +#define SELECTIVE_READ_ADDRESSING REG_BIT(30) +#define SELECTIVE_READ_GROUP REG_GENMASK(29, 23) +#define SELECTIVE_READ_INSTANCE REG_GENMASK(22, 16) +/* * CMD_CCTL read/write fields take a MOCS value and _not_ a table index. * The lsb of each can be considered a separate enabling bit for encryption.
drivers/gpu/drm/xe/xe_gt.c +54 -12
115 lines not on this page · raw message
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 43/311 cgroup/cpuset: Fix incorrect change to effective_xcpus in partition_xcpus_del()
In reply to Sasha LevinFrom: Waiman Long <[email protected]>
[ Upstream commit f9a1767ce3a34bc33c3d33473f65dc13a380e379 ]
The effective_xcpus of a cpuset can contain offline CPUs. In partition_xcpus_del(), the xcpus parameter is incorrectly used as a temporary cpumask to mask out offline CPUs. As xcpus can be the effective_xcpus of a cpuset, this can result in unexpected changes in that cpumask. Fix this problem by not making any changes to the xcpus parameter.
--- kernel/cgroup/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/cpuset.c +1 -1
@@ -1401,8 +1401,8 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent,isolated_cpus_update (old_prs, parent->partition_root_state, xcpus); -cpumask_and (xcpus, xcpus, cpu_active_mask);cpumask_or (parent->effective_cpus, parent->effective_cpus, xcpus); +cpumask_and (parent->effective_cpus, parent->effective_cpus, cpu_active_mask); }/*
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 44/311 cgroup/cpuset: Fix incorrect use of cpuset_update_tasks_cpumask() in update_cpumasks_hier()
In reply to Sasha LevinFrom: Waiman Long <[email protected]>
[ Upstream commit 68230aac8b9aad243626fbaf3ca170012c17fec5 ]
Commit e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2") incorrectly changed the 2nd parameter of cpuset_update_tasks_cpumask() from tmp->new_cpus to cp->effective_cpus. This second parameter is just a temporary cpumask for internal use. The cpuset_update_tasks_cpumask() function was originally called update_tasks_cpumask() before commit 381b53c3b549 ("cgroup/cpuset: rename functions shared between v1 and v2").
This mistake can incorrectly change the effective_cpus of the cpuset when it is the top_cpuset or in arm64 architecture where task_cpu_possible_mask() may differ from cpu_possible_mask. So far top_cpuset hasn't been passed to update_cpumasks_hier() yet, but arm64 arch can still be impacted. Fix it by reverting the incorrect change.
--- kernel/cgroup/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/cpuset.c +1 -1
@@ -2350,7 +2350,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,WARN_ON (!is_in_v2_mode () && !cpumask_equal (cp->cpus_allowed, cp->effective_cpus)); -cpuset_update_tasks_cpumask (cp, cp->effective_cpus); +cpuset_update_tasks_cpumask (cp, tmp->new_cpus);/* * On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 45/311 clk: scu/imx8qxp: do not register driver in probe()
In reply to Sasha LevinFrom: Danilo Krummrich <[email protected]>
[ Upstream commit 78437ab3b769f80526416570f60173c89858dd84 ]
imx_clk_scu_init() registers the imx_clk_scu_driver while commonly being called from IMX driver's probe() callbacks.
However, it neither makes sense to register drivers from probe() callbacks of other drivers, nor does the driver core allow registering drivers with a device lock already being held.
The latter was revealed by commit dc23806a7c47 ("driver core: enforce device_lock for driver_match_device()") leading to a deadlock condition described in [1].
Besides that, nothing seems to unregister the imx_clk_scu_driver once the corresponding driver module is unloaded, which leaves the driver-core with a dangling pointer.
Also, if there are multiple matching devices for the imx8qxp_clk_driver, imx8qxp_clk_probe() calls imx_clk_scu_init() multiple times. However, any subsequent call after the first one will fail, since the driver-core does not allow to register the same struct platform_driver multiple times.
Hence, register the imx_clk_scu_driver from module_init() and unregister it in module_exit().
Note that we first register the imx8qxp_clk_driver and then call imx_clk_scu_module_init() to avoid having to call imx_clk_scu_module_exit() in the unwind path of imx8qxp_clk_init().
--- drivers/clk/imx/clk-imx8qxp.c | 24 +++++++++++++++++++++++- drivers/clk/imx/clk-scu.c | 12 +++++++++++- drivers/clk/imx/clk-scu.h | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-)
drivers/clk/imx/clk-imx8qxp.c +23 -1
@@ -346,7 +346,29 @@ static struct platform_driver imx8qxp_clk_driver = { }, .probe = imx8qxp_clk_probe, }; -module_platform_driver (imx8qxp_clk_driver); + +static int __init imx8qxp_clk_init (void ) +{ +int ret; + + ret =platform_driver_register (&imx8qxp_clk_driver); +if (ret) +return ret; + + ret =imx_clk_scu_module_init (); +if (ret) +platform_driver_unregister (&imx8qxp_clk_driver); + +return ret; +} +module_init (imx8qxp_clk_init); + +static void __exit imx8qxp_clk_exit(void) +{ +imx_clk_scu_module_exit (); +platform_driver_unregister (&imx8qxp_clk_driver); +} +module_exit (imx8qxp_clk_exit);MODULE_AUTHOR ("Aisheng Dong <[email protected]>" );MODULE_DESCRIPTION ("NXP i.MX8QXP clock driver" );
drivers/clk/imx/clk-scu.c +11 -1
@@ -191,6 +191,16 @@ static bool imx_scu_clk_is_valid(u32 rsrc_id)return p !=NULL ; } +int __init imx_clk_scu_module_init (void ) +{ +return platform_driver_register (&imx_clk_scu_driver); +} + +void __exit imx_clk_scu_module_exit(void) +{ +return platform_driver_unregister (&imx_clk_scu_driver); +} +int imx_clk_scu_init (struct device_node *np,const struct imx_clk_scu_rsrc_table *data) {
@@ -215,7 +225,7 @@ int imx_clk_scu_init(struct device_node *np, rsrc_table = data; } -return platform_driver_register (&imx_clk_scu_driver); +return 0 ; }/*
drivers/clk/imx/clk-scu.h +2 -0
@@ -25,6 +25,8 @@ extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl;extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm; +int __init imx_clk_scu_module_init (void ); +void __exit imx_clk_scu_module_exit(void);int imx_clk_scu_init (struct device_node *np,const struct imx_clk_scu_rsrc_table *data); struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 46/311 cxl: Move devm_cxl_add_nvdimm_bridge() to cxl_pmem.ko
In reply to Sasha LevinFrom: Dave Jiang <[email protected]>
[ Upstream commit e7e222ad73d93fe54d6e6e3a15253a0ecf081a1b ]
Moving the symbol devm_cxl_add_nvdimm_bridge() to drivers/cxl/cxl_pmem.c, so that cxl_pmem can export a symbol that gives cxl_acpi a depedency on cxl_pmem kernel module. This is a prepatory patch to resolve the issue of a race for nvdimm_bus object that is created during cxl_acpi_probe().
No functional changes besides moving code.
Stable-dep-of: 96a1fd0d84b1 ("cxl: Fix race of nvdimm_bus object when creating nvdimm objects")
--- drivers/cxl/core/pmem.c | 13 +++---------- drivers/cxl/cxl.h | 2 ++ drivers/cxl/pmem.c | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 10 deletions(-)
drivers/cxl/core/pmem.c +3 -10
@@ -115,15 +115,8 @@ static void unregister_nvb(void *_cxl_nvb)device_unregister (&cxl_nvb->dev); } -/** -* devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology -* @host: platform firmware root device -* @port: CXL port at the root of a CXL topology -* -* Return: bridge device that can host cxl_nvdimm objects -*/ -struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge (struct device *host, -struct cxl_port *port) +struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge (struct device *host, +struct cxl_port *port) {struct cxl_nvdimm_bridge *cxl_nvb;struct device *dev;
@@ -155,7 +148,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,put_device (dev);return ERR_PTR (rc); } -EXPORT_SYMBOL_NS_GPL (devm_cxl_add_nvdimm_bridge,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (__devm_cxl_add_nvdimm_bridge,"cxl_pmem" );static void cxl_nvdimm_release (struct device *dev) {
drivers/cxl/cxl.h +2 -0
@@ -893,6 +893,8 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge (struct device *dev);struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge (struct device *host,struct cxl_port *port); +struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge (struct device *host, +struct cxl_port *port);struct cxl_nvdimm *to_cxl_nvdimm (struct device *dev);bool is_cxl_nvdimm (struct device *dev);int devm_cxl_add_nvdimm (struct cxl_port *parent_port,struct cxl_memdev *cxlmd);
drivers/cxl/pmem.c +14 -0
@@ -13,6 +13,20 @@ static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); +/** +* __devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology +* @host: platform firmware root device +* @port: CXL port at the root of a CXL topology +* +* Return: bridge device that can host cxl_nvdimm objects +*/ +struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge (struct device *host, +struct cxl_port *port) +{ +return __devm_cxl_add_nvdimm_bridge (host, port); +} +EXPORT_SYMBOL_NS_GPL (devm_cxl_add_nvdimm_bridge,"CXL" ); +static void clear_exclusive (void *mds) {clear_exclusive_cxl_commands (mds, exclusive_cmds);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 47/311 cxl: Fix race of nvdimm_bus object when creating nvdimm objects
In reply to Sasha LevinFrom: Dave Jiang <[email protected]>
[ Upstream commit 96a1fd0d84b17360840f344826897fa71049870e ]
Found issue during running of cxl-translate.sh unit test. Adding a 3s sleep right before the test seems to make the issue reproduce fairly consistently. The cxl_translate module has dependency on cxl_acpi and causes orphaned nvdimm objects to reprobe after cxl_acpi is removed. The nvdimm_bus object is registered by the cxl_nvb object when cxl_acpi_probe() is called. With the nvdimm_bus object missing, __nd_device_register() will trigger NULL pointer dereference when accessing the dev->parent that points to &nvdimm_bus->dev.
[ 192.884510] BUG: kernel NULL pointer dereference, address: 000000000000006c [ 192.895383] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS edk2-20250812-19.fc42 08/12/2025 [ 192.897721] Workqueue: cxl_port cxl_bus_rescan_queue [cxl_core] [ 192.899459] RIP: 0010:kobject_get+0xc/0x90 [ 192.924871] Call Trace: [ 192.925959] <TASK> [ 192.926976] ? pm_runtime_init+0xb9/0xe0 [ 192.929712] __nd_device_register.part.0+0x4d/0xc0 [libnvdimm] [ 192.933314] __nvdimm_create+0x206/0x290 [libnvdimm] [ 192.936662] cxl_nvdimm_probe+0x119/0x1d0 [cxl_pmem] [ 192.940245] cxl_bus_probe+0x1a/0x60 [cxl_core] [ 192.943349] really_probe+0xde/0x380
This patch also relies on the previous change where devm_cxl_add_nvdimm_bridge() is called from drivers/cxl/pmem.c instead of drivers/cxl/core.c to ensure the dependency of cxl_acpi on cxl_pmem.
1. Set probe_type of cxl_nvb to PROBE_FORCE_SYNCHRONOUS to ensure the driver is probed synchronously when add_device() is called.
2. Add a check in __devm_cxl_add_nvdimm_bridge() to ensure that the cxl_nvb driver is attached during cxl_acpi_probe().
3. Take the cxl_root uport_dev lock and the cxl_nvb->dev lock in devm_cxl_add_nvdimm() before checking nvdimm_bus is valid.
4. Set cxl_nvdimm flag to CXL_NVD_F_INVALIDATED so cxl_nvdimm_probe() will exit with -EBUSY.
The removal of cxl_nvdimm devices should prevent any orphaned devices from probing once the nvdimm_bus is gone.
[ dj: Fixed 0-day reported kdoc issue. ]
[ dj: Fix cxl_nvb reference leak on error. Gregory (kreview-0811365) ]
--- drivers/cxl/core/pmem.c | 29 +++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 5 +++++ drivers/cxl/pmem.c | 10 ++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-)
drivers/cxl/core/pmem.c +29 -0
@@ -115,6 +115,15 @@ static void unregister_nvb(void *_cxl_nvb)device_unregister (&cxl_nvb->dev); } +static bool cxl_nvdimm_bridge_failed_attach (struct cxl_nvdimm_bridge *cxl_nvb) +{ +struct device *dev = &cxl_nvb->dev; + +guard (device)(dev); +/* If the device has no driver, then it failed to attach. */ +return dev->driver ==NULL ; +} +struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge (struct device *host,struct cxl_port *port) {
@@ -138,6 +147,11 @@ struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,if (rc) goto err; +if (cxl_nvdimm_bridge_failed_attach (cxl_nvb)) { +unregister_nvb (cxl_nvb); +return ERR_PTR (-ENODEV ); + } + rc =devm_add_action_or_reset (host, unregister_nvb, cxl_nvb);if (rc)return ERR_PTR (rc);
@@ -247,6 +261,21 @@ int devm_cxl_add_nvdimm(struct cxl_port *parent_port,if (!cxl_nvb)return -ENODEV ; +/* +* Take the uport_dev lock to guard against race of nvdimm_bus object. +* cxl_acpi_probe() registers the nvdimm_bus and is done under the +* root port uport_dev lock. +* +* Take the cxl_nvb device lock to ensure that cxl_nvb driver is in a +* consistent state. And the driver registers nvdimm_bus. +*/ +guard (device)(cxl_nvb->port->uport_dev); +guard (device)(&cxl_nvb->dev); +if (!cxl_nvb->nvdimm_bus) { + rc = -ENODEV ; + goto err_alloc; + } + cxl_nvd =cxl_nvdimm_alloc (cxl_nvb, cxlmd);if (IS_ERR (cxl_nvd)) { rc =PTR_ERR (cxl_nvd);
drivers/cxl/cxl.h +5 -0
@@ -563,11 +563,16 @@ struct cxl_nvdimm_bridge {#define CXL_DEV_ID_LEN 19 +enum { +CXL_NVD_F_INVALIDATED =0 , +}; +struct cxl_nvdimm {struct device dev;struct cxl_memdev *cxlmd;u8 dev_id[CXL_DEV_ID_LEN ];/* for nvdimm, string of 'serial' */ u64 dirty_shutdowns; +unsigned long flags; };struct cxl_pmem_region_mapping {
drivers/cxl/pmem.c +8 -2
@@ -14,7 +14,7 @@ static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);/** -* __devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology +* devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology * @host: platform firmware root device * @port: CXL port at the root of a CXL topology *
@@ -143,6 +143,9 @@ static int cxl_nvdimm_probe(struct device *dev)struct nvdimm *nvdimm;int rc; +if (test_bit (CXL_NVD_F_INVALIDATED , &cxl_nvd->flags)) +return -EBUSY ; +set_exclusive_cxl_commands (mds, exclusive_cmds); rc =devm_add_action_or_reset (dev, clear_exclusive, mds);if (rc)
@@ -323,8 +326,10 @@ static int detach_nvdimm(struct device *dev, void *data) scoped_guard(device, dev) {if (dev->driver) { cxl_nvd =to_cxl_nvdimm (dev); -if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data) +if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data) { release = true; +set_bit (CXL_NVD_F_INVALIDATED , &cxl_nvd->flags); + } } }if (release)
@@ -367,6 +372,7 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = { .probe = cxl_nvdimm_bridge_probe, .id = CXL_DEVICE_NVDIMM_BRIDGE, .drv = { + .probe_type = PROBE_FORCE_SYNCHRONOUS, .suppress_bind_attrs = true, }, };
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 48/311 cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed()
In reply to Sasha LevinFrom: Davidlohr Bueso <[email protected]>
[ 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.
--- drivers/cxl/core/mbox.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/cxl/core/mbox.c +9 -2
@@ -311,6 +311,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.
@@ -325,12 +326,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 ;
@@ -338,6 +342,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.
@@ -365,7 +371,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);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 49/311 scsi: ufs: core: Move link recovery for hibern8 exit failure to wl_resume
In reply to Sasha LevinFrom: Peter Wang <[email protected]>
[ Upstream commit 62c015373e1cdb1cdca824bd2dbce2dac0819467 ]
Move the link recovery trigger from ufshcd_uic_pwr_ctrl() to __ufshcd_wl_resume(). Ensure link recovery is only attempted when hibern8 exit fails during resume, not during hibern8 enter in suspend. Improve error handling and prevent unnecessary link recovery attempts.
--- drivers/ufs/core/ufshcd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/ufs/core/ufshcd.c +9 -9
@@ -4385,14 +4385,6 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)spin_unlock_irqrestore (hba->host->host_lock, flags);mutex_unlock (&hba->uic_cmd_mutex); -/* -* If the h8 exit fails during the runtime resume process, it becomes -* stuck and cannot be recovered through the error handler. To fix -* this, use link recovery instead of the error handler. -*/ -if (ret && hba->pm_op_in_progress) - ret =ufshcd_link_recovery (hba); -return ret; }
@@ -10174,7 +10166,15 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) }else {dev_err (hba->dev,"%s: hibern8 exit failed %d\n" , __func__, ret); - goto vendor_suspend; +/* +* If the h8 exit fails during the runtime resume +* process, it becomes stuck and cannot be recovered +* through the error handler. To fix this, use link +* recovery instead of the error handler. +*/ + ret =ufshcd_link_recovery (hba); +if (ret) + goto vendor_suspend; } }else if (ufshcd_is_link_off (hba)) {/*
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 50/311 regulator: fp9931: Fix PM runtime reference leak in fp9931_hwmon_read()
In reply to Sasha LevinFrom: Felix Gu <[email protected]>
[ Upstream commit 0902010c8d163f7b62e655efda1a843529152c7c ]
In fp9931_hwmon_read(), if regmap_read() failed, the function returned the error code without calling pm_runtime_put_autosuspend(), causing a PM reference leak.
--- drivers/regulator/fp9931.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/regulator/fp9931.c +3 -4
@@ -144,13 +144,12 @@ static int fp9931_hwmon_read(struct device *dev, enum hwmon_sensor_types type,return ret; ret =regmap_read (data->regmap,FP9931_REG_TMST_VALUE , &val); -if (ret) -return ret; +if (!ret) + *temp = (s8 )val *1000 ;pm_runtime_put_autosuspend (data->dev); - *temp = (s8 )val *1000 ; -return 0 ; +return ret; } static umode_t fp9931_hwmon_is_visible(const void *data,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 51/311 regulator: bq257xx: Fix device node reference leak in bq257xx_reg_dt_parse_gpio()
In reply to Sasha LevinFrom: Felix Gu <[email protected]>
[ Upstream commit 4baaddaa44af01cd4ce239493060738fd0881835 ]
In bq257xx_reg_dt_parse_gpio(), if fails to get subchild, it returns without calling of_node_put(child), causing the device node reference leak.
--- drivers/regulator/bq257xx-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/regulator/bq257xx-regulator.c +1 -2
@@ -115,11 +115,10 @@ static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)return ; subchild =of_get_child_by_name (child, pdata->desc.of_match); +of_node_put (child);if (!subchild)return ; -of_node_put (child); - pdata->otg_en_gpio = devm_fwnode_gpiod_get_index(&pdev->dev, of_fwnode_handle(subchild), "enable", 0,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 52/311 irqchip/ls-extirq: Fix devm_of_iomap() error check
In reply to Sasha LevinFrom: Ioana Ciornei <[email protected]>
[ Upstream commit fe5669e363b129cde285bfb4d45abb72d1d77cfc ]
The devm_of_iomap() function returns an ERR_PTR() encoded error code on failure. Replace the incorrect check against NULL with IS_ERR().
--- drivers/irqchip/irq-ls-extirq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/irqchip/irq-ls-extirq.c +4 -2
@@ -190,8 +190,10 @@ static int ls_extirq_probe(struct platform_device *pdev)return dev_err_probe (dev, -ENOMEM ,"Failed to allocate memory\n" ); priv->intpcr =devm_of_iomap (dev, node,0 ,NULL ); -if (!priv->intpcr) -return dev_err_probe (dev, -ENOMEM ,"Cannot ioremap OF node %pOF\n" , node); +if (IS_ERR (priv->intpcr)) { +return dev_err_probe (dev,PTR_ERR (priv->intpcr), +"Cannot ioremap OF node %pOF\n" , node); + } ret =ls_extirq_parse_map (priv, node);if (ret)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 53/311 io_uring/cmd_net: use READ_ONCE() for ->addr3 read
In reply to Sasha LevinFrom: Jens Axboe <[email protected]>
[ Upstream commit a46435537a844d0f7b4b620baf962cad136422de ]
Any SQE read should use READ_ONCE(), to ensure the result is read once and only once. Doesn't really matter for this case, but it's better to keep these 100% consistent and always use READ_ONCE() for the prep side of SQE handling.
--- io_uring/cmd_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
io_uring/cmd_net.c +1 -1
@@ -145,7 +145,7 @@ static int io_uring_cmd_getsockname(struct socket *sock,return -EINVAL ; uaddr =u64_to_user_ptr (READ_ONCE (sqe->addr)); - ulen =u64_to_user_ptr (sqe->addr3); + ulen =u64_to_user_ptr (READ_ONCE (sqe->addr3)); peer =READ_ONCE (sqe->optlen);if (peer >1 )return -EINVAL ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 54/311 zloop: advertise a volatile write cache
In reply to Sasha LevinFrom: Christoph Hellwig <[email protected]>
[ Upstream commit 6acf7860dcc79ed045cc9e6a79c8a8bb6959dba7 ]
Zloop is file system backed and thus needs to sync the underlying file system to persist data. Set BLK_FEAT_WRITE_CACHE so that the block layer actually send flush commands, and fix the flush implementation as sync_filesystem requires s_umount to be held and the code currently misses that.
--- drivers/block/zloop.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/block/zloop.c +18 -6
@@ -542,6 +542,21 @@ static void zloop_rw(struct zloop_cmd *cmd)zloop_put_cmd (cmd); } +/* +* Sync the entire FS containing the zone files instead of walking all files. +*/ +static int zloop_flush (struct zloop_device *zlo) +{ +struct super_block *sb =file_inode (zlo->data_dir)->i_sb; +int ret; + +down_read (&sb->s_umount); + ret =sync_filesystem (sb); +up_read (&sb->s_umount); + +return ret; +} +static void zloop_handle_cmd (struct zloop_cmd *cmd) {struct request *rq =blk_mq_rq_from_pdu (cmd);
@@ -562,11 +577,7 @@ static void zloop_handle_cmd(struct zloop_cmd *cmd)zloop_rw (cmd);return ;case REQ_OP_FLUSH : -/* -* Sync the entire FS containing the zone files instead of -* walking all files -*/ - cmd->ret =sync_filesystem (file_inode (zlo->data_dir)->i_sb); + cmd->ret =zloop_flush (zlo);break ;case REQ_OP_ZONE_RESET : cmd->ret =zloop_reset_zone (zlo,rq_zone_no (rq));
@@ -981,7 +992,8 @@ static int zloop_ctl_add(struct zloop_options *opts)struct queue_limits lim = { .max_hw_sectors =SZ_1M >>SECTOR_SHIFT , .chunk_sectors = opts->zone_size, - .features =BLK_FEAT_ZONED , + .features =BLK_FEAT_ZONED |BLK_FEAT_WRITE_CACHE , + };unsigned int nr_zones, i, j;struct zloop_device *zlo;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 55/311 zloop: check for spurious options passed to remove
In reply to Sasha LevinFrom: Christoph Hellwig <[email protected]>
[ Upstream commit 3c4617117a2b7682cf037be5e5533e379707f050 ]
Zloop uses a command option parser for all control commands, but most options are only valid for adding a new device. Check for incorrectly specified options in the remove handler.
--- drivers/block/zloop.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/zloop.c +6 -1
@@ -1174,7 +1174,12 @@ static int zloop_ctl_remove(struct zloop_options *opts)int ret;if (!(opts->mask &ZLOOP_OPT_ID )) { -pr_err ("No ID specified\n" ); +pr_err ("No ID specified for remove\n" ); +return -EINVAL ; + } + +if (opts->mask & ~ZLOOP_OPT_ID ) { +pr_err ("Invalid option specified for remove\n" );return -EINVAL ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 56/311 drm/client: Do not destroy NULL modes
In reply to Sasha LevinFrom: Jonathan Cavitt <[email protected]>
[ Upstream commit c601fd5414315fc515f746b499110e46272e7243 ]
'modes' in drm_client_modeset_probe may fail to kcalloc. If this occurs, we jump to 'out', calling modes_destroy on it, which dereferences it. This may result in a NULL pointer dereference in the error case. Prevent that.
--- drivers/gpu/drm/drm_client_modeset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_client_modeset.c +2 -1
@@ -930,7 +930,8 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width,mutex_unlock (&client->modeset_mutex); out:kfree (crtcs); -modes_destroy (dev, modes, connector_count); +if (modes) +modes_destroy (dev, modes, connector_count);kfree (modes);kfree (offsets);kfree (enabled);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 57/311 ALSA: usb-audio: Cap the packet size pre-calculations
In reply to Sasha LevinFrom: Takashi Iwai <[email protected]>
[ Upstream commit 7fe8dec3f628e9779f1631576f8e693370050348 ]
We calculate the possible packet sizes beforehand for adaptive and synchronous endpoints, but we didn't take care of the max frame size for those pre-calculated values. When a device or a bus limits the packet size, a high sample rate or a high number of channels may lead to the packet sizes that are larger than the given limit, which results in an error from the USB core at submitting URBs.
As a simple workaround, just add the sanity checks of pre-calculated packet sizes to have the upper boundary of ep->maxframesize.
--- sound/usb/endpoint.c | 3 +++ 1 file changed, 3 insertions(+)
sound/usb/endpoint.c +3 -0
@@ -1374,6 +1374,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,return -EINVAL ; } + ep->packsize[0 ] =min (ep->packsize[0 ], ep->maxframesize); + ep->packsize[1 ] =min (ep->packsize[1 ], ep->maxframesize); +/* calculate the frequency in 16.16 format */ ep->freqm = ep->freqn; ep->freqshift =INT_MIN ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 58/311 ALSA: usb-audio: Use inclusive terms
In reply to Sasha LevinFrom: Takashi Iwai <[email protected]>
[ Upstream commit 4e9113c533acee2ba1f72fd68ee6ecd36b64484e ]
Replace the remaining with inclusive terms; it's only this function name we overlooked at the previous conversion.
--- sound/usb/endpoint.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +3 -3
@@ -160,8 +160,8 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)* This won't be used for implicit feedback which takes the packet size * returned from the sync source */ -static int slave_next_packet_size (struct snd_usb_endpoint *ep, -unsigned int avail) +static int synced_next_packet_size (struct snd_usb_endpoint *ep, +unsigned int avail) {unsigned int phase;int ret;
@@ -227,7 +227,7 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep, }if (ep->sync_source) -return slave_next_packet_size (ep, avail); +return synced_next_packet_size (ep, avail);else return next_packet_size (ep, avail); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 59/311 perf: Fix __perf_event_overflow() vs perf_remove_from_context() race
In reply to Sasha LevinFrom: Peter Zijlstra <[email protected]>
[ Upstream commit c9bc1753b3cc41d0e01fbca7f035258b5f4db0ae ]
Make sure that __perf_event_overflow() runs with IRQs disabled for all possible callchains. Specifically the software events can end up running it with only preemption disabled.
This opens up a race vs perf_event_exit_event() and friends that will go and free various things the overflow path expects to be present, like the BPF program.
--- kernel/events/core.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-)
kernel/events/core.c +41 -1
@@ -10498,6 +10498,13 @@ int perf_event_overflow(struct perf_event *event,struct perf_sample_data *data, struct pt_regs *regs) { +/* +* Entry point from hardware PMI, interrupts should be disabled here. +* This serializes us against perf_event_remove_from_context() in +* things like perf_event_release_kernel(). +*/ +lockdep_assert_irqs_disabled (); +return __perf_event_overflow (event,1 , data, regs); }
@@ -10574,6 +10581,19 @@ static void perf_swevent_event(struct perf_event *event, u64 nr, {struct hw_perf_event *hwc = &event->hw; +/* +* This is: +* - software preempt +* - tracepoint preempt +* - tp_target_task irq (ctx->lock) +* - uprobes preempt/irq +* - kprobes preempt/irq +* - hw_breakpoint irq +* +* Any of these are sufficient to hold off RCU and thus ensure @event +* exists. +*/ +lockdep_assert_preemption_disabled ();local64_add (nr, &event->count);if (!regs)
@@ -10582,6 +10602,16 @@ static void perf_swevent_event(struct perf_event *event, u64 nr,if (!is_sampling_event (event))return ; +/* +* Serialize against event_function_call() IPIs like normal overflow +* event handling. Specifically, must not allow +* perf_event_release_kernel() -> perf_remove_from_context() to make +* progress and 'release' the event from under us. +*/ +guard (irqsave)(); +if (event->state !=PERF_EVENT_STATE_ACTIVE ) +return ; +if ((event->attr.sample_type &PERF_SAMPLE_PERIOD ) && !event->attr.freq) { data->period = nr;return perf_swevent_overflow (event,1 , data, regs);
@@ -11080,6 +11110,11 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,struct perf_sample_data data;struct perf_event *event; +/* +* Per being a tracepoint, this runs with preemption disabled. +*/ +lockdep_assert_preemption_disabled (); +struct perf_raw_record raw = { .frag = { .size = entry_size,
@@ -11412,6 +11447,11 @@ void perf_bp_event(struct perf_event *bp, void *data)struct perf_sample_data sample;struct pt_regs *regs = data; +/* +* Exception context, will have interrupts disabled. +*/ +lockdep_assert_irqs_disabled (); +perf_sample_data_init (&sample, bp->attr.bp_addr,0 );if (!bp->hw.state && !perf_exclude_event (bp, regs))
@@ -11876,7 +11916,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)if (regs && !perf_exclude_event (event, regs)) {if (!(event->attr.exclude_idle &&is_idle_task (current))) -if (__perf_event_overflow (event,1 , &data, regs)) +if (perf_event_overflow (event, &data, regs)) ret =HRTIMER_NORESTART ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 60/311 s390/idle: Fix cpu idle exit cpu time accounting
In reply to Sasha LevinFrom: Heiko Carstens <[email protected]>
[ Upstream commit 0d785e2c324c90662baa4fe07a0d02233ff92824 ]
With the conversion to generic entry [1] cpu idle exit cpu time accounting was converted from assembly to C. This introduced an reversed order of cpu time accounting.
On cpu idle exit the current accounting happens with the following call chain:
-> do_io_irq()/do_ext_irq()
-> irq_enter_rcu()
-> account_hardirq_enter()
-> vtime_account_irq()
-> vtime_account_kernel()
vtime_account_kernel() accounts the passed cpu time since last_update_timer as system time, and updates last_update_timer to the current cpu timer value.
However the subsequent call of
-> account_idle_time_irq()
will incorrectly subtract passed cpu time from timer_idle_enter to the updated last_update_timer value from system_timer. Then last_update_timer is updated to a sys_enter_timer, which means that last_update_timer goes back in time.
Subsequently account_hardirq_exit() will account too much cpu time as hardirq time. The sum of all accounted cpu times is still correct, however some cpu time which was previously accounted as system time is now accounted as hardirq time, plus there is the oddity that last_update_timer goes back in time.
Restore previous behavior by extracting cpu time accounting code from account_idle_time_irq() into a new update_timer_idle() function and call it before irq_enter_rcu().
--- arch/s390/include/asm/idle.h | 1 + arch/s390/kernel/idle.c | 13 +++++++++---- arch/s390/kernel/irq.c | 10 ++++++++-- 3 files changed, 18 insertions(+), 6 deletions(-)
arch/s390/include/asm/idle.h +1 -0
@@ -23,5 +23,6 @@ extern struct device_attribute dev_attr_idle_count;extern struct device_attribute dev_attr_idle_time_us;void psw_idle (struct s390_idle_data *data,unsigned long psw_mask); +void update_timer_idle (void );#endif /* _S390_IDLE_H */
arch/s390/kernel/idle.c +9 -4
@@ -21,11 +21,10 @@ static DEFINE_PER_CPU(struct s390_idle_data, s390_idle); -void account_idle_time_irq (void ) +void update_timer_idle (void ) {struct s390_idle_data *idle =this_cpu_ptr (&s390_idle);struct lowcore *lc =get_lowcore (); -unsigned long idle_time;u64 cycles_new[8 ];int i;
@@ -35,13 +34,19 @@ void account_idle_time_irq(void)this_cpu_add (mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]); } - idle_time = lc->int_clock - idle->clock_idle_enter; - lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock; lc->last_update_clock = lc->int_clock; lc->system_timer += lc->last_update_timer - idle->timer_idle_enter; lc->last_update_timer = lc->sys_enter_timer; +} + +void account_idle_time_irq (void ) +{ +struct s390_idle_data *idle =this_cpu_ptr (&s390_idle); +unsigned long idle_time; + + idle_time =get_lowcore ()->int_clock - idle->clock_idle_enter;/* Account time spent with enabled wait psw loaded as idle time. */ WRITE_ONCE (idle->idle_time,READ_ONCE (idle->idle_time) + idle_time);
arch/s390/kernel/irq.c +8 -2
@@ -146,6 +146,10 @@ void noinstr do_io_irq(struct pt_regs *regs)struct pt_regs *old_regs =set_irq_regs (regs);bool from_idle; + from_idle =test_and_clear_cpu_flag (CIF_ENABLED_WAIT ); +if (from_idle) +update_timer_idle (); +irq_enter_rcu ();if (user_mode (regs)) {
@@ -154,7 +158,6 @@ void noinstr do_io_irq(struct pt_regs *regs) current->thread.last_break = regs->last_break; } - from_idle =test_and_clear_cpu_flag (CIF_ENABLED_WAIT );if (from_idle)account_idle_time_irq ();
@@ -182,6 +185,10 @@ void noinstr do_ext_irq(struct pt_regs *regs)struct pt_regs *old_regs =set_irq_regs (regs);bool from_idle; + from_idle =test_and_clear_cpu_flag (CIF_ENABLED_WAIT ); +if (from_idle) +update_timer_idle (); +irq_enter_rcu ();if (user_mode (regs)) {
@@ -194,7 +201,6 @@ void noinstr do_ext_irq(struct pt_regs *regs) regs->int_parm =get_lowcore ()->ext_params; regs->int_parm_long =get_lowcore ()->ext_params2; - from_idle =test_and_clear_cpu_flag (CIF_ENABLED_WAIT );if (from_idle)account_idle_time_irq ();
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 61/311 s390/vtime: Fix virtual timer forwarding
In reply to Sasha LevinFrom: Heiko Carstens <[email protected]>
[ Upstream commit dbc0fb35679ed5d0adecf7d02137ac2c77244b3b ]
Since delayed accounting of system time [1] the virtual timer is forwarded by do_account_vtime() but also vtime_account_kernel(), vtime_account_softirq(), and vtime_account_hardirq(). This leads to double accounting of system, guest, softirq, and hardirq time.
Remove accounting from the vtime_account*() family to restore old behavior.
There is only one user of the vtimer interface, which might explain why nobody noticed this so far.
--- arch/s390/kernel/vtime.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-)
arch/s390/kernel/vtime.c +2 -16
@@ -225,10 +225,6 @@ static u64 vtime_delta(void)return timer - lc->last_update_timer; } -/* -* Update process times based on virtual cpu times stored by entry.S -* to the lowcore fields user_timer, system_timer & steal_clock. -*/ void vtime_account_kernel (struct task_struct *tsk) {struct lowcore *lc =get_lowcore ();
@@ -238,27 +234,17 @@ void vtime_account_kernel(struct task_struct *tsk) lc->guest_timer += delta; else lc->system_timer += delta; - -virt_timer_forward (delta); }EXPORT_SYMBOL_GPL (vtime_account_kernel);void vtime_account_softirq (struct task_struct *tsk) { -u64 delta =vtime_delta (); - -get_lowcore ()->softirq_timer += delta; - -virt_timer_forward (delta); +get_lowcore ()->softirq_timer +=vtime_delta (); }void vtime_account_hardirq (struct task_struct *tsk) { -u64 delta =vtime_delta (); - -get_lowcore ()->hardirq_timer += delta; - -virt_timer_forward (delta); +get_lowcore ()->hardirq_timer +=vtime_delta (); }/*
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 62/311 s390/kexec: Disable stack protector in s390_reset_system()
In reply to Sasha LevinFrom: Vasily Gorbik <[email protected]>
[ Upstream commit 1623a554c68f352c17d0a358bc62580dc187f06b ]
s390_reset_system() calls set_prefix(0), which switches back to the absolute lowcore. At that point the stack protector canary no longer matches the canary from the lowcore the function was entered with, so the stack check fails.
Mark s390_reset_system() __no_stack_protector. This is safe here since its callers (__do_machine_kdump() and __do_machine_kexec()) are effectively no-return and fall back to disabled_wait() on failure.
--- arch/s390/kernel/ipl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/ipl.c +1 -1
@@ -2377,7 +2377,7 @@ void __init setup_ipl(void)atomic_notifier_chain_register (&panic_notifier_list, &on_panic_nb); } -void s390_reset_system (void ) +void __no_stack_protector s390_reset_system(void) {/* Disable prefixing */ set_prefix (0 );
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 63/311 arm64: io: Rename ioremap_prot() to __ioremap_prot()
In reply to Sasha LevinFrom: Will Deacon <[email protected]>
[ Upstream commit f6bf47ab32e0863df50f5501d207dcdddb7fc507 ]
Rename our ioremap_prot() implementation to __ioremap_prot() and convert all arch-internal callers over to the new function.
ioremap_prot() remains as a #define to __ioremap_prot() for generic_access_phys() and will be subsequently extended to handle user permissions in 'prot'.
Stable-dep-of: 8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()")
--- arch/arm64/include/asm/io.h | 11 ++++++----- arch/arm64/kernel/acpi.c | 2 +- arch/arm64/mm/ioremap.c | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-)
arch/arm64/include/asm/io.h +6 -5
@@ -264,19 +264,20 @@ __iowrite64_copy(void __iomem *to, const void *from, size_t count)typedef int (*ioremap_prot_hook_t )(phys_addr_t phys_addr,size_t size,pgprot_t *prot);int arm64_ioremap_prot_hook_register (const ioremap_prot_hook_t hook); +void __iomem *__ioremap_prot (phys_addr_t phys,size_t size,pgprot_t prot); -#define ioremap_prot ioremap_prot +#define ioremap_prot __ioremap_prot#define _PAGE_IOREMAP PROT_DEVICE_nGnRE#define ioremap_wc (addr, size) \ - ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC)) + __ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))#define ioremap_np (addr, size) \ - ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRnE)) + __ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRnE))#define ioremap_encrypted (addr, size) \ - ioremap_prot((addr), (size), PAGE_KERNEL) + __ioremap_prot((addr), (size), PAGE_KERNEL)/* * io{read,write}{16,32,64}be() macros
@@ -297,7 +298,7 @@ static inline void __iomem *ioremap_cache(phys_addr_t addr, size_t size)if (pfn_is_map_memory (__phys_to_pfn (addr)))return (void __iomem *)__phys_to_virt (addr); -return ioremap_prot (addr, size,__pgprot (PROT_NORMAL )); +return __ioremap_prot (addr, size,__pgprot (PROT_NORMAL )); }/*
arch/arm64/kernel/acpi.c +1 -1
@@ -377,7 +377,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) prot =__acpi_get_writethrough_mem_attribute (); } } -return ioremap_prot (phys, size, prot); +return __ioremap_prot (phys, size, prot); }/*
arch/arm64/mm/ioremap.c +3 -3
@@ -14,8 +14,8 @@ int arm64_ioremap_prot_hook_register(ioremap_prot_hook_t hook)return 0 ; } -void __iomem *ioremap_prot (phys_addr_t phys_addr,size_t size, -pgprot_t pgprot) +void __iomem *__ioremap_prot (phys_addr_t phys_addr,size_t size, +pgprot_t pgprot) {unsigned long last_addr = phys_addr + size -1 ;
@@ -38,7 +38,7 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,return generic_ioremap_prot (phys_addr, size, pgprot); } -EXPORT_SYMBOL (ioremap_prot); +EXPORT_SYMBOL (__ioremap_prot);/* * Must be called after early_fixmap_init
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 64/311 arm64: io: Extract user memory type in ioremap_prot()
In reply to Sasha LevinFrom: Will Deacon <[email protected]>
[ Upstream commit 8f098037139b294050053123ab2bc0f819d08932 ]
The only caller of ioremap_prot() outside of the generic ioremap() implementation is generic_access_phys(), which passes a 'pgprot_t' value determined from the user mapping of the target 'pfn' being accessed by the kernel. On arm64, the 'pgprot_t' contains all of the non-address bits from the pte, including the permission controls, and so we end up returning a new user mapping from ioremap_prot() which faults when accessed from the kernel on systems with PAN:
| Unable to handle kernel read from unreadable memory at virtual address ffff80008ea89000 | ... | Call trace: | __memcpy_fromio+0x80/0xf8 | generic_access_phys+0x20c/0x2b8 | __access_remote_vm+0x46c/0x5b8 | access_remote_vm+0x18/0x30 | environ_read+0x238/0x3e8 | vfs_read+0xe4/0x2b0 | ksys_read+0xcc/0x178 | __arm64_sys_read+0x4c/0x68
Extract only the memory type from the user 'pgprot_t' in ioremap_prot() and assert that we're being passed a user mapping, to protect us against any changes in future that may require additional handling. To avoid falsely flagging users of ioremap(), provide our own ioremap() macro which simply wraps __ioremap_prot().
--- arch/arm64/include/asm/io.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
arch/arm64/include/asm/io.h +15 -2
@@ -266,10 +266,23 @@ typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size,int arm64_ioremap_prot_hook_register (const ioremap_prot_hook_t hook);void __iomem *__ioremap_prot (phys_addr_t phys,size_t size,pgprot_t prot); -#define ioremap_prot __ioremap_prot +static inline void __iomem *ioremap_prot (phys_addr_t phys,size_t size, +pgprot_t user_prot) +{ +pgprot_t prot; +ptdesc_t user_prot_val =pgprot_val (user_prot); + +if (WARN_ON_ONCE (!(user_prot_val &PTE_USER ))) +return NULL ; -#define _PAGE_IOREMAP PROT_DEVICE_nGnRE + prot =__pgprot_modify (PAGE_KERNEL ,PTE_ATTRINDX_MASK , + user_prot_val &PTE_ATTRINDX_MASK ); +return __ioremap_prot (phys, size, prot); +} +#define ioremap_prot ioremap_prot +#define ioremap (addr, size) \ + __ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRE))#define ioremap_wc (addr, size) \ __ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))#define ioremap_np (addr, size) \
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 65/311 PCI: dwc: ep: Refresh MSI Message Address cache on change
In reply to Sasha LevinFrom: Niklas Cassel <[email protected]>
[ Upstream commit 468711a40d5dfc01bf0a24c1981246a2c93ac405 ]
Endpoint drivers use dw_pcie_ep_raise_msi_irq() to raise MSI interrupts to the host. After 8719c64e76bf ("PCI: dwc: ep: Cache MSI outbound iATU mapping"), dw_pcie_ep_raise_msi_irq() caches the Message Address from the MSI Capability in ep->msi_msg_addr. But that Message Address is controlled by the host, and it may change. For example, if:
- firmware on the host configures the Message Address and triggers an MSI,
- a driver on the Endpoint raises the MSI via dw_pcie_ep_raise_msi_irq(), which caches the Message Address,
- a kernel on the host reconfigures the Message Address and the host kernel driver triggers another MSI,
dw_pcie_ep_raise_msi_irq() notices that the Message Address no longer matches the cached ep->msi_msg_addr, warns about it, and returns error instead of raising the MSI. The host kernel may hang because it never receives the MSI.
This was seen with the nvmet_pci_epf_driver: the host UEFI performs NVMe commands, e.g. Identify Controller to get the name of the controller, nvmet-pci-epf posts the completion queue entry and raises an IRQ using dw_pcie_ep_raise_msi_irq(). When the host boots Linux, we see a WARN_ON_ONCE() from dw_pcie_ep_raise_msi_irq(), and the host kernel hangs because the nvme driver never gets an IRQ.
Remove the warning when dw_pcie_ep_raise_msi_irq() notices that Message Address has changed, remap using the new address, and update the ep->msi_msg_addr cache.
--- .../pci/controller/dwc/pcie-designware-ep.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-)
drivers/pci/controller/dwc/pcie-designware-ep.c +13 -9
@@ -904,6 +904,19 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,* supported, so we avoid reprogramming the region on every MSI, * specifically unmapping immediately after writel(). */ +if (ep->msi_iatu_mapped && (ep->msi_msg_addr != msg_addr || + ep->msi_map_size != map_size)) { +/* +* The host changed the MSI target address or the required +* mapping size changed. Reprogramming the iATU when there are +* operations in flight is unsafe on this controller. However, +* there is no unified way to check if we have operations in +* flight, thus we don't know if we should WARN() or not. +*/ +dw_pcie_ep_unmap_addr (epc, func_no,0 , ep->msi_mem_phys); + ep->msi_iatu_mapped = false; + } +if (!ep->msi_iatu_mapped) { ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr,
@@ -914,15 +927,6 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, ep->msi_iatu_mapped = true; ep->msi_msg_addr = msg_addr; ep->msi_map_size = map_size; - }else if (WARN_ON_ONCE (ep->msi_msg_addr != msg_addr || - ep->msi_map_size != map_size)) { -/* -* The host changed the MSI target address or the required -* mapping size changed. Reprogramming the iATU at runtime is -* unsafe on this controller, so bail out instead of trying to -* update the existing region. -*/ -return -EINVAL ; }writel (msg_data | (interrupt_num -1 ), ep->msi_mem + offset);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 66/311 PCI: dwc: ep: Flush MSI-X write before unmapping its ATU entry
In reply to Sasha LevinFrom: Niklas Cassel <[email protected]>
[ Upstream commit c22533c66ccae10511ad6a7afc34bb26c47577e3 ]
Endpoint drivers use dw_pcie_ep_raise_msix_irq() to raise an MSI-X interrupt to the host using a writel(), which generates a PCI posted write transaction. There's no completion for posted writes, so the writel() may return before the PCI write completes. dw_pcie_ep_raise_msix_irq() also unmaps the outbound ATU entry used for the PCI write, so the write races with the unmap.
If the PCI write loses the race with the ATU unmap, the write may corrupt host memory or cause IOMMU errors, e.g., these when running fio with a larger queue depth against nvmet-pci-epf:
arm-smmu-v3 fc900000.iommu: 0x0000010000000010 arm-smmu-v3 fc900000.iommu: 0x0000020000000000 arm-smmu-v3 fc900000.iommu: 0x000000090000f040 arm-smmu-v3 fc900000.iommu: 0x0000000000000000
arm-smmu-v3 fc900000.iommu: event: F_TRANSLATION client: 0000:01:00.0 sid: 0x100 ssid: 0x0 iova: 0x90000f040 ipa: 0x0 arm-smmu-v3 fc900000.iommu: unpriv data write s1 "Input address caused fault" stag: 0x0
Flush the write by performing a readl() of the same address to ensure that the write has reached the destination before the ATU entry is unmapped.
The same problem was solved for dw_pcie_ep_raise_msi_irq() in commit 8719c64e76bf ("PCI: dwc: ep: Cache MSI outbound iATU mapping"), but there it was solved by dedicating an outbound iATU only for MSI. We can't do the same for MSI-X because each vector can have a different msg_addr and the msg_addr may be changed while the vector is masked.
--- drivers/pci/controller/dwc/pcie-designware-ep.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/pci/controller/dwc/pcie-designware-ep.c +3 -0
@@ -1013,6 +1013,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,writel (msg_data, ep->msi_mem + offset); +/* flush posted write before unmap */ +readl (ep->msi_mem + offset); +dw_pcie_ep_unmap_addr (epc, func_no,0 , ep->msi_mem_phys);return 0 ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 67/311 drm/amdgpu/userq: Do not allow userspace to trivially triger kernel warnings
In reply to Sasha LevinFrom: Tvrtko Ursulin <[email protected]>
[ Upstream commit 7b7d7693a55d606d700beb9549c9f7f0e5d9c24f ]
Userspace can either deliberately pass in the too small num_fences, or the required number can legitimately grow between the two calls to the userq wait ioctl. In both cases we do not want the emit the kernel warning backtrace since nothing is wrong with the kernel and userspace will simply get an errno reported back. So lets simply drop the WARN_ONs.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +4 -4
@@ -830,7 +830,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,dma_resv_for_each_fence (&resv_cursor, gobj_read[i]->resv,DMA_RESV_USAGE_READ , fence) { -if (WARN_ON_ONCE (num_fences >= wait_info->num_fences)) { +if (num_fences >= wait_info->num_fences) { r = -EINVAL ; goto free_fences; }
@@ -847,7 +847,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,dma_resv_for_each_fence (&resv_cursor, gobj_write[i]->resv,DMA_RESV_USAGE_WRITE , fence) { -if (WARN_ON_ONCE (num_fences >= wait_info->num_fences)) { +if (num_fences >= wait_info->num_fences) { r = -EINVAL ; goto free_fences; }
@@ -871,7 +871,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, goto free_fences;dma_fence_unwrap_for_each (f, &iter, fence) { -if (WARN_ON_ONCE (num_fences >= wait_info->num_fences)) { +if (num_fences >= wait_info->num_fences) { r = -EINVAL ; goto free_fences; }
@@ -895,7 +895,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,if (r) goto free_fences; -if (WARN_ON_ONCE (num_fences >= wait_info->num_fences)) { +if (num_fences >= wait_info->num_fences) { r = -EINVAL ; goto free_fences; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 68/311 drm/amdgpu: Unlock a mutex before destroying it
In reply to Sasha LevinFrom: Bart Van Assche <[email protected]>
[ Upstream commit 5e0bcc7b88bcd081aaae6f481b10d9ab294fcb69 ]
Mutexes must be unlocked before these are destroyed. This has been detected by the Clang thread-safety analyzer.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +1 -0
@@ -641,6 +641,7 @@ static void aca_error_fini(struct aca_error *aerr)aca_bank_error_remove (aerr, bank_error); out_unlock: +mutex_unlock (&aerr->lock);mutex_destroy (&aerr->lock); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 69/311 drm/amdgpu: Fix locking bugs in error paths
In reply to Sasha LevinFrom: Bart Van Assche <[email protected]>
[ Upstream commit 480ad5f6ead4a47b969aab6618573cd6822bb6a4 ]
Do not unlock psp->ras_context.mutex if it has not been locked. This has been detected by the Clang thread-safety analyzer.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +7 -5
@@ -332,13 +332,13 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, sizeif (!context || !context->initialized) {dev_err (adev->dev,"TA is not initialized\n" ); ret = -EINVAL ; - goto err_free_shared_buf; + goto free_shared_buf; }if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {dev_err (adev->dev,"Unsupported function to invoke TA\n" ); ret = -EOPNOTSUPP ; - goto err_free_shared_buf; + goto free_shared_buf; } context->session_id = ta_id;
@@ -346,7 +346,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, sizemutex_lock (&psp->ras_context.mutex); ret =prep_ta_mem_context (&context->mem_context, shared_buf, shared_buf_len);if (ret) - goto err_free_shared_buf; + goto unlock; ret =psp_fn_ta_invoke (psp, cmd_id);if (ret || context->resp_status) {
@@ -354,15 +354,17 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size ret, context->resp_status);if (!ret) { ret = -EINVAL ; - goto err_free_shared_buf; + goto unlock; } }if (copy_to_user ((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len)) ret = -EFAULT ; -err_free_shared_buf: +unlock:mutex_unlock (&psp->ras_context.mutex); + +free_shared_buf:kfree (shared_buf);return ret;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 70/311 drm/amdgpu: Fix error handling in slot reset
In reply to Sasha LevinFrom: Lijo Lazar <[email protected]>
[ Upstream commit b57c4ec98c17789136a4db948aec6daadceb5024 ]
If the device has not recovered after slot reset is called, it goes to out label for error handling. There it could make decision based on uninitialized hive pointer and could result in accessing an uninitialized list.
Initialize the list and hive properly so that it handles the error situation and also releases the reset domain lock which is acquired during error_detected callback.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +10 -7
@@ -7203,6 +7203,15 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)dev_info (adev->dev,"PCI error: slot reset callback!!\n" );memset (&reset_context,0 ,sizeof (reset_context)); +INIT_LIST_HEAD (&device_list); + hive =amdgpu_get_xgmi_hive (adev); +if (hive) { +mutex_lock (&hive->hive_lock); +list_for_each_entry (tmp_adev, &hive->device_list, gmc.xgmi.head) +list_add_tail (&tmp_adev->reset_list, &device_list); + }else { +list_add_tail (&adev->reset_list, &device_list); + }if (adev->pcie_reset_ctx.swus) link_dev = adev->pcie_reset_ctx.swus;
@@ -7243,19 +7252,13 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) reset_context.reset_req_dev = adev;set_bit (AMDGPU_NEED_FULL_RESET , &reset_context.flags);set_bit (AMDGPU_SKIP_COREDUMP , &reset_context.flags); -INIT_LIST_HEAD (&device_list); - hive =amdgpu_get_xgmi_hive (adev);if (hive) { -mutex_lock (&hive->hive_lock); reset_context.hive = hive; -list_for_each_entry (tmp_adev, &hive->device_list, gmc.xgmi.head) { +list_for_each_entry (tmp_adev, &hive->device_list, gmc.xgmi.head) tmp_adev->pcie_reset_ctx.in_link_reset = true; -list_add_tail (&tmp_adev->reset_list, &device_list); - } }else {set_bit (AMDGPU_SKIP_HW_RESET , &reset_context.flags); -list_add_tail (&adev->reset_list, &device_list); } r =amdgpu_device_asic_reset (adev, &device_list, &reset_context);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 71/311 ALSA: hda: cs35l56: Fix signedness error in cs35l56_hda_posture_put()
In reply to Sasha LevinFrom: Richard Fitzgerald <[email protected]>
[ Upstream commit 003ce8c9b2ca28fbb4860651e76fb1c9a91f2ea1 ]
In cs35l56_hda_posture_put() assign ucontrol->value.integer.value[0] to a long instead of an unsigned long. ucontrol->value.integer.value[0] is a long.
This fixes the sparse warning:
sound/hda/codecs/side-codecs/cs35l56_hda.c:256:20: warning: unsigned value that used to be signed checked against zero? sound/hda/codecs/side-codecs/cs35l56_hda.c:252:29: signed value source
--- sound/hda/codecs/side-codecs/cs35l56_hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/hda/codecs/side-codecs/cs35l56_hda.c +1 -1
@@ -249,7 +249,7 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {struct cs35l56_hda *cs35l56 =snd_kcontrol_chip (kcontrol); -unsigned long pos = ucontrol->value.integer.value[0 ]; +long pos = ucontrol->value.integer.value[0 ];bool changed;int ret;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 72/311 btrfs: free pages on error in btrfs_uring_read_extent()
In reply to Sasha LevinFrom: Miquel Sabaté Solà <[email protected]>
[ Upstream commit 3f501412f2079ca14bf68a18d80a2b7a823f1f64 ]
In this function the 'pages' object is never freed in the hopes that it is picked up by btrfs_uring_read_finished() whenever that executes in the future. But that's just the happy path. Along the way previous allocations might have gone wrong, or we might not get -EIOCBQUEUED from btrfs_encoded_read_regular_fill_pages(). In all these cases, we go to a cleanup section that frees all memory allocated by this function without assuming any deferred execution, and this also needs to happen for the 'pages' allocation.
--- fs/btrfs/ioctl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/btrfs/ioctl.c +6 -1
@@ -4661,7 +4661,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter, {struct btrfs_inode *inode =BTRFS_I (file_inode (iocb->ki_filp));struct extent_io_tree *io_tree = &inode->io_tree; -struct page **pages; +struct page **pages =NULL ;struct btrfs_uring_priv *priv =NULL ;unsigned long nr_pages;int ret;
@@ -4719,6 +4719,11 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,btrfs_unlock_extent (io_tree, start, lockend, &cached_state);btrfs_inode_unlock (inode,BTRFS_ILOCK_SHARED );kfree (priv); +for (int i =0 ; i < nr_pages; i++) { +if (pages[i]) +__free_page (pages[i]); + } +kfree (pages);return ret; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 73/311 btrfs: fix error message order of parameters in btrfs_delete_delayed_dir_index()
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit 3cf0f35779d364cf2003c617bb7f3f3e41023372 ]
Fix the error message in btrfs_delete_delayed_dir_index() if __btrfs_add_delayed_item() fails: the message says root, inode, index, error, but we're actually passing index, root, inode, error.
--- fs/btrfs/delayed-inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/delayed-inode.c +1 -1
@@ -1673,7 +1673,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,if (unlikely (ret)) {btrfs_err (trans->fs_info,"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d" , - index,btrfs_root_id (node->root), node->inode_id, ret); +btrfs_root_id (node->root), node->inode_id, index, ret);btrfs_delayed_item_release_metadata (dir->root, item);btrfs_release_delayed_item (item); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 74/311 btrfs: fix incorrect key offset in error message in check_dev_extent_item()
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit 511dc8912ae3e929c1a182f5e6b2326516fd42a0 ]
Fix the error message in check_dev_extent_item(), when an overlapping stripe is encountered. For dev extents, objectid is the disk number and offset the physical address, so prev_key->objectid should actually be prev_key->offset.
(I can't take any credit for this one - this was discovered by Chris and his friend Claude.)
--- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
@@ -1893,7 +1893,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,if (unlikely (prev_key->offset + prev_len > key->offset)) {generic_err (leaf, slot,"dev extent overlap, prev offset %llu len %llu current offset %llu" , - prev_key->objectid, prev_len, key->offset); + prev_key->offset, prev_len, key->offset);return -EUCLEAN ; } }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 75/311 btrfs: fix objectid value in error message in check_extent_data_ref()
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit a10172780526c2002e062102ad4f2aabac495889 ]
Fix a copy-paste error in check_extent_data_ref(): we're printing root as in the message above, we should be printing objectid.
--- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
@@ -1712,7 +1712,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf, objectid > BTRFS_LAST_FREE_OBJECTID)) {extent_err (leaf, slot,"invalid extent data backref objectid value %llu" , - root); + objectid);return -EUCLEAN ; }if (unlikely (!IS_ALIGNED (offset, leaf->fs_info->sectorsize))) {
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 76/311 btrfs: fix warning in scrub_verify_one_metadata()
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit 44e2fda66427a0442d8d2c0e6443256fb458ab6b ]
Commit b471965fdb2d ("btrfs: fix replace/scrub failure with metadata_uuid") fixed the comparison in scrub_verify_one_metadata() to use metadata_uuid rather than fsid, but left the warning as it was. Fix it so it matches what we're doing.
--- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/scrub.c +1 -1
@@ -745,7 +745,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nrbtrfs_warn_rl (fs_info,"scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU" , logical, stripe->mirror_num, - header->fsid, fs_info->fs_devices->fsid); + header->fsid, fs_info->fs_devices->metadata_uuid);return ; } if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 77/311 btrfs: print correct subvol num if active swapfile prevents deletion
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit 1c7e9111f4e6d6d42bc47759c9af1ef91f03ac2c ]
Fix the error message in btrfs_delete_subvolume() if we can't delete a subvolume because it has an active swapfile: we were printing the number of the parent rather than the target.
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -4720,7 +4720,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)spin_unlock (&dest->root_item_lock);btrfs_warn (fs_info,"attempt to delete subvolume %llu with active swapfile" , -btrfs_root_id (root)); +btrfs_root_id (dest)); ret = -EPERM ; goto out_up_write; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 78/311 btrfs: fix compat mask in error messages in btrfs_check_features()
In reply to Sasha LevinFrom: Mark Harmstone <[email protected]>
[ Upstream commit 587bb33b10bda645a1028c1737ad3992b3d7cf61 ]
Commit d7f67ac9a928 ("btrfs: relax block-group-tree feature dependency checks") introduced a regression when it comes to handling unsupported incompat or compat_ro flags. Beforehand we only printed the flags that we didn't recognize, afterwards we printed them all, which is less useful. Fix the error handling so it behaves like it used to.
--- fs/btrfs/disk-io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/btrfs/disk-io.c +3 -3
@@ -3150,7 +3150,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP ) {btrfs_err (fs_info,"cannot mount because of unknown incompat features (0x%llx)" , - incompat); + incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP );return -EINVAL ; }
@@ -3182,7 +3182,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)if (compat_ro_unsupp && is_rw_mount) {btrfs_err (fs_info,"cannot mount read-write because of unknown compat_ro features (0x%llx)" , - compat_ro); + compat_ro_unsupp);return -EINVAL ; }
@@ -3195,7 +3195,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount) !btrfs_test_opt(fs_info, NOLOGREPLAY)) {btrfs_err (fs_info,"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay" , - compat_ro); + compat_ro_unsupp);return -EINVAL ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 79/311 ALSA: usb: qcom: Correct parameter comment for uaudio_transfer_buffer_setup()
In reply to Sasha LevinFrom: Takashi Iwai <[email protected]>
[ Upstream commit 1d6452a0ce78cd3f4e48943b5ba21d273a658298 ]
At fixing the memory leak of xfer buffer, we forgot to update the corresponding comment, too. This resulted in a kernel-doc warning with W=1. Let's correct it.
--- sound/usb/qcom/qc_audio_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/qcom/qc_audio_offload.c +1 -1
@@ -1007,7 +1007,7 @@ static int enable_audio_stream(struct snd_usb_substream *subs,/** * uaudio_transfer_buffer_setup() - fetch and populate xfer buffer params * @subs: usb substream -* @xfer_buf: xfer buf to be allocated +* @xfer_buf_cpu: xfer buf to be allocated * @xfer_buf_len: size of allocation * @mem_info: QMI response info *
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 80/311 mm/slab: pass __GFP_NOWARN to refill_sheaf() if fallback is available
In reply to Sasha LevinFrom: Harry Yoo <[email protected]>
[ Upstream commit 021ca6b670bebebc409d43845efcfe8c11c1dd54 ]
When refill_sheaf() is called, failing to refill the sheaf doesn't necessarily mean the allocation will fail because a fallback path might be available and serve the allocation request.
Suppress spurious warnings by passing __GFP_NOWARN along with __GFP_NOMEMALLOC whenever a fallback path is available.
When the caller is alloc_full_sheaf() or __pcs_replace_empty_main(), the kernel always falls back to the slowpath (__slab_alloc_node()). For __prefill_sheaf_pfmemalloc(), the fallback path is available only when gfp_pfmemalloc_allowed() returns true.
--- mm/slub.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
mm/slub.c +9 -4
@@ -2715,7 +2715,7 @@ static struct slab_sheaf *alloc_full_sheaf(struct kmem_cache *s, gfp_t gfp)if (!sheaf)return NULL ; -if (refill_sheaf (s, sheaf, gfp | __GFP_NOMEMALLOC)) { +if (refill_sheaf (s, sheaf, gfp | __GFP_NOMEMALLOC | __GFP_NOWARN)) {free_empty_sheaf (s, sheaf);return NULL ; }
@@ -5092,7 +5092,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,return NULL ;if (empty) { -if (!refill_sheaf (s, empty, gfp | __GFP_NOMEMALLOC)) { +if (!refill_sheaf (s, empty, gfp | __GFP_NOMEMALLOC | __GFP_NOWARN)) { full = empty; }else {/*
@@ -5395,9 +5395,14 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_noprof);static int __prefill_sheaf_pfmemalloc (struct kmem_cache *s,struct slab_sheaf *sheaf,gfp_t gfp) { -int ret =0 ; +gfp_t gfp_nomemalloc; +int ret; + + gfp_nomemalloc = gfp | __GFP_NOMEMALLOC; +if (gfp_pfmemalloc_allowed (gfp)) + gfp_nomemalloc |= __GFP_NOWARN; - ret =refill_sheaf (s, sheaf, gfp | __GFP_NOMEMALLOC); + ret =refill_sheaf (s, sheaf, gfp_nomemalloc);if (likely (!ret || !gfp_pfmemalloc_allowed (gfp)))return ret;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 81/311 ASoC: SDCA: Fix comments for sdca_irq_request()
In reply to Sasha LevinFrom: Takashi Iwai <[email protected]>
[ Upstream commit 71c1978ab6d2c6d48c31311855f1a85377c152ae ]
The kernel-doc comments for sdca_irq_request() contained some typos that lead to build warnings with W=1. Let's correct them.
--- sound/soc/sdca/sdca_interrupts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/sdca/sdca_interrupts.c +2 -2
@@ -246,9 +246,9 @@ static int sdca_irq_request_locked(struct device *dev, }/** -* sdca_request_irq - request an individual SDCA interrupt +* sdca_irq_request - request an individual SDCA interrupt * @dev: Pointer to the struct device against which things should be allocated. -* @interrupt_info: Pointer to the interrupt information structure. +* @info: Pointer to the interrupt information structure. * @sdca_irq: SDCA interrupt position. * @name: Name to be given to the IRQ. * @handler: A callback thread function to be called for the IRQ.
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 82/311 bpf, arm64: Force 8-byte alignment for JIT buffer to prevent atomic tearing
In reply to Sasha LevinFrom: Fuad Tabba <[email protected]>
[ Upstream commit ef06fd16d48704eac868441d98d4ef083d8f3d07 ]
struct bpf_plt contains a u64 target field. Currently, the BPF JIT allocator requests an alignment of 4 bytes (sizeof(u32)) for the JIT buffer.
Because the base address of the JIT buffer can be 4-byte aligned (e.g., ending in 0x4 or 0xc), the relative padding logic in build_plt() fails to ensure that target lands on an 8-byte boundary.
This leads to two issues:
1. UBSAN reports misaligned-access warnings when dereferencing the structure.
2. More critically, target is updated concurrently via WRITE_ONCE() in bpf_arch_text_poke() while the JIT'd code executes ldr. On arm64, 64-bit loads/stores are only guaranteed to be single-copy atomic if they are 64-bit aligned. A misaligned target risks a torn read, causing the JIT to jump to a corrupted address.
Fix this by increasing the allocation alignment requirement to 8 bytes (sizeof(u64)) in bpf_jit_binary_pack_alloc(). This anchors the base of the JIT buffer to an 8-byte boundary, allowing the relative padding math in build_plt() to correctly align the target field.
--- arch/arm64/net/bpf_jit_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/net/bpf_jit_comp.c +1 -1
@@ -2126,7 +2126,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) extable_offset =round_up (prog_size +PLT_TARGET_SIZE , extable_align); image_size = extable_offset + extable_size; ro_header =bpf_jit_binary_pack_alloc (image_size, &ro_image_ptr, -sizeof (u32), &header, &image_ptr, +sizeof (u64), &header, &image_ptr, jit_fill_hole);if (!ro_header) { prog = orig_prog;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 83/311 bpf: Fix stack-out-of-bounds write in devmap
In reply to Sasha LevinFrom: Kohei Enju <[email protected]>
[ Upstream commit b7bf516c3ecd9a2aae2dc2635178ab87b734fef1 ]
get_upper_ifindexes() iterates over all upper devices and writes their indices into an array without checking bounds.
Also the callers assume that the max number of upper devices is MAX_NEST_DEV and allocate excluded_devices[1+MAX_NEST_DEV] on the stack, but that assumption is not correct and the number of upper devices could be larger than MAX_NEST_DEV (e.g., many macvlans), causing a stack-out-of-bounds write.
Add a max parameter to get_upper_ifindexes() to avoid the issue. When there are too many upper devices, return -EOVERFLOW and abort the redirect.
To reproduce, create more than MAX_NEST_DEV(8) macvlans on a device with an XDP program attached using BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS. Then send a packet to the device to trigger the XDP redirect path.
--- kernel/bpf/devmap.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
kernel/bpf/devmap.c +17 -5
@@ -588,18 +588,22 @@ static inline bool is_ifindex_excluded(int *excluded, int num_excluded, int ifin }/* Get ifindex of each upper device. 'indexes' must be able to hold at -* least MAX_NEST_DEV elements. -* Returns the number of ifindexes added. +* least 'max' elements. +* Returns the number of ifindexes added, or -EOVERFLOW if there are too +* many upper devices. */ -static int get_upper_ifindexes (struct net_device *dev,int *indexes) +static int get_upper_ifindexes (struct net_device *dev,int *indexes,int max) {struct net_device *upper;struct list_head *iter;int n =0 ;netdev_for_each_upper_dev_rcu (dev, upper, iter) { +if (n >= max) +return -EOVERFLOW ; indexes[n++] = upper->ifindex; } +return n; }
@@ -615,7 +619,11 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,int err;if (exclude_ingress) { - num_excluded =get_upper_ifindexes (dev_rx, excluded_devices); + num_excluded =get_upper_ifindexes (dev_rx, excluded_devices, +ARRAY_SIZE (excluded_devices) -1 ); +if (num_excluded <0 ) +return num_excluded; + excluded_devices[num_excluded++] = dev_rx->ifindex; }
@@ -733,7 +741,11 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,int err;if (exclude_ingress) { - num_excluded =get_upper_ifindexes (dev, excluded_devices); + num_excluded =get_upper_ifindexes (dev, excluded_devices, +ARRAY_SIZE (excluded_devices) -1 ); +if (num_excluded <0 ) +return num_excluded; + excluded_devices[num_excluded++] = dev->ifindex; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 84/311 selftests/bpf: Fix OOB read in dmabuf_collector
In reply to Sasha LevinFrom: "T.J. Mercier" <[email protected]>
[ Upstream commit 6881af27f9ea0f5ca8f606f573ef5cc25ca31fe4 ]
Dmabuf name allocations can be less than DMA_BUF_NAME_LEN characters, but bpf_probe_read_kernel always tries to read exactly that many bytes. If a name is less than DMA_BUF_NAME_LEN characters, bpf_probe_read_kernel will read past the end. bpf_probe_read_kernel_str stops at the first NUL terminator so use it instead, like iter_dmabuf_for_each already does.
--- tools/testing/selftests/bpf/progs/dmabuf_iter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/progs/dmabuf_iter.c +1 -1
@@ -48,7 +48,7 @@ int dmabuf_collector(struct bpf_iter__dmabuf *ctx)/* Buffers are not required to be named */ if (pname) { -if (bpf_probe_read_kernel (name,sizeof (name), pname)) +if (bpf_probe_read_kernel_str (name,sizeof (name), pname) <0 )return 1 ;/* Name strings can be provided by userspace */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 85/311 sched_ext: Fix SCX_EFLAG_INITIALIZED being a no-op flag
In reply to Sasha LevinFrom: David Carlier <[email protected]>
[ Upstream commit 749989b2d90ddc7dd253ad3b11a77cf882721acf ]
SCX_EFLAG_INITIALIZED is the sole member of enum scx_exit_flags with no explicit value, so the compiler assigns it 0. This makes the bitwise OR in scx_ops_init() a no-op:
sch->exit_info->flags |= SCX_EFLAG_INITIALIZED; /* |= 0 */
As a result, BPF schedulers cannot distinguish whether ops.init() completed successfully by inspecting exit_info->flags.
Assign the value 1LLU << 0 so the flag is actually set.
--- kernel/sched/ext_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/ext_internal.h +1 -1
@@ -74,7 +74,7 @@ enum scx_exit_flags {* info communication. The following flag indicates whether ops.init() * finished successfully. */ - SCX_EFLAG_INITIALIZED, + SCX_EFLAG_INITIALIZED = 1LLU << 0, };/*
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 86/311 spi: stm32: fix missing pointer assignment in case of dma chaining
In reply to Sasha LevinFrom: Alain Volmat <[email protected]>
[ Upstream commit e96493229a6399e902062213c6381162464cdd50 ]
Commit c4f2c05ab029 ("spi: stm32: fix pointer-to-pointer variables usage") introduced a regression since dma descriptors generated as part of the stm32_spi_prepare_rx_dma_mdma_chaining function are not well propagated to the caller function, leading to mdma-dma chaining being no more functional.
--- drivers/spi/spi-stm32.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/spi/spi-stm32.c +3 -0
@@ -1570,6 +1570,9 @@ static int stm32_spi_prepare_rx_dma_mdma_chaining(struct stm32_spi *spi,return -EINVAL ; } + *rx_mdma_desc = _mdma_desc; + *rx_dma_desc = _dma_desc; +return 0 ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 87/311 PCI: Correct PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value
In reply to Sasha LevinFrom: Bjorn Helgaas <[email protected]>
[ Upstream commit 39195990e4c093c9eecf88f29811c6de29265214 ]
fb82437fdd8c ("PCI: Change capability register offsets to hex") incorrectly converted the PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value from decimal 52 to hex 0x32:
-#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */
+#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32 /* end of v2 EPs w/ link */
This broke PCI capabilities in a VMM because subsequent ones weren't DWORD-aligned.
Change PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 to the correct value of 0x34.
fb82437fdd8c was from Baruch Siach <[email protected]>, but this was not Baruch's fault; it's a mistake I made when applying the patch.
--- include/uapi/linux/pci_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/pci_regs.h +1 -1
@@ -707,7 +707,7 @@#define PCI_EXP_LNKCTL2_HASD 0x0020/* HW Autonomous Speed Disable */ #define PCI_EXP_LNKSTA2 0x32/* Link Status 2 */ #define PCI_EXP_LNKSTA2_FLIT 0x0400/* Flit Mode Status */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32/* end of v2 EPs w/ link */ +#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x34/* end of v2 EPs w/ link */ #define PCI_EXP_SLTCAP2 0x34/* Slot Capabilities 2 */ #define PCI_EXP_SLTCAP2_IBPD 0x00000001/* In-band PD Disable Supported */ #define PCI_EXP_SLTCTL2 0x38/* Slot Control 2 */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 88/311 bpf: Fix race in cpumap on PREEMPT_RT
In reply to Sasha LevinFrom: Jiayuan Chen <[email protected]>
[ Upstream commit 869c63d5975d55e97f6b168e885452b3da20ea47 ]
On PREEMPT_RT kernels, the per-CPU xdp_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU.
The original code assumes bq_enqueue() and __cpu_map_flush() run atomically with respect to each other on the same CPU, relying on local_bh_disable() to prevent preemption. However, on PREEMPT_RT, local_bh_disable() only calls migrate_disable() (when PREEMPT_RT_NEEDS_BH_LOCK is not set) and does not disable preemption, which allows CFS scheduling to preempt a task during bq_flush_to_queue(), enabling another task on the same CPU to enter bq_enqueue() and operate on the same per-CPU bq concurrently.
This leads to several races:
1. Double __list_del_clearprev(): after bq->count is reset in bq_flush_to_queue(), a preempting task can call bq_enqueue() -> bq_flush_to_queue() on the same bq when bq->count reaches CPU_MAP_BULK_SIZE. Both tasks then call __list_del_clearprev() on the same bq->flush_node, the second call dereferences the prev pointer that was already set to NULL by the first.
2. bq->count and bq->q[] races: concurrent bq_enqueue() can corrupt the packet queue while bq_flush_to_queue() is processing it.
The race between task A (__cpu_map_flush -> bq_flush_to_queue) and task B (bq_enqueue -> bq_flush_to_queue) on the same CPU:
Task A (xdp_do_flush) Task B (cpu_map_enqueue)
---------------------- ------------------------
bq_flush_to_queue(bq)
spin_lock(&q->producer_lock)
/* flush bq->q[] to ptr_ring */
bq->count = 0
spin_unlock(&q->producer_lock)
bq_enqueue(rcpu, xdpf)
<-- CFS preempts Task A --> bq->q[bq->count++] = xdpf
/* ... more enqueues until full ... */
bq_flush_to_queue(bq)
spin_lock(&q->producer_lock)
/* flush to ptr_ring */
spin_unlock(&q->producer_lock)
__list_del_clearprev(flush_node)
/* sets flush_node.prev = NULL */
<-- Task A resumes -->
__list_del_clearprev(flush_node)
flush_node.prev->next = ...
/* prev is NULL -> kernel oops */Fix this by adding a local_lock_t to xdp_bulk_queue and acquiring it in bq_enqueue() and __cpu_map_flush(). These paths already run under local_bh_disable(), so use local_lock_nested_bh() which on non-RT is a pure annotation with no overhead, and on PREEMPT_RT provides a per-CPU sleeping lock that serializes access to the bq.
To reproduce, insert an mdelay(100) between bq->count = 0 and __list_del_clearprev() in bq_flush_to_queue(), then run reproducer provided by syzkaller.
--- kernel/bpf/cpumap.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
kernel/bpf/cpumap.c +15 -2
@@ -29,6 +29,7 @@#include <linux/sched.h> #include <linux/workqueue.h> #include <linux/kthread.h> +#include <linux/local_lock.h> #include <linux/completion.h> #include <trace/events/xdp.h> #include <linux/btf_ids.h>
@@ -52,6 +53,7 @@ struct xdp_bulk_queue {struct list_head flush_node;struct bpf_cpu_map_entry *obj;unsigned int count; +local_lock_t bq_lock; };/* Struct for every remote "destination" CPU in map */
@@ -451,6 +453,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,for_each_possible_cpu (i) { bq =per_cpu_ptr (rcpu->bulkq, i); bq->obj = rcpu; +local_lock_init (&bq->bq_lock); }/* Alloc queue */
@@ -717,6 +720,8 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)struct ptr_ring *q;int i; +lockdep_assert_held (&bq->bq_lock); +if (unlikely (!bq->count))return ;
@@ -744,11 +749,15 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq) }/* Runs under RCU-read-side, plus in softirq under NAPI protection. -* Thus, safe percpu variable access. +* Thus, safe percpu variable access. PREEMPT_RT relies on +* local_lock_nested_bh() to serialise access to the per-CPU bq. */ static void bq_enqueue (struct bpf_cpu_map_entry *rcpu,struct xdp_frame *xdpf) { -struct xdp_bulk_queue *bq =this_cpu_ptr (rcpu->bulkq); +struct xdp_bulk_queue *bq; + +local_lock_nested_bh (&rcpu->bulkq->bq_lock); + bq =this_cpu_ptr (rcpu->bulkq);if (unlikely (bq->count ==CPU_MAP_BULK_SIZE ))bq_flush_to_queue (bq);
@@ -769,6 +778,8 @@ static void bq_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf)list_add (&bq->flush_node, flush_list); } + +local_unlock_nested_bh (&rcpu->bulkq->bq_lock); } int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf,
@@ -805,7 +816,9 @@ void __cpu_map_flush(struct list_head *flush_list)struct xdp_bulk_queue *bq, *tmp;list_for_each_entry_safe (bq, tmp, flush_list, flush_node) { +local_lock_nested_bh (&bq->obj->bulkq->bq_lock);bq_flush_to_queue (bq); +local_unlock_nested_bh (&bq->obj->bulkq->bq_lock);/* If already running, costs spin_lock_irqsave + smb_mb */ wake_up_process (bq->obj->kthread);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 89/311 bpf: Fix race in devmap on PREEMPT_RT
In reply to Sasha LevinFrom: Jiayuan Chen <[email protected]>
[ Upstream commit 1872e75375c40add4a35990de3be77b5741c252c ]
On PREEMPT_RT kernels, the per-CPU xdp_dev_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU.
The original code assumes bq_enqueue() and __dev_flush() run atomically with respect to each other on the same CPU, relying on local_bh_disable() to prevent preemption. However, on PREEMPT_RT, local_bh_disable() only calls migrate_disable() (when PREEMPT_RT_NEEDS_BH_LOCK is not set) and does not disable preemption, which allows CFS scheduling to preempt a task during bq_xmit_all(), enabling another task on the same CPU to enter bq_enqueue() and operate on the same per-CPU bq concurrently.
This leads to several races:
1. Double-free / use-after-free on bq->q[]: bq_xmit_all() snapshots cnt = bq->count, then iterates bq->q[0..cnt-1] to transmit frames. If preempted after the snapshot, a second task can call bq_enqueue() -> bq_xmit_all() on the same bq, transmitting (and freeing) the same frames. When the first task resumes, it operates on stale pointers in bq->q[], causing use-after-free.
2. bq->count and bq->q[] corruption: concurrent bq_enqueue() modifying bq->count and bq->q[] while bq_xmit_all() is reading them.
3. dev_rx/xdp_prog teardown race: __dev_flush() clears bq->dev_rx and bq->xdp_prog after bq_xmit_all(). If preempted between bq_xmit_all() return and bq->dev_rx = NULL, a preempting bq_enqueue() sees dev_rx still set (non-NULL), skips adding bq to the flush_list, and enqueues a frame. When __dev_flush() resumes, it clears dev_rx and removes bq from the flush_list, orphaning the newly enqueued frame.
4. __list_del_clearprev() on flush_node: similar to the cpumap race, both tasks can call __list_del_clearprev() on the same flush_node, the second dereferences the prev pointer already set to NULL.
The race between task A (__dev_flush -> bq_xmit_all) and task B (bq_enqueue -> bq_xmit_all) on the same CPU:
Task A (xdp_do_flush) Task B (ndo_xdp_xmit redirect)
---------------------- --------------------------------
__dev_flush(flush_list)
bq_xmit_all(bq)
cnt = bq->count /* e.g. 16 */
/* start iterating bq->q[] */
<-- CFS preempts Task A -->
bq_enqueue(dev, xdpf)
bq->count == DEV_MAP_BULK_SIZE
bq_xmit_all(bq, 0)
cnt = bq->count /* same 16! */
ndo_xdp_xmit(bq->q[])
/* frames freed by driver */
bq->count = 0
<-- Task A resumes -->
ndo_xdp_xmit(bq->q[])
/* use-after-free: frames already freed! */Fix this by adding a local_lock_t to xdp_dev_bulk_queue and acquiring it in bq_enqueue() and __dev_flush(). These paths already run under local_bh_disable(), so use local_lock_nested_bh() which on non-RT is a pure annotation with no overhead, and on PREEMPT_RT provides a per-CPU sleeping lock that serializes access to the bq.
--- kernel/bpf/devmap.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
kernel/bpf/devmap.c +21 -4
@@ -45,6 +45,7 @@* types of devmap; only the lookup and insertion is different. */ #include <linux/bpf.h> +#include <linux/local_lock.h> #include <net/xdp.h> #include <linux/filter.h> #include <trace/events/xdp.h>
@@ -60,6 +61,7 @@ struct xdp_dev_bulk_queue {struct net_device *dev_rx;struct bpf_prog *xdp_prog;unsigned int count; +local_lock_t bq_lock; };struct bpf_dtab_netdev {
@@ -381,6 +383,8 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)int to_send = cnt;int i; +lockdep_assert_held (&bq->bq_lock); +if (unlikely (!cnt))return ;
@@ -425,10 +429,12 @@ void __dev_flush(struct list_head *flush_list)struct xdp_dev_bulk_queue *bq, *tmp;list_for_each_entry_safe (bq, tmp, flush_list, flush_node) { +local_lock_nested_bh (&bq->dev->xdp_bulkq->bq_lock);bq_xmit_all (bq,XDP_XMIT_FLUSH ); bq->dev_rx =NULL ; bq->xdp_prog =NULL ;__list_del_clearprev (&bq->flush_node); +local_unlock_nested_bh (&bq->dev->xdp_bulkq->bq_lock); } }
@@ -451,12 +457,16 @@ static void *__dev_map_lookup_elem(struct bpf_map *map, u32 key)/* Runs in NAPI, i.e., softirq under local_bh_disable(). Thus, safe percpu * variable access, and map elements stick around. See comment above -* xdp_do_flush() in filter.c. +* xdp_do_flush() in filter.c. PREEMPT_RT relies on local_lock_nested_bh() +* to serialise access to the per-CPU bq. */ static void bq_enqueue (struct net_device *dev,struct xdp_frame *xdpf,struct net_device *dev_rx,struct bpf_prog *xdp_prog) { -struct xdp_dev_bulk_queue *bq =this_cpu_ptr (dev->xdp_bulkq); +struct xdp_dev_bulk_queue *bq; + +local_lock_nested_bh (&dev->xdp_bulkq->bq_lock); + bq =this_cpu_ptr (dev->xdp_bulkq);if (unlikely (bq->count ==DEV_MAP_BULK_SIZE ))bq_xmit_all (bq,0 );
@@ -477,6 +487,8 @@ static void bq_enqueue(struct net_device *dev, struct xdp_frame *xdpf, } bq->q[bq->count++] = xdpf; + +local_unlock_nested_bh (&dev->xdp_bulkq->bq_lock); } static inline int __xdp_enqueue(struct net_device *dev, struct xdp_frame *xdpf,
@@ -1127,8 +1139,13 @@ static int dev_map_notification(struct notifier_block *notifier,if (!netdev->xdp_bulkq)return NOTIFY_BAD ; -for_each_possible_cpu (cpu) -per_cpu_ptr (netdev->xdp_bulkq, cpu)->dev = netdev; +for_each_possible_cpu (cpu) { +struct xdp_dev_bulk_queue *bq; + + bq =per_cpu_ptr (netdev->xdp_bulkq, cpu); + bq->dev = netdev; +local_lock_init (&bq->bq_lock); + }break ;case NETDEV_UNREGISTER :/* This rcu_read_lock/unlock pair is needed because
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 90/311 bpf: Add bitwise tracking for BPF_END
In reply to Sasha LevinFrom: Tianci Cao <[email protected]>
[ Upstream commit 9d21199842247ab05c675fb9b6c6ca393a5c0024 ]
This patch implements bitwise tracking (tnum analysis) for BPF_END (byte swap) operation.
Currently, the BPF verifier does not track value for BPF_END operation, treating the result as completely unknown. This limits the verifier's ability to prove safety of programs that perform endianness conversions, which are common in networking code.
For example, the following code pattern for port number validation:
int test(struct pt_regs *ctx) {
__u64 x = bpf_get_prandom_u32();
x &= 0x3f00; // Range: [0, 0x3f00], var_off: (0x0; 0x3f00)
x = bswap16(x); // Should swap to range [0, 0x3f], var_off: (0x0; 0x3f)
if (x > 0x3f) goto trap;
return 0;trap:
return *(u64 *)NULL; // Should be unreachable
}
Currently generates verifier output:
1: (54) w0 &= 16128 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=16128,var_off=(0x0; 0x3f00)) 2: (d7) r0 = bswap16 r0 ; R0=scalar() 3: (25) if r0 > 0x3f goto pc+2 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=63,var_off=(0x0; 0x3f))
Without this patch, even though the verifier knows x has certain bits set, after bswap16, it loses all tracking information and treats port as having a completely unknown value [0, 65535].
According to the BPF instruction set[1], there are 3 kinds of BPF_END:
1. bswap(16|32|64): opcode=0xd7 (BPF_END | BPF_ALU64 | BPF_TO_LE)
- do unconditional swap
2. le(16|32|64): opcode=0xd4 (BPF_END | BPF_ALU | BPF_TO_LE)
- on big-endian: do swap
- on little-endian: truncation (16/32-bit) or no-op (64-bit)
3. be(16|32|64): opcode=0xdc (BPF_END | BPF_ALU | BPF_TO_BE)
- on little-endian: do swap
- on big-endian: truncation (16/32-bit) or no-op (64-bit)
Since BPF_END operations are inherently bit-wise permutations, tnum (bitwise tracking) offers the most efficient and precise mechanism for value analysis. By implementing tnum_bswap16, tnum_bswap32, and tnum_bswap64, we can derive exact var_off values concisely, directly reflecting the bit-level changes.
Here is the overview of changes:
1. In tnum_bswap(16|32|64) (kernel/bpf/tnum.c):
Call swab(16|32|64) function on the value and mask of var_off, and do truncation for 16/32-bit cases.
2. In adjust_scalar_min_max_vals (kernel/bpf/verifier.c):
Call helper function scalar_byte_swap.
- Only do byte swap when
* alu64 (unconditional swap) OR
* switching between big-endian and little-endian machines.
- If need do byte swap:
* Firstly call tnum_bswap(16|32|64) to update var_off.
* Then reset the bound since byte swap scrambles the range.
- For 16/32-bit cases, truncate dst register to match the swapped size.
This enables better verification of networking code that frequently uses byte swaps for protocol processing, reducing false positive rejections.
[1] https://www.kernel.org/doc/Documentation/bpf/standardization/instruction-set.rst
Stable-dep-of: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value")
--- include/linux/tnum.h | 5 ++++ kernel/bpf/tnum.c | 16 ++++++++++++ kernel/bpf/verifier.c | 60 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 3 deletions(-)
include/linux/tnum.h +5 -0
@@ -63,6 +63,11 @@ struct tnum tnum_union(struct tnum t1, struct tnum t2);/* Return @a with all but the lowest @size bytes cleared */ struct tnum tnum_cast (struct tnum a,u8 size); +/* Swap the bytes of a tnum */ +struct tnum tnum_bswap16 (struct tnum a); +struct tnum tnum_bswap32 (struct tnum a); +struct tnum tnum_bswap64 (struct tnum a); +/* Returns true if @a is a known constant */ static inline bool tnum_is_const (struct tnum a) {
kernel/bpf/tnum.c +16 -0
@@ -8,6 +8,7 @@*/ #include <linux/kernel.h> #include <linux/tnum.h> +#include <linux/swab.h> #define TNUM (_v, _m) (struct tnum){.value = _v, .mask = _m}/* A completely unknown value */
@@ -253,3 +254,18 @@ struct tnum tnum_const_subreg(struct tnum a, u32 value) {return tnum_with_subreg (a,tnum_const (value)); } + +struct tnum tnum_bswap16 (struct tnum a) +{ +return TNUM (swab16 (a.value &0xFFFF ),swab16 (a.mask &0xFFFF )); +} + +struct tnum tnum_bswap32 (struct tnum a) +{ +return TNUM (swab32 (a.value &0xFFFFFFFF ),swab32 (a.mask &0xFFFFFFFF )); +} + +struct tnum tnum_bswap64 (struct tnum a) +{ +return TNUM (swab64 (a.value),swab64 (a.mask)); +}
kernel/bpf/verifier.c +57 -3
88 lines not on this page · raw message
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 91/311 bpf: Introduce tnum_step to step through tnum's members
In reply to Sasha LevinFrom: Harishankar Vishwanathan <[email protected]>
[ Upstream commit 76e954155b45294c502e3d3a9e15757c858ca55e ]
This commit introduces tnum_step(), a function that, when given t, and a number z returns the smallest member of t larger than z. The number z must be greater or equal to the smallest member of t and less than the largest member of t.
The first step is to compute j, a number that keeps all of t's known bits, and matches all unknown bits to z's bits. Since j is a member of the t, it is already a candidate for result. However, we want our result to be (minimally) greater than z.
There are only two possible cases:
(1) Case j <= z. In this case, we want to increase the value of j and make it > z.
(2) Case j > z. In this case, we want to decrease the value of j while keeping it > z.
(Case 1) j <= z
t = xx11x0x0
z = 10111101 (189)
j = 10111000 (184)
^
k(Case 1.1) Let's first consider the case where j < z. We will address j == z later.
Since z > j, there had to be a bit position that was 1 in z and a 0 in j, beyond which all positions of higher significance are equal in j and z. Further, this position could not have been unknown in a, because the unknown positions of a match z. This position had to be a 1 in z and known 0 in t.
Let k be position of the most significant 1-to-0 flip. In our example, k = 3 (starting the count at 1 at the least significant bit). Setting (to
1) the unknown bits of t in positions of significance smaller than k will not produce a result > z. Hence, we must set/unset the unknown bits at positions of significance higher than k. Specifically, we look for the next larger combination of 1s and 0s to place in those positions, relative to the combination that exists in z. We can achieve this by concatenating bits at unknown positions of t into an integer, adding 1, and writing the bits of that result back into the corresponding bit positions previously extracted from z.
Quoted 1 line
From our example, considering only positions of significance greater
than k:
t = xx..x
z = 10..1
+ 1
-----
11..0This is the exact combination 1s and 0s we need at the unknown bits of t in positions of significance greater than k. Further, our result must only increase the value minimally above z. Hence, unknown bits in positions of significance smaller than k should remain 0. We finally have,
result = 11110000 (240)
(Case 1.2) Now consider the case when j = z, for example
t = 1x1x0xxx
z = 10110100 (180)
j = 10110100 (180)
Matching the unknown bits of the t to the bits of z yielded exactly z. To produce a number greater than z, we must set/unset the unknown bits in t, and *all* the unknown bits of t candidates for being set/unset. We can do this similar to Case 1.1, by adding 1 to the bits extracted from the masked bit positions of z. Essentially, this case is equivalent to Case 1.1, with k = 0.
t = 1x1x0xxx
z = .0.1.100
+ 1
---------
.0.1.101This is the exact combination of bits needed in the unknown positions of t. After recalling the known positions of t, we get
result = 10110101 (181)
(Case 2) j > z
t = x00010x1
z = 10000010 (130)
j = 10001011 (139)
^ k
Since j > z, there had to be a bit position which was 0 in z, and a 1 in j, beyond which all positions of higher significance are equal in j and z. This position had to be a 0 in z and known 1 in t. Let k be the position of the most significant 0-to-1 flip. In our example, k = 4.
Because of the 0-to-1 flip at position k, a member of t can become greater than z if the bits in positions greater than k are themselves >= to z. To make that member *minimally* greater than z, the bits in positions greater than k must be exactly = z. Hence, we simply match all of t's unknown bits in positions more significant than k to z's bits. In positions less significant than k, we set all t's unknown bits to 0 to retain minimality.
In our example, in positions of greater significance than k (=4), t=x000. These positions are matched with z (1000) to produce 1000. In positions of lower significance than k, t=10x1. All unknown bits are set to 0 to produce 1001. The final result is:
result = 10001001 (137)
This concludes the computation for a result > z that is a member of t.
The procedure for tnum_step() in this commit implements the idea described above. As a proof of correctness, we verified the algorithm against a logical specification of tnum_step. The specification asserts the following about the inputs t, z and output res that:
1. res is a member of t, and
2. res is strictly greater than z, and
3. there does not exist another value res2 such that 3a. res2 is also a member of t, and 3b. res2 is greater than z
3c. res2 is smaller than res
We checked the implementation against this logical specification using an SMT solver. The verification formula in SMTLIB format is available at [1]. The verification returned an "unsat": indicating that no input assignment exists for which the implementation and the specification produce different outputs.
In addition, we also automatically generated the logical encoding of the C implementation using Agni [2] and verified it against the same specification. This verification also returned an "unsat", confirming that the implementation is equivalent to the specification. The formula for this check is also available at [3].
Stable-dep-of: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value")
--- include/linux/tnum.h | 3 +++ kernel/bpf/tnum.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
include/linux/tnum.h +3 -0
@@ -131,4 +131,7 @@ static inline bool tnum_subreg_is_const(struct tnum a) return !(tnum_subreg(a)).mask; } +/* Returns the smallest member of t larger than z */ +u64 tnum_step (struct tnum t,u64 z); +#endif /* _LINUX_TNUM_H */
kernel/bpf/tnum.c +56 -0
59 lines not on this page · raw message
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 92/311 bpf: Improve bounds when tnum has a single possible value
In reply to Sasha LevinFrom: Paul Chaignon <[email protected]>
[ Upstream commit efc11a667878a1d655ff034a93a539debbfedb12 ]
We're hitting an invariant violation in Cilium that sometimes leads to BPF programs being rejected and Cilium failing to start [1]. The following extract from verifier logs shows what's happening:
from 201 to 236: R1=0 R6=ctx() R7=1 R9=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) R10=fp0 236: R1=0 R6=ctx() R7=1 R9=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) R10=fp0 ; if (magic == MARK_MAGIC_HOST || magic == MARK_MAGIC_OVERLAY || magic == MARK_MAGIC_ENCRYPT) @ bpf_host.c:1337 236: (16) if w9 == 0xe00 goto pc+45 ; R9=scalar(smin=umin=smin32=umin32=3585,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) 237: (16) if w9 == 0xf00 goto pc+1 verifier bug: REG INVARIANTS VIOLATION (false_reg1): range bounds violation u64=[0xe01, 0xe00] s64=[0xe01, 0xe00] u32=[0xe01, 0xe00] s32=[0xe01, 0xe00] var_off=(0xe00, 0x0)
We reach instruction 236 with two possible values for R9, 0xe00 and 0xf00. This is perfectly reflected in the tnum, but of course the ranges are less accurate and cover [0xe00; 0xf00]. Taking the fallthrough path at instruction 236 allows the verifier to reduce the range to [0xe01; 0xf00]. The tnum is however not updated.
With these ranges, at instruction 237, the verifier is not able to deduce that R9 is always equal to 0xf00. Hence the fallthrough pass is explored first, the verifier refines the bounds using the assumption that R9 != 0xf00, and ends up with an invariant violation.
This pattern of impossible branch + bounds refinement is common to all invariant violations seen so far. The long-term solution is likely to rely on the refinement + invariant violation check to detect dead branches, as started by Eduard. To fix the current issue, we need something with less refactoring that we can backport.
This patch uses the tnum_step helper introduced in the previous patch to detect the above situation. In particular, three cases are now detected in the bounds refinement:
1. The u64 range and the tnum only overlap in umin.
u64: ---[xxxxxx]-----
tnum: --xx----------x-
2. The u64 range and the tnum only overlap in the maximum value represented by the tnum, called tmax.
u64: ---[xxxxxx]-----
tnum: xx-----x--------
3. The u64 range and the tnum only overlap in between umin (excluded) and umax.
u64: ---[xxxxxx]-----
tnum: xx----x-------x-
To detect these three cases, we call tnum_step(tnum, umin), which returns the smallest member of the tnum greater than umin, called tnum_next here. We're in case (1) if umin is part of the tnum and tnum_next is greater than umax. We're in case (2) if umin is not part of the tnum and tnum_next is equal to tmax. Finally, we're in case (3) if umin is not part of the tnum, tnum_next is inferior or equal to umax, and calling tnum_step a second time gives us a value past umax.
This change implements these three cases. With it, the above bytecode looks as follows:
0: (85) call bpf_get_prandom_u32#7 ; R0=scalar() 1: (47) r0 |= 3584 ; R0=scalar(smin=0x8000000000000e00,umin=umin32=3584,smin32=0x80000e00,var_off=(0xe00; 0xfffffffffffff1ff)) 2: (57) r0 &= 3840 ; R0=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) 3: (15) if r0 == 0xe00 goto pc+2 ; R0=3840
4: (15) if r0 == 0xf00 goto pc+1
4: R0=3840
6: (95) exit
In addition to the new selftests, this change was also verified with Agni [3]. For the record, the raw SMT is available at [4]. The property it verifies is that: If a concrete value x is contained in all input abstract values, after __update_reg_bounds, it will continue to be contained in all output abstract values.
--- kernel/bpf/verifier.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
kernel/bpf/verifier.c +30 -0
@@ -2358,6 +2358,9 @@ static void __update_reg32_bounds(struct bpf_reg_state *reg)static void __update_reg64_bounds (struct bpf_reg_state *reg) { +u64 tnum_next, tmax; +bool umin_in_tnum; +/* min signed is max(sign bit) | min(other bits) */ reg->smin_value =max_t (s64, reg->smin_value, reg->var_off.value | (reg->var_off.mask &S64_MIN ));
@@ -2367,6 +2370,33 @@ static void __update_reg64_bounds(struct bpf_reg_state *reg) reg->umin_value =max (reg->umin_value, reg->var_off.value); reg->umax_value =min (reg->umax_value, reg->var_off.value | reg->var_off.mask); + +/* Check if u64 and tnum overlap in a single value */ + tnum_next =tnum_step (reg->var_off, reg->umin_value); + umin_in_tnum = (reg->umin_value & ~reg->var_off.mask) == reg->var_off.value; + tmax = reg->var_off.value | reg->var_off.mask; +if (umin_in_tnum && tnum_next > reg->umax_value) { +/* The u64 range and the tnum only overlap in umin. +* u64: ---[xxxxxx]----- +* tnum: --xx----------x- +*/ +___mark_reg_known (reg, reg->umin_value); + }else if (!umin_in_tnum && tnum_next == tmax) { +/* The u64 range and the tnum only overlap in the maximum value +* represented by the tnum, called tmax. +* u64: ---[xxxxxx]----- +* tnum: xx-----x-------- +*/ +___mark_reg_known (reg, tmax); + }else if (!umin_in_tnum && tnum_next <= reg->umax_value && +tnum_step (reg->var_off, tnum_next) > reg->umax_value) { +/* The u64 range and the tnum only overlap in between umin +* (excluded) and umax. +* u64: ---[xxxxxx]----- +* tnum: xx----x-------x- +*/ +___mark_reg_known (reg, tnum_next); + } }static void __update_reg_bounds (struct bpf_reg_state *reg)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 93/311 uaccess: Fix scoped_user_read_access() for 'pointer to const'
In reply to Sasha LevinFrom: David Laight <[email protected]>
[ Upstream commit af4e9ef3d78420feb8fe58cd9a1ab80c501b3c08 ]
If a 'const struct foo __user *ptr' is used for the address passed to scoped_user_read_access() then you get a warning/error
uaccess.h:691:1: error: initialization discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers]
for the
void __user *_tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl)
assignment.
Fix by using 'auto' for both _tmpptr and the redeclaration of uptr. Replace the CLASS() with explicit __cleanup() functions on uptr.
--- include/linux/uaccess.h | 54 +++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 34 deletions(-)
include/linux/uaccess.h +20 -34
@@ -647,36 +647,22 @@ static inline void user_access_restore(unsigned long flags) { }/* Define RW variant so the below _mode macro expansion works */ #define masked_user_rw_access_begin (u) masked_user_access_begin(u)#define user_rw_access_begin (u, s) user_access_begin(u, s) -#define user_rw_access_end () user_access_end()/* Scoped user access */ -#define USER_ACCESS_GUARD (_mode) \ -static __always_inline void __user * \ -class_user_##_mode##_begin(void __user *ptr) \ -{ \ - return ptr; \ -} \ - \ -static __always_inline void \ -class_user_##_mode##_end(void __user *ptr) \ -{ \ - user_##_mode##_access_end(); \ -} \ - \ -DEFINE_CLASS(user_ ##_mode## _access, void __user *, \ - class_user_##_mode##_end(_T), \ - class_user_##_mode##_begin(ptr), void __user *ptr) \ - \ -static __always_inline class_user_##_mode##_access_t \ -class_user_##_mode##_access_ptr(void __user *scope) \ -{ \ - return scope; \ -} -USER_ACCESS_GUARD(read) -USER_ACCESS_GUARD(write) -USER_ACCESS_GUARD(rw) -#undef USER_ACCESS_GUARD +/* Cleanup wrapper functions */ +static __always_inline void __scoped_user_read_access_end(const void *p) +{ +user_read_access_end (); +}; +static __always_inline void __scoped_user_write_access_end(const void *p) +{ +user_write_access_end (); +}; +static __always_inline void __scoped_user_rw_access_end(const void *p) +{ +user_access_end (); +};/** * __scoped_user_access_begin - Start a scoped user access
@@ -750,13 +736,13 @@ USER_ACCESS_GUARD(rw)* * Don't use directly. Use scoped_masked_user_$MODE_access() instead. */ -#define __scoped_user_access (mode, uptr, size, elbl) \ -for (bool done = false; !done; done = true) \ - for (void __user *_tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \ - !done; done = true) \ - for (CLASS(user_##mode##_access, scope)(_tmpptr); !done; done = true) \ -/* Force modified pointer usage within the scope */ \ -for (const typeof (uptr) uptr = _tmpptr; !done; done = true) +#define __scoped_user_access (mode, uptr, size, elbl) \ +for (bool done = false; !done; done = true) \ + for (auto _tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \ + !done; done = true) \ +/* Force modified pointer usage within the scope */ \ + for (const auto uptr __cleanup(__scoped_user_##mode##_access_end) = \ + _tmpptr; !done; done = true)/** * scoped_user_read_access_size - Start a scoped user read access with given size
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 94/311 usb: gadget: u_ether: add gether_opts for config caching
In reply to Sasha LevinFrom: Kuen-Han Tsai <[email protected]>
[ Upstream commit e065c6a7e46c2ee9c677fdbf50035323d2de1215 ]
Currently, the net_device is allocated when the function instance is created (e.g., in ncm_alloc_inst()). While this allows userspace to configure the device early, it decouples the net_device lifecycle from the actual USB connection state (bind/unbind). The goal is to defer net_device creation to the bind callback to properly align the lifecycle with its parent gadget device.
However, deferring net_device allocation would prevent userspace from configuring parameters (like interface name or MAC address) before the net_device exists.
Introduce a new structure, struct gether_opts, associated with the usb_function_instance, to cache settings independently of the net_device. These settings include the interface name pattern, MAC addresses (device and host), queue multiplier, and address assignment type.
New helper functions are added:
- gether_setup_opts_default(): Initializes struct gether_opts with defaults, including random MAC addresses.
- gether_apply_opts(): Applies the cached options from a struct gether_opts to a valid net_device.
To expose these options to userspace, new configfs macros (USB_ETHER_OPTS_ITEM and USB_ETHER_OPTS_ATTR_*) are defined in u_ether_configfs.h. These attributes are part of the function instance's configfs group.
This refactoring is a preparatory step. It allows the subsequent patch to safely move the net_device allocation from the instance creation phase to the bind phase without losing the ability to pre-configure the interface via configfs.
Stable-dep-of: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind")
--- drivers/usb/gadget/function/u_ether.c | 30 +++ drivers/usb/gadget/function/u_ether.h | 28 +++ .../usb/gadget/function/u_ether_configfs.h | 176 ++++++++++++++++++ 3 files changed, 234 insertions(+)
drivers/usb/gadget/function/u_ether.c +30 -0
@@ -1039,6 +1039,36 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) }EXPORT_SYMBOL_GPL (gether_set_ifname); +void gether_setup_opts_default (struct gether_opts *opts,const char *name) +{ + opts->qmult =QMULT_DEFAULT ; +snprintf (opts->name,sizeof (opts->name),"%s%%d" , name); +eth_random_addr (opts->dev_mac); + opts->addr_assign_type =NET_ADDR_RANDOM ; +eth_random_addr (opts->host_mac); +} +EXPORT_SYMBOL_GPL (gether_setup_opts_default); + +void gether_apply_opts (struct net_device *net,struct gether_opts *opts) +{ +struct eth_dev *dev =netdev_priv (net); + + dev->qmult = opts->qmult; + +if (opts->ifname_set) { +strscpy (net->name, opts->name,sizeof (net->name)); + dev->ifname_set = true; + } + +memcpy (dev->host_mac, opts->host_mac,sizeof (dev->host_mac)); + +if (opts->addr_assign_type ==NET_ADDR_SET ) { +memcpy (dev->dev_mac, opts->dev_mac,sizeof (dev->dev_mac)); + net->addr_assign_type = opts->addr_assign_type; + } +} +EXPORT_SYMBOL_GPL (gether_apply_opts); +void gether_suspend (struct gether *link) {struct eth_dev *dev = link->ioport;
drivers/usb/gadget/function/u_ether.h +28 -0
@@ -38,6 +38,31 @@struct eth_dev ; +/** +* struct gether_opts - Options for Ethernet gadget function instances +* @name: Pattern for the network interface name (e.g., "usb%d"). +* Used to generate the net device name. +* @qmult: Queue length multiplier for high/super speed. +* @host_mac: The MAC address to be used by the host side. +* @dev_mac: The MAC address to be used by the device side. +* @ifname_set: True if the interface name pattern has been set by userspace. +* @addr_assign_type: The method used for assigning the device MAC address +* (e.g., NET_ADDR_RANDOM, NET_ADDR_SET). +* +* This structure caches network-related settings provided through configfs +* before the net_device is fully instantiated. This allows for early +* configuration while deferring net_device allocation until the function +* is bound. +*/ +struct gether_opts { +char name[IFNAMSIZ ]; +unsigned int qmult; +u8 host_mac[ETH_ALEN ]; +u8 dev_mac[ETH_ALEN ]; +bool ifname_set; +unsigned char addr_assign_type; +}; +/* * This represents the USB side of an "ethernet" link, managed by a USB * function which provides control and (maybe) framing. Two functions
@@ -259,6 +284,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len);void gether_cleanup (struct eth_dev *dev); +void gether_setup_opts_default (struct gether_opts *opts,const char *name); +void gether_apply_opts (struct net_device *net,struct gether_opts *opts); +void gether_suspend (struct gether *link);void gether_resume (struct gether *link);
drivers/usb/gadget/function/u_ether_configfs.h +176 -0
186 lines not on this page · raw message
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 95/311 usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device
In reply to Sasha LevinFrom: Kuen-Han Tsai <[email protected]>
[ Upstream commit 0c0981126b99288ed354d3d414c8a5fd42ac9e25 ]
The net_device in the u_ether framework currently requires explicit calls to unregister and free the device.
Introduce gether_unregister_free_netdev() and the corresponding auto-cleanup macro. This ensures that if a net_device is registered, it is properly unregistered and the associated work queue is flushed before the memory is freed.
This is a preparatory patch to simplify error handling paths in gadget drivers by removing the need for explicit goto labels for net_device cleanup.
Stable-dep-of: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind")
--- drivers/usb/gadget/function/u_ether.c | 15 +++++++++++++++ drivers/usb/gadget/function/u_ether.h | 2 ++ 2 files changed, 17 insertions(+)
drivers/usb/gadget/function/u_ether.c +15 -0
@@ -1125,6 +1125,21 @@ void gether_cleanup(struct eth_dev *dev) }EXPORT_SYMBOL_GPL (gether_cleanup); +void gether_unregister_free_netdev (struct net_device *net) +{ +if (!net) +return ; + +struct eth_dev *dev =netdev_priv (net); + +if (net->reg_state ==NETREG_REGISTERED ) { +unregister_netdev (net); +flush_work (&dev->work); + } +free_netdev (net); +} +EXPORT_SYMBOL_GPL (gether_unregister_free_netdev); +/** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching
drivers/usb/gadget/function/u_ether.h +2 -0
@@ -283,6 +283,8 @@ int gether_get_ifname(struct net_device *net, char *name, int len);int gether_set_ifname (struct net_device *net,const char *name,int len);void gether_cleanup (struct eth_dev *dev); +void gether_unregister_free_netdev (struct net_device *net); +DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_free_netdev(_T));void gether_setup_opts_default (struct gether_opts *opts,const char *name);void gether_apply_opts (struct net_device *net,struct gether_opts *opts);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 96/311 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
In reply to Sasha LevinFrom: Kuen-Han Tsai <[email protected]>
[ Upstream commit 56a512a9b4107079f68701e7d55da8507eb963d9 ]
Currently, the net_device is allocated in ncm_alloc_inst() and freed in ncm_free_inst(). This ties the network interface's lifetime to the configuration instance rather than the USB connection (bind/unbind).
This decoupling causes issues when the USB gadget is disconnected where the underlying gadget device is removed. The net_device can outlive its parent, leading to dangling sysfs links and NULL pointer dereferences when accessing the freed gadget device.
Problem 1: NULL pointer dereference on disconnect
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 Call trace: __pi_strlen+0x14/0x150 rtnl_fill_ifinfo+0x6b4/0x708 rtmsg_ifinfo_build_skb+0xd8/0x13c rtmsg_ifinfo+0x50/0xa0 __dev_notify_flags+0x4c/0x1f0 dev_change_flags+0x54/0x70 do_setlink+0x390/0xebc rtnl_newlink+0x7d0/0xac8 rtnetlink_rcv_msg+0x27c/0x410 netlink_rcv_skb+0x134/0x150 rtnetlink_rcv+0x18/0x28 netlink_unicast+0x254/0x3f0 netlink_sendmsg+0x2e0/0x3d4
Problem 2: Dangling sysfs symlinks
console:/ # ls -l /sys/class/net/ncm0
lrwxrwxrwx ... /sys/class/net/ncm0 -> /sys/devices/platform/.../gadget.0/net/ncm0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/ncm0
ls: .../gadget.0/net/ncm0: No such file or directory
Move the net_device allocation to ncm_bind() and deallocation to ncm_unbind(). This ensures the network interface exists only when the gadget function is actually bound to a configuration.
To support pre-bind configuration (e.g., setting interface name or MAC address via configfs), cache user-provided options in f_ncm_opts using the gether_opts structure. Apply these cached settings to the net_device upon creation in ncm_bind().
Preserve the use-after-free fix from commit 6334b8e4553c ("usb: gadget:f_ncm: Fix UAF ncm object at re-bind after usb ep transport error"). Check opts->net in ncm_set_alt() and ncm_disable() to ensure gether_disconnect() runs only if a connection was established.
--- drivers/usb/gadget/function/f_ncm.c | 128 ++++++++++++++-------------- drivers/usb/gadget/function/u_ncm.h | 4 +- 2 files changed, 66 insertions(+), 66 deletions(-)
drivers/usb/gadget/function/f_ncm.c +63 -65
@@ -83,6 +83,11 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) return container_of(f, struct f_ncm, port.func); } +static inline struct f_ncm_opts *func_to_ncm_opts (struct usb_function *f) +{ + return container_of(f->fi, struct f_ncm_opts, func_inst); +} +/*-------------------------------------------------------------------------*/ /*
@@ -859,6 +864,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)static int ncm_set_alt (struct usb_function *f,unsigned intf,unsigned alt) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;/* Control interface has only altsetting 0 */
@@ -881,12 +887,13 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)if (alt >1 ) goto fail; -if (ncm->netdev) { -DBG (cdev,"reset ncm\n" ); - ncm->netdev =NULL ; -gether_disconnect (&ncm->port); -ncm_reset_values (ncm); - } + scoped_guard(mutex, &opts->lock) +if (opts->net) { +DBG (cdev,"reset ncm\n" ); + opts->net =NULL ; +gether_disconnect (&ncm->port); +ncm_reset_values (ncm); + }/* * CDC Network only sends data in non-default altsettings.
@@ -919,7 +926,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) net =gether_connect (&ncm->port);if (IS_ERR (net))return PTR_ERR (net); - ncm->netdev = net; +scoped_guard (mutex, &opts->lock) + opts->net = net; }spin_lock (&ncm->lock);
@@ -1366,14 +1374,16 @@ static int ncm_unwrap_ntb(struct gether *port,static void ncm_disable (struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;DBG (cdev,"ncm deactivated\n" ); -if (ncm->netdev) { - ncm->netdev =NULL ; -gether_disconnect (&ncm->port); - } + scoped_guard(mutex, &opts->lock) +if (opts->net) { + opts->net =NULL ; +gether_disconnect (&ncm->port); + }if (ncm->notify->enabled) {usb_ep_disable (ncm->notify);
@@ -1433,39 +1443,44 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) {struct usb_composite_dev *cdev = c->cdev;struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *ncm_opts =func_to_ncm_opts (f);struct usb_string *us;int status =0 ;struct usb_ep *ep; -struct f_ncm_opts *ncm_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *netdev __free(free_gether_netdev) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_ecm (cdev->gadget))return -EINVAL ; - ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); -if (cdev->use_os_string) { os_desc_table =kzalloc (sizeof (*os_desc_table),GFP_KERNEL );if (!os_desc_table)return -ENOMEM ; } -mutex_lock (&ncm_opts->lock); -gether_set_gadget (ncm_opts->net, cdev->gadget); -if (!ncm_opts->bound) { - ncm_opts->net->mtu = (ncm_opts->max_segment_size -ETH_HLEN ); - status =gether_register_netdev (ncm_opts->net); + netdev =gether_setup_default (); +if (IS_ERR (netdev)) +return -ENOMEM ; + + scoped_guard(mutex, &ncm_opts->lock) { +gether_apply_opts (netdev, &ncm_opts->net_opts); + netdev->mtu = ncm_opts->max_segment_size -ETH_HLEN ; } -mutex_unlock (&ncm_opts->lock); +gether_set_gadget (netdev, cdev->gadget); + status =gether_register_netdev (netdev);if (status)return status; - ncm_opts->bound = true; - - ncm_string_defs[1 ].s = ncm->ethaddr; +/* export host's Ethernet address in CDC format */ + status =gether_get_host_addr_cdc (netdev, ncm->ethaddr, +sizeof (ncm->ethaddr)); +if (status <12 ) +return -EINVAL ; + ncm_string_defs[STRING_MAC_IDX ].s = ncm->ethaddr; us =usb_gstrings_attach (cdev, ncm_strings,ARRAY_SIZE (ncm_string_defs));
@@ -1563,6 +1578,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) f->os_desc_n =1 ; } ncm->notify_req =no_free_ptr (request); + ncm->netdev =no_free_ptr (netdev); + ncm->port.ioport =netdev_priv (ncm->netdev); DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1577,19 +1594,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item) }/* f_ncm_item_ops */ -USB_ETHERNET_CONFIGFS_ITEM (ncm); +USB_ETHER_OPTS_ITEM (ncm);/* f_ncm_opts_dev_addr */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR (ncm); +USB_ETHER_OPTS_ATTR_DEV_ADDR (ncm);/* f_ncm_opts_host_addr */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR (ncm); +USB_ETHER_OPTS_ATTR_HOST_ADDR (ncm);/* f_ncm_opts_qmult */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT (ncm); +USB_ETHER_OPTS_ATTR_QMULT (ncm);/* f_ncm_opts_ifname */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME (ncm); +USB_ETHER_OPTS_ATTR_IFNAME (ncm);static ssize_t ncm_opts_max_segment_size_show (struct config_item *item,char *page)
@@ -1655,34 +1672,27 @@ static void ncm_free_inst(struct usb_function_instance *f)struct f_ncm_opts *opts; opts = container_of(f, struct f_ncm_opts, func_inst); -if (opts->bound) -gether_cleanup (netdev_priv (opts->net)); -else -free_netdev (opts->net);kfree (opts->ncm_interf_group);kfree (opts); }static struct usb_function_instance *ncm_alloc_inst (void ) { -struct f_ncm_opts *opts; +struct usb_function_instance *ret;struct usb_os_desc *descs[1 ];char *names[1 ];struct config_group *ncm_interf_group; - opts =kzalloc (sizeof (*opts),GFP_KERNEL ); + struct f_ncm_opts *opts __free(kfree) = kzalloc(sizeof(*opts), GFP_KERNEL);if (!opts)return ERR_PTR (-ENOMEM ); + + opts->net =NULL ; opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; +gether_setup_opts_default (&opts->net_opts,"usb" );mutex_init (&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; - opts->net =gether_setup_default (); -if (IS_ERR (opts->net)) { -struct net_device *net = opts->net; -kfree (opts); -return ERR_CAST (net); - } opts->max_segment_size =ETH_FRAME_LEN ;INIT_LIST_HEAD (&opts->ncm_os_desc.ext_prop);
@@ -1693,26 +1703,22 @@ static struct usb_function_instance *ncm_alloc_inst(void) ncm_interf_group =usb_os_desc_prepare_interf_dir (&opts->func_inst.group,1 , descs, names,THIS_MODULE ); -if (IS_ERR (ncm_interf_group)) { -ncm_free_inst (&opts->func_inst); +if (IS_ERR (ncm_interf_group))return ERR_CAST (ncm_interf_group); - } opts->ncm_interf_group = ncm_interf_group; -return &opts->func_inst; + ret = &opts->func_inst; +retain_and_null_ptr (opts); +return ret; }static void ncm_free (struct usb_function *f) { -struct f_ncm *ncm; -struct f_ncm_opts *opts; +struct f_ncm_opts *opts =func_to_ncm_opts (f); - ncm =func_to_ncm (f); - opts = container_of(f->fi, struct f_ncm_opts, func_inst); -kfree (ncm); -mutex_lock (&opts->lock); - opts->refcnt--; -mutex_unlock (&opts->lock); +scoped_guard (mutex, &opts->lock) + opts->refcnt--; +kfree (func_to_ncm (f)); }static void ncm_unbind (struct usb_configuration *c,struct usb_function *f)
@@ -1736,13 +1742,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)kfree (ncm->notify_req->buf);usb_ep_free_request (ncm->notify, ncm->notify_req); + + ncm->port.ioport =NULL ; +gether_cleanup (netdev_priv (ncm->netdev)); }static struct usb_function *ncm_alloc (struct usb_function_instance *fi) {struct f_ncm *ncm;struct f_ncm_opts *opts; -int status;/* allocate and initialize one new instance */ ncm =kzalloc (sizeof (*ncm),GFP_KERNEL );
@@ -1750,22 +1758,12 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)return ERR_PTR (-ENOMEM ); opts = container_of(fi, struct f_ncm_opts, func_inst); -mutex_lock (&opts->lock); - opts->refcnt++; -/* export host's Ethernet address in CDC format */ - status =gether_get_host_addr_cdc (opts->net, ncm->ethaddr, -sizeof (ncm->ethaddr)); -if (status <12 ) {/* strlen("01234567890a") */ -kfree (ncm); -mutex_unlock (&opts->lock); -return ERR_PTR (-EINVAL ); - } +scoped_guard (mutex, &opts->lock) + opts->refcnt++;spin_lock_init (&ncm->lock);ncm_reset_values (ncm); - ncm->port.ioport =netdev_priv (opts->net); -mutex_unlock (&opts->lock); ncm->port.is_fixed = true; ncm->port.supports_multi_frame = true;
drivers/usb/gadget/function/u_ncm.h +3 -1
@@ -15,11 +15,13 @@#include <linux/usb/composite.h> +#include "u_ether.h" +struct f_ncm_opts {struct usb_function_instance func_inst;struct net_device *net; -bool bound; +struct gether_opts net_opts;struct config_group *ncm_interf_group;struct usb_os_desc ncm_os_desc;char ncm_ext_compat_id[16 ];
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 97/311 accel/rocket: fix unwinding in error path in rocket_core_init
In reply to Sasha LevinFrom: Quentin Schulz <[email protected]>
[ Upstream commit f509a081f6a289f7c66856333b3becce7a33c97e ]
When rocket_job_init() is called, iommu_group_get() has already been called, therefore we should call iommu_group_put() and make the iommu_group pointer NULL. This aligns with what's done in rocket_core_fini().
If pm_runtime_resume_and_get() somehow fails, not only should rocket_job_fini() be called but we should also unwind everything done before that, that is, disable PM, put the iommu_group, NULLify it and then call rocket_job_fini(). This is exactly what's done in rocket_core_fini() so let's call that function instead of duplicating the code.
--- drivers/accel/rocket/rocket_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/accel/rocket/rocket_core.c +5 -2
@@ -59,8 +59,11 @@ int rocket_core_init(struct rocket_core *core) core->iommu_group =iommu_group_get (dev); err =rocket_job_init (core); -if (err) +if (err) { +iommu_group_put (core->iommu_group); + core->iommu_group =NULL ;return err; + }pm_runtime_use_autosuspend (dev);
@@ -76,7 +79,7 @@ int rocket_core_init(struct rocket_core *core) err =pm_runtime_resume_and_get (dev);if (err) { -rocket_job_fini (core); +rocket_core_fini (core);return err; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 98/311 accel/rocket: fix unwinding in error path in rocket_probe
In reply to Sasha LevinFrom: Quentin Schulz <[email protected]>
[ Upstream commit 34f4495a7f72895776b81969639f527c99eb12b9 ]
When rocket_core_init() fails (as could be the case with EPROBE_DEFER), we need to properly unwind by decrementing the counter we just incremented and if this is the first core we failed to probe, remove the rocket DRM device with rocket_device_fini() as well. This matches the logic in rocket_remove(). Failing to properly unwind results in out-of-bounds accesses.
--- drivers/accel/rocket/rocket_drv.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/accel/rocket/rocket_drv.c +14 -1
@@ -13,6 +13,7 @@#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include "rocket_device.h" #include "rocket_drv.h" #include "rocket_gem.h" #include "rocket_job.h"
@@ -158,6 +159,8 @@ static const struct drm_driver rocket_drm_driver = {static int rocket_probe (struct platform_device *pdev) { +int ret; +if (rdev ==NULL ) {/* First core probing, initialize DRM device. */ rdev =rocket_device_init (drm_dev, &rocket_drm_driver);
@@ -177,7 +180,17 @@ static int rocket_probe(struct platform_device *pdev) rdev->num_cores++; -return rocket_core_init (&rdev->cores[core]); + ret =rocket_core_init (&rdev->cores[core]); +if (ret) { + rdev->num_cores--; + +if (rdev->num_cores ==0 ) { +rocket_device_fini (rdev); + rdev =NULL ; + } + } + +return ret; }static void rocket_remove (struct platform_device *pdev)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 99/311 KVM: x86: Add x2APIC "features" to control EOI broadcast suppression
In reply to Sasha LevinFrom: Khushit Shah <[email protected]>
[ Upstream commit 6517dfbcc918f970a928d9dc17586904bac06893 ]
Add two flags for KVM_CAP_X2APIC_API to allow userspace to control support for Suppress EOI Broadcasts when using a split IRQCHIP (I/O APIC emulated by userspace), which KVM completely mishandles. When x2APIC support was first added, KVM incorrectly advertised and "enabled" Suppress EOI Broadcast, without fully supporting the I/O APIC side of the equation, i.e. without adding directed EOI to KVM's in-kernel I/O APIC.
That flaw was carried over to split IRQCHIP support, i.e. KVM advertised support for Suppress EOI Broadcasts irrespective of whether or not the userspace I/O APIC implementation supported directed EOIs. Even worse, KVM didn't actually suppress EOI broadcasts, i.e. userspace VMMs without support for directed EOI came to rely on the "spurious" broadcasts.
KVM "fixed" the in-kernel I/O APIC implementation by completely disabling support for Suppress EOI Broadcasts in commit 0bcc3fb95b97 ("KVM: lapic:
stop advertising DIRECTED_EOI when in-kernel IOAPIC is in use"), but didn't do anything to remedy userspace I/O APIC implementations.
KVM's bogus handling of Suppress EOI Broadcast is problematic when the guest relies on interrupts being masked in the I/O APIC until well after the initial local APIC EOI. E.g. Windows with Credential Guard enabled handles interrupts in the following order:
1. Interrupt for L2 arrives.
2. L1 APIC EOIs the interrupt.
3. L1 resumes L2 and injects the interrupt.
4. L2 EOIs after servicing.
5. L1 performs the I/O APIC EOI.
Because KVM EOIs the I/O APIC at step #2, the guest can get an interrupt storm, e.g. if the IRQ line is still asserted and userspace reacts to the EOI by re-injecting the IRQ, because the guest doesn't de-assert the line until step #4, and doesn't expect the interrupt to be re-enabled until step #5.
Unfortunately, simply "fixing" the bug isn't an option, as KVM has no way of knowing if the userspace I/O APIC supports directed EOIs, i.e. suppressing EOI broadcasts would result in interrupts being stuck masked in the userspace I/O APIC due to step #5 being ignored by userspace. And fully disabling support for Suppress EOI Broadcast is also undesirable, as picking up the fix would require a guest reboot, *and* more importantly would change the virtual CPU model exposed to the guest without any buy-in from userspace.
Add KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST and KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST flags to allow userspace to explicitly enable or disable support for Suppress EOI Broadcasts. This gives userspace control over the virtual CPU model exposed to the guest, as KVM should never have enabled support for Suppress EOI Broadcast without userspace opt-in. Not setting either flag will result in legacy quirky behavior for backward compatibility.
Disallow fully enabling SUPPRESS_EOI_BROADCAST when using an in-kernel I/O APIC, as KVM's history/support is just as tragic. E.g. it's not clear that commit c806a6ad35bf ("KVM: x86: call irq notifiers with directed EOI") was entirely correct, i.e. it may have simply papered over the lack of Directed EOI emulation in the I/O APIC.
Note, Suppress EOI Broadcasts is defined only in Intel's SDM, not in AMD's APM. But the bit is writable on some AMD CPUs, e.g. Turin, and KVM's ABI is to support Directed EOI (KVM's name) irrespective of guest CPU vendor.
--- Documentation/virt/kvm/api.rst | 28 +++++++++++- arch/x86/include/asm/kvm_host.h | 7 +++ arch/x86/include/uapi/asm/kvm.h | 6 ++- arch/x86/kvm/ioapic.c | 2 +- arch/x86/kvm/lapic.c | 76 +++++++++++++++++++++++++++++---- arch/x86/kvm/lapic.h | 2 + arch/x86/kvm/x86.c | 21 ++++++++- 7 files changed, 127 insertions(+), 15 deletions(-)
Documentation/virt/kvm/api.rst +26 -2
@@ -7835,8 +7835,10 @@ Will return -EBUSY if a VCPU has already been created. Valid feature flags in args[0] are:: - #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) - #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) + #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) + #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) + #define KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST (1ULL << 2) + #define KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST (1ULL << 3) Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
@@ -7849,6 +7851,28 @@ as a broadcast even in x2APIC mode in order to support physical x2APIC without interrupt remapping. This is undesirable in logical mode, where 0xff represents CPUs 0-7 in cluster 0. +Setting KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST instructs KVM to enable +Suppress EOI Broadcasts. KVM will advertise support for Suppress EOI +Broadcast to the guest and suppress LAPIC EOI broadcasts when the guest +sets the Suppress EOI Broadcast bit in the SPIV register. This flag is +supported only when using a split IRQCHIP. + +Setting KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST disables support for +Suppress EOI Broadcasts entirely, i.e. instructs KVM to NOT advertise +support to the guest. + +Modern VMMs should either enable KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST +or KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST. If not, legacy quirky +behavior will be used by KVM: in split IRQCHIP mode, KVM will advertise +support for Suppress EOI Broadcasts but not actually suppress EOI +broadcasts; for in-kernel IRQCHIP mode, KVM will not advertise support for +Suppress EOI Broadcasts. + +Setting both KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST and +KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST will fail with an EINVAL error, +as will setting KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST without a split +IRCHIP. + 7.8 KVM_CAP_S390_USER_INSTR0 ----------------------------
arch/x86/include/asm/kvm_host.h +7 -0
@@ -1226,6 +1226,12 @@ enum kvm_irqchip_mode { KVM_IRQCHIP_SPLIT, /* created with KVM_CAP_SPLIT_IRQCHIP */ }; +enum kvm_suppress_eoi_broadcast_mode { +KVM_SUPPRESS_EOI_BROADCAST_QUIRKED ,/* Legacy behavior */ +KVM_SUPPRESS_EOI_BROADCAST_ENABLED ,/* Enable Suppress EOI broadcast */ +KVM_SUPPRESS_EOI_BROADCAST_DISABLED /* Disable Suppress EOI broadcast */ +}; +struct kvm_x86_msr_filter {u8 count;bool default_allow:1 ;
@@ -1475,6 +1481,7 @@ struct kvm_arch {bool x2apic_format;bool x2apic_broadcast_quirk_disabled; +enum kvm_suppress_eoi_broadcast_mode suppress_eoi_broadcast_mode;bool has_mapped_host_mmio;bool guest_can_read_msr_platform_info;
arch/x86/include/uapi/asm/kvm.h +4 -2
@@ -914,8 +914,10 @@ struct kvm_sev_snp_launch_finish {__u64 pad1[4 ]; }; -#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) -#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) +#define KVM_X2APIC_API_USE_32BIT_IDS _BITULL(0) +#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK _BITULL(1) +#define KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST _BITULL(2) +#define KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST _BITULL(3)struct kvm_hyperv_eventfd {__u32 conn_id;
arch/x86/kvm/ioapic.c +1 -1
@@ -561,7 +561,7 @@ static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,spin_lock (&ioapic->lock);if (trigger_mode !=IOAPIC_LEVEL_TRIG || -kvm_lapic_get_reg (apic,APIC_SPIV ) &APIC_SPIV_DIRECTED_EOI ) +kvm_lapic_suppress_eoi_broadcast (apic))return ;ASSERT (ent->fields.trig_mode ==IOAPIC_LEVEL_TRIG );
arch/x86/kvm/lapic.c +68 -8
95 lines not on this page · raw message
arch/x86/kvm/lapic.h +2 -0
@@ -231,6 +231,8 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)bool kvm_apic_pending_eoi (struct kvm_vcpu *vcpu,int vector); +bool kvm_lapic_suppress_eoi_broadcast (struct kvm_lapic *apic); +void kvm_wait_lapic_expire (struct kvm_vcpu *vcpu); void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct kvm_lapic_irq *irq,
arch/x86/kvm/x86.c +19 -2
@@ -121,8 +121,10 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);#define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE -#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ - KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK) +#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ + KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK | \ + KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST | \ + KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST)static void update_cr8_intercept (struct kvm_vcpu *vcpu);static void process_nmi (struct kvm_vcpu *vcpu);
@@ -4931,6 +4933,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)break ;case KVM_CAP_X2APIC_API : r =KVM_X2APIC_API_VALID_FLAGS ; +if (kvm && !irqchip_split (kvm)) + r &= ~KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST ;break ;case KVM_CAP_NESTED_STATE : r = kvm_x86_ops.nested_ops->get_state ?
@@ -6748,11 +6752,24 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,if (cap->args[0 ] & ~KVM_X2APIC_API_VALID_FLAGS )break ; +if ((cap->args[0 ] &KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST ) && + (cap->args[0 ] &KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST )) +break ; + +if ((cap->args[0 ] &KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST ) && + !irqchip_split (kvm)) +break ; +if (cap->args[0 ] &KVM_X2APIC_API_USE_32BIT_IDS ) kvm->arch.x2apic_format = true;if (cap->args[0 ] &KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK ) kvm->arch.x2apic_broadcast_quirk_disabled = true; +if (cap->args[0 ] &KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST ) + kvm->arch.suppress_eoi_broadcast_mode =KVM_SUPPRESS_EOI_BROADCAST_ENABLED ; +if (cap->args[0 ] &KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST ) + kvm->arch.suppress_eoi_broadcast_mode =KVM_SUPPRESS_EOI_BROADCAST_DISABLED ; + r =0 ;break ;case KVM_CAP_X86_DISABLE_EXITS :
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 100/311 eventpoll: Fix integer overflow in ep_loop_check_proc()
In reply to Sasha LevinFrom: Jann Horn <[email protected]>
commit fdcfce93073d990ed4b71752e31ad1c1d6e9d58b upstream.
If a recursive call to ep_loop_check_proc() hits the result = INT_MAX, an integer overflow will occur in the calling ep_loop_check_proc() at result = max(result, ep_loop_check_proc(ep_tovisit, depth + 1) + 1), breaking the recursion depth check.
Fix it by using a different placeholder value that can't lead to an overflow.
--- fs/eventpoll.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/eventpoll.c +3 -2
@@ -2061,7 +2061,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,* @ep: the &struct eventpoll to be currently checked. * @depth: Current depth of the path being checked. * -* Return: depth of the subtree, or INT_MAX if we found a loop or went too deep. +* Return: depth of the subtree, or a value bigger than EP_MAX_NESTS if we found +* a loop or went too deep. */ static int ep_loop_check_proc (struct eventpoll *ep,int depth) {
@@ -2080,7 +2081,7 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)struct eventpoll *ep_tovisit; ep_tovisit = epi->ffd.file->private_data;if (ep_tovisit == inserting_into || depth >EP_MAX_NESTS ) - result =INT_MAX ; + result =EP_MAX_NESTS +1 ;else result =max (result,ep_loop_check_proc (ep_tovisit, depth +1 ) +1 );if (result >EP_MAX_NESTS )
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 101/311 namespace: fix proc mount iteration
In reply to Sasha LevinFrom: Christian Brauner <[email protected]>
commit 4a403d7aa9074f527f064ef0806aaab38d14b07c upstream.
The m->index isn't updated when m->show() overflows and retains its value before the current mount causing a restart to start at the same value. If that happens in short order to due a quickly expanding mount table this would cause the same mount to be shown again and again.
Ensure that *pos always equals the mount id of the mount that was returned by start/next. On restart after overflow mnt_find_id_at(*pos) finds the exact mount. This should avoid duplicates, avoid skips and should handle concurrent modification just fine.
Cc: <[email protected]>
Fixed: 2eea9ce4310d8 ("mounts: keep list of mounts in an rbtree")
--- fs/namespace.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
fs/namespace.c +15 -5
@@ -1537,23 +1537,33 @@ static struct mount *mnt_find_id_at_reverse(struct mnt_namespace *ns, u64 mnt_idstatic void *m_start (struct seq_file *m,loff_t *pos) {struct proc_mounts *p = m->private; +struct mount *mnt;down_read (&namespace_sem); -return mnt_find_id_at (p->ns, *pos); + mnt =mnt_find_id_at (p->ns, *pos); +if (mnt) + *pos = mnt->mnt_id_unique; +return mnt; }static void *m_next (struct seq_file *m,void *v,loff_t *pos) { -struct mount *next =NULL , *mnt = v; +struct mount *mnt = v;struct rb_node *node =rb_next (&mnt->mnt_node); - ++*pos;if (node) { - next =node_to_mount (node); +struct mount *next =node_to_mount (node); *pos = next->mnt_id_unique; +return next; } -return next; + +/* +* No more mounts. Set pos past current mount's ID so that if +* iteration restarts, mnt_find_id_at() returns NULL. +*/ + *pos = mnt->mnt_id_unique +1 ; +return NULL ; }static void m_stop (struct seq_file *m,void *v)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 102/311 media: dvb-core: fix wrong reinitialization of ringbuffer on reopen
In reply to Sasha LevinFrom: Jens Axboe <[email protected]>
commit bfbc0b5b32a8f28ce284add619bf226716a59bc0 upstream.
dvb_dvr_open() calls dvb_ringbuffer_init() when a new reader opens the DVR device. dvb_ringbuffer_init() calls init_waitqueue_head(), which reinitializes the waitqueue list head to empty.
Since dmxdev->dvr_buffer.queue is a shared waitqueue (all opens of the same DVR device share it), this orphans any existing waitqueue entries from io_uring poll or epoll, leaving them with stale prev/next pointers while the list head is reset to {self, self}.
The waitqueue and spinlock in dvr_buffer are already properly initialized once in dvb_dmxdev_init(). The open path only needs to reset the buffer data pointer, size, and read/write positions.
Replace the dvb_ringbuffer_init() call in dvb_dvr_open() with direct assignment of data/size and a call to dvb_ringbuffer_reset(), which properly resets pread, pwrite, and error with correct memory ordering without touching the waitqueue or spinlock.
--- drivers/media/dvb-core/dmxdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/media/dvb-core/dmxdev.c +3 -1
@@ -168,7 +168,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)mutex_unlock (&dmxdev->mutex);return -ENOMEM ; } -dvb_ringbuffer_init (&dmxdev->dvr_buffer, mem,DVR_BUFFER_SIZE ); + dmxdev->dvr_buffer.data = mem; + dmxdev->dvr_buffer.size =DVR_BUFFER_SIZE ; +dvb_ringbuffer_reset (&dmxdev->dvr_buffer);if (dmxdev->may_do_mmap)dvb_vb2_init (&dmxdev->dvr_vb2_ctx,"dvr" , file->f_flags &O_NONBLOCK );
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 103/311 nfc: pn533: properly drop the usb interface reference on disconnect
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 12133a483dfa832241fbbf09321109a0ea8a520e upstream.
When the device is disconnected from the driver, there is a "dangling" reference count on the usb interface that was grabbed in the probe callback. Fix this up by properly dropping the reference after we are done with it.
--- drivers/nfc/pn533/usb.c | 1 + 1 file changed, 1 insertion(+)
drivers/nfc/pn533/usb.c +1 -0
@@ -628,6 +628,7 @@ static void pn533_usb_disconnect(struct usb_interface *interface)usb_free_urb (phy->out_urb);usb_free_urb (phy->ack_urb);kfree (phy->ack_buffer); +usb_put_dev (phy->udev);nfc_info (&interface->dev,"NXP PN533 NFC device disconnected\n" ); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 104/311 net: usb: kaweth: validate USB endpoints
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 4b063c002ca759d1b299988ee23f564c9609c875 upstream.
The kaweth driver should validate that the device it is probing has the proper number and types of USB endpoints it is expecting before it binds to it. If a malicious device were to not have the same urbs the driver will crash later on when it blindly accesses these endpoints.
--- drivers/net/usb/kaweth.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/net/usb/kaweth.c +13 -0
@@ -883,6 +883,13 @@ static int kaweth_probe(const eth_addr_t bcast_addr = {0xFF ,0xFF ,0xFF ,0xFF ,0xFF ,0xFF };int result =0 ;int rv = -EIO ; +static const u8 bulk_ep_addr[] = { +1 |USB_DIR_IN , +2 |USB_DIR_OUT , +0 }; +static const u8 int_ep_addr[] = { +3 |USB_DIR_IN , +0 }; dev_dbg(dev, "Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
@@ -896,6 +903,12 @@ static int kaweth_probe( (int )udev->descriptor.bLength, (int)udev->descriptor.bDescriptorType); +if (!usb_check_bulk_endpoints (intf, bulk_ep_addr) || + !usb_check_int_endpoints (intf, int_ep_addr)) { +dev_err (dev,"couldn't find required endpoints\n" ); +return -ENODEV ; + } + netdev =alloc_etherdev (sizeof (*kaweth));if (!netdev)return -ENOMEM ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 105/311 net: usb: kalmia: validate USB endpoints
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit c58b6c29a4c9b8125e8ad3bca0637e00b71e2693 upstream.
The kalmia driver should validate that the device it is probing has the proper number and types of USB endpoints it is expecting before it binds to it. If a malicious device were to not have the same urbs the driver will crash later on when it blindly accesses these endpoints.
--- drivers/net/usb/kalmia.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/usb/kalmia.c +7 -0
@@ -132,11 +132,18 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf) {int status;u8 ethernet_addr[ETH_ALEN ]; +static const u8 ep_addr[] = { +1 |USB_DIR_IN , +2 |USB_DIR_OUT , +0 };/* Don't bind to AT command interface */ if (intf->cur_altsetting->desc.bInterfaceClass !=USB_CLASS_VENDOR_SPEC )return -EINVAL ; +if (!usb_check_bulk_endpoints (intf, ep_addr)) +return -ENODEV ; + dev->in =usb_rcvbulkpipe (dev->udev,0x81 &USB_ENDPOINT_NUMBER_MASK ); dev->out =usb_sndbulkpipe (dev->udev,0x02 &USB_ENDPOINT_NUMBER_MASK ); dev->status =NULL ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 106/311 net: usb: pegasus: validate USB endpoints
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 11de1d3ae5565ed22ef1f89d73d8f2d00322c699 upstream.
The pegasus driver should validate that the device it is probing has the proper number and types of USB endpoints it is expecting before it binds to it. If a malicious device were to not have the same urbs the driver will crash later on when it blindly accesses these endpoints.
--- drivers/net/usb/pegasus.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/net/usb/pegasus.c +12 -1
@@ -815,8 +815,19 @@ static void unlink_all_urbs(pegasus_t *pegasus)static int alloc_urbs (pegasus_t *pegasus) { +static const u8 bulk_ep_addr[] = { +1 |USB_DIR_IN , +2 |USB_DIR_OUT , +0 }; +static const u8 int_ep_addr[] = { +3 |USB_DIR_IN , +0 };int res = -ENOMEM ; +if (!usb_check_bulk_endpoints (pegasus->intf, bulk_ep_addr) || + !usb_check_int_endpoints (pegasus->intf, int_ep_addr)) +return -ENODEV ; + pegasus->rx_urb =usb_alloc_urb (0 ,GFP_KERNEL );if (!pegasus->rx_urb) {return res;
@@ -1171,6 +1182,7 @@ static int pegasus_probe(struct usb_interface *intf, pegasus =netdev_priv (net); pegasus->dev_index = dev_index; + pegasus->intf = intf; res =alloc_urbs (pegasus);if (res <0 ) {
@@ -1182,7 +1194,6 @@ static int pegasus_probe(struct usb_interface *intf,INIT_DELAYED_WORK (&pegasus->carrier_check, check_carrier); - pegasus->intf = intf; pegasus->usb = dev; pegasus->net = net;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 107/311 can: ems_usb: ems_usb_read_bulk_callback(): check the proper length of a message
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 38a01c9700b0dcafe97dfa9dc7531bf4a245deff upstream.
When looking at the data in a USB urb, the actual_length is the size of the buffer passed to the driver, not the transfer_buffer_length which is set by the driver as the max size of the buffer.
When parsing the messages in ems_usb_read_bulk_callback() properly check the size both at the beginning of parsing the message to make sure it is big enough for the expected structure, and at the end of the message to make sure we don't overflow past the end of the buffer for the next message.
--- drivers/net/can/usb/ems_usb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/can/usb/ems_usb.c +6 -1
@@ -445,6 +445,11 @@ static void ems_usb_read_bulk_callback(struct urb *urb) start =CPC_HEADER_SIZE ;while (msg_count) { +if (start +CPC_MSG_HEADER_LEN > urb->actual_length) { +netdev_err (netdev,"format error\n" ); +break ; + } + msg = (struct ems_cpc_msg *)&ibuf[start];switch (msg->type) {
@@ -474,7 +479,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb) start +=CPC_MSG_HEADER_LEN + msg->length; msg_count--; -if (start > urb->transfer_buffer_length) { +if (start > urb->actual_length) {netdev_err (netdev,"format error\n" );break ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 108/311 can: usb: f81604: correctly anchor the urb in the read bulk callback
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 952caa5da10bed22be09612433964f6877ba0dde upstream.
When submitting an urb, that is using the anchor pattern, it needs to be anchored before submitting it otherwise it could be leaked if usb_kill_anchored_urbs() is called. This logic is correctly done elsewhere in the driver, except in the read bulk callback so do that here also.
--- drivers/net/can/usb/f81604.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/net/can/usb/f81604.c +13 -2
@@ -413,6 +413,7 @@ static void f81604_read_bulk_callback(struct urb *urb) {struct f81604_can_frame *frame = urb->transfer_buffer;struct net_device *netdev = urb->context; +struct f81604_port_priv *priv =netdev_priv (netdev);int ret;if (!netif_device_present (netdev))
@@ -445,10 +446,15 @@ static void f81604_read_bulk_callback(struct urb *urb)f81604_process_rx_packet (netdev, frame); resubmit_urb: +usb_anchor_urb (urb, &priv->urbs_anchor); ret =usb_submit_urb (urb,GFP_ATOMIC ); +if (!ret) +return ; +usb_unanchor_urb (urb); +if (ret == -ENODEV )netif_device_detach (netdev); -else if (ret) +else netdev_err (netdev,"%s: failed to resubmit read bulk urb: %pe\n" , __func__,ERR_PTR (ret));
@@ -646,10 +652,15 @@ static void f81604_read_int_callback(struct urb *urb)f81604_handle_tx (priv, data); resubmit_urb: +usb_anchor_urb (urb, &priv->urbs_anchor); ret =usb_submit_urb (urb,GFP_ATOMIC ); +if (!ret) +return ; +usb_unanchor_urb (urb); +if (ret == -ENODEV )netif_device_detach (netdev); -else if (ret) +else netdev_err (netdev,"%s: failed to resubmit int urb: %pe\n" , __func__,ERR_PTR (ret)); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 109/311 can: ucan: Fix infinite loop from zero-length messages
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 1e446fd0582ad8be9f6dafb115fc2e7245f9bea7 upstream.
If a broken ucan device gets a message with the message length field set to 0, then the driver will loop for forever in ucan_read_bulk_callback(), hanging the system. If the length is 0, just skip the message and go on to the next one.
This has been fixed in the kvaser_usb driver in the past in commit 0c73772cd2b8 ("can: kvaser_usb: leaf: Fix potential infinite loop in command parsers"), so there must be some broken devices out there like this somewhere.
--- drivers/net/can/usb/ucan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/can/usb/ucan.c +1 -1
@@ -749,7 +749,7 @@ static void ucan_read_bulk_callback(struct urb *urb) len =le16_to_cpu (m->len);/* check sanity (length of content) */ -if (urb->actual_length - pos < len) { +if ((len ==0 ) || (urb->actual_length - pos < len)) {netdev_warn (up->netdev,"invalid message (short; no data; l:%d)\n" , urb->actual_length);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 110/311 can: usb: etas_es58x: correctly anchor the urb in the read bulk callback
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 5eaad4f768266f1f17e01232ffe2ef009f8129b7 upstream.
When submitting an urb, that is using the anchor pattern, it needs to be anchored before submitting it otherwise it could be leaked if usb_kill_anchored_urbs() is called. This logic is correctly done elsewhere in the driver, except in the read bulk callback so do that here also.
--- drivers/net/can/usb/etas_es58x/es58x_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/can/usb/etas_es58x/es58x_core.c +7 -1
@@ -1461,12 +1461,18 @@ static void es58x_read_bulk_callback(struct urb *urb) } resubmit_urb: +usb_anchor_urb (urb, &es58x_dev->rx_urbs); ret =usb_submit_urb (urb,GFP_ATOMIC ); +if (!ret) +return ; + +usb_unanchor_urb (urb); +if (ret == -ENODEV ) {for (i =0 ; i < es58x_dev->num_can_ch; i++)if (es58x_dev->netdev[i])netif_device_detach (es58x_dev->netdev[i]); - }else if (ret) + }else dev_err_ratelimited (dev,"Failed resubmitting read bulk urb: %pe\n" ,ERR_PTR (ret));
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 111/311 can: usb: f81604: handle short interrupt urb messages properly
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 7299b1b39a255f6092ce4ec0b65f66e9d6a357af upstream.
If an interrupt urb is received that is not the correct length, properly detect it and don't attempt to treat the data as valid.
--- drivers/net/can/usb/f81604.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/can/usb/f81604.c +6 -0
@@ -626,6 +626,12 @@ static void f81604_read_int_callback(struct urb *urb)netdev_info (netdev,"%s: Int URB aborted: %pe\n" , __func__,ERR_PTR (urb->status)); +if (urb->actual_length <sizeof (*data)) { +netdev_warn (netdev,"%s: short int URB: %u < %zu\n" , + __func__, urb->actual_length,sizeof (*data)); + goto resubmit_urb; + } +switch (urb->status) {case 0 :/* success */ break ;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 112/311 can: usb: f81604: handle bulk write errors properly
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit 51f94780720fa90c424f67e3e9784cb8ef8190e5 upstream.
If a write urb fails then more needs to be done other than just logging the message, otherwise the transmission could be stalled. Properly increment the error counters and wake up the queues so that data will continue to flow.
--- drivers/net/can/usb/f81604.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
drivers/net/can/usb/f81604.c +21 -3
@@ -891,9 +891,27 @@ static void f81604_write_bulk_callback(struct urb *urb)if (!netif_device_present (netdev))return ; -if (urb->status) -netdev_info (netdev,"%s: Tx URB error: %pe\n" , __func__, -ERR_PTR (urb->status)); +if (!urb->status) +return ; + +switch (urb->status) { +case -ENOENT : +case -ECONNRESET : +case -ESHUTDOWN : +return ; +default : +break ; + } + +if (net_ratelimit ()) +netdev_err (netdev,"%s: Tx URB error: %pe\n" , __func__, +ERR_PTR (urb->status)); + +can_free_echo_skb (netdev,0 ,NULL ); + netdev->stats.tx_dropped++; + netdev->stats.tx_errors++; + +netif_wake_queue (netdev); }static void f81604_clear_reg_work (struct work_struct *work)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 113/311 HID: Add HID_CLAIMED_INPUT guards in raw_event callbacks missing them
In reply to Sasha LevinFrom: Greg Kroah-Hartman <[email protected]>
commit ecfa6f34492c493a9a1dc2900f3edeb01c79946b upstream.
In commit 2ff5baa9b527 ("HID: appleir: Fix potential NULL dereference at raw event handle"), we handle the fact that raw event callbacks can happen even for a HID device that has not been "claimed" causing a crash if a broken device were attempted to be connected to the system.
Fix up the remaining in-tree HID drivers that forgot to add this same check to resolve the same issue.
--- drivers/hid/hid-cmedia.c | 2 +- drivers/hid/hid-creative-sb0540.c | 2 +- drivers/hid/hid-zydacron.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
drivers/hid/hid-cmedia.c +1 -1
@@ -99,7 +99,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report, {struct cmhid *cm =hid_get_drvdata (hid); -if (len !=CM6533_JD_RAWEV_LEN ) +if (len !=CM6533_JD_RAWEV_LEN || !(hid->claimed &HID_CLAIMED_INPUT )) goto out;if (memcmp (data+CM6533_JD_SFX_OFFSET , ji_sfx,sizeof (ji_sfx))) goto out;
drivers/hid/hid-creative-sb0540.c +1 -1
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,u64 code, main_code;int key; -if (len !=6 ) +if (len !=6 || !(hid->claimed &HID_CLAIMED_INPUT ))return 0 ;/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
drivers/hid/hid-zydacron.c +1 -1
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,unsigned key;unsigned short index; -if (report->id == data[0 ]) { +if (report->id == data[0 ] && (hdev->claimed &HID_CLAIMED_INPUT )) {/* break keys */ for (index =0 ; index <4 ; index++) {
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 114/311 HID: pidff: Fix condition effect bit clearing
In reply to Sasha LevinFrom: Tomasz Pakuła <[email protected]>
commit 97d5c8f5c09a604c4873c8348f58de3cea69a7df upstream.
As reported by MPDarkGuy on discord, NULL pointer dereferences were happening because not all the conditional effects bits were cleared.
Properly clear all conditional effect bits from ffbit
--- drivers/hid/usbhid/hid-pidff.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/hid/usbhid/hid-pidff.c +7 -4
@@ -1452,10 +1452,13 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)hid_warn (pidff->hid,"unknown ramp effect layout\n" );if (PIDFF_FIND_FIELDS (set_condition,PID_SET_CONDITION ,1 )) { -if (test_and_clear_bit (FF_SPRING , dev->ffbit) || -test_and_clear_bit (FF_DAMPER , dev->ffbit) || -test_and_clear_bit (FF_FRICTION , dev->ffbit) || -test_and_clear_bit (FF_INERTIA , dev->ffbit)) +bool test = false; + + test |=test_and_clear_bit (FF_SPRING , dev->ffbit); + test |=test_and_clear_bit (FF_DAMPER , dev->ffbit); + test |=test_and_clear_bit (FF_FRICTION , dev->ffbit); + test |=test_and_clear_bit (FF_INERTIA , dev->ffbit); +if (test)hid_warn (pidff->hid,"unknown condition effect layout\n" ); }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 115/311 HID: multitouch: Keep latency normal on deactivate for reactivation gesture
In reply to Sasha LevinFrom: Werner Sembach <[email protected]>
commit ec3070f01fa30f2c5547d645dbb76174304bf0e4 upstream.
Uniwill devices have a built in gesture in the touchpad to de- and reactivate it by double taping the upper left corner. This gesture stops working when latency is set to high, so this patch keeps the latency on normal.
--- drivers/hid/hid-multitouch.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
drivers/hid/hid-multitouch.c +29 -3
@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");#define MT_QUIRK_ORIENTATION_INVERT BIT(22)#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)#define MT_QUIRK_YOGABOOK9I BIT(24) +#define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25)#define MT_INPUTMODE_TOUCHSCREEN 0x02#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -214,6 +215,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);#define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016#define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018 +#define MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE 0x0019/* vendor specific classes */ #define MT_CLS_3M 0x0101
@@ -334,6 +336,15 @@ static const struct mt_class mt_classes[] = {MT_QUIRK_CONTACT_CNT_ACCURATE | MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, + { .name = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE, + .quirks =MT_QUIRK_ALWAYS_VALID | +MT_QUIRK_IGNORE_DUPLICATES | +MT_QUIRK_HOVERING | +MT_QUIRK_CONTACT_CNT_ACCURATE | +MT_QUIRK_STICKY_FINGERS | +MT_QUIRK_WIN8_PTP_BUTTONS | + MT_QUIRK_KEEP_LATENCY_ON_CLOSE, + .export_all_inputs = true },/* * vendor specific classes
@@ -849,7 +860,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,if ((cls->name ==MT_CLS_WIN_8 || cls->name ==MT_CLS_WIN_8_FORCE_MULTI_INPUT || cls->name ==MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU || - cls->name ==MT_CLS_WIN_8_DISABLE_WAKEUP ) && + cls->name ==MT_CLS_WIN_8_DISABLE_WAKEUP || + cls->name ==MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE ) && (field->application ==HID_DG_TOUCHPAD || field->application ==HID_DG_TOUCHSCREEN )) app->quirks |=MT_QUIRK_CONFIDENCE ;
@@ -1762,7 +1774,8 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)int ret;if (td->is_haptic_touchpad && (td->mtclass.name ==MT_CLS_WIN_8 || - td->mtclass.name ==MT_CLS_WIN_8_FORCE_MULTI_INPUT )) { + td->mtclass.name ==MT_CLS_WIN_8_FORCE_MULTI_INPUT || + td->mtclass.name ==MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE )) {if (hid_haptic_input_configured (hdev, td->haptic, hi) ==0 ) td->is_haptic_touchpad = false; }else {
@@ -2075,7 +2088,12 @@ static void mt_on_hid_hw_open(struct hid_device *hdev)static void mt_on_hid_hw_close (struct hid_device *hdev) { -mt_set_modes (hdev,HID_LATENCY_HIGH ,TOUCHPAD_REPORT_NONE ); +struct mt_device *td =hid_get_drvdata (hdev); + +if (td->mtclass.quirks &MT_QUIRK_KEEP_LATENCY_ON_CLOSE ) +mt_set_modes (hdev,HID_LATENCY_NORMAL ,TOUCHPAD_REPORT_NONE ); +else +mt_set_modes (hdev,HID_LATENCY_HIGH ,TOUCHPAD_REPORT_NONE ); }/*
@@ -2461,6 +2479,14 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, +/* Uniwill touchpads */ + { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE, +HID_DEVICE (BUS_I2C ,HID_GROUP_MULTITOUCH_WIN_8 , + USB_VENDOR_ID_PIXART, 0x0255) }, + { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE, +HID_DEVICE (BUS_I2C ,HID_GROUP_MULTITOUCH_WIN_8 , + USB_VENDOR_ID_PIXART, 0x0274) }, + /* VTL panels */ { .driver_data = MT_CLS_VTL, MT_USB_DEVICE(USB_VENDOR_ID_VTL,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 116/311 x86/efi: defer freeing of boot services memory
In reply to Sasha LevinFrom: "Mike Rapoport (Microsoft)" <[email protected]>
commit a4b0bf6a40f3c107c67a24fbc614510ef5719980 upstream.
efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().
There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().
More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.
Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.
If the freed memory resides in the areas that memory map for them is still uninitialized, they won't be actually freed because memblock_free_late() calls memblock_free_pages() and the latter skips uninitialized pages.
Using free_reserved_area() at this point is also problematic because __free_page() accesses the buddy of the freed page and that again might end up in uninitialized part of the memory map.
Delaying the entire efi_free_boot_services() could be problematic because in addition to freeing boot services memory it updates efi.memmap without any synchronization and that's undesirable late in boot when there is concurrency.
More robust approach is to only defer freeing of the EFI boot services memory.
Split efi_free_boot_services() in two. First efi_unmap_boot_services() collects ranges that should be freed into an array then efi_free_boot_services() later frees them after deferred init is complete.
--- arch/x86/include/asm/efi.h | 2 +- arch/x86/platform/efi/efi.c | 2 +- arch/x86/platform/efi/quirks.c | 55 +++++++++++++++++++++++++++-- drivers/firmware/efi/mokvar-table.c | 2 +- 4 files changed, 55 insertions(+), 6 deletions(-)
arch/x86/include/asm/efi.h +1 -1
@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);extern int __init efi_reuse_config (u64 tables,int nr_tables);extern void efi_delete_dummy_variable (void );extern void efi_crash_gracefully_on_page_fault (unsigned long phys_addr); -extern void efi_free_boot_services (void ); +extern void efi_unmap_boot_services (void );void arch_efi_call_virt_setup (void );void arch_efi_call_virt_teardown (void );
arch/x86/platform/efi/efi.c +1 -1
@@ -837,7 +837,7 @@ static void __init __efi_enter_virtual_mode(void) }efi_check_for_embedded_firmwares (); -efi_free_boot_services (); +efi_unmap_boot_services ();if (!efi_is_mixed ())efi_native_runtime_setup ();
arch/x86/platform/efi/quirks.c +52 -3
89 lines not on this page · raw message
drivers/firmware/efi/mokvar-table.c +1 -1
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;* as an alternative to ordinary EFI variables, due to platform-dependent * limitations. The memory occupied by this table is marked as reserved. * -* This routine must be called before efi_free_boot_services() in order +* This routine must be called before efi_unmap_boot_services() in order * to guarantee that it can mark the table as reserved. * * Implicit inputs:
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 117/311 perf/x86/intel/uncore: Add per-scheduler IMC CAS count events
In reply to Sasha LevinFrom: Zide Chen <[email protected]>
commit 6a8a48644c4b804123e59dbfc5d6cd29a0194046 upstream.
IMC on SPR and EMR does not support sub-channels. In contrast, CPUs that use gnr_uncores[] (e.g. Granite Rapids and Sierra Forest) implement two command schedulers (SCH0/SCH1) per memory channel, providing logically independent command and data paths.
Do not reuse the spr_uncore_imc[] configuration for these CPUs. Instead, introduce a dedicated gnr_uncore_imc[] with per-scheduler events, so userspace can monitor SCH0 and SCH1 independently.
On these CPUs, replace cas_count_{read,write} with cas_count_{read,write}_sch{0,1}. This may break existing userspace that relies on cas_count_{read,write}, prompting it to switch to the per-scheduler events, as the legacy event reports only partial traffic (SCH0).
--- arch/x86/events/intel/uncore_snbep.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
arch/x86/events/intel/uncore_snbep.c +27 -1
@@ -6610,6 +6610,32 @@ static struct intel_uncore_type gnr_uncore_ubox = { .attr_update = uncore_alias_groups, }; +static struct uncore_event_desc gnr_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0x01,umask=0x00" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0,"event=0x05,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1,"event=0x06,umask=0xcf" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_read_sch1.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0,"event=0x05,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch0.unit,"MiB" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1,"event=0x06,umask=0xf0" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.scale,"6.103515625e-5" ), +INTEL_UNCORE_EVENT_DESC (cas_count_write_sch1.unit,"MiB" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_type gnr_uncore_imc = { +SPR_UNCORE_MMIO_COMMON_FORMAT (), + .name ="imc" , + .fixed_ctr_bits =48 , + .fixed_ctr =SNR_IMC_MMIO_PMON_FIXED_CTR , + .fixed_ctl =SNR_IMC_MMIO_PMON_FIXED_CTL , + .event_descs = gnr_uncore_imc_events, +}; +static struct intel_uncore_type gnr_uncore_pciex8 = {SPR_UNCORE_PCI_COMMON_FORMAT (), .name ="pciex8" ,
@@ -6657,7 +6683,7 @@ static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = {NULL , &spr_uncore_pcu, &gnr_uncore_ubox, - &spr_uncore_imc, + &gnr_uncore_imc,NULL , &gnr_uncore_upi, NULL,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 118/311 x86/boot: Handle relative CONFIG_EFI_SBAT_FILE file paths
In reply to Sasha LevinFrom: Jan Stancek <[email protected]>
commit 3d1973a0c76a78a4728cff13648a188ed486cf44 upstream.
CONFIG_EFI_SBAT_FILE can be a relative path. When compiling using a different output directory (O=) the build currently fails because it can't find the filename set in CONFIG_EFI_SBAT_FILE:
arch/x86/boot/compressed/sbat.S: Assembler messages:
arch/x86/boot/compressed/sbat.S:6: Error: file not found: kernel.sbat
Add $(srctree) as include dir for sbat.o.
[ bp: Massage commit message. ]
--- arch/x86/boot/compressed/Makefile | 1 + 1 file changed, 1 insertion(+)
arch/x86/boot/compressed/Makefile +1 -0
@@ -113,6 +113,7 @@ vmlinux-objs-$(CONFIG_EFI_SBAT) += $(obj)/sbat.o ifdef CONFIG_EFI_SBAT $(obj)/sbat.o: $(CONFIG_EFI_SBAT_FILE) +AFLAGS_sbat.o += -I $(srctree) endif $(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 119/311 x86/sev: Allow IBPB-on-Entry feature for SNP guests
In reply to Sasha LevinFrom: Kim Phillips <[email protected]>
commit 9073428bb204d921ae15326bb7d4558d9d269aab upstream.
The SEV-SNP IBPB-on-Entry feature does not require a guest-side implementation. It was added in Zen5 h/w, after the first SNP Zen implementation, and thus was not accounted for when the initial set of SNP features were added to the kernel.
In its abundant precaution, commit
8c29f0165405 ("x86/sev: Add SEV-SNP guest feature negotiation support")
included SEV_STATUS' IBPB-on-Entry bit as a reserved bit, thereby masking guests from using the feature.
Allow guests to make use of IBPB-on-Entry when supported by the hypervisor, as the bit is now architecturally defined and safe to expose.
--- arch/x86/boot/compressed/sev.c | 1 + arch/x86/coco/sev/core.c | 1 + arch/x86/include/asm/msr-index.h | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/sev.c +1 -0
@@ -188,6 +188,7 @@ bool sev_es_check_ghcb_fault(unsigned long address)MSR_AMD64_SNP_RESERVED_BIT13 | \MSR_AMD64_SNP_RESERVED_BIT15 | \MSR_AMD64_SNP_SECURE_AVIC | \ +MSR_AMD64_SNP_RESERVED_BITS19_22 | \ MSR_AMD64_SNP_RESERVED_MASK) #ifdef CONFIG_AMD_SECURE_AVIC
arch/x86/coco/sev/core.c +1 -0
@@ -122,6 +122,7 @@ static const char * const sev_status_feat_names[] = { [MSR_AMD64_SNP_VMSA_REG_PROT_BIT] = "VMSARegProt", [MSR_AMD64_SNP_SMT_PROT_BIT] = "SMTProt", [MSR_AMD64_SNP_SECURE_AVIC_BIT] = "SecureAVIC", + [MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT] = "IBPBOnEntry", };/*
arch/x86/include/asm/msr-index.h +4 -1
@@ -735,7 +735,10 @@#define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)#define MSR_AMD64_SNP_SECURE_AVIC_BIT 18#define MSR_AMD64_SNP_SECURE_AVIC BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT) -#define MSR_AMD64_SNP_RESV_BIT 19 +#define MSR_AMD64_SNP_RESERVED_BITS19_22 GENMASK_ULL(22, 19) +#define MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT 23 +#define MSR_AMD64_SNP_IBPB_ON_ENTRY BIT_ULL(MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT) +#define MSR_AMD64_SNP_RESV_BIT 24#define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, MSR_AMD64_SNP_RESV_BIT)#define MSR_AMD64_SAVIC_CONTROL 0xc0010138#define MSR_AMD64_SAVIC_EN_BIT 0
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 120/311 x86/boot/sev: Move SEV decompressor variables into the .data section
In reply to Sasha LevinFrom: Tom Lendacky <[email protected]>
commit 4ca191cec17a997d0e3b2cd312f3a884288acc27 upstream.
As part of the work to remove the dependency on calling into the decompressor code (startup_64()) for a UEFI boot, a call to rmpadjust() was removed from sev_enable() in favor of checking the value of the snp_vmpl variable.
When booting through a non-UEFI path and calling startup_64(), the call to sev_enable() is performed before the BSS section is zeroed. With the removal of the rmpadjust() call and the corresponding check of the return code, the snp_vmpl variable is checked.
Since the kernel is running at VMPL0, the snp_vmpl variable will not have been set and should be the default value of 0. However, since the call occurs before the BSS is zeroed, the snp_vmpl variable may not actually be zero, which will cause the guest boot to fail.
Since the decompressor relocates itself, the BSS would need to be cleared both before and after the relocation, but this would, in effect, cause all of the changes to BSS variables before relocation to be lost after relocation.
Instead, move the snp_vmpl variable into the .data section so that it is initialized and the value made safe during relocation. As a pre-caution against future changes, move other SEV-related decompressor variables into the .data section, too.
--- arch/x86/boot/compressed/sev.c | 8 ++++---- arch/x86/boot/startup/sev-shared.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-)
arch/x86/boot/compressed/sev.c +4 -4
@@ -28,17 +28,17 @@#include "sev.h" static struct ghcb boot_ghcb_page__aligned(PAGE_SIZE) ; -struct ghcb *boot_ghcb; +struct ghcb *boot_ghcb __section(".data");#undef __init#define __init#define __BOOT_COMPRESSED -u8 snp_vmpl; -u16 ghcb_version; +u8 snp_vmpl __section(".data"); +u16 ghcb_version __section(".data"); -u64 boot_svsm_caa_pa; +u64 boot_svsm_caa_pa __section(".data");/* Include code for early handlers */ #include "../../boot/startup/sev-shared.c"
arch/x86/boot/startup/sev-shared.c +1 -1
@@ -31,7 +31,7 @@ static u32 cpuid_std_range_max __ro_after_init;static u32 cpuid_hyp_range_max__ro_after_init ;static u32 cpuid_ext_range_max__ro_after_init ; -bool sev_snp_needs_sfw; +bool sev_snp_needs_sfw __section(".data");void __noreturn sev_es_terminate (unsigned int set,unsigned int reason)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 121/311 platform/x86: dell-wmi-sysman: Don't hex dump plaintext password data
In reply to Sasha LevinFrom: Thorsten Blum <[email protected]>
commit d1a196e0a6dcddd03748468a0e9e3100790fc85c upstream.
set_new_password() hex dumps the entire buffer, which contains plaintext password data, including current and new passwords. Remove the hex dump to avoid leaking credentials.
--- .../platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c | 1 - 1 file changed, 1 deletion(-)
drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c +0 -1
@@ -93,7 +93,6 @@ int set_new_password(const char *password_type, const char *new)if (ret <0 ) goto out; -print_hex_dump_bytes ("set new password data: " ,DUMP_PREFIX_NONE , buffer, buffer_size); ret =call_password_interface (wmi_priv.password_attr_wdev, buffer, buffer_size);/* on success copy the new password to current password */ if (!ret)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 122/311 platform/x86: alienware-wmi-wmax: Add G-Mode support to m18 laptops
In reply to Sasha LevinFrom: Kurt Borja <[email protected]>
commit bd5914caeb4b2de233992c31babccda88041b035 upstream.
Alienware m18 laptops support G-Mode. Therefore, match them with G-Series quirks.
--- drivers/platform/x86/dell/alienware-wmi-wmax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/dell/alienware-wmi-wmax.c +1 -1
@@ -175,7 +175,7 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {DMI_MATCH (DMI_SYS_VENDOR ,"Alienware" ), DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18"), }, - .driver_data = &generic_quirks, + .driver_data = &g_series_quirks, }, { .ident = "Alienware x15",
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 123/311 platform/x86: dell-wmi: Add audio/mic mute key codes
In reply to Sasha LevinFrom: Kurt Borja <[email protected]>
commit 26a7601471f62b95d56a81c3a8ccb551b5a6630f upstream.
Add audio/mic mute key codes found in Alienware m18 r1 AMD.
--- drivers/platform/x86/dell/dell-wmi-base.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/platform/x86/dell/dell-wmi-base.c +6 -0
@@ -80,6 +80,12 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {static const struct key_entry dell_wmi_keymap_type_0000[] = { {KE_IGNORE ,0x003a , {KEY_CAPSLOCK } }, +/* Audio mute toggle */ + {KE_KEY ,0x0109 , {KEY_MUTE } }, + +/* Mic mute toggle */ + {KE_KEY ,0x0150 , {KEY_MICMUTE } }, +/* Meta key lock */ {KE_IGNORE ,0xe000 , {KEY_RIGHTMETA } },
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 124/311 ALSA: hda/realtek: Add quirk for HP Pavilion 15-eh1xxx to enable mute LED
In reply to Sasha LevinFrom: Zhang Heng <[email protected]>
commit 068641bc9dc3d680d1ec4f6ee9199d4812041dff upstream.
The HP Pavilion 15-eh1xxx series uses the HP mainboard 88D1 with ALC245 and needs the ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT quirk to make the mute led working.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -6872,6 +6872,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x103c ,0x8898 ,"HP EliteBook 845 G8 Notebook PC" ,ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST ),SND_PCI_QUIRK (0x103c ,0x88b3 ,"HP ENVY x360 Convertible 15-es0xxx" ,ALC245_FIXUP_HP_ENVY_X360_MUTE_LED ),SND_PCI_QUIRK (0x103c ,0x88d0 ,"HP Pavilion 15-eh1xxx (mainboard 88D0)" ,ALC287_FIXUP_HP_GPIO_LED ), +SND_PCI_QUIRK (0x103c ,0x88d1 ,"HP Pavilion 15-eh1xxx (mainboard 88D1)" ,ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT ),SND_PCI_QUIRK (0x103c ,0x88dd ,"HP Pavilion 15z-ec200" ,ALC285_FIXUP_HP_MUTE_LED ),SND_PCI_QUIRK (0x103c ,0x88eb ,"HP Victus 16-e0xxx" ,ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT ), SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 125/311 ALSA: doc: usb-audio: Add doc for QUIRK_FLAG_SKIP_IFACE_SETUP
In reply to Sasha LevinFrom: Rong Zhang <[email protected]>
commit 93992667d0ab695ac30ceec91a516fd4bf725d75 upstream.
QUIRK_FLAG_SKIP_IFACE_SETUP was introduced into usb-audio before without appropriate documentation, so add it.
--- Documentation/sound/alsa-configuration.rst | 4 ++++ 1 file changed, 4 insertions(+)
Documentation/sound/alsa-configuration.rst +4 -0
@@ -2372,6 +2372,10 @@ quirk_flags audible volume * bit 25: ``mixer_capture_min_mute`` Similar to bit 24 but for capture streams + * bit 26: ``skip_iface_setup`` + Skip the probe-time interface setup (usb_set_interface, + init_pitch, init_sample_rate); redundant with + snd_usb_endpoint_prepare() at stream-open time This module supports multiple devices, autoprobe and hotplugging.
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 126/311 ALSA: usb-audio: Use correct version for UAC3 header validation
In reply to Sasha LevinFrom: Jun Seo <[email protected]>
commit 54f9d645a5453d0bfece0c465d34aaf072ea99fa upstream.
The entry of the validators table for UAC3 AC header descriptor is defined with the wrong protocol version UAC_VERSION_2, while it should have been UAC_VERSION_3. This results in the validator never matching for actual UAC3 devices (protocol == UAC_VERSION_3), causing their header descriptors to bypass validation entirely. A malicious USB device presenting a truncated UAC3 header could exploit this to cause out-of-bounds reads when the driver later accesses unvalidated descriptor fields.
The bug was introduced in the same commit as the recently fixed UAC3 feature unit sub-type typo, and appears to be from the same copy-paste error when the UAC3 section was created from the UAC2 section.
--- sound/usb/validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/validate.c +1 -1
@@ -281,7 +281,7 @@ static const struct usb_desc_validator audio_validators[] = {/* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */ /* UAC3 */ - FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor), + FIXED(UAC_VERSION_3, UAC_HEADER, struct uac3_ac_header_descriptor),FIXED (UAC_VERSION_3 ,UAC_INPUT_TERMINAL , struct uac3_input_terminal_descriptor), FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 127/311 ALSA: hda/intel: increase default bdl_pos_adj for Nvidia controllers
In reply to Sasha LevinFrom: Panagiotis Foliadis <[email protected]>
commit e9fb2028f1eb563e653cff3b0d1c87c5e0203d45 upstream.
The default bdl_pos_adj of 32 for Nvidia HDA controllers is insufficient on GA102 (and likely other recent Nvidia GPUs) after S3 suspend/resume. The controller's DMA timing degrades after resume, causing premature IRQ detection in azx_position_ok() which results in silent HDMI/DP audio output despite userspace reporting a valid playback state and correct ELD data.
Increase bdl_pos_adj to 64 for AZX_DRIVER_NVIDIA, matching the value already used by Intel Apollo Lake for the same class of timing issue.
--- sound/hda/controllers/intel.c | 2 ++ 1 file changed, 2 insertions(+)
sound/hda/controllers/intel.c +2 -0
@@ -1751,6 +1751,8 @@ static int default_bdl_pos_adj(struct azx *chip)return 1 ;case AZX_DRIVER_ZHAOXINHDMI :return 128 ; +case AZX_DRIVER_NVIDIA : +return 64 ;default :return 32 ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 128/311 ALSA: hda/realtek: fix model name typo for Samsung Galaxy Book Flex (NT950QCG-X716)
In reply to Sasha LevinFrom: Juhyung Park <[email protected]>
commit 43a44fb7f2fa163926b23149805e989ba2395db1 upstream.
There's no product named "Samsung Galaxy Flex Book". Use the correct "Samsung Galaxy Book Flex" name.
--- sound/hda/codecs/realtek/alc269.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/hda/codecs/realtek/alc269.c +1 -1
@@ -7312,7 +7312,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x144d ,0xc109 ,"Samsung Ativ book 9 (NP900X3G)" ,ALC269_FIXUP_INV_DMIC ),SND_PCI_QUIRK (0x144d ,0xc169 ,"Samsung Notebook 9 Pen (NP930SBE-K01US)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc176 ,"Samsung Notebook 9 Pro (NP930MBE-K04US)" ,ALC298_FIXUP_SAMSUNG_AMP ), -SND_PCI_QUIRK (0x144d ,0xc189 ,"Samsung Galaxy Flex Book (NT950QCG-X716)" ,ALC298_FIXUP_SAMSUNG_AMP ), +SND_PCI_QUIRK (0x144d ,0xc189 ,"Samsung Galaxy Book Flex (NT950QCG-X716)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc18a ,"Samsung Galaxy Book Ion (NP930XCJ-K01US)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc1a3 ,"Samsung Galaxy Book Pro (NP935XDB-KC1SE)" ,ALC298_FIXUP_SAMSUNG_AMP ), SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP),
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 129/311 ALSA: hda/realtek: Add quirk for Acer Aspire V3-572G
In reply to Sasha LevinFrom: Panagiotis Foliadis <[email protected]>
commit cbddd303416456db5ceeedaf9e262096f079e861 upstream.
The Acer Aspire V3-572G has a combo jack (ALC283) but the BIOS sets pin 0x19 to 0x411111f0 (not connected), so the headset mic is not detected.
Add a quirk to override pin 0x19 as a headset mic and enable headset mode.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -6591,6 +6591,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x1025 ,0x079b ,"Acer Aspire V5-573G" ,ALC282_FIXUP_ASPIRE_V5_PINS ),SND_PCI_QUIRK (0x1025 ,0x080d ,"Acer Aspire V5-122P" ,ALC269_FIXUP_ASPIRE_HEADSET_MIC ),SND_PCI_QUIRK (0x1025 ,0x0840 ,"Acer Aspire E1" ,ALC269VB_FIXUP_ASPIRE_E1_COEF ), +SND_PCI_QUIRK (0x1025 ,0x0943 ,"Acer Aspire V3-572G" ,ALC269_FIXUP_ASPIRE_HEADSET_MIC ),SND_PCI_QUIRK (0x1025 ,0x100c ,"Acer Aspire E5-574G" ,ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST ),SND_PCI_QUIRK (0x1025 ,0x101c ,"Acer Veriton N2510G" ,ALC269_FIXUP_LIFEBOOK ), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 130/311 ALSA: hda/realtek: add quirk for Samsung Galaxy Book Flex (NT950QCT-A38A)
In reply to Sasha LevinFrom: Juhyung Park <[email protected]>
commit 9fb16a5c5ff93058851099a2b80a899b0c53fe3f upstream.
Similar to other Samsung laptops, NT950QCT also requires the ALC298_FIXUP_SAMSUNG_AMP quirk applied.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7313,6 +7313,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x144d ,0xc109 ,"Samsung Ativ book 9 (NP900X3G)" ,ALC269_FIXUP_INV_DMIC ),SND_PCI_QUIRK (0x144d ,0xc169 ,"Samsung Notebook 9 Pen (NP930SBE-K01US)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc176 ,"Samsung Notebook 9 Pro (NP930MBE-K04US)" ,ALC298_FIXUP_SAMSUNG_AMP ), +SND_PCI_QUIRK (0x144d ,0xc188 ,"Samsung Galaxy Book Flex (NT950QCT-A38A)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc189 ,"Samsung Galaxy Book Flex (NT950QCG-X716)" ,ALC298_FIXUP_SAMSUNG_AMP ),SND_PCI_QUIRK (0x144d ,0xc18a ,"Samsung Galaxy Book Ion (NP930XCJ-K01US)" ,ALC298_FIXUP_SAMSUNG_AMP ), SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 131/311 ALSA: hda/realtek: add quirk for Acer Nitro ANV15-51
In reply to Sasha LevinFrom: Zhang Heng <[email protected]>
commit aa4876fe2d9fcbcaa0592b25f34ec6f6ea7876c1 upstream.
fix mute/micmute LEDs and headset microphone for Acer Nitro ANV15-51.
[ The headset microphone issue is solved by Kailang]
--- sound/hda/codecs/realtek/alc269.c | 8 ++++++++ 1 file changed, 8 insertions(+)
sound/hda/codecs/realtek/alc269.c +8 -0
@@ -4056,6 +4056,7 @@ enum {ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO ,ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY ,ALC245_FIXUP_BASS_HP_DAC , + ALC245_FIXUP_ACER_MICMUTE_LED, };/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -6576,6 +6577,12 @@ static const struct hda_fixup alc269_fixups[] = {/* Borrow the DAC routing selected for those Thinkpads */ .v.func = alc285_fixup_thinkpad_x1_gen7, }, + [ALC245_FIXUP_ACER_MICMUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_coef_micmute_led, + .chained = true, + .chain_id = ALC2XX_FIXUP_HEADSET_MIC, + } };static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -6628,6 +6635,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x1025 ,0x159c ,"Acer Nitro 5 AN515-58" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1025 ,0x1597 ,"Acer Nitro 5 AN517-55" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1025 ,0x169a ,"Acer Swift SFG16" ,ALC256_FIXUP_ACER_SFG16_MICMUTE_LED ), +SND_PCI_QUIRK (0x1025 ,0x171e ,"Acer Nitro ANV15-51" ,ALC245_FIXUP_ACER_MICMUTE_LED ),SND_PCI_QUIRK (0x1025 ,0x1826 ,"Acer Helios ZPC" ,ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2 ),SND_PCI_QUIRK (0x1025 ,0x182c ,"Acer Helios ZPD" ,ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2 ), SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 132/311 wifi: radiotap: reject radiotap with unknown bits
In reply to Sasha LevinFrom: Johannes Berg <[email protected]>
commit c854758abe0b8d86f9c43dc060ff56a0ee5b31e0 upstream.
The radiotap parser is currently only used with the radiotap namespace (not with vendor namespaces), but if the undefined field 18 is used, the alignment/size is unknown as well. In this case, iterator->_next_ns_data isn't initialized (it's only set for skipping vendor namespaces), and syzbot points out that we later compare against this uninitialized value.
Fix this by moving the rejection of unknown radiotap fields down to after the in-namespace lookup, so it will really use iterator->_next_ns_data only for vendor namespaces, even in case undefined fields are present.
--- net/wireless/radiotap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/wireless/radiotap.c +2 -2
@@ -239,14 +239,14 @@ int ieee80211_radiotap_iterator_next(default :if (!iterator->current_namespace || iterator->_arg_index >= iterator->current_namespace->n_bits) { -if (iterator->current_namespace == &radiotap_ns) -return -ENOENT ; align =0 ; }else { align = iterator->current_namespace->align_size[iterator->_arg_index].align; size = iterator->current_namespace->align_size[iterator->_arg_index].size; }if (!align) { +if (iterator->current_namespace == &radiotap_ns) +return -ENOENT ;/* skip all subsequent data */ iterator->_arg = iterator->_next_ns_data;/* give up on this namespace */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 133/311 wifi: libertas: fix use-after-free in lbs_free_adapter()
In reply to Sasha LevinFrom: Daniel Hodges <[email protected]>
commit 03cc8f90d0537fcd4985c3319b4fafbf2e3fb1f0 upstream.
The lbs_free_adapter() function uses timer_delete() (non-synchronous) for both command_timer and tx_lockup_timer before the structure is freed. This is incorrect because timer_delete() does not wait for any running timer callback to complete.
If a timer callback is executing when lbs_free_adapter() is called, the callback will access freed memory since lbs_cfg_free() frees the containing structure immediately after lbs_free_adapter() returns.
Both timer callbacks (lbs_cmd_timeout_handler and lbs_tx_lockup_handler) access priv->driver_lock, priv->cur_cmd, priv->dev, and other fields, which would all be use-after-free violations.
Use timer_delete_sync() instead to ensure any running timer callback has completed before returning.
This bug was introduced in commit 8f641d93c38a ("libertas: detect TX lockups and reset hardware") where del_timer() was used instead of del_timer_sync() in the cleanup path. The command_timer has had the same issue since the driver was first written.
--- drivers/net/wireless/marvell/libertas/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/libertas/main.c +2 -2
@@ -799,8 +799,8 @@ static void lbs_free_adapter(struct lbs_private *priv) {lbs_free_cmd_buffer (priv);kfifo_free (&priv->event_fifo); -timer_delete (&priv->command_timer); -timer_delete (&priv->tx_lockup_timer); +timer_delete_sync (&priv->command_timer); +timer_delete_sync (&priv->tx_lockup_timer); }static const struct net_device_ops lbs_netdev_ops = {
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 134/311 wifi: cfg80211: cancel rfkill_block work in wiphy_unregister()
In reply to Sasha LevinFrom: Daniil Dulov <[email protected]>
commit 767d23ade706d5fa51c36168e92a9c5533c351a1 upstream.
There is a use-after-free error in cfg80211_shutdown_all_interfaces found by syzkaller:
BUG: KASAN: use-after-free in cfg80211_shutdown_all_interfaces+0x213/0x220 Read of size 8 at addr ffff888112a78d98 by task kworker/0:5/5326 CPU: 0 UID: 0 PID: 5326 Comm: kworker/0:5 Not tainted 6.19.0-rc2 #2 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Workqueue: events cfg80211_rfkill_block_work Call Trace: <TASK> dump_stack_lvl+0x116/0x1f0 print_report+0xcd/0x630 kasan_report+0xe0/0x110 cfg80211_shutdown_all_interfaces+0x213/0x220 cfg80211_rfkill_block_work+0x1e/0x30 process_one_work+0x9cf/0x1b70 worker_thread+0x6c8/0xf10 kthread+0x3c5/0x780 ret_from_fork+0x56d/0x700 ret_from_fork_asm+0x1a/0x30 </TASK>
The problem arises due to the rfkill_block work is not cancelled when wiphy is being unregistered. In order to fix the issue cancel the corresponding work in wiphy_unregister().
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- net/wireless/core.c | 1 + 1 file changed, 1 insertion(+)
net/wireless/core.c +1 -0
@@ -1210,6 +1210,7 @@ void wiphy_unregister(struct wiphy *wiphy)/* this has nothing to do now but make sure it's gone */ cancel_work_sync (&rdev->wiphy_work); +cancel_work_sync (&rdev->rfkill_block);cancel_work_sync (&rdev->conn_work);flush_work (&rdev->event_work);cancel_delayed_work_sync (&rdev->dfs_update_channels_wk);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 135/311 wifi: mac80211: bounds-check link_id in ieee80211_ml_reconfiguration
In reply to Sasha LevinFrom: Ariel Silver <[email protected]>
commit 162d331d833dc73a3e905a24c44dd33732af1fc5 upstream.
link_id is taken from the ML Reconfiguration element (control & 0x000f), so it can be 0..15. link_removal_timeout[] has IEEE80211_MLD_MAX_NUM_LINKS
(15) elements, so index 15 is out-of-bounds. Skip subelements with link_id >= IEEE80211_MLD_MAX_NUM_LINKS to avoid a stack out-of-bounds write.
--- net/mac80211/mlme.c | 3 +++ 1 file changed, 3 insertions(+)
net/mac80211/mlme.c +3 -0
@@ -6975,6 +6975,9 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, control =le16_to_cpu (prof->control); link_id = control &IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID ; +if (link_id >=IEEE80211_MLD_MAX_NUM_LINKS ) +continue ; + removed_links |=BIT (link_id);/* the MAC address should not be included, but handle it */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 136/311 wifi: mac80211: fix NULL pointer dereference in mesh_rx_csa_frame()
In reply to Sasha LevinFrom: Vahagn Vardanian <[email protected]>
commit 017c1792525064a723971f0216e6ef86a8c7af11 upstream.
In mesh_rx_csa_frame(), elems->mesh_chansw_params_ie is dereferenced at lines 1638 and 1642 without a prior NULL check:
ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
...
pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);The mesh_matches_local() check above only validates the Mesh ID, Mesh Configuration, and Supported Rates IEs. It does not verify the presence of the Mesh Channel Switch Parameters IE (element ID 118). When a received CSA action frame omits that IE, ieee802_11_parse_elems() leaves elems->mesh_chansw_params_ie as NULL, and the unconditional dereference causes a kernel NULL pointer dereference.
A remote mesh peer with an established peer link (PLINK_ESTAB) can trigger this by sending a crafted SPECTRUM_MGMT/CHL_SWITCH action frame that includes a matching Mesh ID and Mesh Configuration IE but omits the Mesh Channel Switch Parameters IE. No authentication beyond the default open mesh peering is required.
Crash confirmed on kernel 6.17.0-5-generic via mac80211_hwsim:
BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: Oops: 0000 [#1] SMP NOPTI RIP: 0010:ieee80211_mesh_rx_queued_mgmt+0x143/0x2a0 [mac80211] CR2: 0000000000000000
Fix by adding a NULL check for mesh_chansw_params_ie after mesh_matches_local() returns, consistent with how other optional IEs are guarded throughout the mesh code.
The bug has been present since v3.13 (released 2014-01-19).
--- net/mac80211/mesh.c | 3 +++ 1 file changed, 3 insertions(+)
net/mac80211/mesh.c +3 -0
@@ -1636,6 +1636,9 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,if (!mesh_matches_local (sdata, elems)) goto free; +if (!elems->mesh_chansw_params_ie) + goto free; + ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;if (!--ifmsh->chsw_ttl) fwd_csa = false;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 137/311 Bluetooth: purge error queues in socket destructors
In reply to Sasha LevinFrom: Heitor Alves de Siqueira <[email protected]>
commit 21e4271e65094172aadd5beb8caea95dd0fbf6d7 upstream.
When TX timestamping is enabled via SO_TIMESTAMPING, SKBs may be queued into sk_error_queue and will stay there until consumed. If userspace never gets to read the timestamps, or if the controller is removed unexpectedly, these SKBs will leak.
Fix by adding skb_queue_purge() calls for sk_error_queue in affected bluetooth destructors. RFCOMM does not currently use sk_error_queue.
--- net/bluetooth/hci_sock.c | 1 + net/bluetooth/iso.c | 1 + net/bluetooth/l2cap_sock.c | 1 + net/bluetooth/sco.c | 1 + 4 files changed, 4 insertions(+)
net/bluetooth/hci_sock.c +1 -0
@@ -2166,6 +2166,7 @@ static void hci_sock_destruct(struct sock *sk)mgmt_cleanup (sk);skb_queue_purge (&sk->sk_receive_queue);skb_queue_purge (&sk->sk_write_queue); +skb_queue_purge (&sk->sk_error_queue); }static const struct proto_ops hci_sock_ops = {
net/bluetooth/iso.c +1 -0
@@ -746,6 +746,7 @@ static void iso_sock_destruct(struct sock *sk)skb_queue_purge (&sk->sk_receive_queue);skb_queue_purge (&sk->sk_write_queue); +skb_queue_purge (&sk->sk_error_queue); }static void iso_sock_cleanup_listen (struct sock *parent)
net/bluetooth/l2cap_sock.c +1 -0
@@ -1806,6 +1806,7 @@ static void l2cap_sock_destruct(struct sock *sk)skb_queue_purge (&sk->sk_receive_queue);skb_queue_purge (&sk->sk_write_queue); +skb_queue_purge (&sk->sk_error_queue); } static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,
net/bluetooth/sco.c +1 -0
@@ -470,6 +470,7 @@ static void sco_sock_destruct(struct sock *sk)skb_queue_purge (&sk->sk_receive_queue);skb_queue_purge (&sk->sk_write_queue); +skb_queue_purge (&sk->sk_error_queue); }static void sco_sock_cleanup_listen (struct sock *parent)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 138/311 gve: fix incorrect buffer cleanup in gve_tx_clean_pending_packets for QPL
In reply to Sasha LevinFrom: Ankit Garg <[email protected]>
commit fb868db5f4bccd7a78219313ab2917429f715cea upstream.
In DQ-QPL mode, gve_tx_clean_pending_packets() incorrectly uses the RDA buffer cleanup path. It iterates num_bufs times and attempts to unmap entries in the dma array.
This leads to two issues:
1. The dma array shares storage with tx_qpl_buf_ids (union). Interpreting buffer IDs as DMA addresses results in attempting to unmap incorrect memory locations.
2. num_bufs in QPL mode (counting 2K chunks) can significantly exceed the size of the dma array, causing out-of-bounds access warnings
(trace below is how we noticed this issue).
UBSAN: array-index-out-of-bounds in drivers/net/ethernet/drivers/net/ethernet/google/gve/gve_tx_dqo.c:178:5 index 18 is out of range for type 'dma_addr_t[18]' (aka 'unsigned long long[18]') Workqueue: gve gve_service_task [gve] Call Trace: <TASK> dump_stack_lvl+0x33/0xa0 __ubsan_handle_out_of_bounds+0xdc/0x110 gve_tx_stop_ring_dqo+0x182/0x200 [gve] gve_close+0x1be/0x450 [gve] gve_reset+0x99/0x120 [gve] gve_service_task+0x61/0x100 [gve] process_scheduled_works+0x1e9/0x380
Fix this by properly checking for QPL mode and delegating to gve_free_tx_qpl_bufs() to reclaim the buffers.
--- drivers/net/ethernet/google/gve/gve_tx_dqo.c | 56 +++++++++----------- 1 file changed, 25 insertions(+), 31 deletions(-)
drivers/net/ethernet/google/gve/gve_tx_dqo.c +25 -31
@@ -167,6 +167,25 @@ gve_free_pending_packet(struct gve_tx_ring *tx, } } +static void gve_unmap_packet (struct device *dev, +struct gve_tx_pending_packet_dqo *pkt) +{ +int i; + +if (!pkt->num_bufs) +return ; + +/* SKB linear portion is guaranteed to be mapped */ +dma_unmap_single (dev,dma_unmap_addr (pkt, dma[0 ]), +dma_unmap_len (pkt, len[0 ]),DMA_TO_DEVICE ); +for (i =1 ; i < pkt->num_bufs; i++) { +netmem_dma_unmap_page_attrs (dev,dma_unmap_addr (pkt, dma[i]), +dma_unmap_len (pkt, len[i]), +DMA_TO_DEVICE ,0 ); + } + pkt->num_bufs =0 ; +} +/* gve_tx_free_desc - Cleans up all pending tx requests and buffers. */ static void gve_tx_clean_pending_packets (struct gve_tx_ring *tx)
@@ -176,21 +195,12 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)for (i =0 ; i < tx->dqo.num_pending_packets; i++) {struct gve_tx_pending_packet_dqo *cur_state = &tx->dqo.pending_packets[i]; -int j; - -for (j =0 ; j < cur_state->num_bufs; j++) { -if (j ==0 ) { -dma_unmap_single (tx->dev, -dma_unmap_addr (cur_state, dma[j]), -dma_unmap_len (cur_state, len[j]), -DMA_TO_DEVICE ); - }else { -dma_unmap_page (tx->dev, -dma_unmap_addr (cur_state, dma[j]), -dma_unmap_len (cur_state, len[j]), -DMA_TO_DEVICE ); - } - } + +if (tx->dqo.qpl) +gve_free_tx_qpl_bufs (tx, cur_state); +else +gve_unmap_packet (tx->dev, cur_state); +if (cur_state->skb) {dev_consume_skb_any (cur_state->skb); cur_state->skb =NULL ;
@@ -1160,22 +1170,6 @@ static void remove_from_list(struct gve_tx_ring *tx, } } -static void gve_unmap_packet (struct device *dev, -struct gve_tx_pending_packet_dqo *pkt) -{ -int i; - -/* SKB linear portion is guaranteed to be mapped */ -dma_unmap_single (dev,dma_unmap_addr (pkt, dma[0 ]), -dma_unmap_len (pkt, len[0 ]),DMA_TO_DEVICE ); -for (i =1 ; i < pkt->num_bufs; i++) { -netmem_dma_unmap_page_attrs (dev,dma_unmap_addr (pkt, dma[i]), -dma_unmap_len (pkt, len[i]), -DMA_TO_DEVICE ,0 ); - } - pkt->num_bufs =0 ; -} -/* Completion types and expected behavior: * No Miss compl + Packet compl = Packet completed normally. * Miss compl + Re-inject compl = Packet completed normally.
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 139/311 net: phy: register phy led_triggers during probe to avoid AB-BA deadlock
In reply to Sasha LevinFrom: Andrew Lunn <[email protected]>
commit c8dbdc6e380e7e96a51706db3e4b7870d8a9402d upstream.
There is an AB-BA deadlock when both LEDS_TRIGGER_NETDEV and LED_TRIGGER_PHY are enabled:
[ 1362.049207] [<8054e4b8>] led_trigger_register+0x5c/0x1fc <-- Trying to get lock "triggers_list_lock" via down_write(&triggers_list_lock); [ 1362.054536] [<80662830>] phy_led_triggers_register+0xd0/0x234 [ 1362.060329] [<8065e200>] phy_attach_direct+0x33c/0x40c [ 1362.065489] [<80651fc4>] phylink_fwnode_phy_connect+0x15c/0x23c [ 1362.071480] [<8066ee18>] mtk_open+0x7c/0xba0 [ 1362.075849] [<806d714c>] __dev_open+0x280/0x2b0 [ 1362.080384] [<806d7668>] __dev_change_flags+0x244/0x24c [ 1362.085598] [<806d7698>] dev_change_flags+0x28/0x78 [ 1362.090528] [<807150e4>] dev_ioctl+0x4c0/0x654 <-- Hold lock "rtnl_mutex" by calling rtnl_lock(); [ 1362.094985] [<80694360>] sock_ioctl+0x2f4/0x4e0 [ 1362.099567] [<802e9c4c>] sys_ioctl+0x32c/0xd8c [ 1362.104022] [<80014504>] syscall_common+0x34/0x58
Here LED_TRIGGER_PHY is registering LED triggers during phy_attach while holding RTNL and then taking triggers_list_lock.
[ 1362.191101] [<806c2640>] register_netdevice_notifier+0x60/0x168 <-- Trying to get lock "rtnl_mutex" via rtnl_lock(); [ 1362.197073] [<805504ac>] netdev_trig_activate+0x194/0x1e4 [ 1362.202490] [<8054e28c>] led_trigger_set+0x1d4/0x360 <-- Hold lock "triggers_list_lock" by down_read(&triggers_list_lock); [ 1362.207511] [<8054eb38>] led_trigger_write+0xd8/0x14c [ 1362.212566] [<80381d98>] sysfs_kf_bin_write+0x80/0xbc [ 1362.217688] [<8037fcd8>] kernfs_fop_write_iter+0x17c/0x28c [ 1362.223174] [<802cbd70>] vfs_write+0x21c/0x3c4 [ 1362.227712] [<802cc0c4>] ksys_write+0x78/0x12c [ 1362.232164] [<80014504>] syscall_common+0x34/0x58
Here LEDS_TRIGGER_NETDEV is being enabled on an LED. It first takes triggers_list_lock and then RTNL. A classical AB-BA deadlock.
phy_led_triggers_registers() does not require the RTNL, it does not make any calls into the network stack which require protection. There is also no requirement the PHY has been attached to a MAC, the triggers only make use of phydev state. This allows the call to phy_led_triggers_registers() to be placed elsewhere. PHY probe() and release() don't hold RTNL, so solving the AB-BA deadlock.
--- drivers/net/phy/phy_device.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
drivers/net/phy/phy_device.c +17 -8
@@ -1763,8 +1763,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, goto error;phy_resume (phydev); -if (!phydev->is_on_sfp_module) -phy_led_triggers_register (phydev);/** * If the external phy used by current mac interface is managed by
@@ -1879,9 +1877,6 @@ void phy_detach(struct phy_device *phydev) phydev->phy_link_change =NULL ; phydev->phylink =NULL ; -if (!phydev->is_on_sfp_module) -phy_led_triggers_unregister (phydev); -if (phydev->mdio.dev.driver)module_put (phydev->mdio.dev.driver->owner);
@@ -3512,16 +3507,27 @@ static int phy_probe(struct device *dev)/* Set the state to READY by default */ phydev->state =PHY_READY ; +/* Register the PHY LED triggers */ +if (!phydev->is_on_sfp_module) +phy_led_triggers_register (phydev); +/* Get the LEDs from the device tree, and instantiate standard * LEDs for them. */ -if (IS_ENABLED (CONFIG_PHYLIB_LEDS ) && !phy_driver_is_genphy (phydev)) +if (IS_ENABLED (CONFIG_PHYLIB_LEDS ) && !phy_driver_is_genphy (phydev)) { err =of_phy_leds (phydev); +if (err) + goto out; + } + +return 0 ; out: +if (!phydev->is_on_sfp_module) +phy_led_triggers_unregister (phydev); +/* Re-assert the reset signal on error */ -if (err) -phy_device_reset (phydev,1 ); +phy_device_reset (phydev,1 );return err; }
@@ -3535,6 +3541,9 @@ static int phy_remove(struct device *dev)if (IS_ENABLED (CONFIG_PHYLIB_LEDS ) && !phy_driver_is_genphy (phydev))phy_leds_unregister (phydev); +if (!phydev->is_on_sfp_module) +phy_led_triggers_unregister (phydev); + phydev->state =PHY_DOWN ;sfp_bus_del_upstream (phydev->sfp_bus);
Signature · 1 line
2.51.0