Changes in 6.1.16
HID: asus: use spinlock to protect concurrent accesses
HID: asus: use spinlock to safely schedule workers
powerpc/mm: Rearrange if-else block to avoid clang warning
ata: ahci: Revert "ata: ahci: Add Tiger Lake UP{3,4} AHCI controller"
ARM: OMAP2+: Fix memory leak in realtime_counter_init()
arm64: dts: qcom: qcs404: use symbol names for PCIe resets
arm64: dts: qcom: msm8996-tone: Fix USB taking 6 minutes to wake up
arm64: dts: qcom: sm8150-kumano: Panel framebuffer is 2.5k instead of 4k
arm64: dts: qcom: sm6350: Fix up the ramoops node
arm64: dts: qcom: sm6125: Reorder HSUSB PHY clocks to match bindings
arm64: dts: qcom: sm6125-seine: Clean up gpio-keys (volume down)
arm64: dts: imx8m: Align SoC unique ID node unit address
ARM: zynq: Fix refcount leak in zynq_early_slcr_init
arm64: dts: mediatek: mt8195: Add power domain to U3PHY1 T-PHY
arm64: dts: mediatek: mt8183: Fix systimer 13 MHz clock description
arm64: dts: mediatek: mt8192: Fix systimer 13 MHz clock description
arm64: dts: mediatek: mt8195: Fix systimer 13 MHz clock description
arm64: dts: mediatek: mt8186: Fix systimer 13 MHz clock description
arm64: dts: qcom: sdm845-db845c: fix audio codec interrupt pin name
x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC
arm64: dts: qcom: sc7180: correct SPMI bus address cells
arm64: dts: qcom: sc7280: correct SPMI bus address cells
arm64: dts: qcom: sc8280xp: correct SPMI bus address cells
arm64: dts: qcom: sc8280xp: Vote for CX in USB controllers
arm64: dts: meson-gxl: jethub-j80: Fix WiFi MAC address node
arm64: dts: meson-gxl: jethub-j80: Fix Bluetooth MAC node name
arm64: dts: meson-axg: jethub-j1xx: Fix MAC address node names
arm64: dts: meson-gx: Fix Ethernet MAC address unit name
arm64: dts: meson-g12a: Fix internal Ethernet PHY unit name
arm64: dts: meson-gx: Fix the SCPI DVFS node name and unit address
cpuidle, intel_idle: Fix CPUIDLE_FLAG_IRQ_ENABLE *again*
arm64: dts: ti: k3-am62: Enable SPI nodes at the board level
arm64: dts: ti: k3-am62-main: Fix clocks for McSPI
arm64: tegra: Fix duplicate regulator on Jetson TX1
arm64: dts: msm8992-bullhead: add memory hole region
arm64: dts: qcom: msm8992-bullhead: Fix cont_splash_mem size
arm64: dts: qcom: msm8992-bullhead: Disable dfps_data_mem
arm64: dts: qcom: ipq8074: correct USB3 QMP PHY-s clock output names
arm64: dts: qcom: ipq8074: fix Gen2 PCIe QMP PHY
arm64: dts: qcom: ipq8074: fix Gen3 PCIe QMP PHY
arm64: dts: qcom: ipq8074: correct Gen2 PCIe ranges
arm64: dts: qcom: ipq8074: fix Gen3 PCIe node
arm64: dts: qcom: ipq8074: correct PCIe QMP PHY output clock names
arm64: dts: meson: remove CPU opps below 1GHz for G12A boards
ARM: OMAP1: call platform_device_put() in error case in omap1_dm_timer_init()
arm64: dts: mediatek: mt8192: Mark scp_adsp clock as broken
ARM: bcm2835_defconfig: Enable the framebuffer
ARM: s3c: fix s3c64xx_set_timer_source prototype
arm64: dts: ti: k3-j7200: Fix wakeup pinmux range
ARM: dts: exynos: correct wr-active property in Exynos3250 Rinato
ARM: imx: Call ida_simple_remove() for ida_simple_get
arm64: dts: amlogic: meson-gx: fix SCPI clock dvfs node name
arm64: dts: amlogic: meson-axg: fix SCPI clock dvfs node name
arm64: dts: amlogic: meson-gx: add missing SCPI sensors compatible
arm64: dts: amlogic: meson-axg-jethome-jethub-j1xx: fix supply name of USB controller node
arm64: dts: amlogic: meson-gxl-s905d-sml5442tw: drop invalid clock-names property
arm64: dts: amlogic: meson-gx: add missing unit address to rng node name
arm64: dts: amlogic: meson-gxl-s905w-jethome-jethub-j80: fix invalid rtc node name
arm64: dts: amlogic: meson-axg-jethome-jethub-j1xx: fix invalid rtc node name
arm64: dts: amlogic: meson-gxl: add missing unit address to eth-phy-mux node name
arm64: dts: amlogic: meson-gx-libretech-pc: fix update button name
arm64: dts: amlogic: meson-sm1-bananapi-m5: fix adc keys node names
arm64: dts: amlogic: meson-gxl-s905d-phicomm-n1: fix led node name
arm64: dts: amlogic: meson-gxbb-kii-pro: fix led node name
arm64: dts: amlogic: meson-sm1-odroid-hc4: fix active fan thermal trip
locking/rwsem: Disable preemption in all down_read*() and up_read() code paths
arm64: dts: renesas: beacon-renesom: Fix gpio expander reference
arm64: dts: meson: radxa-zero: allow usb otg mode
arm64: dts: meson: bananapi-m5: switch VDDIO_C pin to OPEN_DRAIN
ARM: dts: sun8i: nanopi-duo2: Fix regulator GPIO reference
ublk_drv: remove nr_aborted_queues from ublk_device
ublk_drv: don't probe partitions if the ubq daemon isn't trusted
ARM: dts: imx7s: correct iomuxc gpr mux controller cells
sbitmap: remove redundant check in __sbitmap_queue_get_batch
sbitmap: Use single per-bitmap counting to wake up queued tags
sbitmap: correct wake_batch recalculation to avoid potential IO hung
arm64: dts: mt8195: Fix CPU map for single-cluster SoC
arm64: dts: mt8192: Fix CPU map for single-cluster SoC
arm64: dts: mt8186: Fix CPU map for single-cluster SoC
arm64: dts: mediatek: mt7622: Add missing pwm-cells to pwm node
arm64: dts: mediatek: mt8186: Fix watchdog compatible
arm64: dts: mediatek: mt8195: Fix watchdog compatible
arm64: dts: mediatek: mt7986: Fix watchdog compatible
ARM: dts: stm32: Update part number NVMEM description on stm32mp131
blk-mq: avoid sleep in blk_mq_alloc_request_hctx
blk-mq: remove stale comment for blk_mq_sched_mark_restart_hctx
blk-mq: wait on correct sbitmap_queue in blk_mq_mark_tag_wait
blk-mq: Fix potential io hung for shared sbitmap per tagset
blk-mq: correct stale comment of .get_budget
arm64: dts: qcom: msm8996: support using GPLL0 as kryocc input
arm64: dts: qcom: msm8996 switch from RPM_SMD_BB_CLK1 to RPM_SMD_XO_CLK_SRC
arm64: dts: qcom: sm8350: drop incorrect cells from serial
arm64: dts: qcom: sm8450: drop incorrect cells from serial
arm64: dts: qcom: msm8992-lg-bullhead: Correct memory overlaps with the SMEM and MPSS memory regions
arm64: dts: qcom: msm8953: correct TLMM gpio-ranges
arm64: dts: qcom: msm8992-*: Fix up comments
arm64: dts: qcom: msm8992-lg-bullhead: Enable regulators
s390/dasd: Fix potential memleak in dasd_eckd_init()
sched/rt: pick_next_rt_entity(): check list_entry
perf/x86/intel/ds: Fix the conversion from TSC to perf time
x86/perf/zhaoxin: Add stepping check for ZXC
KEYS: asymmetric: Fix ECDSA use via keyctl uapi
block: ublk: check IO buffer based on flag need_get_data
arm64: dts: qcom: pmk8350: Specify PBS register for PON
arm64: dts: qcom: pmk8350: Use the correct PON compatible
erofs: relinquish volume with mutex held
block: sync mixed merged request's failfast with 1st bio's
block: Fix io statistics for cgroup in throttle path
block: bio-integrity: Copy flags when bio_integrity_payload is cloned
block: use proper return value from bio_failfast()
wifi: mt76: mt7915: add missing of_node_put()
wifi: mt76: mt7921s: fix slab-out-of-bounds access in sdio host
wifi: mt76: mt7915: check return value before accessing free_block_num
wifi: mt76: mt7915: drop always true condition of __mt7915_reg_addr()
wifi: mt76: mt7915: fix unintended sign extension of mt7915_hw_queue_read()
wifi: mt76: fix coverity uninit_use_in_call in mt76_connac2_reverse_frag0_hdr_trans()
wifi: rsi: Fix memory leak in rsi_coex_attach()
wifi: rtlwifi: rtl8821ae: don't call kfree_skb() under spin_lock_irqsave()
wifi: rtlwifi: rtl8188ee: don't call kfree_skb() under spin_lock_irqsave()
wifi: rtlwifi: rtl8723be: don't call kfree_skb() under spin_lock_irqsave()
wifi: iwlegacy: common: don't call dev_kfree_skb() under spin_lock_irqsave()
wifi: libertas: fix memory leak in lbs_init_adapter()
wifi: rtl8xxxu: don't call dev_kfree_skb() under spin_lock_irqsave()
wifi: rtw89: 8852c: rfk: correct DACK setting
wifi: rtw89: 8852c: rfk: correct DPK settings
wifi: rtlwifi: Fix global-out-of-bounds bug in _rtl8812ae_phy_set_txpower_limit()
libbpf: Fix btf__align_of() by taking into account field offsets
wifi: ipw2x00: don't call dev_kfree_skb() under spin_lock_irqsave()
wifi: ipw2200: fix memory leak in ipw_wdev_init()
wifi: wilc1000: fix potential memory leak in wilc_mac_xmit()
wifi: wilc1000: add missing unregister_netdev() in wilc_netdev_ifc_init()
wifi: brcmfmac: fix potential memory leak in brcmf_netdev_start_xmit()
wifi: brcmfmac: unmap dma buffer in brcmf_msgbuf_alloc_pktid()
wifi: libertas_tf: don't call kfree_skb() under spin_lock_irqsave()
wifi: libertas: if_usb: don't call kfree_skb() under spin_lock_irqsave()
wifi: libertas: main: don't call kfree_skb() under spin_lock_irqsave()
wifi: libertas: cmdresp: don't call kfree_skb() under spin_lock_irqsave()
wifi: wl3501_cs: don't call kfree_skb() under spin_lock_irqsave()
libbpf: Fix invalid return address register in s390
crypto: x86/ghash - fix unaligned access in ghash_setkey()
ACPICA: Drop port I/O validation for some regions
genirq: Fix the return type of kstat_cpu_irqs_sum()
rcu-tasks: Improve comments explaining tasks_rcu_exit_srcu purpose
rcu-tasks: Remove preemption disablement around srcu_read_[un]lock() calls
rcu-tasks: Fix synchronize_rcu_tasks() VS zap_pid_ns_processes()
lib/mpi: Fix buffer overrun when SG is too long
crypto: ccp - Avoid page allocation failure warning for SEV_GET_ID2
platform/chrome: cros_ec_typec: Update port DP VDO
ACPICA: nsrepair: handle cases without a return value correctly
selftests/xsk: print correct payload for packet dump
selftests/xsk: print correct error codes when exiting
arm64/cpufeature: Fix field sign for DIT hwcap detection
kselftest/arm64: Fix syscall-abi for systems without 128 bit SME
workqueue: Protects wq_unbound_cpumask with wq_pool_attach_mutex
s390/early: fix sclp_early_sccb variable lifetime
s390/vfio-ap: fix an error handling path in vfio_ap_mdev_probe_queue()
x86/signal: Fix the value returned by strict_sas_size()
thermal/drivers/tsens: Drop msm8976-specific defines
thermal/drivers/tsens: Sort out msm8976 vs msm8956 data
thermal/drivers/tsens: fix slope values for msm8939
thermal/drivers/tsens: limit num_sensors to 9 for msm8939
wifi: rtw89: fix potential leak in rtw89_append_probe_req_ie()
wifi: rtw89: Add missing check for alloc_workqueue
wifi: rtl8xxxu: Fix memory leaks with RTL8723BU, RTL8192EU
wifi: orinoco: check return value of hermes_write_wordrec()
thermal/drivers/imx_sc_thermal: Drop empty platform remove function
thermal/drivers/imx_sc_thermal: Fix the loop condition
wifi: ath9k: htc_hst: free skb in ath9k_htc_rx_msg() if there is no callback function
wifi: ath9k: hif_usb: clean up skbs if ath9k_hif_usb_rx_stream() fails
wifi: ath9k: Fix potential stack-out-of-bounds write in ath9k_wmi_rsp_callback()
wifi: ath11k: Fix memory leak in ath11k_peer_rx_frag_setup
wifi: cfg80211: Fix extended KCK key length check in nl80211_set_rekey_data()
ACPI: battery: Fix missing NUL-termination with large strings
selftests/bpf: Fix build errors if CONFIG_NF_CONNTRACK=m
crypto: ccp - Failure on re-initialization due to duplicate sysfs filename
crypto: essiv - Handle EBUSY correctly
crypto: seqiv - Handle EBUSY correctly
powercap: fix possible name leak in powercap_register_zone()
x86/microcode: Add a parameter to microcode_check() to store CPU capabilities
x86/microcode: Check CPU capabilities after late microcode update correctly
x86/microcode: Adjust late loading result reporting message
selftests/bpf: Use consistent build-id type for liburandom_read.so
selftests/bpf: Fix vmtest static compilation error
crypto: xts - Handle EBUSY correctly
leds: led-class: Add missing put_device() to led_put()
s390/bpf: Add expoline to tail calls
wifi: iwlwifi: mei: fix compilation errors in rfkill()
kselftest/arm64: Fix enumeration of systems without 128 bit SME
can: rcar_canfd: Fix R-Car V3U GAFLCFG field accesses
selftests/bpf: Initialize tc in xdp_synproxy
crypto: ccp - Flush the SEV-ES TMR memory before giving it to firmware
bpftool: profile online CPUs instead of possible
wifi: mt76: mt7915: call mt7915_mcu_set_thermal_throttling() only after init_work
wifi: mt76: mt7915: fix memory leak in mt7915_mcu_exit
wifi: mt76: mt7915: fix WED TxS reporting
wifi: mt76: add memory barrier to SDIO queue kick
wifi: mt76: mt7921: fix error code of return in mt7921_acpi_read
net/mlx5: Enhance debug print in page allocation failure
irqchip: Fix refcount leak in platform_irqchip_probe
irqchip/alpine-msi: Fix refcount leak in alpine_msix_init_domains
irqchip/irq-mvebu-gicp: Fix refcount leak in mvebu_gicp_probe
irqchip/ti-sci: Fix refcount leak in ti_sci_intr_irq_domain_probe
s390/mem_detect: fix detect_memory() error handling
s390/vmem: fix empty page tables cleanup under KASAN
s390/boot: cleanup decompressor header files
s390/mem_detect: rely on diag260() if sclp_early_get_memsize() fails
s390/boot: fix mem_detect extended area allocation
net: add sock_init_data_uid()
tun: tun_chr_open(): correctly initialize socket uid
tap: tap_open(): correctly initialize socket uid
OPP: fix error checking in opp_migrate_dentry()
cpufreq: davinci: Fix clk use after free
Bluetooth: hci_conn: Refactor hci_bind_bis() since it always succeeds
Bluetooth: L2CAP: Fix potential user-after-free
Bluetooth: hci_qca: get wakeup status from serdev device handle
net: ipa: generic command param fix
s390: vfio-ap: tighten the NIB validity check
s390/ap: fix status returned by ap_aqic()
s390/ap: fix status returned by ap_qact()
libbpf: Fix alen calculation in libbpf_nla_dump_errormsg()
xen/grant-dma-iommu: Implement a dummy probe_device() callback
rds: rds_rm_zerocopy_callback() correct order for list_add_tail()
crypto: rsa-pkcs1pad - Use akcipher_request_complete
m68k: /proc/hardware should depend on PROC_FS
RISC-V: time: initialize hrtimer based broadcast clock event device
clocksource/drivers/riscv: Patch riscv_clock_next_event() jump before first use
wifi: iwl3945: Add missing check for create_singlethread_workqueue
wifi: iwl4965: Add missing check for create_singlethread_workqueue()
wifi: mwifiex: fix loop iterator in mwifiex_update_ampdu_txwinsize()
selftests/bpf: Fix out-of-srctree build
ACPI: resource: Add IRQ overrides for MAINGEAR Vector Pro 2 models
ACPI: resource: Do IRQ override on all TongFang GMxRGxx
crypto: octeontx2 - Fix objects shared between several modules
crypto: crypto4xx - Call dma_unmap_page when done
wifi: mac80211: move color collision detection report in a delayed work
wifi: mac80211: make rate u32 in sta_set_rate_info_rx()
wifi: mac80211: fix non-MLO station association
wifi: mac80211: Don't translate MLD addresses for multicast
wifi: mac80211: avoid u32_encode_bits() warning
wifi: mac80211: fix off-by-one link setting
tools/lib/thermal: Fix thermal_sampling_exit()
thermal/drivers/hisi: Drop second sensor hi3660
selftests/bpf: Fix map_kptr test.
wifi: mac80211: pass 'sta' to ieee80211_rx_data_set_sta()
bpf: Zeroing allocated object from slab in bpf memory allocator
selftests/bpf: Fix xdp_do_redirect on s390x
can: esd_usb: Move mislocated storage of SJA1000_ECC_SEG bits in case of a bus error
can: esd_usb: Make use of can_change_state() and relocate checking skb for NULL
xsk: check IFF_UP earlier in Tx path
LoongArch, bpf: Use 4 instructions for function address in JIT
bpf: Fix global subprog context argument resolution logic
irqchip/irq-brcmstb-l2: Set IRQ_LEVEL for level triggered interrupts
irqchip/irq-bcm7120-l2: Set IRQ_LEVEL for level triggered interrupts
net/smc: fix potential panic dues to unprotected smc_llc_srv_add_link()
net/smc: fix application data exception
selftests/net: Interpret UDP_GRO cmsg data as an int value
l2tp: Avoid possible recursive deadlock in l2tp_tunnel_register()
net: bcmgenet: fix MoCA LED control
net: lan966x: Fix possible deadlock inside PTP
net/mlx4_en: Introduce flexible array to silence overflow warning
selftest: fib_tests: Always cleanup before exit
sefltests: netdevsim: wait for devlink instance after netns removal
drm: Fix potential null-ptr-deref due to drmm_mode_config_init()
drm/fourcc: Add missing big-endian XRGB1555 and RGB565 formats
drm/bridge: ti-sn65dsi83: Fix delay after reset deassert to match spec
drm: mxsfb: DRM_IMX_LCDIF should depend on ARCH_MXC
drm: mxsfb: DRM_MXSFB should depend on ARCH_MXS || ARCH_MXC
drm/bridge: megachips: Fix error handling in i2c_register_driver()
drm/vkms: Fix memory leak in vkms_init()
drm/vkms: Fix null-ptr-deref in vkms_release()
drm/vc4: dpi: Fix format mapping for RGB565
drm: tidss: Fix pixel format definition
gpu: ipu-v3: common: Add of_node_put() for reference returned by of_graph_get_port_by_id()
drm/vc4: drop all currently held locks if deadlock happens
hwmon: (ftsteutates) Fix scaling of measurements
drm/msm/dpu: check for null return of devm_kzalloc() in dpu_writeback_init()
drm/msm/hdmi: Add missing check for alloc_ordered_workqueue
pinctrl: qcom: pinctrl-msm8976: Correct function names for wcss pins
pinctrl: stm32: Fix refcount leak in stm32_pctrl_get_irq_domain
pinctrl: rockchip: Fix refcount leak in rockchip_pinctrl_parse_groups
drm/vc4: hvs: Set AXI panic modes
drm/vc4: hvs: SCALER_DISPBKGND_AUTOHS is only valid on HVS4
drm/vc4: hvs: Correct interrupt masking bit assignment for HVS5
drm/vc4: hvs: Fix colour order for xRGB1555 on HVS5
drm/vc4: hdmi: Correct interlaced timings again
drm/msm: clean event_thread->worker in case of an error
drm/panel-edp: fix name for IVO product id 854b
scsi: qla2xxx: Fix exchange oversubscription
scsi: qla2xxx: Fix exchange oversubscription for management commands
scsi: qla2xxx: edif: Fix clang warning
ASoC: fsl_sai: initialize is_dsp_mode flag
drm/bridge: tc358767: Set default CLRSIPO count
drm/msm/adreno: Fix null ptr access in adreno_gpu_cleanup()
ALSA: hda/ca0132: minor fix for allocation size
drm/amdgpu: Use the sched from entity for amdgpu_cs trace
drm/msm/gem: Add check for kmalloc
drm/msm/dpu: Disallow unallocated resources to be returned
drm/bridge: lt9611: fix sleep mode setup
drm/bridge: lt9611: fix HPD reenablement
drm/bridge: lt9611: fix polarity programming
drm/bridge: lt9611: fix programming of video modes
drm/bridge: lt9611: fix clock calculation
drm/bridge: lt9611: pass a pointer to the of node
regulator: tps65219: use IS_ERR() to detect an error pointer
drm/mipi-dsi: Fix byte order of 16-bit DCS set/get brightness
drm: exynos: dsi: Fix MIPI_DSI*_NO_* mode flags
drm/msm/dsi: Allow 2 CTRLs on v2.5.0
scsi: ufs: exynos: Fix DMA alignment for PAGE_SIZE != 4096
drm/msm/dpu: sc7180: add missing WB2 clock control
drm/msm: use strscpy instead of strncpy
drm/msm/dpu: Add check for cstate
drm/msm/dpu: Add check for pstates
drm/msm/mdp5: Add check for kzalloc
habanalabs: bugs fixes in timestamps buff alloc
pinctrl: bcm2835: Remove of_node_put() in bcm2835_of_gpio_ranges_fallback()
pinctrl: mediatek: Initialize variable pullen and pullup to zero
pinctrl: mediatek: Initialize variable *buf to zero
gpu: host1x: Fix mask for syncpoint increment register
gpu: host1x: Don't skip assigning syncpoints to channels
drm/tegra: firewall: Check for is_addr_reg existence in IMM check
pinctrl: renesas: rzg2l: Fix configuring the GPIO pins as interrupts
drm/msm/dpu: set pdpu->is_rt_pipe early in dpu_plane_sspp_atomic_update()
drm/mediatek: dsi: Reduce the time of dsi from LP11 to sending cmd
drm/mediatek: Use NULL instead of 0 for NULL pointer
drm/mediatek: Drop unbalanced obj unref
drm/mediatek: mtk_drm_crtc: Add checks for devm_kcalloc
drm/mediatek: Clean dangling pointer on bind error path
ASoC: soc-compress.c: fixup private_data on snd_soc_new_compress()
dt-bindings: display: mediatek: Fix the fallback for mediatek,mt8186-disp-ccorr
gpio: vf610: connect GPIO label to dev name
ASoC: topology: Properly access value coming from topology file
spi: dw_bt1: fix MUX_MMIO dependencies
ASoC: mchp-spdifrx: fix controls which rely on rsr register
ASoC: mchp-spdifrx: fix return value in case completion times out
ASoC: mchp-spdifrx: fix controls that works with completion mechanism
ASoC: mchp-spdifrx: disable all interrupts in mchp_spdifrx_dai_remove()
dm: improve shrinker debug names
regmap: apply reg_base and reg_downshift for single register ops
ASoC: rsnd: fixup #endif position
ASoC: mchp-spdifrx: Fix uninitialized use of mr in mchp_spdifrx_hw_params()
ASoC: dt-bindings: meson: fix gx-card codec node regex
regulator: tps65219: use generic set_bypass()
hwmon: (asus-ec-sensors) add missing mutex path
hwmon: (ltc2945) Handle error case in ltc2945_value_store
ALSA: hda: Fix the control element identification for multiple codecs
drm/amdgpu: fix enum odm_combine_mode mismatch
scsi: mpt3sas: Fix a memory leak
scsi: aic94xx: Add missing check for dma_map_single()
HID: multitouch: Add quirks for flipped axes
HID: retain initial quirks set up when creating HID devices
ASoC: qcom: q6apm-lpass-dai: unprepare stream if its already prepared
ASoC: qcom: q6apm-dai: fix race condition while updating the position pointer
ASoC: qcom: q6apm-dai: Add SNDRV_PCM_INFO_BATCH flag
ASoC: codecs: lpass: register mclk after runtime pm
ASoC: codecs: lpass: fix incorrect mclk rate
drm/amd/display: don't call dc_interrupt_set() for disabled crtcs
HID: logitech-hidpp: Hard-code HID++ 1.0 fast scroll support
spi: bcm63xx-hsspi: Fix multi-bit mode setting
hwmon: (mlxreg-fan) Return zero speed for broken fan
ASoC: tlv320adcx140: fix 'ti,gpio-config' DT property init
dm: remove flush_scheduled_work() during local_exit()
nfs4trace: fix state manager flag printing
NFS: fix disabling of swap
spi: synquacer: Fix timeout handling in synquacer_spi_transfer_one()
ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared
HID: bigben: use spinlock to protect concurrent accesses
HID: bigben_worker() remove unneeded check on report_field
HID: bigben: use spinlock to safely schedule workers
hid: bigben_probe(): validate report count
ALSA: hda/hdmi: Register with vga_switcheroo on Dual GPU Macbooks
drm/shmem-helper: Fix locking for drm_gem_shmem_get_pages_sgt()
NFSD: enhance inter-server copy cleanup
NFSD: fix leaked reference count of nfsd4_ssc_umount_item
nfsd: fix race to check ls_layouts
nfsd: clean up potential nfsd_file refcount leaks in COPY codepath
NFSD: fix problems with cleanup on errors in nfsd4_copy
nfsd: fix courtesy client with deny mode handling in nfs4_upgrade_open
nfsd: don't fsync nfsd_files on last close
NFSD: copy the whole verifier in nfsd_copy_write_verifier
cifs: Fix lost destroy smbd connection when MR allocate failed
cifs: Fix warning and UAF when destroy the MR list
cifs: use tcon allocation functions even for dummy tcon
gfs2: jdata writepage fix
perf llvm: Fix inadvertent file creation
leds: led-core: Fix refcount leak in of_led_get()
leds: is31fl319x: Wrap mutex_destroy() for devm_add_action_or_rest()
leds: simatic-ipc-leds-gpio: Make sure we have the GPIO providing driver
tools/tracing/rtla: osnoise_hist: use total duration for average calculation
perf inject: Use perf_data__read() for auxtrace
perf intel-pt: Do not try to queue auxtrace data on pipe
perf test bpf: Skip test if kernel-debuginfo is not present
perf tools: Fix auto-complete on aarch64
sparc: allow PM configs for sparc32 COMPILE_TEST
selftests: find echo binary to use -ne options
selftests/ftrace: Fix bash specific "==" operator
selftests: use printf instead of echo -ne
perf record: Fix segfault with --overwrite and --max-size
printf: fix errname.c list
perf tests stat_all_metrics: Change true workload to sleep workload for system wide check
objtool: add UACCESS exceptions for __tsan_volatile_read/write
mfd: cs5535: Don't build on UML
mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read()
dmaengine: idxd: Set traffic class values in GRPCFG on DSA 2.0
RDMA/erdma: Fix refcount leak in erdma_mmap
dmaengine: HISI_DMA should depend on ARCH_HISI
RDMA/hns: Fix refcount leak in hns_roce_mmap
iio: light: tsl2563: Do not hardcode interrupt trigger type
usb: gadget: fusb300_udc: free irq on the error path in fusb300_probe()
i2c: designware: fix i2c_dw_clk_rate() return size to be u32
soundwire: cadence: Don't overflow the command FIFOs
driver core: fix potential null-ptr-deref in device_add()
kobject: modify kobject_get_path() to take a const *
kobject: Fix slab-out-of-bounds in fill_kobj_path()
alpha/boot/tools/objstrip: fix the check for ELF header
media: uvcvideo: Check for INACTIVE in uvc_ctrl_is_accessible()
media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU
media: uvcvideo: Refactor uvc_ctrl_mappings_uvcXX
media: uvcvideo: Refactor power_line_frequency_controls_limited
coresight: etm4x: Fix accesses to TRCSEQRSTEVR and TRCSEQSTR
coresight: cti: Prevent negative values of enable count
coresight: cti: Add PM runtime call in enable_store
usb: typec: intel_pmc_mux: Don't leak the ACPI device reference count
PCI/IOV: Enlarge virtfn sysfs name buffer
PCI: switchtec: Return -EFAULT for copy_to_user() errors
PCI: endpoint: pci-epf-vntb: Clean up kernel_doc warning
PCI: endpoint: pci-epf-vntb: Add epf_ntb_mw_bar_clear() num_mws kernel-doc
hwtracing: hisi_ptt: Only add the supported devices to the filters list
tty: serial: fsl_lpuart: disable Rx/Tx DMA in lpuart32_shutdown()
tty: serial: fsl_lpuart: clear LPUART Status Register in lpuart32_shutdown()
serial: tegra: Add missing clk_disable_unprepare() in tegra_uart_hw_init()
Revert "char: pcmcia: cm4000_cs: Replace mdelay with usleep_range in set_protocol"
eeprom: idt_89hpesx: Fix error handling in idt_init()
applicom: Fix PCI device refcount leak in applicom_init()
firmware: stratix10-svc: add missing gen_pool_destroy() in stratix10_svc_drv_probe()
firmware: stratix10-svc: fix error handle while alloc/add device failed
VMCI: check context->notify_page after call to get_user_pages_fast() to avoid GPF
mei: pxp: Use correct macros to initialize uuid_le
misc/mei/hdcp: Use correct macros to initialize uuid_le
misc: fastrpc: Fix an error handling path in fastrpc_rpmsg_probe()
driver core: fix resource leak in device_add()
driver core: location: Free struct acpi_pld_info *pld before return false
drivers: base: transport_class: fix possible memory leak
drivers: base: transport_class: fix resource leak when transport_add_device() fails
firmware: dmi-sysfs: Fix null-ptr-deref in dmi_sysfs_register_handle
fotg210-udc: Add missing completion handler
dmaengine: dw-edma: Fix missing src/dst address of interleaved xfers
fpga: microchip-spi: move SPI I/O buffers out of stack
fpga: microchip-spi: rewrite status polling in a time measurable way
usb: early: xhci-dbc: Fix a potential out-of-bound memory access
tty: serial: fsl_lpuart: Fix the wrong RXWATER setting for rx dma case
RDMA/cxgb4: add null-ptr-check after ip_dev_find()
usb: musb: mediatek: don't unregister something that wasn't registered
usb: gadget: configfs: Restrict symlink creation is UDC already binded
phy: mediatek: remove temporary variable @mask_
PCI: mt7621: Delay phy ports initialization
iommu: dart: Add suspend/resume support
iommu: dart: Support >64 stream IDs
iommu/dart: Fix apple_dart_device_group for PCI groups
iommu/vt-d: Set No Execute Enable bit in PASID table entry
power: supply: remove faulty cooling logic
RDMA/cxgb4: Fix potential null-ptr-deref in pass_establish()
usb: max-3421: Fix setting of I/O pins
RDMA/irdma: Cap MSIX used to online CPUs + 1
serial: fsl_lpuart: fix RS485 RTS polariy inverse issue
tty: serial: imx: Handle RS485 DE signal active high
tty: serial: imx: disable Ageing Timer interrupt request irq
driver core: fw_devlink: Add DL_FLAG_CYCLE support to device links
driver core: fw_devlink: Don't purge child fwnode's consumer links
driver core: fw_devlink: Allow marking a fwnode link as being part of a cycle
driver core: fw_devlink: Consolidate device link flag computation
driver core: fw_devlink: Improve check for fwnode with no device/driver
driver core: fw_devlink: Make cycle detection more robust
mtd: mtdpart: Don't create platform device that'll never probe
usb: host: fsl-mph-dr-of: reuse device_set_of_node_from_dev
dmaengine: dw-edma: Fix readq_ch() return value truncation
PCI: Fix dropping valid root bus resources with .end = zero
phy: rockchip-typec: fix tcphy_get_mode error case
PCI: qcom: Fix host-init error handling
iw_cxgb4: Fix potential NULL dereference in c4iw_fill_res_cm_id_entry()
iommu: Fix error unwind in iommu_group_alloc()
iommu/amd: Do not identity map v2 capable device when snp is enabled
dmaengine: sf-pdma: pdma_desc memory leak fix
dmaengine: dw-axi-dmac: Do not dereference NULL structure
dmaengine: ptdma: check for null desc before calling pt_cmd_callback
iommu/vt-d: Fix error handling in sva enable/disable paths
iommu/vt-d: Allow to use flush-queue when first level is default
RDMA/rxe: cleanup some error handling in rxe_verbs.c
RDMA/rxe: Fix missing memory barriers in rxe_queue.h
IB/hfi1: Fix math bugs in hfi1_can_pin_pages()
IB/hfi1: Fix sdma.h tx->num_descs off-by-one errors
Revert "remoteproc: qcom_q6v5_mss: map/unmap metadata region before/after use"
remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
media: ti: cal: fix possible memory leak in cal_ctx_create()
media: platform: ti: Add missing check for devm_regulator_get
media: imx: imx7-media-csi: fix missing clk_disable_unprepare() in imx7_csi_init()
powerpc: Remove linker flag from KBUILD_AFLAGS
s390/vdso: Drop '-shared' from KBUILD_CFLAGS_64
builddeb: clean generated package content
media: max9286: Fix memleak in max9286_v4l2_register()
media: ov2740: Fix memleak in ov2740_init_controls()
media: ov5675: Fix memleak in ov5675_init_controls()
media: ov5640: Fix soft reset sequence and timings
media: ov5640: Handle delays when no reset_gpio set
media: mc: Get media_device directly from pad
media: i2c: ov772x: Fix memleak in ov772x_probe()
media: i2c: imx219: Split common registers from mode tables
media: i2c: imx219: Fix binning for RAW8 capture
media: platform: mtk-mdp3: Fix return value check in mdp_probe()
media: camss: csiphy-3ph: avoid undefined behavior
media: platform: mtk-mdp3: remove unused VIDEO_MEDIATEK_VPU config
media: platform: mtk-mdp3: fix Kconfig dependencies
media: v4l2-jpeg: correct the skip count in jpeg_parse_app14_data
media: v4l2-jpeg: ignore the unknown APP14 marker
media: hantro: Fix JPEG encoder ENUM_FRMSIZE on RK3399
media: imx-jpeg: Apply clk_bulk api instead of operating specific clk
media: amphion: correct the unspecified color space
media: drivers/media/v4l2-core/v4l2-h264 : add detection of null pointers
media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
media: atomisp: Only set default_run_mode on first open of a stream/asd
media: i2c: ov7670: 0 instead of -EINVAL was returned
media: usb: siano: Fix use after free bugs caused by do_submit_urb
media: saa7134: Use video_unregister_device for radio_dev
rpmsg: glink: Avoid infinite loop on intent for missing channel
rpmsg: glink: Release driver_override
ARM: OMAP2+: omap4-common: Fix refcount leak bug
arm64: dts: qcom: msm8996: Add additional A2NoC clocks
udf: Define EFSCORRUPTED error code
context_tracking: Fix noinstr vs KASAN
exit: Detect and fix irq disabled state in oops
ARM: dts: exynos: Use Exynos5420 compatible for the MIPI video phy
fs: Use CHECK_DATA_CORRUPTION() when kernel bugs are detected
blk-iocost: fix divide by 0 error in calc_lcoefs()
blk-cgroup: dropping parent refcount after pd_free_fn() is done
blk-cgroup: synchronize pd_free_fn() from blkg_free_workfn() and blkcg_deactivate_policy()
trace/blktrace: fix memory leak with using debugfs_lookup()
btrfs: scrub: improve tree block error reporting
arm64: zynqmp: Enable hs termination flag for USB dwc3 controller
cpuidle, intel_idle: Fix CPUIDLE_FLAG_INIT_XSTATE
x86/fpu: Don't set TIF_NEED_FPU_LOAD for PF_IO_WORKER threads
cpuidle: drivers: firmware: psci: Dont instrument suspend code
cpuidle: lib/bug: Disable rcu_is_watching() during WARN/BUG
perf/x86/intel/uncore: Add Meteor Lake support
wifi: ath9k: Fix use-after-free in ath9k_hif_usb_disconnect()
wifi: ath11k: fix monitor mode bringup crash
wifi: brcmfmac: Fix potential stack-out-of-bounds in brcmf_c_preinit_dcmds()
rcu: Make RCU_LOCKDEP_WARN() avoid early lockdep checks
rcu: Suppress smp_processor_id() complaint in synchronize_rcu_expedited_wait()
srcu: Delegate work to the boot cpu if using SRCU_SIZE_SMALL
rcu-tasks: Make rude RCU-Tasks work well with CPU hotplug
rcu-tasks: Handle queue-shrink/callback-enqueue race condition
wifi: ath11k: debugfs: fix to work with multiple PCI devices
thermal: intel: Fix unsigned comparison with less than zero
timers: Prevent union confusion from unexpected restart_syscall()
x86/bugs: Reset speculation control settings on init
bpftool: Always disable stack protection for BPF objects
wifi: brcmfmac: ensure CLM version is null-terminated to prevent stack-out-of-bounds
wifi: mt7601u: fix an integer underflow
inet: fix fast path in __inet_hash_connect()
ice: restrict PTP HW clock freq adjustments to 100, 000, 000 PPB
ice: add missing checks for PF vsi type
ACPI: Don't build ACPICA with '-Os'
bpf, docs: Fix modulo zero, division by zero, overflow, and underflow
thermal: intel: intel_pch: Add support for Wellsburg PCH
clocksource: Suspend the watchdog temporarily when high read latency detected
crypto: hisilicon: Wipe entire pool on error
net: bcmgenet: Add a check for oversized packets
m68k: Check syscall_trace_enter() return code
s390/mm,ptdump: avoid Kasan vs Memcpy Real markers swapping
netfilter: nf_tables: NULL pointer dereference in nf_tables_updobj()
can: isotp: check CAN address family in isotp_bind()
gcc-plugins: drop -std=gnu++11 to fix GCC 13 build
tools/power/x86/intel-speed-select: Add Emerald Rapid quirk
wifi: mt76: dma: free rx_head in mt76_dma_rx_cleanup
ACPI: video: Fix Lenovo Ideapad Z570 DMI match
net/mlx5: fw_tracer: Fix debug print
coda: Avoid partial allocation of sig_inputArgs
uaccess: Add minimum bounds check on kernel buffer size
s390/idle: mark arch_cpu_idle() noinstr
time/debug: Fix memory leak with using debugfs_lookup()
PM: domains: fix memory leak with using debugfs_lookup()
PM: EM: fix memory leak with using debugfs_lookup()
Bluetooth: Fix issue with Actions Semi ATS2851 based devices
Bluetooth: btusb: Add new PID/VID 0489:e0f2 for MT7921
Bluetooth: btusb: Add VID:PID 13d3:3529 for Realtek RTL8821CE
wifi: rtw89: debug: avoid invalid access on RTW89_DBG_SEL_MAC_30
hv_netvsc: Check status in SEND_RNDIS_PKT completion message
s390/kfence: fix page fault reporting
devlink: Fix TP_STRUCT_entry in trace of devlink health report
scm: add user copy checks to put_cmsg()
drm: panel-orientation-quirks: Add quirk for Lenovo Yoga Tab 3 X90F
drm: panel-orientation-quirks: Add quirk for DynaBook K50
drm/amd/display: Reduce expected sdp bandwidth for dcn321
drm/amd/display: Revert Reduce delay when sink device not able to ACK 00340h write
drm/amd/display: Fix potential null-deref in dm_resume
drm/omap: dsi: Fix excessive stack usage
HID: Add Mapping for System Microphone Mute
drm/tiny: ili9486: Do not assume 8-bit only SPI controllers
drm/amd/display: Defer DIG FIFO disable after VID stream enable
drm/radeon: free iio for atombios when driver shutdown
drm/amd: Avoid BUG() for case of SRIOV missing IP version
drm/amdkfd: Page aligned memory reserve size
scsi: lpfc: Fix use-after-free KFENCE violation during sysfs firmware write
Revert "fbcon: don't lose the console font across generic->chip driver switch"
drm/amd: Avoid ASSERT for some message failures
drm: amd: display: Fix memory leakage
drm/amd/display: fix mapping to non-allocated address
HID: uclogic: Add frame type quirk
HID: uclogic: Add battery quirk
HID: uclogic: Add support for XP-PEN Deco Pro SW
HID: uclogic: Add support for XP-PEN Deco Pro MW
drm/msm/dsi: Add missing check for alloc_ordered_workqueue
drm: rcar-du: Add quirk for H3 ES1.x pclk workaround
drm: rcar-du: Fix setting a reserved bit in DPLLCR
drm/drm_print: correct format problem
drm/amd/display: Set hvm_enabled flag for S/G mode
habanalabs: extend fatal messages to contain PCI info
habanalabs: fix bug in timestamps registration code
docs/scripts/gdb: add necessary make scripts_gdb step
drm/msm/dpu: Add DSC hardware blocks to register snapshot
ASoC: soc-compress: Reposition and add pcm_mutex
ASoC: kirkwood: Iterate over array indexes instead of using pointer math
regulator: max77802: Bounds check regulator id against opmode
regulator: s5m8767: Bounds check id indexing into arrays
Revert "drm/amdgpu: TA unload messages are not actually sent to psp when amdgpu is uninstalled"
drm/amd/display: fix FCLK pstate change underflow
gfs2: Improve gfs2_make_fs_rw error handling
hwmon: (coretemp) Simplify platform device handling
hwmon: (nct6775) Directly call ASUS ACPI WMI method
hwmon: (nct6775) B650/B660/X670 ASUS boards support
pinctrl: at91: use devm_kasprintf() to avoid potential leaks
drm/amd/display: Do not commit pipe when updating DRR
scsi: snic: Fix memory leak with using debugfs_lookup()
scsi: ufs: core: Fix device management cmd timeout flow
HID: logitech-hidpp: Don't restart communication if not necessary
drm/amd/display: Enable P-state validation checks for DCN314
drm: panel-orientation-quirks: Add quirk for Lenovo IdeaPad Duet 3 10IGL5
drm/amd/display: Disable HUBP/DPP PG on DCN314 for now
dm thin: add cond_resched() to various workqueue loops
dm cache: add cond_resched() to various workqueue loops
nfsd: zero out pointers after putting nfsd_files on COPY setup error
nfsd: don't hand out delegation on setuid files being opened for write
cifs: prevent data race in smb2_reconnect()
drm/shmem-helper: Revert accidental non-GPL export
driver core: fw_devlink: Avoid spurious error message
wifi: rtl8xxxu: fixing transmisison failure for rtl8192eu
scsi: mpt3sas: Remove usage of dma_get_required_mask() API
firmware: coreboot: framebuffer: Ignore reserved pixel color bits
block: don't allow multiple bios for IOCB_NOWAIT issue
block: clear bio->bi_bdev when putting a bio back in the cache
block: be a bit more careful in checking for NULL bdev while polling
rtc: pm8xxx: fix set-alarm race
ipmi: ipmb: Fix the MODULE_PARM_DESC associated to 'retry_time_ms'
ipmi:ssif: resend_msg() cannot fail
ipmi_ssif: Rename idle state and check
io_uring: Replace 0-length array with flexible array
io_uring: use user visible tail in io_uring_poll()
io_uring: handle TIF_NOTIFY_RESUME when checking for task_work
io_uring: add a conditional reschedule to the IOPOLL cancelation loop
io_uring: add reschedule point to handle_tw_list()
io_uring/rsrc: disallow multi-source reg buffers
io_uring: remove MSG_NOSIGNAL from recvmsg
io_uring: fix fget leak when fs don't support nowait buffered read
s390/extmem: return correct segment type in __segment_load()
s390: discard .interp section
s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
s390/kprobes: fix current_kprobe never cleared after kprobes reenter
KVM: s390: disable migration mode when dirty tracking is disabled
cifs: Fix uninitialized memory read in smb3_qfs_tcon()
cifs: Fix uninitialized memory reads for oparms.mode
cifs: fix mount on old smb servers
cifs: introduce cifs_io_parms in smb2_async_writev()
cifs: split out smb3_use_rdma_offload() helper
cifs: don't try to use rdma offload on encrypted connections
cifs: Check the lease context if we actually got a lease
cifs: return a single-use cfid if we did not get a lease
scsi: mpi3mr: Fix missing mrioc->evtack_cmds initialization
scsi: mpi3mr: Fix issues in mpi3mr_get_all_tgt_info()
scsi: mpi3mr: Remove unnecessary memcpy() to alltgt_info->dmi
btrfs: hold block group refcount during async discard
locking/rwsem: Prevent non-first waiter from spinning in down_write() slowpath
ksmbd: fix wrong data area length for smb2 lock request
ksmbd: do not allow the actual frame length to be smaller than the rfc1002 length
ksmbd: fix possible memory leak in smb2_lock()
torture: Fix hang during kthread shutdown phase
ARM: dts: exynos: correct HDMI phy compatible in Exynos4
io_uring: mark task TASK_RUNNING before handling resume/task work
hfs: fix missing hfs_bnode_get() in __hfs_bnode_create
fs: hfsplus: fix UAF issue in hfsplus_put_super
exfat: fix reporting fs error when reading dir beyond EOF
exfat: fix unexpected EOF while reading dir
exfat: redefine DIR_DELETED as the bad cluster number
exfat: fix inode->i_blocks for non-512 byte sector size device
fs: dlm: don't set stop rx flag after node reset
fs: dlm: move sending fin message into state change handling
fs: dlm: send FIN ack back in right cases
f2fs: fix information leak in f2fs_move_inline_dirents()
f2fs: retry to update the inode page given data corruption
f2fs: fix cgroup writeback accounting with fs-layer encryption
f2fs: fix kernel crash due to null io->bio
ocfs2: fix defrag path triggering jbd2 ASSERT
ocfs2: fix non-auto defrag path not working issue
fs/cramfs/inode.c: initialize file_ra_state
selftests/landlock: Skip overlayfs tests when not supported
selftests/landlock: Test ptrace as much as possible with Yama
udf: Truncate added extents on failed expansion
udf: Do not bother merging very long extents
udf: Do not update file length for failed writes to inline files
udf: Preserve link count of system files
udf: Detect system inodes linked into directory hierarchy
udf: Fix file corruption when appending just after end of preallocated extent
md: don't update recovery_cp when curr_resync is ACTIVE
RDMA/siw: Fix user page pinning accounting
KVM: Destroy target device if coalesced MMIO unregistration fails
KVM: VMX: Fix crash due to uninitialized current_vmcs
KVM: Register /dev/kvm as the _very_ last thing during initialization
KVM: x86: Purge "highest ISR" cache when updating APICv state
KVM: x86: Blindly get current x2APIC reg value on "nodecode write" traps
KVM: x86: Don't inhibit APICv/AVIC on xAPIC ID "change" if APIC is disabled
KVM: x86: Don't inhibit APICv/AVIC if xAPIC ID mismatch is due to 32-bit ID
KVM: SVM: Flush the "current" TLB when activating AVIC
KVM: SVM: Process ICR on AVIC IPI delivery failure due to invalid target
KVM: SVM: Don't put/load AVIC when setting virtual APIC mode
KVM: x86: Inject #GP if WRMSR sets reserved bits in APIC Self-IPI
KVM: x86: Inject #GP on x2APIC WRMSR that sets reserved bits 63:32
KVM: SVM: Fix potential overflow in SEV's send|receive_update_data()
KVM: SVM: hyper-v: placate modpost section mismatch error
selftests: x86: Fix incorrect kernel headers search path
x86/virt: Force GIF=1 prior to disabling SVM (for reboot flows)
x86/crash: Disable virt in core NMI crash handler to avoid double shootdown
x86/reboot: Disable virtualization in an emergency if SVM is supported
x86/reboot: Disable SVM, not just VMX, when stopping CPUs
x86/kprobes: Fix __recover_optprobed_insn check optimizing logic
x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe range
x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
x86/microcode/AMD: Add a @cpu parameter to the reloading functions
x86/microcode/AMD: Fix mixed steppings support
x86/speculation: Allow enabling STIBP with legacy IBRS
Documentation/hw-vuln: Document the interaction between IBRS and STIBP
virt/sev-guest: Return -EIO if certificate buffer is not large enough
brd: mark as nowait compatible
brd: return 0/-error from brd_insert_page()
brd: check for REQ_NOWAIT and set correct page allocation mask
ima: fix error handling logic when file measurement failed
ima: Align ima_file_mmap() parameters with mmap_file LSM hook
selftests/powerpc: Fix incorrect kernel headers search path
selftests/ftrace: Fix eprobe syntax test case to check filter support
selftests: sched: Fix incorrect kernel headers search path
selftests: core: Fix incorrect kernel headers search path
selftests: pid_namespace: Fix incorrect kernel headers search path
selftests: arm64: Fix incorrect kernel headers search path
selftests: clone3: Fix incorrect kernel headers search path
selftests: pidfd: Fix incorrect kernel headers search path
selftests: membarrier: Fix incorrect kernel headers search path
selftests: kcmp: Fix incorrect kernel headers search path
selftests: media_tests: Fix incorrect kernel headers search path
selftests: gpio: Fix incorrect kernel headers search path
selftests: filesystems: Fix incorrect kernel headers search path
selftests: user_events: Fix incorrect kernel headers search path
selftests: ptp: Fix incorrect kernel headers search path
selftests: sync: Fix incorrect kernel headers search path
selftests: rseq: Fix incorrect kernel headers search path
selftests: move_mount_set_group: Fix incorrect kernel headers search path
selftests: mount_setattr: Fix incorrect kernel headers search path
selftests: perf_events: Fix incorrect kernel headers search path
selftests: ipc: Fix incorrect kernel headers search path
selftests: futex: Fix incorrect kernel headers search path
selftests: drivers: Fix incorrect kernel headers search path
selftests: dmabuf-heaps: Fix incorrect kernel headers search path
selftests: vm: Fix incorrect kernel headers search path
selftests: seccomp: Fix incorrect kernel headers search path
irqdomain: Fix association race
irqdomain: Fix disassociation race
irqdomain: Look for existing mapping only once
irqdomain: Drop bogus fwspec-mapping error handling
irqdomain: Refactor __irq_domain_alloc_irqs()
irqdomain: Fix mapping-creation race
irqdomain: Fix domain registration race
crypto: qat - fix out-of-bounds read
mm/damon/paddr: fix missing folio_put()
ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls()
ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC
jbd2: fix data missing when reusing bh which is ready to be checkpointed
ext4: optimize ea_inode block expansion
ext4: refuse to create ea block when umounted
cxl/pmem: Fix nvdimm registration races
mtd: spi-nor: sfdp: Fix index value for SCCR dwords
mtd: spi-nor: spansion: Consider reserved bits in CFR5 register
mtd: spi-nor: Fix shift-out-of-bounds in spi_nor_set_erase_type
dm: send just one event on resize, not two
dm: add cond_resched() to dm_wq_work()
dm: add cond_resched() to dm_wq_requeue_work()
wifi: rtw88: use RTW_FLAG_POWERON flag to prevent to power on/off twice
wifi: rtl8xxxu: Use a longer retry limit of 48
wifi: ath11k: allow system suspend to survive ath11k
wifi: cfg80211: Fix use after free for wext
wifi: cfg80211: Set SSID if it is not already set
cpuidle: add ARCH_SUSPEND_POSSIBLE dependencies
qede: fix interrupt coalescing configuration
thermal: intel: powerclamp: Fix cur_state for multi package system
dm flakey: fix logic when corrupting a bio
dm cache: free background tracker's queued work in btracker_destroy
dm flakey: don't corrupt the zero page
dm flakey: fix a bug with 32-bit highmem systems
hwmon: (peci/cputemp) Fix off-by-one in coretemp_label allocation
hwmon: (nct6775) Fix incorrect parenthesization in nct6775_write_fan_div()
ARM: dts: qcom: sdx65: Add Qcom SMMU-500 as the fallback for IOMMU node
ARM: dts: qcom: sdx55: Add Qcom SMMU-500 as the fallback for IOMMU node
ARM: dts: exynos: correct TMU phandle in Exynos4210
ARM: dts: exynos: correct TMU phandle in Exynos4
ARM: dts: exynos: correct TMU phandle in Odroid XU3 family
ARM: dts: exynos: correct TMU phandle in Exynos5250
ARM: dts: exynos: correct TMU phandle in Odroid XU
ARM: dts: exynos: correct TMU phandle in Odroid HC1
arm64: mm: hugetlb: Disable HUGETLB_PAGE_OPTIMIZE_VMEMMAP
fuse: add inode/permission checks to fileattr_get/fileattr_set
rbd: avoid use-after-free in do_rbd_add() when rbd_dev_create() fails
ceph: update the time stamps and try to drop the suid/sgid
regulator: core: Use ktime_get_boottime() to determine how long a regulator was off
panic: fix the panic_print NMI backtrace setting
mm/hwpoison: convert TTU_IGNORE_HWPOISON to TTU_HWPOISON
alpha: fix FEN fault handling
dax/kmem: Fix leak of memory-hotplug resources
mips: fix syscall_get_nr
media: ipu3-cio2: Fix PM runtime usage_count in driver unbind
remoteproc/mtk_scp: Move clk ops outside send_lock
docs: gdbmacros: print newest record
mm: memcontrol: deprecate charge moving
mm/thp: check and bail out if page in deferred queue already
ktest.pl: Give back console on Ctrt^C on monitor
kprobes: Fix to handle forcibly unoptimized kprobes on freeing_list
ktest.pl: Fix missing "end_monitor" when machine check fails
ktest.pl: Add RUN_TIMEOUT option with default unlimited
memory tier: release the new_memtier in find_create_memory_tier()
ring-buffer: Handle race between rb_move_tail and rb_check_pages
tools/bootconfig: fix single & used for logical condition
tracing/eprobe: Fix to add filter on eprobe description in README file
iommu/amd: Add a length limitation for the ivrs_acpihid command-line parameter
iommu/amd: Improve page fault error reporting
scsi: aacraid: Allocate cmd_priv with scsicmd
scsi: qla2xxx: Fix link failure in NPIV environment
scsi: qla2xxx: Check if port is online before sending ELS
scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests
scsi: qla2xxx: Remove unintended flag clearing
scsi: qla2xxx: Fix erroneous link down
scsi: qla2xxx: Remove increment of interface err cnt
scsi: ses: Don't attach if enclosure has no components
scsi: ses: Fix slab-out-of-bounds in ses_enclosure_data_process()
scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses
scsi: ses: Fix possible desc_ptr out-of-bounds accesses
scsi: ses: Fix slab-out-of-bounds in ses_intf_remove()
RISC-V: add a spin_shadow_stack declaration
riscv: Avoid enabling interrupts in die()
riscv: mm: fix regression due to update_mmu_cache change
riscv: jump_label: Fixup unaligned arch_static_branch function
riscv, mm: Perform BPF exhandler fixup on page fault
riscv: ftrace: Remove wasted nops for !RISCV_ISA_C
riscv: ftrace: Reduce the detour code size to half
MIPS: DTS: CI20: fix otg power gpio
PCI/PM: Observe reset delay irrespective of bridge_d3
PCI: Unify delay handling for reset and resume
PCI: hotplug: Allow marking devices as disconnected during bind/unbind
PCI: Avoid FLR for AMD FCH AHCI adapters
PCI/DPC: Await readiness of secondary bus after reset
bus: mhi: ep: Only send -ENOTCONN status if client driver is available
bus: mhi: ep: Move chan->lock to the start of processing queued ch ring
bus: mhi: ep: Save channel state locally during suspend and resume
iommu/vt-d: Avoid superfluous IOTLB tracking in lazy mode
iommu/vt-d: Fix PASID directory pointer coherency
vfio/type1: exclude mdevs from VFIO_UPDATE_VADDR
vfio/type1: prevent underflow of locked_vm via exec()
vfio/type1: track locked_vm per dma
vfio/type1: restore locked_vm
drm/amd: Fix initialization for nbio 7.5.1
drm/i915/quirks: Add inverted backlight quirk for HP 14-r206nv
drm/radeon: Fix eDP for single-display iMac11,2
drm/i915: Don't use stolen memory for ring buffers with LLC
drm/i915: Don't use BAR mappings for ring buffers with LLC
drm/gud: Fix UBSAN warning
drm/edid: fix AVI infoframe aspect ratio handling
drm/edid: fix parsing of 3D modes from HDMI VSDB
qede: avoid uninitialized entries in coal_entry array
brd: use radix_tree_maybe_preload instead of radix_tree_preload
sbitmap: Advance the queue index before waking up a queue
wait: Return number of exclusive waiters awaken
sbitmap: Try each queue to wake up at least one waiter
kbuild: Port silent mode detection to future gnu make.
net: avoid double iput when sock_alloc_file fails
Linux 6.1.16
Change-Id: I705caf70ee547e6d55f38d133bdcd50713aed745
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
1739 lines
47 KiB
C
1739 lines
47 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* kernel/rwsem.c: R/W semaphores, public implementation
|
|
*
|
|
* Written by David Howells (dhowells@redhat.com).
|
|
* Derived from asm-i386/semaphore.h
|
|
*
|
|
* Writer lock-stealing by Alex Shi <alex.shi@intel.com>
|
|
* and Michel Lespinasse <walken@google.com>
|
|
*
|
|
* Optimistic spinning by Tim Chen <tim.c.chen@intel.com>
|
|
* and Davidlohr Bueso <davidlohr@hp.com>. Based on mutexes.
|
|
*
|
|
* Rwsem count bit fields re-definition and rwsem rearchitecture by
|
|
* Waiman Long <longman@redhat.com> and
|
|
* Peter Zijlstra <peterz@infradead.org>.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/rt.h>
|
|
#include <linux/sched/task.h>
|
|
#include <linux/sched/debug.h>
|
|
#include <linux/sched/wake_q.h>
|
|
#include <linux/sched/signal.h>
|
|
#include <linux/sched/clock.h>
|
|
#include <linux/export.h>
|
|
#include <linux/rwsem.h>
|
|
#include <linux/atomic.h>
|
|
#include <trace/events/lock.h>
|
|
|
|
#ifndef CONFIG_PREEMPT_RT
|
|
#include "lock_events.h"
|
|
#include <trace/hooks/dtask.h>
|
|
#include <trace/hooks/rwsem.h>
|
|
|
|
/*
|
|
* The least significant 2 bits of the owner value has the following
|
|
* meanings when set.
|
|
* - Bit 0: RWSEM_READER_OWNED - The rwsem is owned by readers
|
|
* - Bit 1: RWSEM_NONSPINNABLE - Cannot spin on a reader-owned lock
|
|
*
|
|
* When the rwsem is reader-owned and a spinning writer has timed out,
|
|
* the nonspinnable bit will be set to disable optimistic spinning.
|
|
|
|
* When a writer acquires a rwsem, it puts its task_struct pointer
|
|
* into the owner field. It is cleared after an unlock.
|
|
*
|
|
* When a reader acquires a rwsem, it will also puts its task_struct
|
|
* pointer into the owner field with the RWSEM_READER_OWNED bit set.
|
|
* On unlock, the owner field will largely be left untouched. So
|
|
* for a free or reader-owned rwsem, the owner value may contain
|
|
* information about the last reader that acquires the rwsem.
|
|
*
|
|
* That information may be helpful in debugging cases where the system
|
|
* seems to hang on a reader owned rwsem especially if only one reader
|
|
* is involved. Ideally we would like to track all the readers that own
|
|
* a rwsem, but the overhead is simply too big.
|
|
*
|
|
* A fast path reader optimistic lock stealing is supported when the rwsem
|
|
* is previously owned by a writer and the following conditions are met:
|
|
* - rwsem is not currently writer owned
|
|
* - the handoff isn't set.
|
|
*/
|
|
#define RWSEM_READER_OWNED (1UL << 0)
|
|
#define RWSEM_NONSPINNABLE (1UL << 1)
|
|
#define RWSEM_OWNER_FLAGS_MASK (RWSEM_READER_OWNED | RWSEM_NONSPINNABLE)
|
|
|
|
#ifdef CONFIG_DEBUG_RWSEMS
|
|
# define DEBUG_RWSEMS_WARN_ON(c, sem) do { \
|
|
if (!debug_locks_silent && \
|
|
WARN_ONCE(c, "DEBUG_RWSEMS_WARN_ON(%s): count = 0x%lx, magic = 0x%lx, owner = 0x%lx, curr 0x%lx, list %sempty\n",\
|
|
#c, atomic_long_read(&(sem)->count), \
|
|
(unsigned long) sem->magic, \
|
|
atomic_long_read(&(sem)->owner), (long)current, \
|
|
list_empty(&(sem)->wait_list) ? "" : "not ")) \
|
|
debug_locks_off(); \
|
|
} while (0)
|
|
#else
|
|
# define DEBUG_RWSEMS_WARN_ON(c, sem)
|
|
#endif
|
|
|
|
/*
|
|
* On 64-bit architectures, the bit definitions of the count are:
|
|
*
|
|
* Bit 0 - writer locked bit
|
|
* Bit 1 - waiters present bit
|
|
* Bit 2 - lock handoff bit
|
|
* Bits 3-7 - reserved
|
|
* Bits 8-62 - 55-bit reader count
|
|
* Bit 63 - read fail bit
|
|
*
|
|
* On 32-bit architectures, the bit definitions of the count are:
|
|
*
|
|
* Bit 0 - writer locked bit
|
|
* Bit 1 - waiters present bit
|
|
* Bit 2 - lock handoff bit
|
|
* Bits 3-7 - reserved
|
|
* Bits 8-30 - 23-bit reader count
|
|
* Bit 31 - read fail bit
|
|
*
|
|
* It is not likely that the most significant bit (read fail bit) will ever
|
|
* be set. This guard bit is still checked anyway in the down_read() fastpath
|
|
* just in case we need to use up more of the reader bits for other purpose
|
|
* in the future.
|
|
*
|
|
* atomic_long_fetch_add() is used to obtain reader lock, whereas
|
|
* atomic_long_cmpxchg() will be used to obtain writer lock.
|
|
*
|
|
* There are three places where the lock handoff bit may be set or cleared.
|
|
* 1) rwsem_mark_wake() for readers -- set, clear
|
|
* 2) rwsem_try_write_lock() for writers -- set, clear
|
|
* 3) rwsem_del_waiter() -- clear
|
|
*
|
|
* For all the above cases, wait_lock will be held. A writer must also
|
|
* be the first one in the wait_list to be eligible for setting the handoff
|
|
* bit. So concurrent setting/clearing of handoff bit is not possible.
|
|
*/
|
|
#define RWSEM_WRITER_LOCKED (1UL << 0)
|
|
#define RWSEM_FLAG_WAITERS (1UL << 1)
|
|
#define RWSEM_FLAG_HANDOFF (1UL << 2)
|
|
#define RWSEM_FLAG_READFAIL (1UL << (BITS_PER_LONG - 1))
|
|
|
|
#define RWSEM_READER_SHIFT 8
|
|
#define RWSEM_READER_BIAS (1UL << RWSEM_READER_SHIFT)
|
|
#define RWSEM_READER_MASK (~(RWSEM_READER_BIAS - 1))
|
|
#define RWSEM_WRITER_MASK RWSEM_WRITER_LOCKED
|
|
#define RWSEM_LOCK_MASK (RWSEM_WRITER_MASK|RWSEM_READER_MASK)
|
|
#define RWSEM_READ_FAILED_MASK (RWSEM_WRITER_MASK|RWSEM_FLAG_WAITERS|\
|
|
RWSEM_FLAG_HANDOFF|RWSEM_FLAG_READFAIL)
|
|
|
|
/*
|
|
* All writes to owner are protected by WRITE_ONCE() to make sure that
|
|
* store tearing can't happen as optimistic spinners may read and use
|
|
* the owner value concurrently without lock. Read from owner, however,
|
|
* may not need READ_ONCE() as long as the pointer value is only used
|
|
* for comparison and isn't being dereferenced.
|
|
*
|
|
* Both rwsem_{set,clear}_owner() functions should be in the same
|
|
* preempt disable section as the atomic op that changes sem->count.
|
|
*/
|
|
static inline void rwsem_set_owner(struct rw_semaphore *sem)
|
|
{
|
|
lockdep_assert_preemption_disabled();
|
|
atomic_long_set(&sem->owner, (long)current);
|
|
}
|
|
|
|
static inline void rwsem_clear_owner(struct rw_semaphore *sem)
|
|
{
|
|
lockdep_assert_preemption_disabled();
|
|
atomic_long_set(&sem->owner, 0);
|
|
}
|
|
|
|
/*
|
|
* Test the flags in the owner field.
|
|
*/
|
|
static inline bool rwsem_test_oflags(struct rw_semaphore *sem, long flags)
|
|
{
|
|
return atomic_long_read(&sem->owner) & flags;
|
|
}
|
|
|
|
/*
|
|
* The task_struct pointer of the last owning reader will be left in
|
|
* the owner field.
|
|
*
|
|
* Note that the owner value just indicates the task has owned the rwsem
|
|
* previously, it may not be the real owner or one of the real owners
|
|
* anymore when that field is examined, so take it with a grain of salt.
|
|
*
|
|
* The reader non-spinnable bit is preserved.
|
|
*/
|
|
static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
|
|
struct task_struct *owner)
|
|
{
|
|
unsigned long val = (unsigned long)owner | RWSEM_READER_OWNED |
|
|
(atomic_long_read(&sem->owner) & RWSEM_NONSPINNABLE);
|
|
|
|
atomic_long_set(&sem->owner, val);
|
|
}
|
|
|
|
static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
|
|
{
|
|
__rwsem_set_reader_owned(sem, current);
|
|
}
|
|
|
|
/*
|
|
* Return true if the rwsem is owned by a reader.
|
|
*/
|
|
static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
|
|
{
|
|
#ifdef CONFIG_DEBUG_RWSEMS
|
|
/*
|
|
* Check the count to see if it is write-locked.
|
|
*/
|
|
long count = atomic_long_read(&sem->count);
|
|
|
|
if (count & RWSEM_WRITER_MASK)
|
|
return false;
|
|
#endif
|
|
return rwsem_test_oflags(sem, RWSEM_READER_OWNED);
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_RWSEMS
|
|
/*
|
|
* With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there
|
|
* is a task pointer in owner of a reader-owned rwsem, it will be the
|
|
* real owner or one of the real owners. The only exception is when the
|
|
* unlock is done by up_read_non_owner().
|
|
*/
|
|
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
|
|
{
|
|
unsigned long val = atomic_long_read(&sem->owner);
|
|
|
|
while ((val & ~RWSEM_OWNER_FLAGS_MASK) == (unsigned long)current) {
|
|
if (atomic_long_try_cmpxchg(&sem->owner, &val,
|
|
val & RWSEM_OWNER_FLAGS_MASK))
|
|
return;
|
|
}
|
|
}
|
|
#else
|
|
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Set the RWSEM_NONSPINNABLE bits if the RWSEM_READER_OWNED flag
|
|
* remains set. Otherwise, the operation will be aborted.
|
|
*/
|
|
static inline void rwsem_set_nonspinnable(struct rw_semaphore *sem)
|
|
{
|
|
unsigned long owner = atomic_long_read(&sem->owner);
|
|
|
|
do {
|
|
if (!(owner & RWSEM_READER_OWNED))
|
|
break;
|
|
if (owner & RWSEM_NONSPINNABLE)
|
|
break;
|
|
} while (!atomic_long_try_cmpxchg(&sem->owner, &owner,
|
|
owner | RWSEM_NONSPINNABLE));
|
|
}
|
|
|
|
static inline bool rwsem_read_trylock(struct rw_semaphore *sem, long *cntp)
|
|
{
|
|
*cntp = atomic_long_add_return_acquire(RWSEM_READER_BIAS, &sem->count);
|
|
|
|
if (WARN_ON_ONCE(*cntp < 0))
|
|
rwsem_set_nonspinnable(sem);
|
|
|
|
if (!(*cntp & RWSEM_READ_FAILED_MASK)) {
|
|
rwsem_set_reader_owned(sem);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static inline bool rwsem_write_trylock(struct rw_semaphore *sem)
|
|
{
|
|
long tmp = RWSEM_UNLOCKED_VALUE;
|
|
bool ret = false;
|
|
|
|
preempt_disable();
|
|
if (atomic_long_try_cmpxchg_acquire(&sem->count, &tmp, RWSEM_WRITER_LOCKED)) {
|
|
rwsem_set_owner(sem);
|
|
ret = true;
|
|
}
|
|
|
|
preempt_enable();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Return just the real task structure pointer of the owner
|
|
*/
|
|
static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem)
|
|
{
|
|
return (struct task_struct *)
|
|
(atomic_long_read(&sem->owner) & ~RWSEM_OWNER_FLAGS_MASK);
|
|
}
|
|
|
|
/*
|
|
* Return the real task structure pointer of the owner and the embedded
|
|
* flags in the owner. pflags must be non-NULL.
|
|
*/
|
|
static inline struct task_struct *
|
|
rwsem_owner_flags(struct rw_semaphore *sem, unsigned long *pflags)
|
|
{
|
|
unsigned long owner = atomic_long_read(&sem->owner);
|
|
|
|
*pflags = owner & RWSEM_OWNER_FLAGS_MASK;
|
|
return (struct task_struct *)(owner & ~RWSEM_OWNER_FLAGS_MASK);
|
|
}
|
|
|
|
/*
|
|
* Guide to the rw_semaphore's count field.
|
|
*
|
|
* When the RWSEM_WRITER_LOCKED bit in count is set, the lock is owned
|
|
* by a writer.
|
|
*
|
|
* The lock is owned by readers when
|
|
* (1) the RWSEM_WRITER_LOCKED isn't set in count,
|
|
* (2) some of the reader bits are set in count, and
|
|
* (3) the owner field has RWSEM_READ_OWNED bit set.
|
|
*
|
|
* Having some reader bits set is not enough to guarantee a readers owned
|
|
* lock as the readers may be in the process of backing out from the count
|
|
* and a writer has just released the lock. So another writer may steal
|
|
* the lock immediately after that.
|
|
*/
|
|
|
|
/*
|
|
* Initialize an rwsem:
|
|
*/
|
|
void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
|
struct lock_class_key *key)
|
|
{
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
/*
|
|
* Make sure we are not reinitializing a held semaphore:
|
|
*/
|
|
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
|
|
lockdep_init_map_wait(&sem->dep_map, name, key, 0, LD_WAIT_SLEEP);
|
|
#endif
|
|
#ifdef CONFIG_DEBUG_RWSEMS
|
|
sem->magic = sem;
|
|
#endif
|
|
atomic_long_set(&sem->count, RWSEM_UNLOCKED_VALUE);
|
|
raw_spin_lock_init(&sem->wait_lock);
|
|
INIT_LIST_HEAD(&sem->wait_list);
|
|
atomic_long_set(&sem->owner, 0L);
|
|
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
|
|
osq_lock_init(&sem->osq);
|
|
#endif
|
|
trace_android_vh_rwsem_init(sem);
|
|
}
|
|
EXPORT_SYMBOL(__init_rwsem);
|
|
|
|
enum rwsem_waiter_type {
|
|
RWSEM_WAITING_FOR_WRITE,
|
|
RWSEM_WAITING_FOR_READ
|
|
};
|
|
|
|
struct rwsem_waiter {
|
|
struct list_head list;
|
|
struct task_struct *task;
|
|
enum rwsem_waiter_type type;
|
|
unsigned long timeout;
|
|
bool handoff_set;
|
|
};
|
|
#define rwsem_first_waiter(sem) \
|
|
list_first_entry(&sem->wait_list, struct rwsem_waiter, list)
|
|
|
|
enum rwsem_wake_type {
|
|
RWSEM_WAKE_ANY, /* Wake whatever's at head of wait list */
|
|
RWSEM_WAKE_READERS, /* Wake readers only */
|
|
RWSEM_WAKE_READ_OWNED /* Waker thread holds the read lock */
|
|
};
|
|
|
|
/*
|
|
* The typical HZ value is either 250 or 1000. So set the minimum waiting
|
|
* time to at least 4ms or 1 jiffy (if it is higher than 4ms) in the wait
|
|
* queue before initiating the handoff protocol.
|
|
*/
|
|
#define RWSEM_WAIT_TIMEOUT DIV_ROUND_UP(HZ, 250)
|
|
|
|
/*
|
|
* Magic number to batch-wakeup waiting readers, even when writers are
|
|
* also present in the queue. This both limits the amount of work the
|
|
* waking thread must do and also prevents any potential counter overflow,
|
|
* however unlikely.
|
|
*/
|
|
#define MAX_READERS_WAKEUP 0x100
|
|
|
|
static inline void
|
|
rwsem_add_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
|
|
{
|
|
lockdep_assert_held(&sem->wait_lock);
|
|
list_add_tail(&waiter->list, &sem->wait_list);
|
|
/* caller will set RWSEM_FLAG_WAITERS */
|
|
}
|
|
|
|
/*
|
|
* Remove a waiter from the wait_list and clear flags.
|
|
*
|
|
* Both rwsem_mark_wake() and rwsem_try_write_lock() contain a full 'copy' of
|
|
* this function. Modify with care.
|
|
*
|
|
* Return: true if wait_list isn't empty and false otherwise
|
|
*/
|
|
static inline bool
|
|
rwsem_del_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
|
|
{
|
|
lockdep_assert_held(&sem->wait_lock);
|
|
list_del(&waiter->list);
|
|
if (likely(!list_empty(&sem->wait_list)))
|
|
return true;
|
|
|
|
atomic_long_andnot(RWSEM_FLAG_HANDOFF | RWSEM_FLAG_WAITERS, &sem->count);
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* handle the lock release when processes blocked on it that can now run
|
|
* - if we come here from up_xxxx(), then the RWSEM_FLAG_WAITERS bit must
|
|
* have been set.
|
|
* - there must be someone on the queue
|
|
* - the wait_lock must be held by the caller
|
|
* - tasks are marked for wakeup, the caller must later invoke wake_up_q()
|
|
* to actually wakeup the blocked task(s) and drop the reference count,
|
|
* preferably when the wait_lock is released
|
|
* - woken process blocks are discarded from the list after having task zeroed
|
|
* - writers are only marked woken if downgrading is false
|
|
*
|
|
* Implies rwsem_del_waiter() for all woken readers.
|
|
*/
|
|
static void rwsem_mark_wake(struct rw_semaphore *sem,
|
|
enum rwsem_wake_type wake_type,
|
|
struct wake_q_head *wake_q)
|
|
{
|
|
struct rwsem_waiter *waiter, *tmp;
|
|
long oldcount, woken = 0, adjustment = 0;
|
|
struct list_head wlist;
|
|
|
|
lockdep_assert_held(&sem->wait_lock);
|
|
|
|
/*
|
|
* Take a peek at the queue head waiter such that we can determine
|
|
* the wakeup(s) to perform.
|
|
*/
|
|
waiter = rwsem_first_waiter(sem);
|
|
|
|
if (waiter->type == RWSEM_WAITING_FOR_WRITE) {
|
|
if (wake_type == RWSEM_WAKE_ANY) {
|
|
/*
|
|
* Mark writer at the front of the queue for wakeup.
|
|
* Until the task is actually later awoken later by
|
|
* the caller, other writers are able to steal it.
|
|
* Readers, on the other hand, will block as they
|
|
* will notice the queued writer.
|
|
*/
|
|
wake_q_add(wake_q, waiter->task);
|
|
lockevent_inc(rwsem_wake_writer);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* No reader wakeup if there are too many of them already.
|
|
*/
|
|
if (unlikely(atomic_long_read(&sem->count) < 0))
|
|
return;
|
|
|
|
/*
|
|
* Writers might steal the lock before we grant it to the next reader.
|
|
* We prefer to do the first reader grant before counting readers
|
|
* so we can bail out early if a writer stole the lock.
|
|
*/
|
|
if (wake_type != RWSEM_WAKE_READ_OWNED) {
|
|
struct task_struct *owner;
|
|
|
|
adjustment = RWSEM_READER_BIAS;
|
|
oldcount = atomic_long_fetch_add(adjustment, &sem->count);
|
|
if (unlikely(oldcount & RWSEM_WRITER_MASK)) {
|
|
/*
|
|
* When we've been waiting "too" long (for writers
|
|
* to give up the lock), request a HANDOFF to
|
|
* force the issue.
|
|
*/
|
|
if (time_after(jiffies, waiter->timeout)) {
|
|
if (!(oldcount & RWSEM_FLAG_HANDOFF)) {
|
|
adjustment -= RWSEM_FLAG_HANDOFF;
|
|
lockevent_inc(rwsem_rlock_handoff);
|
|
}
|
|
waiter->handoff_set = true;
|
|
}
|
|
|
|
atomic_long_add(-adjustment, &sem->count);
|
|
return;
|
|
}
|
|
/*
|
|
* Set it to reader-owned to give spinners an early
|
|
* indication that readers now have the lock.
|
|
* The reader nonspinnable bit seen at slowpath entry of
|
|
* the reader is copied over.
|
|
*/
|
|
owner = waiter->task;
|
|
__rwsem_set_reader_owned(sem, owner);
|
|
}
|
|
|
|
/*
|
|
* Grant up to MAX_READERS_WAKEUP read locks to all the readers in the
|
|
* queue. We know that the woken will be at least 1 as we accounted
|
|
* for above. Note we increment the 'active part' of the count by the
|
|
* number of readers before waking any processes up.
|
|
*
|
|
* This is an adaptation of the phase-fair R/W locks where at the
|
|
* reader phase (first waiter is a reader), all readers are eligible
|
|
* to acquire the lock at the same time irrespective of their order
|
|
* in the queue. The writers acquire the lock according to their
|
|
* order in the queue.
|
|
*
|
|
* We have to do wakeup in 2 passes to prevent the possibility that
|
|
* the reader count may be decremented before it is incremented. It
|
|
* is because the to-be-woken waiter may not have slept yet. So it
|
|
* may see waiter->task got cleared, finish its critical section and
|
|
* do an unlock before the reader count increment.
|
|
*
|
|
* 1) Collect the read-waiters in a separate list, count them and
|
|
* fully increment the reader count in rwsem.
|
|
* 2) For each waiters in the new list, clear waiter->task and
|
|
* put them into wake_q to be woken up later.
|
|
*/
|
|
INIT_LIST_HEAD(&wlist);
|
|
list_for_each_entry_safe(waiter, tmp, &sem->wait_list, list) {
|
|
if (waiter->type == RWSEM_WAITING_FOR_WRITE)
|
|
continue;
|
|
|
|
woken++;
|
|
list_move_tail(&waiter->list, &wlist);
|
|
|
|
/*
|
|
* Limit # of readers that can be woken up per wakeup call.
|
|
*/
|
|
if (unlikely(woken >= MAX_READERS_WAKEUP))
|
|
break;
|
|
}
|
|
|
|
adjustment = woken * RWSEM_READER_BIAS - adjustment;
|
|
lockevent_cond_inc(rwsem_wake_reader, woken);
|
|
|
|
oldcount = atomic_long_read(&sem->count);
|
|
if (list_empty(&sem->wait_list)) {
|
|
/*
|
|
* Combined with list_move_tail() above, this implies
|
|
* rwsem_del_waiter().
|
|
*/
|
|
adjustment -= RWSEM_FLAG_WAITERS;
|
|
if (oldcount & RWSEM_FLAG_HANDOFF)
|
|
adjustment -= RWSEM_FLAG_HANDOFF;
|
|
} else if (woken) {
|
|
/*
|
|
* When we've woken a reader, we no longer need to force
|
|
* writers to give up the lock and we can clear HANDOFF.
|
|
*/
|
|
if (oldcount & RWSEM_FLAG_HANDOFF)
|
|
adjustment -= RWSEM_FLAG_HANDOFF;
|
|
}
|
|
|
|
if (adjustment)
|
|
atomic_long_add(adjustment, &sem->count);
|
|
|
|
/* 2nd pass */
|
|
list_for_each_entry_safe(waiter, tmp, &wlist, list) {
|
|
struct task_struct *tsk;
|
|
|
|
tsk = waiter->task;
|
|
get_task_struct(tsk);
|
|
|
|
/*
|
|
* Ensure calling get_task_struct() before setting the reader
|
|
* waiter to nil such that rwsem_down_read_slowpath() cannot
|
|
* race with do_exit() by always holding a reference count
|
|
* to the task to wakeup.
|
|
*/
|
|
smp_store_release(&waiter->task, NULL);
|
|
/*
|
|
* Ensure issuing the wakeup (either by us or someone else)
|
|
* after setting the reader waiter to nil.
|
|
*/
|
|
wake_q_add_safe(wake_q, tsk);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Remove a waiter and try to wake up other waiters in the wait queue
|
|
* This function is called from the out_nolock path of both the reader and
|
|
* writer slowpaths with wait_lock held. It releases the wait_lock and
|
|
* optionally wake up waiters before it returns.
|
|
*/
|
|
static inline void
|
|
rwsem_del_wake_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter,
|
|
struct wake_q_head *wake_q)
|
|
__releases(&sem->wait_lock)
|
|
{
|
|
bool first = rwsem_first_waiter(sem) == waiter;
|
|
|
|
wake_q_init(wake_q);
|
|
|
|
/*
|
|
* If the wait_list isn't empty and the waiter to be deleted is
|
|
* the first waiter, we wake up the remaining waiters as they may
|
|
* be eligible to acquire or spin on the lock.
|
|
*/
|
|
if (rwsem_del_waiter(sem, waiter) && first)
|
|
rwsem_mark_wake(sem, RWSEM_WAKE_ANY, wake_q);
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
if (!wake_q_empty(wake_q))
|
|
wake_up_q(wake_q);
|
|
}
|
|
|
|
/*
|
|
* This function must be called with the sem->wait_lock held to prevent
|
|
* race conditions between checking the rwsem wait list and setting the
|
|
* sem->count accordingly.
|
|
*
|
|
* Implies rwsem_del_waiter() on success.
|
|
*/
|
|
static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
|
|
struct rwsem_waiter *waiter)
|
|
{
|
|
struct rwsem_waiter *first = rwsem_first_waiter(sem);
|
|
long count, new;
|
|
|
|
lockdep_assert_held(&sem->wait_lock);
|
|
|
|
count = atomic_long_read(&sem->count);
|
|
do {
|
|
bool has_handoff = !!(count & RWSEM_FLAG_HANDOFF);
|
|
|
|
if (has_handoff) {
|
|
/*
|
|
* Honor handoff bit and yield only when the first
|
|
* waiter is the one that set it. Otherwisee, we
|
|
* still try to acquire the rwsem.
|
|
*/
|
|
if (first->handoff_set && (waiter != first))
|
|
return false;
|
|
}
|
|
|
|
new = count;
|
|
|
|
if (count & RWSEM_LOCK_MASK) {
|
|
/*
|
|
* A waiter (first or not) can set the handoff bit
|
|
* if it is an RT task or wait in the wait queue
|
|
* for too long.
|
|
*/
|
|
if (has_handoff || (!rt_task(waiter->task) &&
|
|
!time_after(jiffies, waiter->timeout)))
|
|
return false;
|
|
|
|
new |= RWSEM_FLAG_HANDOFF;
|
|
} else {
|
|
new |= RWSEM_WRITER_LOCKED;
|
|
new &= ~RWSEM_FLAG_HANDOFF;
|
|
|
|
if (list_is_singular(&sem->wait_list))
|
|
new &= ~RWSEM_FLAG_WAITERS;
|
|
}
|
|
} while (!atomic_long_try_cmpxchg_acquire(&sem->count, &count, new));
|
|
|
|
/*
|
|
* We have either acquired the lock with handoff bit cleared or set
|
|
* the handoff bit. Only the first waiter can have its handoff_set
|
|
* set here to enable optimistic spinning in slowpath loop.
|
|
*/
|
|
if (new & RWSEM_FLAG_HANDOFF) {
|
|
first->handoff_set = true;
|
|
lockevent_inc(rwsem_wlock_handoff);
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Have rwsem_try_write_lock() fully imply rwsem_del_waiter() on
|
|
* success.
|
|
*/
|
|
list_del(&waiter->list);
|
|
rwsem_set_owner(sem);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* The rwsem_spin_on_owner() function returns the following 4 values
|
|
* depending on the lock owner state.
|
|
* OWNER_NULL : owner is currently NULL
|
|
* OWNER_WRITER: when owner changes and is a writer
|
|
* OWNER_READER: when owner changes and the new owner may be a reader.
|
|
* OWNER_NONSPINNABLE:
|
|
* when optimistic spinning has to stop because either the
|
|
* owner stops running, is unknown, or its timeslice has
|
|
* been used up.
|
|
*/
|
|
enum owner_state {
|
|
OWNER_NULL = 1 << 0,
|
|
OWNER_WRITER = 1 << 1,
|
|
OWNER_READER = 1 << 2,
|
|
OWNER_NONSPINNABLE = 1 << 3,
|
|
};
|
|
|
|
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
|
|
/*
|
|
* Try to acquire write lock before the writer has been put on wait queue.
|
|
*/
|
|
static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem)
|
|
{
|
|
long count = atomic_long_read(&sem->count);
|
|
|
|
while (!(count & (RWSEM_LOCK_MASK|RWSEM_FLAG_HANDOFF))) {
|
|
if (atomic_long_try_cmpxchg_acquire(&sem->count, &count,
|
|
count | RWSEM_WRITER_LOCKED)) {
|
|
rwsem_set_owner(sem);
|
|
lockevent_inc(rwsem_opt_lock);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
|
|
{
|
|
struct task_struct *owner;
|
|
unsigned long flags;
|
|
bool ret = true;
|
|
|
|
if (need_resched()) {
|
|
lockevent_inc(rwsem_opt_fail);
|
|
return false;
|
|
}
|
|
|
|
preempt_disable();
|
|
/*
|
|
* Disable preemption is equal to the RCU read-side crital section,
|
|
* thus the task_strcut structure won't go away.
|
|
*/
|
|
owner = rwsem_owner_flags(sem, &flags);
|
|
/*
|
|
* Don't check the read-owner as the entry may be stale.
|
|
*/
|
|
if ((flags & RWSEM_NONSPINNABLE) ||
|
|
(owner && !(flags & RWSEM_READER_OWNED) && !owner_on_cpu(owner)))
|
|
ret = false;
|
|
preempt_enable();
|
|
|
|
lockevent_cond_inc(rwsem_opt_fail, !ret);
|
|
return ret;
|
|
}
|
|
|
|
#define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER | OWNER_READER)
|
|
|
|
static inline enum owner_state
|
|
rwsem_owner_state(struct task_struct *owner, unsigned long flags)
|
|
{
|
|
if (flags & RWSEM_NONSPINNABLE)
|
|
return OWNER_NONSPINNABLE;
|
|
|
|
if (flags & RWSEM_READER_OWNED)
|
|
return OWNER_READER;
|
|
|
|
return owner ? OWNER_WRITER : OWNER_NULL;
|
|
}
|
|
|
|
static noinline enum owner_state
|
|
rwsem_spin_on_owner(struct rw_semaphore *sem)
|
|
{
|
|
struct task_struct *new, *owner;
|
|
unsigned long flags, new_flags;
|
|
enum owner_state state;
|
|
|
|
lockdep_assert_preemption_disabled();
|
|
|
|
owner = rwsem_owner_flags(sem, &flags);
|
|
state = rwsem_owner_state(owner, flags);
|
|
if (state != OWNER_WRITER)
|
|
return state;
|
|
|
|
for (;;) {
|
|
/*
|
|
* When a waiting writer set the handoff flag, it may spin
|
|
* on the owner as well. Once that writer acquires the lock,
|
|
* we can spin on it. So we don't need to quit even when the
|
|
* handoff bit is set.
|
|
*/
|
|
new = rwsem_owner_flags(sem, &new_flags);
|
|
if ((new != owner) || (new_flags != flags)) {
|
|
state = rwsem_owner_state(new, new_flags);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Ensure we emit the owner->on_cpu, dereference _after_
|
|
* checking sem->owner still matches owner, if that fails,
|
|
* owner might point to free()d memory, if it still matches,
|
|
* our spinning context already disabled preemption which is
|
|
* equal to RCU read-side crital section ensures the memory
|
|
* stays valid.
|
|
*/
|
|
barrier();
|
|
|
|
if (need_resched() || !owner_on_cpu(owner)) {
|
|
state = OWNER_NONSPINNABLE;
|
|
break;
|
|
}
|
|
|
|
cpu_relax();
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
/*
|
|
* Calculate reader-owned rwsem spinning threshold for writer
|
|
*
|
|
* The more readers own the rwsem, the longer it will take for them to
|
|
* wind down and free the rwsem. So the empirical formula used to
|
|
* determine the actual spinning time limit here is:
|
|
*
|
|
* Spinning threshold = (10 + nr_readers/2)us
|
|
*
|
|
* The limit is capped to a maximum of 25us (30 readers). This is just
|
|
* a heuristic and is subjected to change in the future.
|
|
*/
|
|
static inline u64 rwsem_rspin_threshold(struct rw_semaphore *sem)
|
|
{
|
|
long count = atomic_long_read(&sem->count);
|
|
int readers = count >> RWSEM_READER_SHIFT;
|
|
u64 delta;
|
|
|
|
if (readers > 30)
|
|
readers = 30;
|
|
delta = (20 + readers) * NSEC_PER_USEC / 2;
|
|
|
|
return sched_clock() + delta;
|
|
}
|
|
|
|
static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
|
|
{
|
|
bool taken = false;
|
|
int prev_owner_state = OWNER_NULL;
|
|
int loop = 0;
|
|
u64 rspin_threshold = 0;
|
|
|
|
preempt_disable();
|
|
|
|
/* sem->wait_lock should not be held when doing optimistic spinning */
|
|
if (!osq_lock(&sem->osq))
|
|
goto done;
|
|
|
|
/*
|
|
* Optimistically spin on the owner field and attempt to acquire the
|
|
* lock whenever the owner changes. Spinning will be stopped when:
|
|
* 1) the owning writer isn't running; or
|
|
* 2) readers own the lock and spinning time has exceeded limit.
|
|
*/
|
|
for (;;) {
|
|
enum owner_state owner_state;
|
|
|
|
owner_state = rwsem_spin_on_owner(sem);
|
|
if (!(owner_state & OWNER_SPINNABLE))
|
|
break;
|
|
|
|
/*
|
|
* Try to acquire the lock
|
|
*/
|
|
taken = rwsem_try_write_lock_unqueued(sem);
|
|
|
|
if (taken)
|
|
break;
|
|
|
|
/*
|
|
* Time-based reader-owned rwsem optimistic spinning
|
|
*/
|
|
if (owner_state == OWNER_READER) {
|
|
/*
|
|
* Re-initialize rspin_threshold every time when
|
|
* the owner state changes from non-reader to reader.
|
|
* This allows a writer to steal the lock in between
|
|
* 2 reader phases and have the threshold reset at
|
|
* the beginning of the 2nd reader phase.
|
|
*/
|
|
if (prev_owner_state != OWNER_READER) {
|
|
if (rwsem_test_oflags(sem, RWSEM_NONSPINNABLE))
|
|
break;
|
|
rspin_threshold = rwsem_rspin_threshold(sem);
|
|
loop = 0;
|
|
}
|
|
|
|
/*
|
|
* Check time threshold once every 16 iterations to
|
|
* avoid calling sched_clock() too frequently so
|
|
* as to reduce the average latency between the times
|
|
* when the lock becomes free and when the spinner
|
|
* is ready to do a trylock.
|
|
*/
|
|
else if (!(++loop & 0xf) && (sched_clock() > rspin_threshold)) {
|
|
rwsem_set_nonspinnable(sem);
|
|
lockevent_inc(rwsem_opt_nospin);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* An RT task cannot do optimistic spinning if it cannot
|
|
* be sure the lock holder is running or live-lock may
|
|
* happen if the current task and the lock holder happen
|
|
* to run in the same CPU. However, aborting optimistic
|
|
* spinning while a NULL owner is detected may miss some
|
|
* opportunity where spinning can continue without causing
|
|
* problem.
|
|
*
|
|
* There are 2 possible cases where an RT task may be able
|
|
* to continue spinning.
|
|
*
|
|
* 1) The lock owner is in the process of releasing the
|
|
* lock, sem->owner is cleared but the lock has not
|
|
* been released yet.
|
|
* 2) The lock was free and owner cleared, but another
|
|
* task just comes in and acquire the lock before
|
|
* we try to get it. The new owner may be a spinnable
|
|
* writer.
|
|
*
|
|
* To take advantage of two scenarios listed above, the RT
|
|
* task is made to retry one more time to see if it can
|
|
* acquire the lock or continue spinning on the new owning
|
|
* writer. Of course, if the time lag is long enough or the
|
|
* new owner is not a writer or spinnable, the RT task will
|
|
* quit spinning.
|
|
*
|
|
* If the owner is a writer, the need_resched() check is
|
|
* done inside rwsem_spin_on_owner(). If the owner is not
|
|
* a writer, need_resched() check needs to be done here.
|
|
*/
|
|
if (owner_state != OWNER_WRITER) {
|
|
if (need_resched())
|
|
break;
|
|
if (rt_task(current) &&
|
|
(prev_owner_state != OWNER_WRITER))
|
|
break;
|
|
}
|
|
prev_owner_state = owner_state;
|
|
|
|
/*
|
|
* The cpu_relax() call is a compiler barrier which forces
|
|
* everything in this loop to be re-loaded. We don't need
|
|
* memory barriers as we'll eventually observe the right
|
|
* values at the cost of a few extra spins.
|
|
*/
|
|
cpu_relax();
|
|
}
|
|
osq_unlock(&sem->osq);
|
|
done:
|
|
preempt_enable();
|
|
lockevent_cond_inc(rwsem_opt_fail, !taken);
|
|
return taken;
|
|
}
|
|
|
|
/*
|
|
* Clear the owner's RWSEM_NONSPINNABLE bit if it is set. This should
|
|
* only be called when the reader count reaches 0.
|
|
*/
|
|
static inline void clear_nonspinnable(struct rw_semaphore *sem)
|
|
{
|
|
if (unlikely(rwsem_test_oflags(sem, RWSEM_NONSPINNABLE)))
|
|
atomic_long_andnot(RWSEM_NONSPINNABLE, &sem->owner);
|
|
}
|
|
|
|
#else
|
|
static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool rwsem_optimistic_spin(struct rw_semaphore *sem)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void clear_nonspinnable(struct rw_semaphore *sem) { }
|
|
|
|
static inline enum owner_state
|
|
rwsem_spin_on_owner(struct rw_semaphore *sem)
|
|
{
|
|
return OWNER_NONSPINNABLE;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Prepare to wake up waiter(s) in the wait queue by putting them into the
|
|
* given wake_q if the rwsem lock owner isn't a writer. If rwsem is likely
|
|
* reader-owned, wake up read lock waiters in queue front or wake up any
|
|
* front waiter otherwise.
|
|
|
|
* This is being called from both reader and writer slow paths.
|
|
*/
|
|
static inline void rwsem_cond_wake_waiter(struct rw_semaphore *sem, long count,
|
|
struct wake_q_head *wake_q)
|
|
{
|
|
enum rwsem_wake_type wake_type;
|
|
|
|
if (count & RWSEM_WRITER_MASK)
|
|
return;
|
|
|
|
if (count & RWSEM_READER_MASK) {
|
|
wake_type = RWSEM_WAKE_READERS;
|
|
} else {
|
|
wake_type = RWSEM_WAKE_ANY;
|
|
clear_nonspinnable(sem);
|
|
}
|
|
rwsem_mark_wake(sem, wake_type, wake_q);
|
|
}
|
|
|
|
/*
|
|
* Wait for the read lock to be granted
|
|
*/
|
|
static struct rw_semaphore __sched *
|
|
rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int state)
|
|
{
|
|
long adjustment = -RWSEM_READER_BIAS;
|
|
long rcnt = (count >> RWSEM_READER_SHIFT);
|
|
struct rwsem_waiter waiter;
|
|
DEFINE_WAKE_Q(wake_q);
|
|
bool already_on_list = false;
|
|
|
|
/*
|
|
* To prevent a constant stream of readers from starving a sleeping
|
|
* waiter, don't attempt optimistic lock stealing if the lock is
|
|
* currently owned by readers.
|
|
*/
|
|
if ((atomic_long_read(&sem->owner) & RWSEM_READER_OWNED) &&
|
|
(rcnt > 1) && !(count & RWSEM_WRITER_LOCKED))
|
|
goto queue;
|
|
|
|
/*
|
|
* Reader optimistic lock stealing.
|
|
*/
|
|
if (!(count & (RWSEM_WRITER_LOCKED | RWSEM_FLAG_HANDOFF))) {
|
|
rwsem_set_reader_owned(sem);
|
|
lockevent_inc(rwsem_rlock_steal);
|
|
|
|
/*
|
|
* Wake up other readers in the wait queue if it is
|
|
* the first reader.
|
|
*/
|
|
if ((rcnt == 1) && (count & RWSEM_FLAG_WAITERS)) {
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
if (!list_empty(&sem->wait_list))
|
|
rwsem_mark_wake(sem, RWSEM_WAKE_READ_OWNED,
|
|
&wake_q);
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
wake_up_q(&wake_q);
|
|
}
|
|
return sem;
|
|
}
|
|
|
|
queue:
|
|
waiter.task = current;
|
|
waiter.type = RWSEM_WAITING_FOR_READ;
|
|
waiter.timeout = jiffies + RWSEM_WAIT_TIMEOUT;
|
|
waiter.handoff_set = false;
|
|
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
if (list_empty(&sem->wait_list)) {
|
|
/*
|
|
* In case the wait queue is empty and the lock isn't owned
|
|
* by a writer, this reader can exit the slowpath and return
|
|
* immediately as its RWSEM_READER_BIAS has already been set
|
|
* in the count.
|
|
*/
|
|
if (!(atomic_long_read(&sem->count) & RWSEM_WRITER_MASK)) {
|
|
/* Provide lock ACQUIRE */
|
|
smp_acquire__after_ctrl_dep();
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
rwsem_set_reader_owned(sem);
|
|
lockevent_inc(rwsem_rlock_fast);
|
|
return sem;
|
|
}
|
|
adjustment += RWSEM_FLAG_WAITERS;
|
|
}
|
|
trace_android_vh_alter_rwsem_list_add(
|
|
&waiter,
|
|
sem, &already_on_list);
|
|
if (!already_on_list)
|
|
rwsem_add_waiter(sem, &waiter);
|
|
|
|
/* we're now waiting on the lock, but no longer actively locking */
|
|
count = atomic_long_add_return(adjustment, &sem->count);
|
|
|
|
rwsem_cond_wake_waiter(sem, count, &wake_q);
|
|
trace_android_vh_rwsem_wake(sem);
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
|
|
if (!wake_q_empty(&wake_q))
|
|
wake_up_q(&wake_q);
|
|
|
|
trace_contention_begin(sem, LCB_F_READ);
|
|
|
|
/* wait to be given the lock */
|
|
trace_android_vh_rwsem_read_wait_start(sem);
|
|
for (;;) {
|
|
set_current_state(state);
|
|
if (!smp_load_acquire(&waiter.task)) {
|
|
/* Matches rwsem_mark_wake()'s smp_store_release(). */
|
|
break;
|
|
}
|
|
if (signal_pending_state(state, current)) {
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
if (waiter.task)
|
|
goto out_nolock;
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
/* Ordered by sem->wait_lock against rwsem_mark_wake(). */
|
|
break;
|
|
}
|
|
schedule_preempt_disabled();
|
|
lockevent_inc(rwsem_sleep_reader);
|
|
}
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
trace_android_vh_rwsem_read_wait_finish(sem);
|
|
lockevent_inc(rwsem_rlock);
|
|
trace_contention_end(sem, 0);
|
|
return sem;
|
|
|
|
out_nolock:
|
|
rwsem_del_wake_waiter(sem, &waiter, &wake_q);
|
|
__set_current_state(TASK_RUNNING);
|
|
trace_android_vh_rwsem_read_wait_finish(sem);
|
|
lockevent_inc(rwsem_rlock_fail);
|
|
trace_contention_end(sem, -EINTR);
|
|
return ERR_PTR(-EINTR);
|
|
}
|
|
|
|
/*
|
|
* Wait until we successfully acquire the write lock
|
|
*/
|
|
static struct rw_semaphore __sched *
|
|
rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
|
|
{
|
|
struct rwsem_waiter waiter;
|
|
DEFINE_WAKE_Q(wake_q);
|
|
bool already_on_list = false;
|
|
|
|
/* do optimistic spinning and steal lock if possible */
|
|
if (rwsem_can_spin_on_owner(sem) && rwsem_optimistic_spin(sem)) {
|
|
/* rwsem_optimistic_spin() implies ACQUIRE on success */
|
|
return sem;
|
|
}
|
|
|
|
/*
|
|
* Optimistic spinning failed, proceed to the slowpath
|
|
* and block until we can acquire the sem.
|
|
*/
|
|
waiter.task = current;
|
|
waiter.type = RWSEM_WAITING_FOR_WRITE;
|
|
waiter.timeout = jiffies + RWSEM_WAIT_TIMEOUT;
|
|
waiter.handoff_set = false;
|
|
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
trace_android_vh_alter_rwsem_list_add(
|
|
&waiter,
|
|
sem, &already_on_list);
|
|
if (!already_on_list)
|
|
rwsem_add_waiter(sem, &waiter);
|
|
|
|
/* we're now waiting on the lock */
|
|
if (rwsem_first_waiter(sem) != &waiter) {
|
|
rwsem_cond_wake_waiter(sem, atomic_long_read(&sem->count),
|
|
&wake_q);
|
|
if (!wake_q_empty(&wake_q)) {
|
|
/*
|
|
* We want to minimize wait_lock hold time especially
|
|
* when a large number of readers are to be woken up.
|
|
*/
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
wake_up_q(&wake_q);
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
}
|
|
} else {
|
|
atomic_long_or(RWSEM_FLAG_WAITERS, &sem->count);
|
|
}
|
|
|
|
trace_android_vh_rwsem_wake(sem);
|
|
/* wait until we successfully acquire the lock */
|
|
trace_android_vh_rwsem_write_wait_start(sem);
|
|
set_current_state(state);
|
|
trace_contention_begin(sem, LCB_F_WRITE);
|
|
|
|
for (;;) {
|
|
if (rwsem_try_write_lock(sem, &waiter)) {
|
|
/* rwsem_try_write_lock() implies ACQUIRE on success */
|
|
break;
|
|
}
|
|
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
|
|
if (signal_pending_state(state, current))
|
|
goto out_nolock;
|
|
|
|
/*
|
|
* After setting the handoff bit and failing to acquire
|
|
* the lock, attempt to spin on owner to accelerate lock
|
|
* transfer. If the previous owner is a on-cpu writer and it
|
|
* has just released the lock, OWNER_NULL will be returned.
|
|
* In this case, we attempt to acquire the lock again
|
|
* without sleeping.
|
|
*/
|
|
if (waiter.handoff_set) {
|
|
enum owner_state owner_state;
|
|
|
|
preempt_disable();
|
|
owner_state = rwsem_spin_on_owner(sem);
|
|
preempt_enable();
|
|
|
|
if (owner_state == OWNER_NULL)
|
|
goto trylock_again;
|
|
}
|
|
|
|
schedule();
|
|
lockevent_inc(rwsem_sleep_writer);
|
|
set_current_state(state);
|
|
trylock_again:
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
}
|
|
__set_current_state(TASK_RUNNING);
|
|
trace_android_vh_rwsem_write_wait_finish(sem);
|
|
raw_spin_unlock_irq(&sem->wait_lock);
|
|
lockevent_inc(rwsem_wlock);
|
|
trace_contention_end(sem, 0);
|
|
return sem;
|
|
|
|
out_nolock:
|
|
__set_current_state(TASK_RUNNING);
|
|
trace_android_vh_rwsem_write_wait_finish(sem);
|
|
raw_spin_lock_irq(&sem->wait_lock);
|
|
rwsem_del_wake_waiter(sem, &waiter, &wake_q);
|
|
lockevent_inc(rwsem_wlock_fail);
|
|
trace_contention_end(sem, -EINTR);
|
|
return ERR_PTR(-EINTR);
|
|
}
|
|
|
|
/*
|
|
* handle waking up a waiter on the semaphore
|
|
* - up_read/up_write has decremented the active part of count if we come here
|
|
*/
|
|
static struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
|
|
{
|
|
unsigned long flags;
|
|
DEFINE_WAKE_Q(wake_q);
|
|
|
|
raw_spin_lock_irqsave(&sem->wait_lock, flags);
|
|
|
|
if (!list_empty(&sem->wait_list))
|
|
rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q);
|
|
|
|
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
wake_up_q(&wake_q);
|
|
|
|
return sem;
|
|
}
|
|
|
|
/*
|
|
* downgrade a write lock into a read lock
|
|
* - caller incremented waiting part of count and discovered it still negative
|
|
* - just wake up any readers at the front of the queue
|
|
*/
|
|
static struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
|
|
{
|
|
unsigned long flags;
|
|
DEFINE_WAKE_Q(wake_q);
|
|
|
|
raw_spin_lock_irqsave(&sem->wait_lock, flags);
|
|
|
|
if (!list_empty(&sem->wait_list))
|
|
rwsem_mark_wake(sem, RWSEM_WAKE_READ_OWNED, &wake_q);
|
|
|
|
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
wake_up_q(&wake_q);
|
|
|
|
return sem;
|
|
}
|
|
|
|
/*
|
|
* lock for reading
|
|
*/
|
|
static inline int __down_read_common(struct rw_semaphore *sem, int state)
|
|
{
|
|
int ret = 0;
|
|
long count;
|
|
|
|
preempt_disable();
|
|
if (!rwsem_read_trylock(sem, &count)) {
|
|
if (IS_ERR(rwsem_down_read_slowpath(sem, count, state))) {
|
|
ret = -EINTR;
|
|
goto out;
|
|
}
|
|
DEBUG_RWSEMS_WARN_ON(!is_rwsem_reader_owned(sem), sem);
|
|
}
|
|
out:
|
|
preempt_enable();
|
|
return ret;
|
|
}
|
|
|
|
static inline void __down_read(struct rw_semaphore *sem)
|
|
{
|
|
__down_read_common(sem, TASK_UNINTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __down_read_interruptible(struct rw_semaphore *sem)
|
|
{
|
|
return __down_read_common(sem, TASK_INTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __down_read_killable(struct rw_semaphore *sem)
|
|
{
|
|
return __down_read_common(sem, TASK_KILLABLE);
|
|
}
|
|
|
|
static inline int __down_read_trylock(struct rw_semaphore *sem)
|
|
{
|
|
int ret = 0;
|
|
long tmp;
|
|
|
|
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
|
|
|
|
preempt_disable();
|
|
tmp = atomic_long_read(&sem->count);
|
|
while (!(tmp & RWSEM_READ_FAILED_MASK)) {
|
|
if (atomic_long_try_cmpxchg_acquire(&sem->count, &tmp,
|
|
tmp + RWSEM_READER_BIAS)) {
|
|
rwsem_set_reader_owned(sem);
|
|
ret = 1;
|
|
break;
|
|
}
|
|
}
|
|
preempt_enable();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* lock for writing
|
|
*/
|
|
static inline int __down_write_common(struct rw_semaphore *sem, int state)
|
|
{
|
|
if (unlikely(!rwsem_write_trylock(sem))) {
|
|
if (IS_ERR(rwsem_down_write_slowpath(sem, state)))
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void __down_write(struct rw_semaphore *sem)
|
|
{
|
|
__down_write_common(sem, TASK_UNINTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __down_write_killable(struct rw_semaphore *sem)
|
|
{
|
|
return __down_write_common(sem, TASK_KILLABLE);
|
|
}
|
|
|
|
static inline int __down_write_trylock(struct rw_semaphore *sem)
|
|
{
|
|
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
|
|
return rwsem_write_trylock(sem);
|
|
}
|
|
|
|
/*
|
|
* unlock after reading
|
|
*/
|
|
static inline void __up_read(struct rw_semaphore *sem)
|
|
{
|
|
long tmp;
|
|
|
|
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
|
|
DEBUG_RWSEMS_WARN_ON(!is_rwsem_reader_owned(sem), sem);
|
|
|
|
preempt_disable();
|
|
rwsem_clear_reader_owned(sem);
|
|
tmp = atomic_long_add_return_release(-RWSEM_READER_BIAS, &sem->count);
|
|
DEBUG_RWSEMS_WARN_ON(tmp < 0, sem);
|
|
if (unlikely((tmp & (RWSEM_LOCK_MASK|RWSEM_FLAG_WAITERS)) ==
|
|
RWSEM_FLAG_WAITERS)) {
|
|
clear_nonspinnable(sem);
|
|
rwsem_wake(sem);
|
|
}
|
|
preempt_enable();
|
|
}
|
|
|
|
/*
|
|
* unlock after writing
|
|
*/
|
|
static inline void __up_write(struct rw_semaphore *sem)
|
|
{
|
|
long tmp;
|
|
|
|
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
|
|
/*
|
|
* sem->owner may differ from current if the ownership is transferred
|
|
* to an anonymous writer by setting the RWSEM_NONSPINNABLE bits.
|
|
*/
|
|
DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) &&
|
|
!rwsem_test_oflags(sem, RWSEM_NONSPINNABLE), sem);
|
|
|
|
preempt_disable();
|
|
rwsem_clear_owner(sem);
|
|
tmp = atomic_long_fetch_add_release(-RWSEM_WRITER_LOCKED, &sem->count);
|
|
preempt_enable();
|
|
if (unlikely(tmp & RWSEM_FLAG_WAITERS))
|
|
rwsem_wake(sem);
|
|
}
|
|
|
|
/*
|
|
* downgrade write lock to read lock
|
|
*/
|
|
static inline void __downgrade_write(struct rw_semaphore *sem)
|
|
{
|
|
long tmp;
|
|
|
|
/*
|
|
* When downgrading from exclusive to shared ownership,
|
|
* anything inside the write-locked region cannot leak
|
|
* into the read side. In contrast, anything in the
|
|
* read-locked region is ok to be re-ordered into the
|
|
* write side. As such, rely on RELEASE semantics.
|
|
*/
|
|
DEBUG_RWSEMS_WARN_ON(rwsem_owner(sem) != current, sem);
|
|
tmp = atomic_long_fetch_add_release(
|
|
-RWSEM_WRITER_LOCKED+RWSEM_READER_BIAS, &sem->count);
|
|
rwsem_set_reader_owned(sem);
|
|
if (tmp & RWSEM_FLAG_WAITERS)
|
|
rwsem_downgrade_wake(sem);
|
|
}
|
|
|
|
#else /* !CONFIG_PREEMPT_RT */
|
|
|
|
#define RT_MUTEX_BUILD_MUTEX
|
|
#include "rtmutex.c"
|
|
|
|
#define rwbase_set_and_save_current_state(state) \
|
|
set_current_state(state)
|
|
|
|
#define rwbase_restore_current_state() \
|
|
__set_current_state(TASK_RUNNING)
|
|
|
|
#define rwbase_rtmutex_lock_state(rtm, state) \
|
|
__rt_mutex_lock(rtm, state)
|
|
|
|
#define rwbase_rtmutex_slowlock_locked(rtm, state) \
|
|
__rt_mutex_slowlock_locked(rtm, NULL, state)
|
|
|
|
#define rwbase_rtmutex_unlock(rtm) \
|
|
__rt_mutex_unlock(rtm)
|
|
|
|
#define rwbase_rtmutex_trylock(rtm) \
|
|
__rt_mutex_trylock(rtm)
|
|
|
|
#define rwbase_signal_pending_state(state, current) \
|
|
signal_pending_state(state, current)
|
|
|
|
#define rwbase_schedule() \
|
|
schedule()
|
|
|
|
#include "rwbase_rt.c"
|
|
|
|
void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
|
struct lock_class_key *key)
|
|
{
|
|
init_rwbase_rt(&(sem)->rwbase);
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
|
|
lockdep_init_map_wait(&sem->dep_map, name, key, 0, LD_WAIT_SLEEP);
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(__init_rwsem);
|
|
|
|
static inline void __down_read(struct rw_semaphore *sem)
|
|
{
|
|
rwbase_read_lock(&sem->rwbase, TASK_UNINTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __down_read_interruptible(struct rw_semaphore *sem)
|
|
{
|
|
return rwbase_read_lock(&sem->rwbase, TASK_INTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __down_read_killable(struct rw_semaphore *sem)
|
|
{
|
|
return rwbase_read_lock(&sem->rwbase, TASK_KILLABLE);
|
|
}
|
|
|
|
static inline int __down_read_trylock(struct rw_semaphore *sem)
|
|
{
|
|
return rwbase_read_trylock(&sem->rwbase);
|
|
}
|
|
|
|
static inline void __up_read(struct rw_semaphore *sem)
|
|
{
|
|
rwbase_read_unlock(&sem->rwbase, TASK_NORMAL);
|
|
}
|
|
|
|
static inline void __sched __down_write(struct rw_semaphore *sem)
|
|
{
|
|
rwbase_write_lock(&sem->rwbase, TASK_UNINTERRUPTIBLE);
|
|
}
|
|
|
|
static inline int __sched __down_write_killable(struct rw_semaphore *sem)
|
|
{
|
|
return rwbase_write_lock(&sem->rwbase, TASK_KILLABLE);
|
|
}
|
|
|
|
static inline int __down_write_trylock(struct rw_semaphore *sem)
|
|
{
|
|
return rwbase_write_trylock(&sem->rwbase);
|
|
}
|
|
|
|
static inline void __up_write(struct rw_semaphore *sem)
|
|
{
|
|
rwbase_write_unlock(&sem->rwbase);
|
|
}
|
|
|
|
static inline void __downgrade_write(struct rw_semaphore *sem)
|
|
{
|
|
rwbase_write_downgrade(&sem->rwbase);
|
|
}
|
|
|
|
/* Debug stubs for the common API */
|
|
#define DEBUG_RWSEMS_WARN_ON(c, sem)
|
|
|
|
static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
|
|
struct task_struct *owner)
|
|
{
|
|
}
|
|
|
|
static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
|
|
{
|
|
int count = atomic_read(&sem->rwbase.readers);
|
|
|
|
return count < 0 && count != READER_BIAS;
|
|
}
|
|
|
|
#endif /* CONFIG_PREEMPT_RT */
|
|
|
|
/*
|
|
* lock for reading
|
|
*/
|
|
void __sched down_read(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
|
}
|
|
EXPORT_SYMBOL(down_read);
|
|
|
|
int __sched down_read_interruptible(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
if (LOCK_CONTENDED_RETURN(sem, __down_read_trylock, __down_read_interruptible)) {
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(down_read_interruptible);
|
|
|
|
int __sched down_read_killable(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
if (LOCK_CONTENDED_RETURN(sem, __down_read_trylock, __down_read_killable)) {
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(down_read_killable);
|
|
|
|
/*
|
|
* trylock for reading -- returns 1 if successful, 0 if contention
|
|
*/
|
|
int down_read_trylock(struct rw_semaphore *sem)
|
|
{
|
|
int ret = __down_read_trylock(sem);
|
|
|
|
if (ret == 1)
|
|
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(down_read_trylock);
|
|
|
|
/*
|
|
* lock for writing
|
|
*/
|
|
void __sched down_write(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
EXPORT_SYMBOL(down_write);
|
|
|
|
/*
|
|
* lock for writing
|
|
*/
|
|
int __sched down_write_killable(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock,
|
|
__down_write_killable)) {
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(down_write_killable);
|
|
|
|
/*
|
|
* trylock for writing -- returns 1 if successful, 0 if contention
|
|
*/
|
|
int down_write_trylock(struct rw_semaphore *sem)
|
|
{
|
|
int ret = __down_write_trylock(sem);
|
|
|
|
if (ret == 1)
|
|
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(down_write_trylock);
|
|
|
|
/*
|
|
* release a read lock
|
|
*/
|
|
void up_read(struct rw_semaphore *sem)
|
|
{
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
__up_read(sem);
|
|
}
|
|
EXPORT_SYMBOL(up_read);
|
|
|
|
/*
|
|
* release a write lock
|
|
*/
|
|
void up_write(struct rw_semaphore *sem)
|
|
{
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
trace_android_vh_rwsem_write_finished(sem);
|
|
__up_write(sem);
|
|
}
|
|
EXPORT_SYMBOL(up_write);
|
|
|
|
/*
|
|
* downgrade write lock to read lock
|
|
*/
|
|
void downgrade_write(struct rw_semaphore *sem)
|
|
{
|
|
lock_downgrade(&sem->dep_map, _RET_IP_);
|
|
trace_android_vh_rwsem_write_finished(sem);
|
|
__downgrade_write(sem);
|
|
}
|
|
EXPORT_SYMBOL(downgrade_write);
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
void down_read_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
|
}
|
|
EXPORT_SYMBOL(down_read_nested);
|
|
|
|
int down_read_killable_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
if (LOCK_CONTENDED_RETURN(sem, __down_read_trylock, __down_read_killable)) {
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(down_read_killable_nested);
|
|
|
|
void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_);
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
EXPORT_SYMBOL(_down_write_nest_lock);
|
|
|
|
void down_read_non_owner(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
__down_read(sem);
|
|
/*
|
|
* The owner value for a reader-owned lock is mostly for debugging
|
|
* purpose only and is not critical to the correct functioning of
|
|
* rwsem. So it is perfectly fine to set it in a preempt-enabled
|
|
* context here.
|
|
*/
|
|
__rwsem_set_reader_owned(sem, NULL);
|
|
}
|
|
EXPORT_SYMBOL(down_read_non_owner);
|
|
|
|
void down_write_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
EXPORT_SYMBOL(down_write_nested);
|
|
|
|
int __sched down_write_killable_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock,
|
|
__down_write_killable)) {
|
|
rwsem_release(&sem->dep_map, _RET_IP_);
|
|
return -EINTR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(down_write_killable_nested);
|
|
|
|
void up_read_non_owner(struct rw_semaphore *sem)
|
|
{
|
|
DEBUG_RWSEMS_WARN_ON(!is_rwsem_reader_owned(sem), sem);
|
|
__up_read(sem);
|
|
}
|
|
EXPORT_SYMBOL(up_read_non_owner);
|
|
|
|
#endif
|