* Linux 6.6.140
@ 2026-05-17 15:39 Greg Kroah-Hartman
2026-05-17 15:39 ` Greg Kroah-Hartman
0 siblings, 1 reply; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-05-17 15:39 UTC (permalink / raw)
To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
I'm announcing the release of the 6.6.140 kernel.
All users of the 6.6 kernel series must upgrade.
The updated 6.6.y git tree can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-6.6.y
and can be browsed at the normal kernel.org git web browser:
https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary
thanks,
greg k-h
------------
Makefile | 2
arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi | 20
arch/arm64/crypto/aes-modes.S | 4
arch/arm64/kvm/arm.c | 5
arch/arm64/kvm/hyp/nvhe/setup.c | 6
arch/arm64/kvm/vgic/vgic-mmio-v2.c | 2
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2
arch/arm64/mm/mmu.c | 36 -
arch/loongarch/kernel/cpu-probe.c | 7
arch/loongarch/kernel/syscall.c | 3
arch/loongarch/pci/acpi.c | 5
arch/loongarch/pci/pci.c | 3
arch/parisc/kernel/syscalls/syscall.tbl | 2
arch/powerpc/kexec/Makefile | 2
arch/s390/kernel/debug.c | 5
arch/um/drivers/cow_user.c | 8
arch/x86/kernel/shstk.c | 45 +
arch/x86/kvm/hyperv.c | 2
arch/x86/kvm/mmu/mmu.c | 35 -
arch/x86/kvm/svm/nested.c | 56 +
arch/x86/kvm/svm/svm.c | 17
arch/x86/kvm/svm/svm.h | 2
arch/x86/kvm/x86.c | 62 +-
block/bio-integrity.c | 2
block/bio.c | 14
block/blk.h | 21
certs/extract-cert.c | 6
crypto/authencesn.c | 5
crypto/pcrypt.c | 7
drivers/acpi/cppc_acpi.c | 6
drivers/acpi/power.c | 2
drivers/acpi/scan.c | 2
drivers/acpi/video_detect.c | 8
drivers/base/core.c | 39 -
drivers/base/dd.c | 20
drivers/block/rbd.c | 6
drivers/block/zram/zram_drv.c | 3
drivers/bluetooth/virtio_bt.c | 39 +
drivers/bus/imx-weim.c | 2
drivers/char/ipmi/ipmi_si_intf.c | 70 +-
drivers/char/ipmi/ipmi_ssif.c | 36 +
drivers/char/tpm/tpm_tis_core.c | 11
drivers/clk/clk-rk808.c | 2
drivers/clk/imx/clk-imx8-acm.c | 3
drivers/clk/microchip/clk-mpfs-ccc.c | 6
drivers/cpuidle/cpuidle-powernv.c | 5
drivers/cpuidle/cpuidle-pseries.c | 5
drivers/crypto/atmel-aes.c | 2
drivers/crypto/atmel-ecc.c | 1
drivers/crypto/atmel-sha204a.c | 6
drivers/crypto/atmel-tdes.c | 8
drivers/crypto/caam/caamalg_qi2.c | 4
drivers/crypto/caam/caamhash.c | 4
drivers/crypto/ccree/cc_hash.c | 1
drivers/crypto/hisilicon/sec/sec_algs.c | 2
drivers/crypto/nx/nx-842.c | 47 -
drivers/crypto/nx/nx-842.h | 25
drivers/crypto/nx/nx-common-powernv.c | 31 -
drivers/crypto/nx/nx-common-pseries.c | 33 -
drivers/crypto/talitos.c | 254 +++++----
drivers/dma/idxd/device.c | 3
drivers/extcon/extcon-ptn5150.c | 14
drivers/firmware/google/framebuffer-coreboot.c | 12
drivers/gpio/gpiolib-of.c | 9
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 3
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 43 -
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 13
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 11
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 3
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 3
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 4
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 25
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 46 +
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 29 -
drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4
drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 11
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 7
drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 13
drivers/gpu/drm/drm_gem_framebuffer_helper.c | 4
drivers/gpu/drm/nouveau/nouveau_gem.c | 2
drivers/gpu/drm/radeon/ci_dpm.c | 9
drivers/gpu/drm/tiny/arcpgu.c | 3
drivers/hid/hid-playstation.c | 6
drivers/hwmon/corsair-psu.c | 4
drivers/hwmon/ltc2992.c | 43 +
drivers/i2c/i2c-core-of.c | 2
drivers/iio/adc/ad7768-1.c | 9
drivers/iio/adc/ti-ads7950.c | 11
drivers/infiniband/core/addr.c | 3
drivers/infiniband/hw/hns/hns_roce_qp.c | 7
drivers/infiniband/hw/mana/qp.c | 15
drivers/infiniband/hw/mlx4/srq.c | 4
drivers/infiniband/hw/mlx5/main.c | 1
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 4
drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 2
drivers/infiniband/sw/rxe/rxe_recv.c | 14
drivers/infiniband/sw/rxe/rxe_resp.c | 14
drivers/iommu/amd/amd_iommu_types.h | 2
drivers/iommu/amd/init.c | 2
drivers/iommu/amd/iommu.c | 18
drivers/iommu/iommufd/io_pagetable.c | 10
drivers/leds/rgb/leds-qcom-lpg.c | 7
drivers/md/dm-ioctl.c | 6
drivers/md/dm-raid1.c | 6
drivers/md/dm-verity-fec.c | 8
drivers/md/persistent-data/dm-btree-remove.c | 8
drivers/md/raid10.c | 6
drivers/md/raid5-cache.c | 48 +
drivers/md/raid5.c | 8
drivers/media/common/videobuf2/videobuf2-dma-sg.c | 1
drivers/media/dvb-frontends/dib8000.c | 4
drivers/media/i2c/imx219.c | 3
drivers/media/i2c/imx412.c | 2
drivers/media/i2c/ov08d10.c | 10
drivers/media/i2c/ov8856.c | 10
drivers/media/pci/saa7164/saa7164-core.c | 47 +
drivers/media/pci/zoran/zoran_card.c | 2
drivers/media/platform/amphion/vpu_v4l2.c | 9
drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 1
drivers/media/platform/ti/omap3isp/ispvideo.c | 1
drivers/media/rc/igorplugusb.c | 16
drivers/media/rc/streamzap.c | 12
drivers/media/rc/ttusbir.c | 13
drivers/media/rc/xbox_remote.c | 9
drivers/media/usb/uvc/uvc_queue.c | 3
drivers/mfd/stpmic1.c | 20
drivers/misc/ibmasm/ibmasmfs.c | 7
drivers/misc/ibmasm/lowlevel.c | 12
drivers/misc/ibmasm/remote.c | 5
drivers/mmc/core/block.c | 12
drivers/mmc/core/card.h | 5
drivers/mmc/core/queue.c | 8
drivers/mmc/core/queue.h | 3
drivers/mmc/core/quirks.h | 9
drivers/mmc/host/sdhci-of-dwcmshc.c | 19
drivers/mtd/devices/docg3.c | 8
drivers/mtd/spi-nor/debugfs.c | 4
drivers/mtd/spi-nor/sst.c | 50 +
drivers/net/bonding/bond_main.c | 6
drivers/net/can/usb/ucan.c | 2
drivers/net/ethernet/ibm/ibmveth.c | 22
drivers/net/ethernet/ibm/ibmveth.h | 1
drivers/net/ethernet/micrel/ks8851.h | 6
drivers/net/ethernet/micrel/ks8851_common.c | 69 +-
drivers/net/ethernet/micrel/ks8851_par.c | 15
drivers/net/ethernet/micrel/ks8851_spi.c | 11
drivers/net/ethernet/microsoft/mana/mana_en.c | 11
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 2
drivers/net/ethernet/stmicro/stmmac/common.h | 2
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 2
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 47 -
drivers/net/ethernet/wangxun/libwx/wx_hw.c | 7
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 3
drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 2
drivers/net/phy/mdio_bus.c | 4
drivers/net/wireless/ath/ath5k/base.c | 3
drivers/net/wireless/broadcom/b43/xmit.c | 3
drivers/net/wireless/broadcom/b43legacy/xmit.c | 3
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 6
drivers/net/wireless/marvell/mwifiex/init.c | 2
drivers/net/wireless/mediatek/mt76/mt76_connac.h | 6
drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 4
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 3
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 7
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3
drivers/net/wireless/mediatek/mt76/mt792x_regs.h | 4
drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 51 +
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 28
drivers/net/wireless/realtek/rtw88/pci.c | 3
drivers/net/wireless/rsi/rsi_common.h | 5
drivers/net/wwan/t7xx/t7xx_modem_ops.c | 20
drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c | 18
drivers/net/wwan/t7xx/t7xx_port_proxy.h | 2
drivers/nvme/host/apple.c | 6
drivers/nvme/host/core.c | 2
drivers/nvme/host/pci.c | 2
drivers/nvme/target/core.c | 2
drivers/of/base.c | 2
drivers/of/dynamic.c | 2
drivers/of/platform.c | 2
drivers/of/unittest.c | 1
drivers/parisc/lasi.c | 12
drivers/pci/endpoint/functions/pci-epf-mhi.c | 4
drivers/pci/endpoint/functions/pci-epf-ntb.c | 56 -
drivers/pci/pci.c | 7
drivers/pci/pcie/aer.c | 2
drivers/platform/x86/hp/hp-wmi.c | 5
drivers/power/supply/axp288_charger.c | 19
drivers/power/supply/max17042_battery.c | 2
drivers/pwm/pwm-imx-tpm.c | 8
drivers/regulator/act8945a-regulator.c | 3
drivers/regulator/bd9571mwv-regulator.c | 3
drivers/regulator/max77650-regulator.c | 2
drivers/regulator/mt6357-regulator.c | 2
drivers/regulator/rk808-regulator.c | 3
drivers/remoteproc/xlnx_r5_remoteproc.c | 20
drivers/rtc/rtc-ntxec.c | 2
drivers/scsi/sd.c | 1
drivers/spi/spi-at91-usart.c | 8
drivers/spi/spi-atmel.c | 8
drivers/spi/spi-bcm63xx.c | 8
drivers/spi/spi-bcmbca-hsspi.c | 4
drivers/spi/spi-cadence.c | 15
drivers/spi/spi-coldfire-qspi.c | 10
drivers/spi/spi-dln2.c | 8
drivers/spi/spi-fsl-espi.c | 10
drivers/spi/spi-fsl-spi.c | 14
drivers/spi/spi-img-spfi.c | 8
drivers/spi/spi-imx.c | 5
drivers/spi/spi-lantiq-ssc.c | 8
drivers/spi/spi-meson-spicc.c | 2
drivers/spi/spi-microchip-core-qspi.c | 41 -
drivers/spi/spi-mpc52xx.c | 3
drivers/spi/spi-mtk-nor.c | 4
drivers/spi/spi-omap2-mcspi.c | 8
drivers/spi/spi-orion.c | 9
drivers/spi/spi-qup.c | 8
drivers/spi/spi-rockchip.c | 4
drivers/spi/spi-rspi.c | 10
drivers/spi/spi-s3c64xx.c | 9
drivers/spi/spi-sh-hspi.c | 10
drivers/spi/spi-sprd.c | 8
drivers/spi/spi-sun4i.c | 80 +-
drivers/spi/spi-sun6i.c | 154 ++---
drivers/spi/spi-synquacer.c | 88 +--
drivers/spi/spi-tegra114.c | 8
drivers/spi/spi-tegra20-sflash.c | 8
drivers/spi/spi-ti-qspi.c | 97 +--
drivers/spi/spi-topcliff-pch.c | 6
drivers/spi/spi-uniphier.c | 212 +++----
drivers/spi/spi-zynq-qspi.c | 79 --
drivers/spi/spi-zynqmp-gqspi.c | 4
drivers/spi/spi.c | 63 +-
drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 4
drivers/staging/media/imx/imx-media-csi.c | 40 -
drivers/staging/vme_user/vme_fake.c | 2
drivers/target/target_core_configfs.c | 2
drivers/thermal/sprd_thermal.c | 4
drivers/thermal/thermal_core.c | 7
drivers/usb/chipidea/core.c | 45 -
drivers/usb/chipidea/otg.c | 7
drivers/usb/class/usblp.c | 3
drivers/usb/common/ulpi.c | 5
drivers/usb/dwc3/core.c | 12
drivers/usb/gadget/udc/omap_udc.c | 4
drivers/usb/host/xhci.c | 1
drivers/usb/serial/option.c | 4
drivers/usb/typec/tcpm/tcpm.c | 2
drivers/video/fbdev/core/fb_defio.c | 179 +++++-
drivers/video/fbdev/core/fbcon_rotate.c | 5
drivers/video/fbdev/udlfb.c | 31 +
fs/binfmt_elf.c | 2
fs/btrfs/ioctl.c | 5
fs/btrfs/space-info.c | 2
fs/ceph/dir.c | 6
fs/erofs/decompressor.c | 1
fs/erofs/dir.c | 28
fs/ext2/inode.c | 14
fs/ext4/extents.c | 15
fs/ext4/xattr.c | 6
fs/f2fs/data.c | 32 -
fs/f2fs/extent_cache.c | 17
fs/f2fs/f2fs.h | 2
fs/f2fs/inode.c | 2
fs/f2fs/node.c | 17
fs/f2fs/segment.c | 6
fs/f2fs/super.c | 11
fs/hfsplus/bfind.c | 51 +
fs/hfsplus/catalog.c | 4
fs/hfsplus/dir.c | 2
fs/hfsplus/hfsplus_fs.h | 9
fs/hfsplus/super.c | 6
fs/isofs/export.c | 2
fs/isofs/rock.c | 9
fs/notify/fsnotify.c | 2
fs/notify/inotify/inotify_user.c | 1
fs/notify/mark.c | 18
fs/ntfs3/run.c | 18
fs/ocfs2/aops.c | 74 +-
fs/smb/client/cached_dir.c | 8
fs/smb/client/cifsacl.c | 177 ++++--
fs/smb/client/cifsacl.h | 91 ---
fs/smb/client/smb2inode.c | 12
fs/smb/client/smb2misc.c | 3
fs/smb/client/smb2ops.c | 11
fs/smb/common/smbacl.h | 122 ++++
fs/smb/server/connection.c | 28
fs/smb/server/connection.h | 6
fs/smb/server/smb2pdu.c | 4
fs/smb/server/smbacl.c | 48 +
fs/smb/server/smbacl.h | 113 ----
fs/smb/server/transport_rdma.c | 5
fs/smb/server/transport_tcp.c | 25
fs/smb/server/vfs_cache.c | 40 +
fs/tracefs/event_inode.c | 14
fs/tracefs/inode.c | 5
fs/tracefs/internal.h | 3
fs/udf/misc.c | 8
fs/udf/super.c | 4
fs/userfaultfd.c | 2
fs/xfs/xfs_buf.c | 1
include/linux/bpf_verifier.h | 31 -
include/linux/damon.h | 2
include/linux/device.h | 45 +
include/linux/f2fs_fs.h | 1
include/linux/fb.h | 4
include/linux/fsnotify_backend.h | 1
include/linux/fwnode.h | 44 +
include/linux/mmap_lock.h | 6
include/linux/mmc/card.h | 1
include/linux/padata.h | 4
include/linux/printk.h | 13
include/linux/randomize_kstack.h | 26
include/linux/sched.h | 4
include/linux/tpm_eventlog.h | 9
include/linux/usb.h | 3
include/net/mana/mana.h | 1
include/net/mctp.h | 3
include/trace/events/rxrpc.h | 6
include/video/udlfb.h | 1
init/main.c | 1
io_uring/poll.c | 14
io_uring/timeout.c | 4
kernel/bpf/verifier.c | 236 +++++---
kernel/exit.c | 3
kernel/fork.c | 2
kernel/locking/rtmutex.c | 13
kernel/padata.c | 136 +---
kernel/regset.c | 6
kernel/sched/core.c | 2
kernel/sched/rt.c | 2
kernel/sched/sched.h | 2
kernel/taskstats.c | 1
kernel/trace/trace_probe.c | 6
kernel/trace/trace_probe.h | 4
kernel/tracepoint.c | 2
lib/crypto/mpi/mpicoder.c | 2
lib/scatterlist.c | 8
lib/test_hmm.c | 86 +--
lib/ts_kmp.c | 18
mm/damon/core.c | 37 +
mm/damon/lru_sort.c | 88 +--
mm/damon/reclaim.c | 88 +--
mm/damon/sysfs-schemes.c | 12
mm/hugetlb.c | 1
net/batman-adv/bat_iv_ogm.c | 85 ++-
net/batman-adv/bridge_loop_avoidance.c | 11
net/batman-adv/main.c | 1
net/batman-adv/tp_meter.c | 116 +++-
net/batman-adv/tp_meter.h | 1
net/batman-adv/types.h | 4
net/bluetooth/hci_conn.c | 19
net/bluetooth/hci_event.c | 45 +
net/bluetooth/l2cap_sock.c | 9
net/bluetooth/mgmt.c | 262 ++++++---
net/bluetooth/mgmt_util.c | 46 +
net/bluetooth/mgmt_util.h | 3
net/bridge/br_arp_nd_proxy.c | 8
net/bridge/br_fdb.c | 28
net/caif/cfsrvl.c | 14
net/ceph/auth.c | 4
net/ceph/mon_client.c | 2
net/core/flow_dissector.c | 13
net/core/rtnetlink.c | 1
net/ipv4/ah4.c | 29 -
net/ipv4/icmp.c | 8
net/ipv4/inet_connection_sock.c | 3
net/ipv6/ah6.c | 27
net/ipv6/exthdrs.c | 9
net/ipv6/ip6_gre.c | 5
net/ipv6/rpl_iptunnel.c | 9
net/ipv6/seg6_iptunnel.c | 12
net/ipv6/xfrm6_protocol.c | 4
net/mac80211/mlme.c | 9
net/mac80211/rx.c | 2
net/mctp/route.c | 8
net/mptcp/protocol.c | 3
net/mptcp/sockopt.c | 12
net/mptcp/subflow.c | 4
net/netfilter/nft_bitwise.c | 3
net/openvswitch/vport-netdev.c | 6
net/qrtr/ns.c | 86 ++-
net/rds/message.c | 20
net/rds/rdma.c | 4
net/rxrpc/ar-internal.h | 1
net/rxrpc/call_event.c | 27
net/rxrpc/conn_event.c | 44 +
net/rxrpc/io_thread.c | 24
net/rxrpc/rxkad.c | 112 +--
net/rxrpc/skbuff.c | 9
net/sched/sch_red.c | 2
net/sctp/socket.c | 9
net/smc/smc_clc.c | 4
net/strparser/strparser.c | 8
net/unix/af_unix.c | 3
net/vmw_vsock/af_vsock.c | 6
net/vmw_vsock/hyperv_transport.c | 4
net/vmw_vsock/virtio_transport_common.c | 11
net/xfrm/xfrm_state.c | 12
net/xfrm/xfrm_user.c | 1
security/selinux/hooks.c | 3
security/selinux/selinuxfs.c | 54 -
sound/aoa/codecs/onyx.c | 104 +--
sound/aoa/codecs/tas.c | 113 +---
sound/aoa/core/gpio-feature.c | 20
sound/aoa/core/gpio-pmf.c | 26
sound/aoa/soundbus/i2sbus/core.c | 12
sound/aoa/soundbus/i2sbus/pcm.c | 143 ++---
sound/core/control.c | 4
sound/core/misc.c | 44 -
sound/core/seq/oss/seq_oss_rw.c | 6
sound/core/seq/seq_clientmgr.c | 9
sound/core/seq/seq_clientmgr.h | 5
sound/core/seq/seq_ump_client.c | 4
sound/drivers/pcmtest.c | 19
sound/firewire/tascam/tascam-hwdep.c | 1
sound/pci/ctxfi/ctatc.c | 3
sound/pci/hda/cs35l56_hda.c | 19
sound/soc/amd/yc/acp6x-mach.c | 14
sound/soc/fsl/fsl_easrc.c | 2
sound/soc/intel/boards/bytcr_wm5102.c | 1
sound/soc/qcom/qdsp6/q6apm-dai.c | 1
sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 2
sound/soc/qcom/qdsp6/q6apm.c | 3
sound/soc/sof/compress.c | 3
sound/usb/6fire/control.c | 10
sound/usb/caiaq/control.c | 52 +
sound/usb/caiaq/device.c | 35 -
sound/usb/caiaq/input.c | 2
sound/usb/endpoint.c | 6
sound/usb/format.c | 2
sound/usb/midi2.c | 9
sound/usb/misc/ua101.c | 7
sound/usb/mixer.c | 7
sound/usb/mixer_quirks.c | 12
sound/usb/stream.c | 4
tools/accounting/getdelays.c | 41 +
tools/accounting/procacct.c | 40 +
tools/testing/ktest/ktest.pl | 2
tools/testing/selftests/bpf/progs/verifier_spill_fill.c | 281 ++++++++++
tools/testing/selftests/bpf/progs/verifier_subprog_precision.c | 87 ++-
tools/testing/selftests/bpf/verifier/precise.c | 38 -
tools/testing/selftests/mqueue/setting | 1
tools/testing/selftests/mqueue/settings | 1
448 files changed, 5508 insertions(+), 2882 deletions(-)
Aaro Koskinen (1):
USB: omap_udc: DMA: Don't enable burst 4 mode
Abdun Nihaal (1):
media: pci: zoran: fix potential memory leak in zoran_probe()
Alex Deucher (3):
drm/radeon: add missing revision check for CI
drm/amdgpu/pm: add missing revision check for CI
drm/amdgpu/pm: align Hawaii mclk workaround with radeon
Alexander Koskovich (1):
media: i2c: ov8856: free control handler on error in ov8856_init_controls()
Alistair Popple (1):
lib: test_hmm: evict device pages on file close to avoid use-after-free
Alysa Liu (2):
drm/amdkfd: Add upper bound check for num_of_nodes
drm/amdkfd: validate SVM ioctl nattr against buffer size
Amir Shetaia (1):
drm/amdkfd: Clear VRAM on allocation to prevent stale data exposure
Amit Kumar Mahapatra (1):
mtd: spi-nor: sst: Fix SST write failure
Amit Sunil Dhamne (1):
usb: typec: tcpm: reset internal port states on soft reset AMS
Andrea Mayer (2):
seg6: fix seg6 lwtunnel output redirect for L2 reduced encap mode
net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels
Andrii Nakryiko (10):
bpf: support non-r10 register spill/fill to/from stack in precision tracking
selftests/bpf: add stack access precision test
bpf: preserve STACK_ZERO slots on partial reg spills
selftests/bpf: validate STACK_ZERO is preserved on subreg spill
bpf: preserve constant zero when doing partial register restore
selftests/bpf: validate zero preservation for sub-slot loads
bpf: track aligned STACK_ZERO cases as imprecise spilled registers
selftests/bpf: validate precision logic in partial_stack_load_preserves_zeros
bpf: handle fake register spill to stack with BPF_ST_MEM instruction
selftests/bpf: validate fake register spill/fill precision backtracking logic
André Draszik (1):
power: supply: max17042: avoid overflow when determining health
Ankit Soni (1):
iommu/amd: serialize sequence allocation under concurrent TLB invalidations
Anshuman Khandual (1):
arm64/mm: Enable batched TLB flush in unmap_hotplug_range()
Ao Zhou (1):
net: rds: fix MR cleanup on copy error
Ard Biesheuvel (1):
crypto: nx - Migrate to scomp API
Arjan van de Ven (1):
drm/amdgpu: fix zero-size GDS range init on RDNA4
Arnd Bergmann (1):
tpm: avoid -Wunused-but-set-variable
Ashutosh Desai (1):
drm/gem: Fix inconsistent plane dimension calculation in drm_gem_fb_init_with_funcs()
Bartosz Golaszewski (1):
gpio: of: clear OF_POPULATED on hog nodes in remove path
Ben Levinsky (1):
remoteproc: xlnx: Only access buffer information if IPI is buffered
Ben Morris (1):
sctp: revalidate list cursor after sctp_sendmsg_to_asoc() in SCTP_SENDALL
Bence Csókás (1):
mtd: spi-nor: sst: Factor out common write operation to `sst_nor_write_data()`
Benjamin Cheng (7):
drm/amdgpu: Add bounds checking to ib_{get,set}_value
drm/amdgpu/vcn4: Prevent OOB reads when parsing IB
drm/amdgpu/vce: Prevent partial address patches
drm/amdgpu/vcn4: Prevent OOB reads when parsing dec msg
drm/amdgpu/vcn3: Prevent OOB reads when parsing dec msg
drm/amdgpu/vcn3: Avoid overflow on msg bound check
drm/amdgpu/vcn4: Avoid overflow on msg bound check
Bin Liu (1):
mmc: block: use single block write in retry
Bjoern Doebel (1):
smb: client: use kzalloc to zero-initialize security descriptor buffer
Catherine (1):
wifi: mac80211: drop stray 'static' from fast-RX rx_result
Cen Zhang (1):
f2fs: add READ_ONCE() for i_blocks in f2fs_update_inode()
Chaitanya Kulkarni (1):
nvmet: avoid recursive nvmet-wq flush in nvmet_ctrl_free
Chao Yu (2):
f2fs: fix to detect potential corrupted nid in free_nid_list
f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
Chen Ni (1):
media: i2c: imx219: Check return value of devm_gpiod_get_optional() in imx219_probe()
Chen Zhao (1):
IB/core: Fix zero dmac race in neighbor resolution
ChenXiaoSong (1):
smb: move some duplicate definitions to common/smbacl.h
Chia-Ming Chang (2):
md/raid5: fix soft lockup in retry_aligned_read()
inotify: fix watch count leak when fsnotify_add_inode_mark_locked() fails
Christian A. Ehrhardt (2):
lib/scatterlist: fix length calculations in extract_kvec_to_sg
lib/scatterlist: fix temp buffer in extract_user_to_sg()
Conor Dooley (1):
clk: microchip: mpfs-ccc: fix out of bounds access during output registration
Corey Minyard (5):
ipmi: Add limits to event and receive message requests
ipmi: Check event message buffer response for bad data
ipmi:si: Return state to normal if message allocation fails
ipmi:ssif: Fix a shutdown race
ipmi:ssif: Clean up kthread on errors
Cássio Gabriel (16):
ALSA: usb-audio: stop parsing UAC2 rates at MAX_NR_RATES
ALSA: usb-audio: Avoid false E-MU sample-rate notifications
ALSA: usb-audio: Fix Audio Advantage Micro II SPDIF switch
ALSA: aoa: i2sbus: fix OF node lifetime handling
ALSA: seq_oss: return full count for successful SEQ_FULLSIZE writes
ALSA: caiaq: Fix control_put() result and cache rollback
ALSA: 6fire: Fix input volume change detection
ALSA: pcmtest: Fix resource leaks in module init error paths
ALSA: usb-audio: midi2: Restart output URBs on resume
ALSA: usb-audio: Fix UAC3 cluster descriptor size check
ALSA: firewire-tascam: Do not drop unread control events
ASoC: Intel: bytcr_wm5102: Fix MCLK leak on platform_clock_control error
ALSA: aoa: i2sbus: clear stale prepared state
ALSA: hda: cs35l56: Propagate ASP TX source control errors
ALSA: core: Serialize deferred fasync state checks
ALSA: seq: Fix UMP group 16 filtering
DaeMyung Kang (1):
ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()
Daniel Hodges (2):
wifi: mwifiex: fix use-after-free in mwifiex_adapter_cleanup()
PCI: epf-mhi: Return 0, not remaining timeout, when eDMA ops complete
David Carlier (3):
eventfs: Hold eventfs_mutex and SRCU when remount walks events
tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func()
Bluetooth: hci_conn: fix potential UAF in create_big_sync
David Howells (6):
rxrpc: Fix memory leaks in rxkad_verify_response()
rxrpc: Fix rxkad crypto unalignment handling
rxrpc: Fix re-decryption of RESPONSE packets
rxrpc: Fix potential UAF after skb_unshare() failure
rxrpc: Fix rxrpc_input_call_event() to only unshare DATA packets
rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
David Lechner (1):
iio: adc: ti-ads7950: use iio_push_to_buffers_with_ts_unaligned()
David Windsor (1):
selinux: don't reserve xattr slot when we won't fill it
David Woodhouse (1):
KVM: arm64: vgic: Fix IIDR revision field extracted from wrong value
Dawei Feng (1):
rbd: fix null-ptr-deref when device_add_disk() fails
Deepanshu Kartikey (3):
ext4: fix bounds check in check_xattrs() to prevent out-of-bounds access
ALSA: caiaq: fix usb_dev refcount leak on probe failure
hfsplus: fix uninit-value by validating catalog record size
Denis M. Karpov (1):
userfaultfd: allow registration of ranges below mmap_min_addr
Deren Wu (1):
wifi: mt76: connac: introduce helper for mt7925 chipset
Dong Chenchen (1):
net: Fix icmp host relookup triggering ip_rt_bug
Douglas Anderson (4):
regset: use kvzalloc() for regset_get_alloc()
device property: Make modifications of fwnode "flags" thread safe
driver core: Don't let a device probe until it's ready
driver core: Add kernel-doc for DEV_FLAG_COUNT enum value
Dudu Lu (1):
vsock/virtio: fix accept queue count leak on transport mismatch
Eric Biggers (5):
crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
dm-verity-fec: correctly reject too-small FEC devices
dm-verity-fec: correctly reject too-small hash devices
net: ipv4: stop checking crypto_ahash_alignmask
net: ipv6: stop checking crypto_ahash_alignmask
Fabio Porcedda (1):
USB: serial: option: add Telit Cinterion LE910Cx compositions
Fan Wu (1):
media: mtk-jpeg: fix use-after-free in release path due to uncancelled work
Fedor Pchelkin (2):
wifi: rtw88: check for PCI upstream bridge existence
nvme-apple: drop invalid put of admin queue reference count
Felix Gu (2):
spi: meson-spicc: Fix double-put in remove path
usb: ulpi: fix memory leak on ulpi_register() error paths
Francesco Dolcini (1):
arm64: dts: ti: am62-verdin: Enable pullup for eMMC data pins
Gang Yan (2):
mptcp: sockopt: set timestamp flags on subflow socket, not msk
mptcp: fix scheduling with atomic in timestamp sockopt
Gao Xiang (1):
erofs: fix the out-of-bounds nameoff handling for trailing dirents
Greg Kroah-Hartman (8):
drm/nouveau: fix u32 overflow in pushbuf reloc bounds check
leds: qcom-lpg: Check for array overflow when selecting the high resolution
LoongArch: Add spectre boundry for syscall dispatch table
ipv6: rpl: reserve mac_len headroom when recompressed SRH grows
scsi: target: configfs: Bound snprintf() return in tg_pt_gp_members_show()
usb: usblp: fix heap leak in IEEE 1284 device ID via short response
usb: usblp: fix uninitialized heap leak via LPGETSTATUS ioctl
Linux 6.6.140
Guangshuo Li (3):
ALSA: pcmtest: fix reference leak on failed device registration
ACPI: scan: Use acpi_dev_put() in object add error paths
btrfs: fix double free in create_space_info() error path
Gustavo A. R. Silva (1):
crypto: nx - Avoid -Wflex-array-member-not-at-end warning
Hamza Mahfooz (1):
hv_sock: fix ARM64 support
Haoxiang Li (3):
crypto: ccree - fix a memory leak in cc_mac_digest()
media: omap3isp: drop the use count of v4l2 pipeline
xfs: fix a resource leak in xfs_alloc_buftarg()
Harin Lee (1):
ALSA: ctxfi: Add fallback to default RSR for S/PDIF
Helge Deller (1):
parisc: _llseek syscall is only available for 32-bit userspace
Heming Zhao (1):
ocfs2: split transactions in dio completion to avoid credit exhaustion
Herbert Xu (3):
padata: Fix pd UAF once and for all
padata: Remove comment for reorder_work
crypto: pcrypt - Fix handling of MAY_BACKLOG requests
Hongling Zeng (1):
parisc: Fix IRQ leak in LASI driver
Huacai Chen (2):
LoongArch: Show CPU vulnerabilites correctly
LoongArch: Use per-root-bridge PCIH flag to skip mem resource fixup
Hyunwoo Kim (1):
rxrpc: Also unshare DATA/RESPONSE packets when paged frags are present
Ilya Maximets (1):
openvswitch: vport: fix self-deadlock on release of tunnel ports
Jacqueline Wong (2):
tpm: tpm_tis: add error logging for data transfer
tpm: tpm_tis: stop transmit if retries are exhausted
Jamal Hadi Salim (1):
net/sched: sch_red: Replace direct dequeue call with peek and qdisc_dequeue_peeked
James Kim (1):
mtd: docg3: fix use-after-free in docg3_release()
Jann Horn (1):
exit: prevent preemption of oopsing TASK_DEAD task
Janne Grunau (1):
media: videobuf2: Set vma_flags in vb2_dma_sg_mmap
Jason Gunthorpe (4):
RDMA/hns: Fix unlocked call to hns_roce_qp_remove()
RDMA/mlx4: Fix resource leak on error in mlx4_ib_create_srq()
RDMA/ocrdma: Don't NULL deref uctx on errors in ocrdma_copy_pd_uresp()
RDMA/vmw_pvrdma: Fix double free on pvrdma_alloc_ucontext() error path
Jens Axboe (2):
io_uring/poll: ensure EPOLL_ONESHOT is propagated for EPOLL_URING_WAKE
io_uring/poll: fix multishot recv missing EOF on wakeup race
Jeongjun Park (1):
wifi: rsi: fix kthread lifetime race between self-exit and external-stop
Jesse.Zhang (1):
drm/amdgpu: Limit BO list entry count to prevent resource exhaustion
Jianpeng Chang (1):
Bluetooth: MGMT: Fix memory leak in set_ssp_complete
Jiawen Wu (3):
net: txgbe: fix firmware version check
net: txgbe: fix RTNL assertion warning when remove module
net: libwx: fix VF illegal register access
Jiexun Wang (4):
af_unix: Reject SIOCATMARK on non-stream sockets
batman-adv: reject new tp_meter sessions during teardown
batman-adv: stop caching unowned originator pointers in BAT IV
batman-adv: stop tp_meter sessions during mesh teardown
Jinjie Ruan (1):
ACPI: CPPC: Fix related_cpus inconsistency during CPU hotplug
Jiri Slaby (SUSE) (1):
wifi: ath5k: do not access array OOB
Johan Hovold (47):
spi: imx: fix use-after-free on unbind
rtc: ntxec: fix OF node reference imbalance
can: ucan: fix devres lifetime
spi: rockchip: fix controller deregistration
spi: zynqmp-gqspi: fix controller deregistration
spi: s3c64xx: fix NULL-deref on driver unbind
staging: vme_user: fix root device leak on init failure
clk: rk808: fix OF node reference imbalance
spi: topcliff-pch: fix use-after-free on unbind
spi: bcm63xx: fix controller deregistration
spi: atmel: fix controller deregistration
regulator: mt6357: fix OF node reference imbalance
regulator: max77650: fix OF node reference imbalance
regulator: rk808: fix OF node reference imbalance
regulator: act8945a: fix OF node reference imbalance
regulator: bd9571mwv: fix OF node reference imbalance
spi: lantiq-ssc: fix controller deregistration
spi: qup: fix controller deregistration
spi: at91-usart: fix controller deregistration
spi: dln2: fix controller deregistration
spi: s3c64xx: fix controller deregistration
spi: fsl-espi: fix controller deregistration
spi: omap2-mcspi: fix controller deregistration
spi: mtk-nor: fix controller deregistration
spi: sh-hspi: fix controller deregistration
spi: fsl: fix controller deregistration
spi: bcmbca-hsspi: fix controller deregistration
spi: coldfire-qspi: fix controller deregistration
spi: sprd: fix controller deregistration
spi: rspi: fix controller deregistration
spi: img-spfi: fix controller deregistration
spi: imx: fix runtime pm leak on probe deferral
spi: orion: fix runtime pm leak on unbind
spi: orion: fix clock imbalance on registration failure
spi: mpc52xx: fix use-after-free on unbind
spi: cadence: fix controller deregistration
spi: cadence: fix unclocked access on unbind
spi: fix resource leaks on device setup failure
spi: syncuacer: fix controller deregistration
spi: sun4i: fix controller deregistration
spi: ti-qspi: fix controller deregistration
spi: zynq-qspi: fix controller deregistration
spi: sun6i: fix controller deregistration
spi: tegra114: fix controller deregistration
spi: tegra20-sflash: fix controller deregistration
spi: uniphier: fix controller deregistration
spi: microchip-core-qspi: fix controller deregistration
Johannes Berg (1):
wifi: mac80211: remove station if connection prep fails
John B. Moore (2):
drm/amdgpu/gfx9: drop unnecessary 64-bit fence flag check in KIQ
drm/amdgpu/sdma4: replace BUG_ON with WARN_ON in fence emission
Jonathan Santos (1):
iio: adc: ad7768-1: fix one-shot mode data acquisition
Joseph Salisbury (2):
ASoC: fsl_easrc: fix comment typo
sched: Use u64 for bandwidth ratio calculations
Josh Hunt (1):
md/raid10: fix deadlock with check operation and nowait requests
Josh Law (1):
lib/ts_kmp: fix integer overflow in pattern length calculation
Junrui Luo (5):
md/raid5: validate payload size before accessing journal metadata
dm mirror: fix integer overflow in create_dirty_log()
md/raid10: fix divide-by-zero in setup_geo() with zero far_copies
RDMA/mlx5: Fix error path fall-through in mlx5_ib_dev_res_srq_init()
erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap()
Kai Ma (1):
netfilter: reject zero shift in nft_bitwise
Kai Zen (1):
net: rtnetlink: zero ifla_vf_broadcast to avoid stack infoleak in rtnl_fill_vfinfo
Keenan Dong (1):
rtmutex: Use waiter::task instead of current in remove_waiter()
Kevin Cheng (1):
KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
Koichiro Den (1):
PCI: endpoint: pci-epf-ntb: Remove duplicate resource teardown
Krishna Chomal (1):
platform/x86: hp-wmi: Ignore backlight and FnLock events
Krzysztof Kozlowski (1):
power: supply: axp288_charger: Do not cancel work before initializing it
Kumar Kartikeya Dwivedi (1):
bpf: Don't mark STACK_INVALID as STACK_MISC in mark_stack_slot_misc
Leon Yen (1):
wifi: mt76: mt7921: fix a potential clc buffer length underflow
Li Zetao (1):
spi: microchip-core-qspi: Use helper function devm_clk_get_enabled()
Linus Torvalds (1):
x86: shadow stacks: proper error handling for mmap lock
Long Li (1):
RDMA/mana_ib: Disable RX steering on RSS QP destroy
Longxuan Yu (1):
io_uring/poll: fix signed comparison in io_poll_get_ownership()
Luca Ceresoli (1):
drm/arcpgu: fix device node leak
Luiz Augusto von Dentz (3):
Bluetooth: MGMT: Fix possible UAFs
Bluetooth: hci_event: Fix OOB read and infinite loop in hci_le_create_big_complete_evt
Bluetooth: MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete
Lukas Wunner (2):
lib/crypto: mpi: Fix integer underflow in mpi_read_raw_from_sgl()
PCI/AER: Stop ruling out unbound devices as error source
Luke Wang (1):
mmc: core: Optimize time for secure erase/trim for some Kingston eMMCs
Luxiao Xu (1):
net: strparser: fix skb_head leak in strp_abort_strp()
Lyes Bourennani (1):
batman-adv: fix integer overflow on buff_pos
Manivannan Sadhasivam (5):
net: qrtr: ns: Fix use-after-free in driver remove()
net: qrtr: ns: Free the node during ctrl_cmd_bye()
net: qrtr: ns: Limit the maximum server registration per node
net: qrtr: ns: Limit the maximum number of lookups
net: qrtr: ns: Limit the total number of nodes
Maoyi Xie (1):
ip6_gre: Use cached t->net in ip6erspan_changelink().
Marc Zyngier (1):
KVM: arm64: Wake-up from WFI when iqrchip is in userspace
Marek Szyprowski (1):
wifi: brcmfmac: Fix potential use-after-free issue when stopping watchdog task
Marek Vasut (3):
mfd: stpmic1: Attempt system shutdown twice in case PMIC is confused
net: ks8851: Reinstate disabling of BHs around IRQ handler
net: ks8851: Avoid excess softirq scheduling
Mark Brown (1):
ASoC: SOF: Don't allow pointer operations on unconfigured streams
Matthias Fend (1):
media: i2c: ov08d10: fix image vertical start setting
Matthieu Baerts (NGI0) (1):
mptcp: fastclose msk when linger time is 0
Max Kellermann (1):
ceph: only d_add() negative dentries when they are unhashed
Michael Bommarito (12):
um: drivers: call kernel_strrchr() explicitly in cow_user.c
Bluetooth: virtio_bt: clamp rx length before skb_put
Bluetooth: virtio_bt: validate rx pkt_type header length
udf: reject descriptors with oversized CRC length
isofs: validate Rock Ridge CE continuation extent against volume size
isofs: validate block number from NFS file handle in isofs_export_iget
smb: client: validate dacloffset before building DACL pointers
RDMA/rxe: Reject non-8-byte ATOMIC_WRITE payloads
RDMA/rxe: Reject unknown opcodes before ICRC processing
ksmbd: require minimum ACE size in smb_check_perm_dacl()
smb: client: validate the whole DACL before rewriting it in cifsacl
xfrm: ah: account for ESN high bits in async callbacks
Michael Tretter (1):
media: staging: imx: request mbus_config in csi_start
Michal Kosiorek (1):
xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete
Michal Pecio (1):
usb: xhci: Make usb_host_endpoint.hcpriv survive endpoint_disable()
Miklos Szeredi (1):
fanotify: fix false positive on permission events
Mikulas Patocka (3):
dm-thin: fix metadata refcount underflow
dm: don't report warning when doing deferred remove
dm: fix a buffer overflow in ioctl processing
Ming Qian (1):
media: amphion: Fix race between m2m job_abort and device_run
Mingming Cao (1):
ibmveth: Disable GSO for packets with small MSS
Myeonghun Pak (1):
hwmon: (corsair-psu) Close HID device on probe errors
Naman Jain (2):
block: add pgmap check to biovec_phys_mergeable
block: relax pgmap check in bio_add_page for compatible zone device pages
Namjae Jeon (4):
smb: common: change the data type of num_aces to le16
ksmbd: use msleep instaed of schedule_timeout_interruptible()
ksmbd: replace connection list with hash table
ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger
Nan Li (1):
net/rds: handle zerocopy send cleanup before the message is queued
Nathan Chancellor (1):
extract-cert: Wrap key_pass with '#ifdef USE_PKCS11_ENGINE'
Nikolay Aleksandrov (1):
bonding: fix use-after-free due to enslave fail after slave array update
Norbert Szetei (1):
vsock: fix buffer size clamping order
Oliver Neukum (4):
media: rc: xbox_remote: heed DMA restrictions
media: rc: streamzap: Error handling in probe
media: rc: ttusbir: respect DMA coherency rules
media: rc: igorplugusb: heed coherency rules
Paolo Bonzini (2):
KVM: SVM: check validity of VMCB controls when returning from SMM
KVM: x86: check for nEPT/nNPT in slow flush hypercalls
Paul E. McKenney (1):
exit: Sleep at TASK_IDLE when waiting for application core dump
Paul Louvel (2):
crypto: talitos - fix SEC1 32k ahash request limitation
crypto: talitos - rename first/last to first_desc/last_desc
Pavel Begunkov (1):
io_uring/timeout: check unused sqe fields
Pavitra Jha (1):
net: wwan: t7xx: validate port_count against message length in t7xx_port_enum_msg_handler
Pei Xiao (2):
spi: zynq-qspi: Simplify clock handling with devm_clk_get_enabled()
spi: uniphier: Simplify clock handling with devm_clk_get_enabled()
Philip Yang (1):
drm/amdgpu: zero-initialize GART table on allocation
Qingfang Deng (1):
flow_dissector: do not dissect PPPoE PFC frames
Quan Zhou (1):
wifi: mt76: mt7921: fix ROC abort flow interruption in mt7921_roc_work
Quentin Perret (1):
KVM: arm64: Fix initialisation order in __pkvm_init_finalise()
Rafael J. Wysocki (1):
thermal: core: Fix thermal zone governor cleanup issues
Rajat Gupta (1):
fbdev: udlfb: add vm_ops to dlfb_ops_mmap to prevent use-after-free
Raphael Zimmer (2):
libceph: Prevent potential null-ptr-deref in ceph_handle_auth_reply()
libceph: Fix slab-out-of-bounds access in auth message processing
Ricardo Ribalda (1):
media: uvcvideo: Enable VB2_DMABUF for metadata stream
Rick Edgecombe (1):
x86/shstk: Prevent deadlock during shstk sigreturn
Robert Beckett (2):
nvme-pci: add NVME_QUIRK_DISABLE_WRITE_ZEROES for Kingston OM3SGP4
nvme: respect NVME_QUIRK_DISABLE_WRITE_ZEROES when wzsl is set
Rong Zhang (1):
Revert "ALSA: usb: Increase volume range that triggers a warning"
Ruide Cao (1):
ipv4: icmp: validate reply type before using icmp_pointers
Ruijie Li (2):
net/smc: avoid early lgr access in smc_clc_wait_msg
xfrm: provide message size for XFRM_MSG_MAPPING
Russell King (Oracle) (2):
net: stmmac: avoid shadowing global buf_sz
net: stmmac: rename STMMAC_GET_ENTRY() -> STMMAC_NEXT_ENTRY()
Ryan Roberts (1):
randomize_kstack: Maintain kstack_offset per task
Sakari Ailus (1):
staging: media: atomisp: Disallow all private IOCTLs
Sam Edwards (1):
net: stmmac: Prevent NULL deref when RX memory exhausted
Sang-Heon Jeon (1):
mm/hugetlb_cma: round up per_node before logging it
Sanjaikumar V S (1):
mtd: spi-nor: sst: Fix write enable before AAI sequence
Sanman Pradhan (2):
hwmon: (ltc2992) Clamp threshold writes to hardware range
hwmon: (ltc2992) Fix u32 overflow in power read path
Sean Christopherson (3):
KVM: x86: Defer non-architectural deliver of exception payload to userspace read
KVM: SVM: Explicitly mark vmcb01 dirty after modifying VMCB intercepts
KVM: x86: Fix shadow paging use-after-free due to unexpected GFN
Sean Wang (2):
wifi: mt76: mt792x: describe USB WFSYS reset with a descriptor
wifi: mt76: mt792x: fix mt7925u USB WFSYS reset handling
Selvarasu Ganesan (1):
usb: dwc3: Move GUID programming after PHY initialization
Seohyeon Maeng (1):
udf: fix partition descriptor append bookkeeping
SeongJae Park (6):
mm/damon/core: use time_in_range_open() for damos quota window start
mm/damon/sysfs-schemes: protect memcg_path kfree() with damon_sysfs_lock
mm/damon/core: disallow time-quota setting zero esz
mm/damon/core: implement damon_kdamond_pid()
mm/damon/lru_sort: detect and use fresh enabled and kdamond_pid values
mm/damon/reclaim: detect and use fresh enabled and kdamond_pid values
Sergey Senozhatsky (1):
zram: do not forget to endio for partial discard requests
Sergey Shtylyov (1):
media: dib8000: avoid division by 0 in dib8000_set_dds()
SeungJu Cheon (1):
sound: ua101: fix division by zero at probe
Shardul Bankar (2):
mptcp: use MPJoinSynAckHMacFailure for SynAck HMAC failure
mptcp: use MPTCP_RST_EMPTCP for ACK HMAC validation failure
Shawn Lin (1):
mmc: sdhci-of-dwcmshc: Disable clock before DLL configuration
Shivam Kalra (1):
ACPI: video: force native backlight on HP OMEN 16 (8A44)
Shrikanth Hegde (1):
cpuidle: powerpc: avoid double clear when breaking snooze
Shuai Xue (1):
PCI/AER: Clear only error bits in PCIe Device Status
Shuvam Pandey (1):
Bluetooth: hci_event: fix potential UAF in SSP passkey handlers
Shyam Prasad N (2):
cifs: abort open_cached_dir if we don't request leases
cifs: change_conf needs to be called for session setup
Simon Liebold (1):
selftests/mqueue: Fix incorrectly named file
Sina Hassani (1):
iommufd: Fix a race with concurrent allocation and unmap
Siwei Zhang (3):
Bluetooth: L2CAP: Fix null-ptr-deref in l2cap_sock_new_connection_cb()
Bluetooth: L2CAP: Fix null-ptr-deref in l2cap_sock_state_change_cb()
Bluetooth: L2CAP: Fix null-ptr-deref in l2cap_sock_get_sndtimeo_cb()
Sohei Koyama (1):
ext4: fix missing brelse() in ext4_xattr_inode_dec_ref_all()
Sourabh Jain (1):
powerpc/kdump: fix KASAN sanitization flag for core_$(BITS).o
Srinivas Kandagatla (3):
ASoC: qcom: q6apm-dai: reset queue ptr on trigger stop
ASoC: qcom: q6apm-lpass-dai: Fix multiple graph opens
ASoC: qcom: q6apm: remove child devices when apm is removed
Stefan Eichenberger (1):
clk: imx: imx8-acm: fix flags for acm clocks
Stefano Garzarella (1):
vsock/virtio: fix length and offset in tap skb for split packets
Stephen Smalley (2):
selinux: shrink critical section in sel_write_load()
selinux: prune /sys/fs/selinux/disable
Steven Rostedt (2):
ktest: Fix the month in the name of the failure directory
tracing/probes: Limit size of event probe to 3K
Sven Eckelmann (4):
batman-adv: bla: prevent use-after-free when deleting claims
batman-adv: bla: only purge non-released claims
batman-adv: bla: put backbone reference on failed claim hash insert
batman-adv: tp_meter: fix tp_num leak on kmalloc failure
T.J. Mercier (1):
HID: playstation: Clamp num_touch_reports
Takashi Iwai (9):
ALSA: usb-audio: Evaluate packsize caps at the right place
ALSA: core: Fix potential data race at fasync handling
ALSA: caiaq: Handle probe errors properly
ALSA: caiaq: Fix potentially leftover ep1_in_urb at error path
ALSA: caiaq: Don't abort when no input device is available
ALSA: usb-audio: Avoid potential endless loop in convert_chmap_v3()
ALSA: aoa: Use guard() for mutex locks
ALSA: misc: Use guard() for spin locks
ALSA: seq: Notify client and port info changes
Tejas Bharambe (1):
ext4: validate p_idx bounds in ext4_ext_correct_indexes
Thomas Fourier (1):
crypto: hisilicon - Fix dma_unmap_single() direction
Thomas Zimmermann (4):
firmware: google: framebuffer: Do not mark framebuffer as busy
fbdev: defio: Disconnect deferred I/O from the lifetime of struct fb_info
firmware: google: framebuffer: Do not unregister platform device
fbcon: Avoid OOB font access if console rotation fails
Thorsten Blum (11):
crypto: atmel-aes - Fix 3-page memory leak in atmel_aes_buff_cleanup
crypto: atmel-ecc - Release client on allocation failure
crypto: atmel-tdes - fix DMA sync direction
crypto: atmel-sha204a - Fix potential UAF and memory leak in remove path
thermal/drivers/sprd: Fix temperature clamping in sprd_thm_temp_to_rawdata
thermal/drivers/sprd: Fix raw temperature clamping in sprd_thm_rawdata_to_temp
ALSA: aoa: Skip devices with no codecs in i2sbus_resume()
crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx
printk: add print_hex_dump_devel()
crypto: caam - guard HMAC key hex dumps in hash_digest_key
crypto: nx - fix context leak in nx842_crypto_free_ctx
Tobias Gaertner (2):
ntfs3: add buffer boundary checks to run_unpack()
ntfs3: fix integer overflow in run_unpack() volume boundary check
Tommaso Soncin (1):
ASoC: amd: yc: Add HP OMEN Gaming Laptop 16-ap0xxx product line in quirk table
Tristan Madani (2):
wifi: b43legacy: enforce bounds check on firmware key index in RX path
wifi: b43: enforce bounds check on firmware key index in b43_rx()
Tudor Ambarus (1):
mtd: spi-nor: debugfs: fix out-of-bounds read in spi_nor_params_show()
Tvrtko Ursulin (1):
drm/amdgpu: Use vmemdup_array_user in amdgpu_bo_create_list_entry_array
Tyllis Xu (3):
misc: ibmasm: fix OOB MMIO read in ibmasm_handle_mouse_interrupt()
ibmasm: fix OOB reads in command_file_write due to missing size checks
ibmasm: fix heap over-read in ibmasm_send_i2o_message()
Uros Bizjak (1):
iommu/amd: Use atomic64_inc_return() in iommu.c
Uwe Kleine-König (2):
mtd: docg3: Convert to platform remove callback returning void
spi: spi-ti-qspi: Convert to platform remove callback returning void
Vasiliy Kovalev (1):
ext2: reject inodes with zero i_nlink and valid mode in ext2_iget()
Vasily Gorbik (1):
s390/debug: Reject zero-length input in debug_input_flush_fn()
Vinicius Costa Gomes (2):
dmaengine: idxd: Fix crash when the event log is disabled
dmaengine: idxd: Fix leaking event log memory
Viorel Suman (OSS) (1):
pwm: imx-tpm: Count the number of enabled channels in probe
Wang Jun (1):
media: saa7164: add ioremap return checks and cleanups
Wenmeng Liu (1):
media: i2c: imx412: Assert reset GPIO during probe
Wentao Guan (1):
LoongArch: Fix potential ADE in loongson_gpu_fixup_dma_hang()
Wentao Liang (1):
of: unittest: fix use-after-free in testdrv_probe()
Xu Yang (3):
usb: chipidea: otg: not wait vbus drop if use role_switch
usb: chipidea: core: allow ci_irq_handler() handle both ID and VBUS change
extcon: ptn5150: handle pending IRQ events during system resume
Yang Xiuwei (1):
scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails
Yang Yingliang (6):
spi: synquacer: switch to use modern name
spi: sun4i: switch to use modern name
spi: spi-ti-qspi: switch to use modern name
spi: zynq-qspi: switch to use modern name
spi: sun6i: switch to use modern name
spi: uniphier: switch to use modern name
Yi Cong (1):
wifi: rtl8xxxu: fix potential use of uninitialized value
Yilin Zhu (1):
ipv6: xfrm6: release dst on error in xfrm6_rcv_encap()
Yiyang Chen (2):
tools/accounting: handle truncated taskstats netlink messages
taskstats: set version in TGID exit notifications
Yochai Eisenrich (1):
btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
Yongpeng Yang (4):
f2fs: fix fiemap boundary handling when read extent cache is incomplete
f2fs: fix incorrect multidevice info in trace_f2fs_map_blocks()
f2fs: fix node_cnt race between extent node destroy and writeback
f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
Yosry Ahmed (11):
KVM: nSVM: Mark all of vmcb02 dirty when restoring nested state
KVM: nSVM: Sync NextRIP to cached vmcb12 after VMRUN of L2
KVM: nSVM: Sync interrupt shadow to cached vmcb12 after VMRUN of L2
KVM: nSVM: Ensure AVIC is inhibited when restoring a vCPU to guest mode
KVM: nSVM: Use vcpu->arch.cr2 when updating vmcb12 on nested #VMEXIT
KVM: nSVM: Always inject a #GP if mapping VMCB12 fails on nested VMRUN
KVM: nSVM: Clear GIF on nested #VMEXIT(INVALID)
KVM: nSVM: Clear EVENTINJ fields in vmcb12 on nested #VMEXIT
KVM: nSVM: Clear tracking of L1->L2 NMI and soft IRQ on nested #VMEXIT
KVM: nSVM: Add missing consistency check for EFER, CR0, CR4, and CS
KVM: nSVM: Add missing consistency check for nCR3 validity
Yuan Zhaoming (1):
net: mctp: fix don't require received header reserved bits to be zero
Yucheng Lu (1):
crypto: authencesn - reject short ahash digests during instance creation
Yussuf Khalil (1):
drm/amd/display: Do not skip unrelated mode changes in DSC validation
Zhengchuan Liang (2):
net: caif: clear client service pointer on teardown
net: bridge: use a stable FDB dst snapshot in RCU readers
Zhenzhong Wu (1):
tcp: call sk_data_ready() after listener migration
Zilin Guan (1):
hfsplus: fix held lock freed on hfsplus_fill_super()
Ziqing Chen (1):
ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
Zisen Ye (2):
smb/client: fix out-of-bounds read in smb2_compound_op()
smb/client: fix out-of-bounds read in symlink_data()
hkbinbin (1):
RDMA/rxe: Validate pad and ICRC before payload_size() in rxe_rcv
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Linux 6.6.140
2026-05-17 15:39 Linux 6.6.140 Greg Kroah-Hartman
@ 2026-05-17 15:39 ` Greg Kroah-Hartman
0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-05-17 15:39 UTC (permalink / raw)
To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
diff --git a/Makefile b/Makefile
index d00b00f0c54f..870dd6c30c67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 6
-SUBLEVEL = 139
+SUBLEVEL = 140
EXTRAVERSION =
NAME = Pinguïn Aangedreven
diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
index e98d043e5746..7c1063f5b18b 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi
@@ -507,16 +507,16 @@ AM62X_IOPAD(0x15c, PIN_INPUT, 0) /* (AB22) MDIO0_MDIO */ /* ETH_1_MDIO, SODIMM
/* On-module eMMC */
pinctrl_sdhci0: main-mmc0-default-pins {
pinctrl-single,pins = <
- AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */
- AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */
- AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */
- AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (AA1) MMC0_DAT1 */
- AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (AA3) MMC0_DAT2 */
- AM62X_IOPAD(0x208, PIN_INPUT, 0) /* (Y4) MMC0_DAT3 */
- AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (AB2) MMC0_DAT4 */
- AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (AC1) MMC0_DAT5 */
- AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (AD2) MMC0_DAT6 */
- AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (AC2) MMC0_DAT7 */
+ AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */
+ AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */
+ AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */
+ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (AA1) MMC0_DAT1 */
+ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (AA3) MMC0_DAT2 */
+ AM62X_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (Y4) MMC0_DAT3 */
+ AM62X_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (AB2) MMC0_DAT4 */
+ AM62X_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (AC1) MMC0_DAT5 */
+ AM62X_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (AD2) MMC0_DAT6 */
+ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (AC2) MMC0_DAT7 */
>;
};
diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S
index 0e834a2c062c..e793478f37c1 100644
--- a/arch/arm64/crypto/aes-modes.S
+++ b/arch/arm64/crypto/aes-modes.S
@@ -838,7 +838,7 @@ AES_FUNC_START(aes_mac_update)
encrypt_block v0, w2, x1, x7, w8
eor v0.16b, v0.16b, v4.16b
cmp w3, wzr
- csinv x5, x6, xzr, eq
+ csinv w5, w6, wzr, eq
cbz w5, .Lmacout
encrypt_block v0, w2, x1, x7, w8
st1 {v0.16b}, [x4] /* return dg */
@@ -852,7 +852,7 @@ AES_FUNC_START(aes_mac_update)
eor v0.16b, v0.16b, v1.16b /* ..and xor with dg */
subs w3, w3, #1
- csinv x5, x6, xzr, eq
+ csinv w5, w6, wzr, eq
cbz w5, .Lmacout
.Lmacenc:
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index fe4314af8eec..3ae529e967c7 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -557,6 +557,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF);
+
+ irq_lines |= (!irqchip_in_kernel(v->kvm) &&
+ (kvm_timer_should_notify_user(v) ||
+ kvm_pmu_should_notify_user(v)));
+
return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
&& !kvm_arm_vcpu_stopped(v) && !v->arch.pause);
}
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 0d5e0a89ddce..29df463ab350 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -284,15 +284,15 @@ void __noreturn __pkvm_init_finalise(void)
};
pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops;
- ret = fix_host_ownership();
+ ret = fix_hyp_pgtable_refcnt();
if (ret)
goto out;
- ret = fix_hyp_pgtable_refcnt();
+ ret = hyp_create_pcpu_fixmap();
if (ret)
goto out;
- ret = hyp_create_pcpu_fixmap();
+ ret = fix_host_ownership();
if (ret)
goto out;
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v2.c b/arch/arm64/kvm/vgic/vgic-mmio-v2.c
index e070cda86e12..d26155b7ce1e 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v2.c
@@ -91,7 +91,7 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
* migration from old kernels to new kernels with legacy
* userspace.
*/
- reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
+ reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val);
switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 7c0b23415ad9..4c470f20adab 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -167,7 +167,7 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
return -EINVAL;
- reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
+ reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val);
switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index d6411f7f0b72..8c5cbf4c858d 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -870,10 +870,14 @@ static void unmap_hotplug_pte_range(pmd_t *pmdp, unsigned long addr,
WARN_ON(!pte_present(pte));
pte_clear(&init_mm, addr, ptep);
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ /* CONT blocks are not supported in the vmemmap */
+ WARN_ON(pte_cont(pte));
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
free_hotplug_page_range(pte_page(pte),
PAGE_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
} while (addr += PAGE_SIZE, addr < end);
}
@@ -894,15 +898,14 @@ static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,
WARN_ON(!pmd_present(pmd));
if (pmd_sect(pmd)) {
pmd_clear(pmdp);
-
- /*
- * One TLBI should be sufficient here as the PMD_SIZE
- * range is mapped with a single block entry.
- */
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ /* CONT blocks are not supported in the vmemmap */
+ WARN_ON(pmd_cont(pmd));
+ flush_tlb_kernel_range(addr, addr + PMD_SIZE);
free_hotplug_page_range(pmd_page(pmd),
PMD_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
continue;
}
WARN_ON(!pmd_table(pmd));
@@ -927,15 +930,12 @@ static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,
WARN_ON(!pud_present(pud));
if (pud_sect(pud)) {
pud_clear(pudp);
-
- /*
- * One TLBI should be sufficient here as the PUD_SIZE
- * range is mapped with a single block entry.
- */
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ flush_tlb_kernel_range(addr, addr + PUD_SIZE);
free_hotplug_page_range(pud_page(pud),
PUD_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
continue;
}
WARN_ON(!pud_table(pud));
@@ -965,6 +965,7 @@ static void unmap_hotplug_p4d_range(pgd_t *pgdp, unsigned long addr,
static void unmap_hotplug_range(unsigned long addr, unsigned long end,
bool free_mapped, struct vmem_altmap *altmap)
{
+ unsigned long start = addr;
unsigned long next;
pgd_t *pgdp, pgd;
@@ -986,6 +987,9 @@ static void unmap_hotplug_range(unsigned long addr, unsigned long end,
WARN_ON(!pgd_present(pgd));
unmap_hotplug_p4d_range(pgdp, addr, next, free_mapped, altmap);
} while (addr = next, addr < end);
+
+ if (!free_mapped)
+ flush_tlb_kernel_range(start, end);
}
static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,
diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
index 55320813ee08..26e66a77da66 100644
--- a/arch/loongarch/kernel/cpu-probe.c
+++ b/arch/loongarch/kernel/cpu-probe.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
+#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/export.h>
@@ -327,3 +328,9 @@ void cpu_probe(void)
cpu_report();
}
+
+ssize_t cpu_show_spectre_v1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "Mitigation: __user pointer sanitization\n");
+}
diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c
index b4c5acd7aa3b..f4e3bd219b1d 100644
--- a/arch/loongarch/kernel/syscall.c
+++ b/arch/loongarch/kernel/syscall.c
@@ -9,6 +9,7 @@
#include <linux/entry-common.h>
#include <linux/errno.h>
#include <linux/linkage.h>
+#include <linux/nospec.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
@@ -55,7 +56,7 @@ void noinstr do_syscall(struct pt_regs *regs)
nr = syscall_enter_from_user_mode(regs, nr);
if (nr < NR_syscalls) {
- syscall_fn = sys_call_table[nr];
+ syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6],
regs->regs[7], regs->regs[8], regs->regs[9]);
}
diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
index 1da4dc46df43..2d584a59a2a0 100644
--- a/arch/loongarch/pci/acpi.c
+++ b/arch/loongarch/pci/acpi.c
@@ -61,11 +61,16 @@ static void acpi_release_root_info(struct acpi_pci_root_info *ci)
static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
{
int status;
+ unsigned long long pci_h = 0;
struct resource_entry *entry, *tmp;
struct acpi_device *device = ci->bridge;
status = acpi_pci_probe_root_resources(ci);
if (status > 0) {
+ acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
+ if (pci_h)
+ return status;
+
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (entry->res->flags & IORESOURCE_MEM) {
entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40);
diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c
index 70485b167cfa..a25307d6aee8 100644
--- a/arch/loongarch/pci/pci.c
+++ b/arch/loongarch/pci/pci.c
@@ -133,6 +133,9 @@ static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
crtc_reg = regbase;
crtc_offset = 0x400;
break;
+ default:
+ iounmap(regbase);
+ return;
}
for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index 73f560e30957..443ce9a05367 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -154,7 +154,7 @@
# 137 was afs_syscall
138 common setfsuid sys_setfsuid
139 common setfsgid sys_setfsgid
-140 common _llseek sys_llseek
+140 32 _llseek sys_llseek
141 common getdents sys_getdents compat_sys_getdents
142 common _newselect sys_select compat_sys_select
143 common flock sys_flock
diff --git a/arch/powerpc/kexec/Makefile b/arch/powerpc/kexec/Makefile
index 0c2abe7f9908..1146af73a866 100644
--- a/arch/powerpc/kexec/Makefile
+++ b/arch/powerpc/kexec/Makefile
@@ -14,4 +14,4 @@ GCOV_PROFILE_core_$(BITS).o := n
KCOV_INSTRUMENT_core_$(BITS).o := n
UBSAN_SANITIZE_core_$(BITS).o := n
KASAN_SANITIZE_core.o := n
-KASAN_SANITIZE_core_$(BITS) := n
+KASAN_SANITIZE_core_$(BITS).o := n
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index a85e0c3e7027..cbe209fe0df1 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -1434,6 +1434,11 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
char input_buf[1];
int rc = user_len;
+ if (!user_len) {
+ rc = -EINVAL;
+ goto out;
+ }
+
if (user_len > 0x10000)
user_len = 0x10000;
if (*offset != 0) {
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
index 29b46581ddd1..dc1d1bcd85ec 100644
--- a/arch/um/drivers/cow_user.c
+++ b/arch/um/drivers/cow_user.c
@@ -15,6 +15,12 @@
#include "cow.h"
#include "cow_sys.h"
+/*
+ * arch/um/Makefile remaps strrchr to kernel_strrchr; call the kernel
+ * name directly to avoid glibc >= 2.43's C23 strrchr macro.
+ */
+char *kernel_strrchr(const char *, int);
+
#define PATH_LEN_V1 256
/* unsigned time_t works until year 2106 */
@@ -153,7 +159,7 @@ static int absolutize(char *to, int size, char *from)
errno);
return -1;
}
- slash = strrchr(from, '/');
+ slash = kernel_strrchr(from, '/');
if (slash != NULL) {
*slash = '\0';
if (chdir(from)) {
diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c
index 19e4db582fb6..ba93c4e6a231 100644
--- a/arch/x86/kernel/shstk.c
+++ b/arch/x86/kernel/shstk.c
@@ -18,6 +18,7 @@
#include <linux/sizes.h>
#include <linux/user.h>
#include <linux/syscalls.h>
+#include <linux/highmem.h>
#include <asm/msr.h>
#include <asm/fpu/xstate.h>
#include <asm/fpu/types.h>
@@ -262,11 +263,29 @@ static int put_shstk_data(u64 __user *addr, u64 data)
return 0;
}
+/* Copy from aligned address in userspace without risk of page fault. */
+static int shstk_copy_user_gup(unsigned long *ldata, unsigned long __user *addr)
+{
+ struct page *page;
+ void *kaddr;
+
+ mmap_assert_locked(current->mm);
+ if (get_user_pages((unsigned long)addr, 1, 0, &page) != 1)
+ return -EFAULT;
+
+ kaddr = kmap_local_page(page);
+ *ldata = *(unsigned long *)(kaddr + offset_in_page(addr));
+ kunmap_local(kaddr);
+ put_page(page);
+
+ return 0;
+}
+
static int get_shstk_data(unsigned long *data, unsigned long __user *addr)
{
unsigned long ldata;
- if (unlikely(get_user(ldata, addr)))
+ if (shstk_copy_user_gup(&ldata, addr))
return -EFAULT;
if (!(ldata & SHSTK_DATA_BIT))
@@ -296,7 +315,6 @@ static int shstk_pop_sigframe(unsigned long *ssp)
{
struct vm_area_struct *vma;
unsigned long token_addr;
- bool need_to_check_vma;
int err = 1;
/*
@@ -308,25 +326,21 @@ static int shstk_pop_sigframe(unsigned long *ssp)
if (!IS_ALIGNED(*ssp, 8))
return -EINVAL;
- need_to_check_vma = PAGE_ALIGN(*ssp) == *ssp;
-
- if (need_to_check_vma)
- mmap_read_lock_killable(current->mm);
+ if (mmap_read_lock_killable(current->mm))
+ return -EINTR;
err = get_shstk_data(&token_addr, (unsigned long __user *)*ssp);
if (unlikely(err))
goto out_err;
- if (need_to_check_vma) {
- vma = find_vma(current->mm, *ssp);
- if (!vma || !(vma->vm_flags & VM_SHADOW_STACK)) {
- err = -EFAULT;
- goto out_err;
- }
-
- mmap_read_unlock(current->mm);
+ vma = find_vma(current->mm, *ssp);
+ if (!vma || !(vma->vm_flags & VM_SHADOW_STACK)) {
+ err = -EFAULT;
+ goto out_err;
}
+ mmap_read_unlock(current->mm);
+
/* Restore SSP aligned? */
if (unlikely(!IS_ALIGNED(token_addr, 8)))
return -EINVAL;
@@ -339,8 +353,7 @@ static int shstk_pop_sigframe(unsigned long *ssp)
return 0;
out_err:
- if (need_to_check_vma)
- mmap_read_unlock(current->mm);
+ mmap_read_unlock(current->mm);
return err;
}
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 223f4fa6a849..96c03f95212e 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -1987,7 +1987,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
* flush). Translate the address here so the memory can be uniformly
* read with kvm_read_guest().
*/
- if (!hc->fast && is_guest_mode(vcpu)) {
+ if (!hc->fast && mmu_is_nested(vcpu)) {
hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, NULL);
if (unlikely(hc->ingpa == INVALID_GPA))
return HV_STATUS_INVALID_HYPERCALL_INPUT;
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 0dc804149b0f..774bc26b8235 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -182,6 +182,8 @@ struct kmem_cache *mmu_page_header_cache;
static struct percpu_counter kvm_total_used_mmu_pages;
static void mmu_spte_set(u64 *sptep, u64 spte);
+static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
+ u64 *spte, struct list_head *invalid_list);
struct kvm_mmu_role_regs {
const unsigned long cr0;
@@ -1194,19 +1196,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
rmap_remove(kvm, sptep);
}
-static void drop_large_spte(struct kvm *kvm, u64 *sptep, bool flush)
-{
- struct kvm_mmu_page *sp;
-
- sp = sptep_to_sp(sptep);
- WARN_ON_ONCE(sp->role.level == PG_LEVEL_4K);
-
- drop_spte(kvm, sptep);
-
- if (flush)
- kvm_flush_remote_tlbs_sptep(kvm, sptep);
-}
-
/*
* Write-protect on the specified @sptep, @pt_protect indicates whether
* spte write-protection is caused by protecting shadow page table.
@@ -2350,7 +2339,8 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
{
union kvm_mmu_page_role role;
- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
+ if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
+ spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
return ERR_PTR(-EEXIST);
role = kvm_mmu_child_role(sptep, direct, access);
@@ -2428,13 +2418,16 @@ static void __link_shadow_page(struct kvm *kvm,
BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
- /*
- * If an SPTE is present already, it must be a leaf and therefore
- * a large one. Drop it, and flush the TLB if needed, before
- * installing sp.
- */
- if (is_shadow_present_pte(*sptep))
- drop_large_spte(kvm, sptep, flush);
+ if (is_shadow_present_pte(*sptep)) {
+ struct kvm_mmu_page *parent_sp;
+ LIST_HEAD(invalid_list);
+
+ parent_sp = sptep_to_sp(sptep);
+ WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K);
+
+ mmu_page_zap_pte(kvm, parent_sp, sptep, &invalid_list);
+ kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, true);
+ }
spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index eebfea132285..2be600876e0c 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -129,11 +129,13 @@ void recalc_intercepts(struct vcpu_svm *svm)
struct vmcb_ctrl_area_cached *g;
unsigned int i;
- vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
+ vmcb_mark_dirty(svm->vmcb01.ptr, VMCB_INTERCEPTS);
if (!is_guest_mode(&svm->vcpu))
return;
+ vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
+
c = &svm->vmcb->control;
h = &svm->vmcb01.ptr->control;
g = &svm->nested.ctl;
@@ -263,6 +265,10 @@ static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu,
if (CC((control->nested_ctl & SVM_NESTED_CTL_NP_ENABLE) && !npt_enabled))
return false;
+ if (CC((control->nested_ctl & SVM_NESTED_CTL_NP_ENABLE) &&
+ !kvm_vcpu_is_legal_gpa(vcpu, control->nested_cr3)))
+ return false;
+
if (CC(!nested_svm_check_bitmap_pa(vcpu, control->msrpm_base_pa,
MSRPM_SIZE)))
return false;
@@ -302,6 +308,10 @@ static bool __nested_vmcb_check_save(struct kvm_vcpu *vcpu,
CC(!(save->cr0 & X86_CR0_PE)) ||
CC(kvm_vcpu_is_illegal_gpa(vcpu, save->cr3)))
return false;
+
+ if (CC((save->cs.attrib & SVM_SELECTOR_L_MASK) &&
+ (save->cs.attrib & SVM_SELECTOR_DB_MASK)))
+ return false;
}
/* Note, SVM doesn't have any additional restrictions on CR4. */
@@ -388,6 +398,8 @@ static void __nested_copy_vmcb_save_to_cache(struct vmcb_save_area_cached *to,
* Copy only fields that are validated, as we need them
* to avoid TOC/TOU races.
*/
+ to->cs = from->cs;
+
to->efer = from->efer;
to->cr0 = from->cr0;
to->cr3 = from->cr3;
@@ -403,6 +415,15 @@ void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm,
__nested_copy_vmcb_save_to_cache(&svm->nested.save, save);
}
+int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu)
+{
+ if (!nested_vmcb_check_save(vcpu) ||
+ !nested_vmcb_check_controls(vcpu))
+ return -EINVAL;
+
+ return 0;
+}
+
/*
* Synchronize fields that are written by the processor, so that
* they can be copied back into the vmcb12.
@@ -412,6 +433,7 @@ void nested_sync_control_from_vmcb02(struct vcpu_svm *svm)
u32 mask;
svm->nested.ctl.event_inj = svm->vmcb->control.event_inj;
svm->nested.ctl.event_inj_err = svm->vmcb->control.event_inj_err;
+ svm->nested.ctl.int_state = svm->vmcb->control.int_state;
/* Only a few fields of int_ctl are written by the processor. */
mask = V_IRQ_MASK | V_TPR_MASK;
@@ -860,12 +882,9 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
}
vmcb12_gpa = svm->vmcb->save.rax;
- ret = kvm_vcpu_map(vcpu, gpa_to_gfn(vmcb12_gpa), &map);
- if (ret == -EINVAL) {
+ if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcb12_gpa), &map)) {
kvm_inject_gp(vcpu, 0);
return 1;
- } else if (ret) {
- return kvm_skip_emulated_instruction(vcpu);
}
ret = kvm_skip_emulated_instruction(vcpu);
@@ -878,12 +897,14 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
- if (!nested_vmcb_check_save(vcpu) ||
- !nested_vmcb_check_controls(vcpu)) {
+ if (nested_svm_check_cached_vmcb12(vcpu) < 0) {
vmcb12->control.exit_code = SVM_EXIT_ERR;
vmcb12->control.exit_code_hi = -1u;
vmcb12->control.exit_info_1 = 0;
vmcb12->control.exit_info_2 = 0;
+ vmcb12->control.event_inj = 0;
+ vmcb12->control.event_inj_err = 0;
+ svm_set_gif(svm, false);
goto out;
}
@@ -910,8 +931,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
out_exit_err:
svm->nested.nested_run_pending = 0;
- svm->nmi_l1_to_l2 = false;
- svm->soft_int_injected = false;
svm->vmcb->control.exit_code = SVM_EXIT_ERR;
svm->vmcb->control.exit_code_hi = -1u;
@@ -1002,7 +1021,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
vmcb12->save.efer = svm->vcpu.arch.efer;
vmcb12->save.cr0 = kvm_read_cr0(vcpu);
vmcb12->save.cr3 = kvm_read_cr3(vcpu);
- vmcb12->save.cr2 = vmcb02->save.cr2;
+ vmcb12->save.cr2 = vcpu->arch.cr2;
vmcb12->save.cr4 = svm->vcpu.arch.cr4;
vmcb12->save.rflags = kvm_get_rflags(vcpu);
vmcb12->save.rip = kvm_rip_read(vcpu);
@@ -1024,9 +1043,9 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
if (guest_can_use(vcpu, X86_FEATURE_NRIPS))
vmcb12->control.next_rip = vmcb02->control.next_rip;
+ vmcb12->control.event_inj = 0;
+ vmcb12->control.event_inj_err = 0;
vmcb12->control.int_ctl = svm->nested.ctl.int_ctl;
- vmcb12->control.event_inj = svm->nested.ctl.event_inj;
- vmcb12->control.event_inj_err = svm->nested.ctl.event_inj_err;
if (!kvm_pause_in_guest(vcpu->kvm)) {
vmcb01->control.pause_filter_count = vmcb02->control.pause_filter_count;
@@ -1151,6 +1170,10 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
if (unlikely(vmcb01->save.rflags & X86_EFLAGS_TF))
kvm_queue_exception(&(svm->vcpu), DB_VECTOR);
+ /* Drop tracking for L1->L2 injected NMIs and soft IRQs */
+ svm->nmi_l1_to_l2 = false;
+ svm->soft_int_injected = false;
+
/*
* Un-inhibit the AVIC right away, so that other vCPUs can start
* to benefit from it right away.
@@ -1752,6 +1775,12 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
svm_switch_vmcb(svm, &svm->nested.vmcb02);
nested_vmcb02_prepare_control(svm, svm->vmcb->save.rip, svm->vmcb->save.cs.base);
+ /*
+ * Any previously restored state (e.g. KVM_SET_SREGS) would mark fields
+ * dirty in vmcb01 instead of vmcb02, so mark all of vmcb02 dirty here.
+ */
+ vmcb_mark_all_dirty(svm->vmcb);
+
/*
* While the nested guest CR3 is already checked and set by
* KVM_SET_SREGS, it was set when nested state was yet loaded,
@@ -1765,6 +1794,9 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
svm->nested.force_msr_bitmap_recalc = true;
+ if (kvm_vcpu_apicv_active(vcpu))
+ kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
+
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
ret = 0;
out_free:
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index ff65fe738733..31e901661b4e 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2494,6 +2494,9 @@ static int invlpga_interception(struct kvm_vcpu *vcpu)
gva_t gva = kvm_rax_read(vcpu);
u32 asid = kvm_rcx_read(vcpu);
+ if (nested_svm_check_permissions(vcpu))
+ return 1;
+
/* FIXME: Handle an address size prefix. */
if (!is_long_mode(vcpu))
gva = (u32)gva;
@@ -4339,6 +4342,16 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
svm_complete_interrupts(vcpu);
+ /*
+ * Update the cache after completing interrupts to get an accurate
+ * NextRIP, e.g. when re-injecting a soft interrupt.
+ *
+ * FIXME: Rework svm_get_nested_state() to not pull data from the
+ * cache (except for maybe int_ctl).
+ */
+ if (is_guest_mode(vcpu))
+ svm->nested.ctl.next_rip = svm->vmcb->control.next_rip;
+
return svm_exit_handlers_fastpath(vcpu);
}
@@ -4804,6 +4817,10 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
vmcb12 = map.hva;
nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
+
+ if (nested_svm_check_cached_vmcb12(vcpu) < 0)
+ goto unmap_save;
+
ret = enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa, vmcb12, false);
if (ret)
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 0b4344595db3..cf0a516a9f8c 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -115,6 +115,7 @@ struct kvm_vmcb_info {
};
struct vmcb_save_area_cached {
+ struct vmcb_seg cs;
u64 efer;
u64 cr4;
u64 cr3;
@@ -611,6 +612,7 @@ static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
int nested_svm_exit_handled(struct vcpu_svm *svm);
int nested_svm_check_permissions(struct kvm_vcpu *vcpu);
+int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu);
int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
bool has_error_code, u32 error_code);
int nested_svm_exit_special(struct vcpu_svm *svm);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6463a62d0001..3838b7336590 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -695,9 +695,6 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
vcpu->arch.exception.error_code = error_code;
vcpu->arch.exception.has_payload = has_payload;
vcpu->arch.exception.payload = payload;
- if (!is_guest_mode(vcpu))
- kvm_deliver_exception_payload(vcpu,
- &vcpu->arch.exception);
return;
}
@@ -5147,18 +5144,8 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
return 0;
}
-static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
- struct kvm_vcpu_events *events)
+static struct kvm_queued_exception *kvm_get_exception_to_save(struct kvm_vcpu *vcpu)
{
- struct kvm_queued_exception *ex;
-
- process_nmi(vcpu);
-
-#ifdef CONFIG_KVM_SMM
- if (kvm_check_request(KVM_REQ_SMI, vcpu))
- process_smi(vcpu);
-#endif
-
/*
* KVM's ABI only allows for one exception to be migrated. Luckily,
* the only time there can be two queued exceptions is if there's a
@@ -5169,21 +5156,46 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
if (vcpu->arch.exception_vmexit.pending &&
!vcpu->arch.exception.pending &&
!vcpu->arch.exception.injected)
- ex = &vcpu->arch.exception_vmexit;
- else
- ex = &vcpu->arch.exception;
+ return &vcpu->arch.exception_vmexit;
+
+ return &vcpu->arch.exception;
+}
+
+static void kvm_handle_exception_payload_quirk(struct kvm_vcpu *vcpu)
+{
+ struct kvm_queued_exception *ex = kvm_get_exception_to_save(vcpu);
/*
- * In guest mode, payload delivery should be deferred if the exception
- * will be intercepted by L1, e.g. KVM should not modifying CR2 if L1
- * intercepts #PF, ditto for DR6 and #DBs. If the per-VM capability,
- * KVM_CAP_EXCEPTION_PAYLOAD, is not set, userspace may or may not
- * propagate the payload and so it cannot be safely deferred. Deliver
- * the payload if the capability hasn't been requested.
+ * If KVM_CAP_EXCEPTION_PAYLOAD is disabled, then (prematurely) deliver
+ * the pending exception payload when userspace saves *any* vCPU state
+ * that interacts with exception payloads to avoid breaking userspace.
+ *
+ * Architecturally, KVM must not deliver an exception payload until the
+ * exception is actually injected, e.g. to avoid losing pending #DB
+ * information (which VMX tracks in the VMCS), and to avoid clobbering
+ * state if the exception is never injected for whatever reason. But
+ * if KVM_CAP_EXCEPTION_PAYLOAD isn't enabled, then userspace may or
+ * may not propagate the payload across save+restore, and so KVM can't
+ * safely defer delivery of the payload.
*/
if (!vcpu->kvm->arch.exception_payload_enabled &&
ex->pending && ex->has_payload)
kvm_deliver_exception_payload(vcpu, ex);
+}
+
+static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
+ struct kvm_vcpu_events *events)
+{
+ struct kvm_queued_exception *ex = kvm_get_exception_to_save(vcpu);
+
+ process_nmi(vcpu);
+
+#ifdef CONFIG_KVM_SMM
+ if (kvm_check_request(KVM_REQ_SMI, vcpu))
+ process_smi(vcpu);
+#endif
+
+ kvm_handle_exception_payload_quirk(vcpu);
memset(events, 0, sizeof(*events));
@@ -5364,6 +5376,8 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
{
unsigned long val;
+ kvm_handle_exception_payload_quirk(vcpu);
+
memset(dbgregs, 0, sizeof(*dbgregs));
memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
kvm_get_dr(vcpu, 6, &val);
@@ -11396,6 +11410,8 @@ static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
if (vcpu->arch.guest_state_protected)
goto skip_protected_regs;
+ kvm_handle_exception_payload_quirk(vcpu);
+
kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 15e444b2fcc1..dc6a9b0fab36 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -134,6 +134,8 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
struct bio_vec *bv = &bip->bip_vec[bip->bip_vcnt - 1];
bool same_page = false;
+ if (!zone_device_pages_compatible(bv->bv_page, page))
+ return 0;
if (bvec_try_merge_hw_page(q, bv, page, len, offset,
&same_page)) {
bip->bip_iter.bi_size += len;
diff --git a/block/bio.c b/block/bio.c
index b197abbaebc4..14aefb190545 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1098,11 +1098,15 @@ int bio_add_page(struct bio *bio, struct page *page,
if (bio->bi_iter.bi_size > UINT_MAX - len)
return 0;
- if (bio->bi_vcnt > 0 &&
- bvec_try_merge_page(&bio->bi_io_vec[bio->bi_vcnt - 1],
- page, len, offset, &same_page)) {
- bio->bi_iter.bi_size += len;
- return len;
+ if (bio->bi_vcnt > 0) {
+ struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
+
+ if (!zone_device_pages_compatible(bv->bv_page, page))
+ return 0;
+ if (bvec_try_merge_page(bv, page, len, offset, &same_page)) {
+ bio->bi_iter.bi_size += len;
+ return len;
+ }
}
if (bio->bi_vcnt >= bio->bi_max_vecs)
diff --git a/block/blk.h b/block/blk.h
index 67915b04b3c1..13243d9fb896 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -95,6 +95,8 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
if (addr1 + vec1->bv_len != addr2)
return false;
+ if (!zone_device_pages_have_same_pgmap(vec1->bv_page, vec2->bv_page))
+ return false;
if (xen_domain() && !xen_biovec_phys_mergeable(vec1, vec2->bv_page))
return false;
if ((addr1 | mask) != ((addr2 + vec2->bv_len - 1) | mask))
@@ -102,6 +104,25 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
return true;
}
+/*
+ * Check if two pages from potentially different zone device pgmaps can
+ * coexist as separate bvec entries in the same bio.
+ *
+ * The block DMA iterator (blk_dma_map_iter_start) caches the P2PDMA mapping
+ * state from the first segment and applies it to all subsequent segments, so
+ * P2PDMA pages from different pgmaps must not be mixed in the same bio.
+ *
+ * Other zone device types (FS_DAX, GENERIC) use the same dma_map_phys() path
+ * as normal RAM. PRIVATE and COHERENT pages never appear in bios.
+ */
+static inline bool zone_device_pages_compatible(const struct page *a,
+ const struct page *b)
+{
+ if (is_pci_p2pdma_page(a) || is_pci_p2pdma_page(b))
+ return zone_device_pages_have_same_pgmap(a, b);
+ return true;
+}
+
static inline bool __bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{
diff --git a/certs/extract-cert.c b/certs/extract-cert.c
index 7d6d468ed612..54ecd1024274 100644
--- a/certs/extract-cert.c
+++ b/certs/extract-cert.c
@@ -43,7 +43,9 @@ void format(void)
exit(2);
}
+#ifdef USE_PKCS11_ENGINE
static const char *key_pass;
+#endif
static BIO *wb;
static char *cert_dst;
static bool verbose;
@@ -135,7 +137,9 @@ int main(int argc, char **argv)
if (verbose_env && strchr(verbose_env, '1'))
verbose = true;
- key_pass = getenv("KBUILD_SIGN_PIN");
+#ifdef USE_PKCS11_ENGINE
+ key_pass = getenv("KBUILD_SIGN_PIN");
+#endif
if (argc != 3)
format();
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index eeda044a0f5f..55833cfea09a 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -397,6 +397,11 @@ static int crypto_authenc_esn_create(struct crypto_template *tmpl,
auth = crypto_spawn_ahash_alg(&ctx->auth);
auth_base = &auth->base;
+ if (auth->digestsize > 0 && auth->digestsize < 4) {
+ err = -EINVAL;
+ goto err_free_inst;
+ }
+
err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
crypto_attr_alg_name(tb[2]), 0, mask);
if (err)
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index 7fc79e7dce44..71a0c74eb634 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -69,6 +69,9 @@ static void pcrypt_aead_done(void *data, int err)
struct pcrypt_request *preq = aead_request_ctx(req);
struct padata_priv *padata = pcrypt_request_padata(preq);
+ if (err == -EINPROGRESS)
+ return;
+
padata->info = err;
padata_do_serial(padata);
@@ -82,7 +85,7 @@ static void pcrypt_aead_enc(struct padata_priv *padata)
ret = crypto_aead_encrypt(req);
- if (ret == -EINPROGRESS)
+ if (ret == -EINPROGRESS || ret == -EBUSY)
return;
padata->info = ret;
@@ -133,7 +136,7 @@ static void pcrypt_aead_dec(struct padata_priv *padata)
ret = crypto_aead_decrypt(req);
- if (ret == -EINPROGRESS)
+ if (ret == -EINPROGRESS || ret == -EBUSY)
return;
padata->info = ret;
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 0bf3861cf79b..018a98d87bcb 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -347,7 +347,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
end:
if (cmd == CMD_WRITE) {
if (unlikely(ret)) {
- for_each_online_cpu(i) {
+ for_each_possible_cpu(i) {
struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i);
if (!desc)
@@ -509,13 +509,13 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data)
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY;
- for_each_online_cpu(i) {
+ for_each_possible_cpu(i) {
if (i == cpu)
continue;
match_cpc_ptr = per_cpu(cpc_desc_ptr, i);
if (!match_cpc_ptr)
- goto err_fault;
+ continue;
match_pdomain = &(match_cpc_ptr->domain_info);
if (match_pdomain->domain != pdomain->domain)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index ff5fcd541e50..9f9f580e393c 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -986,7 +986,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
return device;
err:
- acpi_release_power_resource(&device->dev);
+ acpi_dev_put(device);
return NULL;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 5b5986e10c2d..2892219c7afd 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1862,7 +1862,7 @@ static int acpi_add_single_object(struct acpi_device **child,
result = acpi_device_add(device);
if (result) {
- acpi_device_release(&device->dev);
+ acpi_dev_put(device);
return result;
}
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index e96afb1622f9..962720aafeda 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -820,6 +820,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Z830"),
},
},
+ {
+ .callback = video_detect_force_native,
+ /* HP OMEN Gaming Laptop 16-n0xxx */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-n0xxx"),
+ },
+ },
/*
* Models which have nvidia-ec-wmi support, but should not use it.
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a192ce5bb8f9..3c172e6d3fe0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -182,7 +182,7 @@ void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode)
if (fwnode->dev)
return;
- fwnode->flags |= FWNODE_FLAG_NOT_DEVICE;
+ fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);
fwnode_links_purge_consumers(fwnode);
fwnode_for_each_available_child_node(fwnode, child)
@@ -228,7 +228,7 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,
if (fwnode->dev && fwnode->dev->bus)
return;
- fwnode->flags |= FWNODE_FLAG_NOT_DEVICE;
+ fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);
__fwnode_links_move_consumers(fwnode, new_sup);
fwnode_for_each_available_child_node(fwnode, child)
@@ -1013,7 +1013,7 @@ static void device_links_missing_supplier(struct device *dev)
static bool dev_is_best_effort(struct device *dev)
{
return (fw_devlink_best_effort && dev->can_match) ||
- (dev->fwnode && (dev->fwnode->flags & FWNODE_FLAG_BEST_EFFORT));
+ (dev->fwnode && fwnode_test_flag(dev->fwnode, FWNODE_FLAG_BEST_EFFORT));
}
static struct fwnode_handle *fwnode_links_check_suppliers(
@@ -1729,11 +1729,11 @@ bool fw_devlink_is_strict(void)
static void fw_devlink_parse_fwnode(struct fwnode_handle *fwnode)
{
- if (fwnode->flags & FWNODE_FLAG_LINKS_ADDED)
+ if (fwnode_test_flag(fwnode, FWNODE_FLAG_LINKS_ADDED))
return;
fwnode_call_int_op(fwnode, add_links);
- fwnode->flags |= FWNODE_FLAG_LINKS_ADDED;
+ fwnode_set_flag(fwnode, FWNODE_FLAG_LINKS_ADDED);
}
static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode)
@@ -1892,7 +1892,7 @@ static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
struct device *dev;
bool ret;
- if (!(fwnode->flags & FWNODE_FLAG_INITIALIZED))
+ if (!fwnode_test_flag(fwnode, FWNODE_FLAG_INITIALIZED))
return false;
dev = get_dev_from_fwnode(fwnode);
@@ -1951,10 +1951,10 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
* We aren't trying to find all cycles. Just a cycle between con and
* sup_handle.
*/
- if (sup_handle->flags & FWNODE_FLAG_VISITED)
+ if (fwnode_test_flag(sup_handle, FWNODE_FLAG_VISITED))
return false;
- sup_handle->flags |= FWNODE_FLAG_VISITED;
+ fwnode_set_flag(sup_handle, FWNODE_FLAG_VISITED);
/* Termination condition. */
if (sup_handle == con_handle) {
@@ -2024,7 +2024,7 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
}
out:
- sup_handle->flags &= ~FWNODE_FLAG_VISITED;
+ fwnode_clear_flag(sup_handle, FWNODE_FLAG_VISITED);
put_device(sup_dev);
put_device(con_dev);
put_device(par_dev);
@@ -2077,7 +2077,7 @@ static int fw_devlink_create_devlink(struct device *con,
* When such a flag is set, we can't create device links where P is the
* supplier of C as that would delay the probe of C.
*/
- if (sup_handle->flags & FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD &&
+ if (fwnode_test_flag(sup_handle, FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD) &&
fwnode_is_ancestor_of(sup_handle, con->fwnode))
return -EINVAL;
@@ -2100,7 +2100,7 @@ static int fw_devlink_create_devlink(struct device *con,
else
flags = FW_DEVLINK_FLAGS_PERMISSIVE;
- if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
+ if (fwnode_test_flag(sup_handle, FWNODE_FLAG_NOT_DEVICE))
sup_dev = fwnode_get_next_parent_dev(sup_handle);
else
sup_dev = get_dev_from_fwnode(sup_handle);
@@ -2112,7 +2112,7 @@ static int fw_devlink_create_devlink(struct device *con,
* supplier device indefinitely.
*/
if (sup_dev->links.status == DL_DEV_NO_DRIVER &&
- sup_handle->flags & FWNODE_FLAG_INITIALIZED) {
+ fwnode_test_flag(sup_handle, FWNODE_FLAG_INITIALIZED)) {
dev_dbg(con,
"Not linking %pfwf - dev might never probe\n",
sup_handle);
@@ -3680,6 +3680,21 @@ int device_add(struct device *dev)
fw_devlink_link_device(dev);
}
+ /*
+ * The moment the device was linked into the bus's "klist_devices" in
+ * bus_add_device() then it's possible that probe could have been
+ * attempted in a different thread via userspace loading a driver
+ * matching the device. "ready_to_probe" being unset would have
+ * blocked those attempts. Now that all of the above initialization has
+ * happened, unblock probe. If probe happens through another thread
+ * after this point but before bus_probe_device() runs then it's fine.
+ * bus_probe_device() -> device_initial_probe() -> __device_attach()
+ * will notice (under device_lock) that the device is already bound.
+ */
+ device_lock(dev);
+ dev_set_ready_to_probe(dev);
+ device_unlock(dev);
+
bus_probe_device(dev);
/*
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 7e2fb159bb89..d371c3437dc6 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -785,6 +785,26 @@ static int __driver_probe_device(struct device_driver *drv, struct device *dev)
if (dev->driver)
return -EBUSY;
+ /*
+ * In device_add(), the "struct device" gets linked into the subsystem's
+ * list of devices and broadcast to userspace (via uevent) before we're
+ * quite ready to probe. Those open pathways to driver probe before
+ * we've finished enough of device_add() to reliably support probe.
+ * Detect this and tell other pathways to try again later. device_add()
+ * itself will also try to probe immediately after setting
+ * "ready_to_probe".
+ */
+ if (!dev_ready_to_probe(dev))
+ return dev_err_probe(dev, -EPROBE_DEFER, "Device not ready to probe\n");
+
+ /*
+ * Set can_match = true after calling dev_ready_to_probe(), so
+ * driver_deferred_probe_add() won't actually add the device to the
+ * deferred probe list when dev_ready_to_probe() returns false.
+ *
+ * When dev_ready_to_probe() returns false, it means that device_add()
+ * will do another probe() attempt for us.
+ */
dev->can_match = true;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 6f68c2a74361..a50b946c3934 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -7172,7 +7172,7 @@ static ssize_t do_rbd_add(const char *buf, size_t count)
rc = device_add_disk(&rbd_dev->dev, rbd_dev->disk, NULL);
if (rc)
- goto err_out_cleanup_disk;
+ goto err_out_device;
spin_lock(&rbd_dev_list_lock);
list_add_tail(&rbd_dev->node, &rbd_dev_list);
@@ -7186,8 +7186,8 @@ static ssize_t do_rbd_add(const char *buf, size_t count)
module_put(THIS_MODULE);
return rc;
-err_out_cleanup_disk:
- rbd_free_disk(rbd_dev);
+err_out_device:
+ device_del(&rbd_dev->dev);
err_out_image_lock:
rbd_dev_image_unlock(rbd_dev);
rbd_dev_device_release(rbd_dev);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 44cf0e51d7db..6584c1ca5a17 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1880,7 +1880,7 @@ static void zram_bio_discard(struct zram *zram, struct bio *bio)
*/
if (offset) {
if (n <= (PAGE_SIZE - offset))
- return;
+ goto end_bio;
n -= (PAGE_SIZE - offset);
index++;
@@ -1895,6 +1895,7 @@ static void zram_bio_discard(struct zram *zram, struct bio *bio)
n -= PAGE_SIZE;
}
+end_bio:
bio_endio(bio);
}
diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c
index 18208e152a36..ca62b7369939 100644
--- a/drivers/bluetooth/virtio_bt.c
+++ b/drivers/bluetooth/virtio_bt.c
@@ -12,6 +12,7 @@
#include <net/bluetooth/hci_core.h>
#define VERSION "0.1"
+#define VIRTBT_RX_BUF_SIZE 1000
enum {
VIRTBT_VQ_TX,
@@ -33,11 +34,11 @@ static int virtbt_add_inbuf(struct virtio_bluetooth *vbt)
struct sk_buff *skb;
int err;
- skb = alloc_skb(1000, GFP_KERNEL);
+ skb = alloc_skb(VIRTBT_RX_BUF_SIZE, GFP_KERNEL);
if (!skb)
return -ENOMEM;
- sg_init_one(sg, skb->data, 1000);
+ sg_init_one(sg, skb->data, VIRTBT_RX_BUF_SIZE);
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
if (err < 0) {
@@ -197,6 +198,7 @@ static int virtbt_shutdown_generic(struct hci_dev *hdev)
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
{
+ size_t min_hdr;
__u8 pkt_type;
pkt_type = *((__u8 *) skb->data);
@@ -204,16 +206,32 @@ static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
switch (pkt_type) {
case HCI_EVENT_PKT:
+ min_hdr = sizeof(struct hci_event_hdr);
+ break;
case HCI_ACLDATA_PKT:
+ min_hdr = sizeof(struct hci_acl_hdr);
+ break;
case HCI_SCODATA_PKT:
+ min_hdr = sizeof(struct hci_sco_hdr);
+ break;
case HCI_ISODATA_PKT:
- hci_skb_pkt_type(skb) = pkt_type;
- hci_recv_frame(vbt->hdev, skb);
+ min_hdr = sizeof(struct hci_iso_hdr);
break;
default:
kfree_skb(skb);
- break;
+ return;
+ }
+
+ if (skb->len < min_hdr) {
+ bt_dev_err_ratelimited(vbt->hdev,
+ "rx pkt_type 0x%02x payload %u < hdr %zu\n",
+ pkt_type, skb->len, min_hdr);
+ kfree_skb(skb);
+ return;
}
+
+ hci_skb_pkt_type(skb) = pkt_type;
+ hci_recv_frame(vbt->hdev, skb);
}
static void virtbt_rx_work(struct work_struct *work)
@@ -227,8 +245,15 @@ static void virtbt_rx_work(struct work_struct *work)
if (!skb)
return;
- skb_put(skb, len);
- virtbt_rx_handle(vbt, skb);
+ if (!len || len > VIRTBT_RX_BUF_SIZE) {
+ bt_dev_err_ratelimited(vbt->hdev,
+ "rx reply len %u outside [1, %u]\n",
+ len, VIRTBT_RX_BUF_SIZE);
+ kfree_skb(skb);
+ } else {
+ skb_put(skb, len);
+ virtbt_rx_handle(vbt, skb);
+ }
if (virtbt_add_inbuf(vbt) < 0)
return;
diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c
index f9fd1582f150..5244013d328f 100644
--- a/drivers/bus/imx-weim.c
+++ b/drivers/bus/imx-weim.c
@@ -335,7 +335,7 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action,
* fw_devlink doesn't skip adding consumers to this
* device.
*/
- rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
+ fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) {
dev_err(&pdev->dev,
"Failed to create child device '%pOF'\n",
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 5cd031f3fc97..0b2c8c4a78a3 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -162,6 +162,10 @@ struct smi_info {
OEM2_DATA_AVAIL)
unsigned char msg_flags;
+ /* When requesting events and messages, don't do it forever. */
+ unsigned int num_requests_in_a_row;
+ bool last_was_flag_fetch;
+
/* Does the BMC have an event buffer? */
bool has_event_buffer;
@@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- smi_info->si_state = SI_GETTING_MESSAGES;
+ if (smi_info->si_state != SI_GETTING_MESSAGES) {
+ smi_info->num_requests_in_a_row = 0;
+ smi_info->si_state = SI_GETTING_MESSAGES;
+ }
}
static void start_getting_events(struct smi_info *smi_info)
@@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- smi_info->si_state = SI_GETTING_EVENTS;
+ if (smi_info->si_state != SI_GETTING_EVENTS) {
+ smi_info->num_requests_in_a_row = 0;
+ smi_info->si_state = SI_GETTING_EVENTS;
+ }
}
/*
@@ -471,15 +481,19 @@ static void handle_flags(struct smi_info *smi_info)
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
- if (!smi_info->curr_msg)
+ if (!smi_info->curr_msg) {
+ smi_info->si_state = SI_NORMAL;
return;
+ }
start_getting_msg_queue(smi_info);
} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
/* Events available. */
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
- if (!smi_info->curr_msg)
+ if (!smi_info->curr_msg) {
+ smi_info->si_state = SI_NORMAL;
return;
+ }
start_getting_events(smi_info);
} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
@@ -579,6 +593,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
} else {
smi_info->msg_flags = msg[3];
+ smi_info->last_was_flag_fetch = true;
handle_flags(smi_info);
}
break;
@@ -614,7 +629,13 @@ static void handle_transaction_done(struct smi_info *smi_info)
*/
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
- if (msg->rsp[2] != 0) {
+ /*
+ * It appears some BMCs, with no event data, return no
+ * data in the message and not a 0x80 error as the
+ * spec says they should. Shut down processing if
+ * the data is not the right length.
+ */
+ if (msg->rsp[2] != 0 || msg->rsp_size != 19) {
/* Error getting event, probably done. */
msg->done(msg);
@@ -624,6 +645,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, events);
+ smi_info->num_requests_in_a_row++;
+ if (smi_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+
/*
* Do this before we deliver the message
* because delivering the message releases the
@@ -662,6 +688,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
smi_inc_stat(smi_info, incoming_messages);
+ smi_info->num_requests_in_a_row++;
+ if (smi_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+
/*
* Do this before we deliver the message
* because delivering the message releases the
@@ -789,6 +820,26 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
goto restart;
}
+ /*
+ * If we are currently idle, or if the last thing that was
+ * done was a flag fetch and there is a message pending, try
+ * to start the next message.
+ *
+ * We do the waiting message check to avoid a stuck flag
+ * completely wedging the driver. Let a message through
+ * in between flag operations if that happens.
+ */
+ if (si_sm_result == SI_SM_IDLE ||
+ (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
+ smi_info->last_was_flag_fetch)) {
+ smi_info->last_was_flag_fetch = false;
+ smi_inc_stat(smi_info, idles);
+
+ si_sm_result = start_next_msg(smi_info);
+ if (si_sm_result != SI_SM_IDLE)
+ goto restart;
+ }
+
/*
* We prefer handling attn over new messages. But don't do
* this if there is not yet an upper layer to handle anything.
@@ -822,15 +873,6 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
}
}
- /* If we are currently idle, try to start the next message. */
- if (si_sm_result == SI_SM_IDLE) {
- smi_inc_stat(smi_info, idles);
-
- si_sm_result = start_next_msg(smi_info);
- if (si_sm_result != SI_SM_IDLE)
- goto restart;
- }
-
if ((si_sm_result == SI_SM_IDLE)
&& (atomic_read(&smi_info->req_events))) {
/*
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index df8dd50b4cbe..d94dd1a527c2 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -225,6 +225,9 @@ struct ssif_info {
bool has_event_buffer;
bool supports_alert;
+ /* When requesting events and messages, don't do it forever. */
+ unsigned int num_requests_in_a_row;
+
/*
* Used to tell what we should do with alerts. If we are
* waiting on a response, read the data immediately.
@@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
}
ssif_info->curr_msg = msg;
- ssif_info->ssif_state = SSIF_GETTING_EVENTS;
+ if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
+ ssif_info->num_requests_in_a_row = 0;
+ ssif_info->ssif_state = SSIF_GETTING_EVENTS;
+ }
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
}
ssif_info->curr_msg = msg;
- ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
+ if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
+ ssif_info->num_requests_in_a_row = 0;
+ ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
+ }
ipmi_ssif_unlock_cond(ssif_info, flags);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -481,8 +490,6 @@ static int ipmi_ssif_thread(void *data)
/* Wait for something to do */
result = wait_for_completion_interruptible(
&ssif_info->wake_thread);
- if (ssif_info->stopping)
- break;
if (result == -ERESTARTSYS)
continue;
init_completion(&ssif_info->wake_thread);
@@ -843,6 +850,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(ssif_info, flags);
} else {
+ ssif_info->num_requests_in_a_row++;
+ if (ssif_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+
handle_flags(ssif_info, flags);
ssif_inc_stat(ssif_info, events);
deliver_recv_msg(ssif_info, msg);
@@ -876,6 +888,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
handle_flags(ssif_info, flags);
} else {
+ ssif_info->num_requests_in_a_row++;
+ if (ssif_info->num_requests_in_a_row > 10)
+ /* Stop if we do this too many times. */
+ ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+
ssif_inc_stat(ssif_info, incoming_messages);
handle_flags(ssif_info, flags);
deliver_recv_msg(ssif_info, msg);
@@ -1271,8 +1288,8 @@ static void shutdown_ssif(void *send_info)
del_timer_sync(&ssif_info->watch_timer);
del_timer_sync(&ssif_info->retry_timer);
if (ssif_info->thread) {
- complete(&ssif_info->wake_thread);
kthread_stop(ssif_info->thread);
+ ssif_info->thread = NULL;
}
}
@@ -1898,6 +1915,15 @@ static int ssif_probe(struct i2c_client *client)
out:
if (rv) {
+ /*
+ * If ipmi_register_smi() starts the interface, it will
+ * call shutdown and that will free the thread and set
+ * it to NULL. Otherwise it must be freed here.
+ */
+ if (ssif_info->thread) {
+ kthread_stop(ssif_info->thread);
+ ssif_info->thread = NULL;
+ }
if (addr_info)
addr_info->client = NULL;
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 5e6ee5b82b8f..aaeace9f4a4d 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -472,6 +472,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
rc = -EIO;
+ dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be set. sts = 0x%08x\n",
+ status);
goto out_err;
}
}
@@ -492,6 +494,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) {
rc = -EIO;
+ dev_err(&chip->dev, "TPM_STS_DATA_EXPECT should be unset. sts = 0x%08x\n",
+ status);
goto out_err;
}
@@ -553,11 +557,16 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
break;
else if (rc != -EAGAIN && rc != -EIO)
/* Data transfer failed, not recoverable */
- return rc;
+ goto out_err;
usleep_range(priv->timeout_min, priv->timeout_max);
}
+ if (rc == -EAGAIN || rc == -EIO) {
+ dev_err(&chip->dev, "Exhausted %d tpm_tis_send_data retries\n", TPM_RETRY);
+ goto out_err;
+ }
+
/* go and do it */
rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
if (rc < 0)
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
index f7412b137e5e..5a75b5c91555 100644
--- a/drivers/clk/clk-rk808.c
+++ b/drivers/clk/clk-rk808.c
@@ -153,7 +153,7 @@ static int rk808_clkout_probe(struct platform_device *pdev)
struct rk808_clkout *rk808_clkout;
int ret;
- dev->of_node = pdev->dev.parent->of_node;
+ device_set_of_node_from_dev(dev, dev->parent);
rk808_clkout = devm_kzalloc(dev,
sizeof(*rk808_clkout), GFP_KERNEL);
diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c
index b9ddb74b86f7..abc4c53fcc36 100644
--- a/drivers/clk/imx/clk-imx8-acm.c
+++ b/drivers/clk/imx/clk-imx8-acm.c
@@ -368,7 +368,8 @@ static int imx8_acm_clk_probe(struct platform_device *pdev)
for (i = 0; i < priv->soc_data->num_sels; i++) {
hws[sels[i].clkid] = devm_clk_hw_register_mux_parent_data_table(dev,
sels[i].name, sels[i].parents,
- sels[i].num_parents, 0,
+ sels[i].num_parents,
+ CLK_SET_RATE_NO_REPARENT,
base + sels[i].reg,
sels[i].shift, sels[i].width,
0, NULL, NULL);
diff --git a/drivers/clk/microchip/clk-mpfs-ccc.c b/drivers/clk/microchip/clk-mpfs-ccc.c
index bce61c45e967..9ed8074a9ee8 100644
--- a/drivers/clk/microchip/clk-mpfs-ccc.c
+++ b/drivers/clk/microchip/clk-mpfs-ccc.c
@@ -178,7 +178,7 @@ static int mpfs_ccc_register_outputs(struct device *dev, struct mpfs_ccc_out_hw_
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
out_hw->id);
- data->hw_data.hws[out_hw->id] = &out_hw->divider.hw;
+ data->hw_data.hws[out_hw->id - 2] = &out_hw->divider.hw;
}
return 0;
@@ -234,6 +234,10 @@ static int mpfs_ccc_probe(struct platform_device *pdev)
unsigned int num_clks;
int ret;
+ /*
+ * If DLLs get added here, mpfs_ccc_register_outputs() currently packs
+ * sparse clock IDs in the hws array
+ */
num_clks = ARRAY_SIZE(mpfs_ccc_pll_clks) + ARRAY_SIZE(mpfs_ccc_pll0out_clks) +
ARRAY_SIZE(mpfs_ccc_pll1out_clks);
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 9ebedd972df0..b89e7111e7b8 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -95,7 +95,10 @@ static int snooze_loop(struct cpuidle_device *dev,
HMT_medium();
ppc64_runlatch_on();
- clear_thread_flag(TIF_POLLING_NRFLAG);
+
+ /* Avoid double clear when breaking */
+ if (!dev->poll_time_limit)
+ clear_thread_flag(TIF_POLLING_NRFLAG);
local_irq_disable();
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index 14db9b7d985d..d8eedb3e09cb 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -63,7 +63,10 @@ int snooze_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv,
}
HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
+
+ /* Avoid double clear when breaking */
+ if (!dev->poll_time_limit)
+ clear_thread_flag(TIF_POLLING_NRFLAG);
raw_local_irq_disable();
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 55b5f577b01c..97fcde012676 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -2323,7 +2323,7 @@ static int atmel_aes_buff_init(struct atmel_aes_dev *dd)
static void atmel_aes_buff_cleanup(struct atmel_aes_dev *dd)
{
- free_page((unsigned long)dd->buf);
+ free_pages((unsigned long)dd->buf, ATMEL_AES_BUFFER_ORDER);
}
static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 590ea984c622..813d8517e1c3 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -261,6 +261,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
if (IS_ERR(fallback)) {
dev_err(&ctx->client->dev, "Failed to allocate transformation for '%s': %ld\n",
alg, PTR_ERR(fallback));
+ atmel_ecc_i2c_client_free(ctx->client);
return PTR_ERR(fallback);
}
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 67fd084a2b97..2cf5407818f1 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -125,10 +125,8 @@ static void atmel_sha204a_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- if (atomic_read(&i2c_priv->tfm_count)) {
- dev_emerg(&client->dev, "Device is busy, will remove it anyhow\n");
- return;
- }
+ devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
+ atmel_i2c_flush_queue();
kfree((void *)i2c_priv->hwrng.priv);
}
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index d234495f1115..6870a13342e2 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -304,8 +304,8 @@ static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd)
dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
} else {
- dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
- dd->dma_size, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(dd->dev, dd->dma_addr_out,
+ dd->dma_size, DMA_FROM_DEVICE);
/* copy data */
count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
@@ -655,8 +655,8 @@ static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
} else {
- dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
- dd->dma_size, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(dd->dev, dd->dma_addr_out,
+ dd->dma_size, DMA_FROM_DEVICE);
/* copy data */
count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
index 06e0681fdbe1..ac97a15ac78b 100644
--- a/drivers/crypto/caam/caamalg_qi2.c
+++ b/drivers/crypto/caam/caamalg_qi2.c
@@ -3268,7 +3268,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
dpaa2_fl_set_addr(out_fle, key_dma);
dpaa2_fl_set_len(out_fle, digestsize);
- print_hex_dump_debug("key_in@" __stringify(__LINE__)": ",
+ print_hex_dump_devel("key_in@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
@@ -3288,7 +3288,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
/* in progress */
wait_for_completion(&result.completion);
ret = result.err;
- print_hex_dump_debug("digested key@" __stringify(__LINE__)": ",
+ print_hex_dump_devel("digested key@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key,
digestsize, 1);
}
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 30cc46c4c33a..c1a06f033b11 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -393,7 +393,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_CONTEXT);
- print_hex_dump_debug("key_in@"__stringify(__LINE__)": ",
+ print_hex_dump_devel("key_in@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
@@ -408,7 +408,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
wait_for_completion(&result.completion);
ret = result.err;
- print_hex_dump_debug("digested key@"__stringify(__LINE__)": ",
+ print_hex_dump_devel("digested key@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, key,
digestsize, 1);
}
diff --git a/drivers/crypto/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c
index f418162932fe..ef9bde93a695 100644
--- a/drivers/crypto/ccree/cc_hash.c
+++ b/drivers/crypto/ccree/cc_hash.c
@@ -1448,6 +1448,7 @@ static int cc_mac_digest(struct ahash_request *req)
if (cc_map_hash_request_final(ctx->drvdata, state, req->src,
req->nbytes, 1, flags)) {
dev_err(dev, "map_ahash_request_final() failed\n");
+ cc_unmap_result(dev, state, digestsize, req->result);
cc_unmap_req(dev, state, ctx);
return -ENOMEM;
}
diff --git a/drivers/crypto/hisilicon/sec/sec_algs.c b/drivers/crypto/hisilicon/sec/sec_algs.c
index 1189effcdad0..512190b31b99 100644
--- a/drivers/crypto/hisilicon/sec/sec_algs.c
+++ b/drivers/crypto/hisilicon/sec/sec_algs.c
@@ -844,7 +844,7 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
if (crypto_skcipher_ivsize(atfm))
dma_unmap_single(info->dev, sec_req->dma_iv,
crypto_skcipher_ivsize(atfm),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
err_unmap_out_sg:
if (split)
sec_unmap_sg_on_err(skreq->dst, steps, splits_out,
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
index 2ab90ec10e61..8b1dc05df8c8 100644
--- a/drivers/crypto/nx/nx-842.c
+++ b/drivers/crypto/nx/nx-842.c
@@ -101,9 +101,13 @@ static int update_param(struct nx842_crypto_param *p,
return 0;
}
-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver)
+void *nx842_crypto_alloc_ctx(struct nx842_driver *driver)
{
- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct nx842_crypto_ctx *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
spin_lock_init(&ctx->lock);
ctx->driver = driver;
@@ -111,25 +115,24 @@ int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver)
ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) {
- kfree(ctx->wmem);
- free_page((unsigned long)ctx->sbounce);
- free_page((unsigned long)ctx->dbounce);
- return -ENOMEM;
+ nx842_crypto_free_ctx(ctx);
+ return ERR_PTR(-ENOMEM);
}
- return 0;
+ return ctx;
}
-EXPORT_SYMBOL_GPL(nx842_crypto_init);
+EXPORT_SYMBOL_GPL(nx842_crypto_alloc_ctx);
-void nx842_crypto_exit(struct crypto_tfm *tfm)
+void nx842_crypto_free_ctx(void *p)
{
- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct nx842_crypto_ctx *ctx = p;
kfree(ctx->wmem);
- free_page((unsigned long)ctx->sbounce);
- free_page((unsigned long)ctx->dbounce);
+ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER);
+ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER);
+ kfree(ctx);
}
-EXPORT_SYMBOL_GPL(nx842_crypto_exit);
+EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx);
static void check_constraints(struct nx842_constraints *c)
{
@@ -246,12 +249,14 @@ static int compress(struct nx842_crypto_ctx *ctx,
return update_param(p, slen, dskip + dlen);
}
-int nx842_crypto_compress(struct crypto_tfm *tfm,
+int nx842_crypto_compress(struct crypto_scomp *tfm,
const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
+ u8 *dst, unsigned int *dlen, void *pctx)
{
- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
- struct nx842_crypto_header *hdr = &ctx->header;
+ struct nx842_crypto_ctx *ctx = pctx;
+ struct nx842_crypto_header *hdr =
+ container_of(&ctx->header,
+ struct nx842_crypto_header, hdr);
struct nx842_crypto_param p;
struct nx842_constraints c = *ctx->driver->constraints;
unsigned int groups, hdrsize, h;
@@ -429,11 +434,11 @@ static int decompress(struct nx842_crypto_ctx *ctx,
return update_param(p, slen + padding, dlen);
}
-int nx842_crypto_decompress(struct crypto_tfm *tfm,
+int nx842_crypto_decompress(struct crypto_scomp *tfm,
const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
+ u8 *dst, unsigned int *dlen, void *pctx)
{
- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct nx842_crypto_ctx *ctx = pctx;
struct nx842_crypto_header *hdr;
struct nx842_crypto_param p;
struct nx842_constraints c = *ctx->driver->constraints;
@@ -490,7 +495,7 @@ int nx842_crypto_decompress(struct crypto_tfm *tfm,
}
memcpy(&ctx->header, src, hdr_len);
- hdr = &ctx->header;
+ hdr = container_of(&ctx->header, struct nx842_crypto_header, hdr);
for (n = 0; n < hdr->groups; n++) {
/* ignore applies to last group */
diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h
index 7590bfb24d79..58137ffd3835 100644
--- a/drivers/crypto/nx/nx-842.h
+++ b/drivers/crypto/nx/nx-842.h
@@ -3,7 +3,6 @@
#ifndef __NX_842_H__
#define __NX_842_H__
-#include <crypto/algapi.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -101,6 +100,8 @@
#define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1)))
#define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE)
+struct crypto_scomp;
+
static inline unsigned long nx842_get_pa(void *addr)
{
if (!is_vmalloc_addr(addr))
@@ -157,9 +158,11 @@ struct nx842_crypto_header_group {
} __packed;
struct nx842_crypto_header {
- __be16 magic; /* NX842_CRYPTO_MAGIC */
- __be16 ignore; /* decompressed end bytes to ignore */
- u8 groups; /* total groups in this header */
+ struct_group_tagged(nx842_crypto_header_hdr, hdr,
+ __be16 magic; /* NX842_CRYPTO_MAGIC */
+ __be16 ignore; /* decompressed end bytes to ignore */
+ u8 groups; /* total groups in this header */
+ );
struct nx842_crypto_header_group group[];
} __packed;
@@ -171,19 +174,19 @@ struct nx842_crypto_ctx {
u8 *wmem;
u8 *sbounce, *dbounce;
- struct nx842_crypto_header header;
+ struct nx842_crypto_header_hdr header;
struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX];
struct nx842_driver *driver;
};
-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver);
-void nx842_crypto_exit(struct crypto_tfm *tfm);
-int nx842_crypto_compress(struct crypto_tfm *tfm,
+void *nx842_crypto_alloc_ctx(struct nx842_driver *driver);
+void nx842_crypto_free_ctx(void *ctx);
+int nx842_crypto_compress(struct crypto_scomp *tfm,
const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
-int nx842_crypto_decompress(struct crypto_tfm *tfm,
+ u8 *dst, unsigned int *dlen, void *ctx);
+int nx842_crypto_decompress(struct crypto_scomp *tfm,
const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
+ u8 *dst, unsigned int *dlen, void *ctx);
#endif /* __NX_842_H__ */
diff --git a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c
index 8c859872c183..fd0a98b2fb1b 100644
--- a/drivers/crypto/nx/nx-common-powernv.c
+++ b/drivers/crypto/nx/nx-common-powernv.c
@@ -9,6 +9,7 @@
#include "nx-842.h"
+#include <crypto/internal/scompress.h>
#include <linux/timer.h>
#include <asm/prom.h>
@@ -1031,23 +1032,21 @@ static struct nx842_driver nx842_powernv_driver = {
.decompress = nx842_powernv_decompress,
};
-static int nx842_powernv_crypto_init(struct crypto_tfm *tfm)
+static void *nx842_powernv_crypto_alloc_ctx(void)
{
- return nx842_crypto_init(tfm, &nx842_powernv_driver);
+ return nx842_crypto_alloc_ctx(&nx842_powernv_driver);
}
-static struct crypto_alg nx842_powernv_alg = {
- .cra_name = "842",
- .cra_driver_name = "842-nx",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
- .cra_ctxsize = sizeof(struct nx842_crypto_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = nx842_powernv_crypto_init,
- .cra_exit = nx842_crypto_exit,
- .cra_u = { .compress = {
- .coa_compress = nx842_crypto_compress,
- .coa_decompress = nx842_crypto_decompress } }
+static struct scomp_alg nx842_powernv_alg = {
+ .base.cra_name = "842",
+ .base.cra_driver_name = "842-nx",
+ .base.cra_priority = 300,
+ .base.cra_module = THIS_MODULE,
+
+ .alloc_ctx = nx842_powernv_crypto_alloc_ctx,
+ .free_ctx = nx842_crypto_free_ctx,
+ .compress = nx842_crypto_compress,
+ .decompress = nx842_crypto_decompress,
};
static __init int nx_compress_powernv_init(void)
@@ -1107,7 +1106,7 @@ static __init int nx_compress_powernv_init(void)
nx842_powernv_exec = nx842_exec_vas;
}
- ret = crypto_register_alg(&nx842_powernv_alg);
+ ret = crypto_register_scomp(&nx842_powernv_alg);
if (ret) {
nx_delete_coprocs();
return ret;
@@ -1128,7 +1127,7 @@ static void __exit nx_compress_powernv_exit(void)
if (!nx842_ct)
vas_unregister_api_powernv();
- crypto_unregister_alg(&nx842_powernv_alg);
+ crypto_unregister_scomp(&nx842_powernv_alg);
nx_delete_coprocs();
}
diff --git a/drivers/crypto/nx/nx-common-pseries.c b/drivers/crypto/nx/nx-common-pseries.c
index 7e98f174f69b..0d26aafd0886 100644
--- a/drivers/crypto/nx/nx-common-pseries.c
+++ b/drivers/crypto/nx/nx-common-pseries.c
@@ -11,6 +11,7 @@
#include <asm/vio.h>
#include <asm/hvcall.h>
#include <asm/vas.h>
+#include <crypto/internal/scompress.h>
#include "nx-842.h"
#include "nx_csbcpb.h" /* struct nx_csbcpb */
@@ -1008,23 +1009,21 @@ static struct nx842_driver nx842_pseries_driver = {
.decompress = nx842_pseries_decompress,
};
-static int nx842_pseries_crypto_init(struct crypto_tfm *tfm)
+static void *nx842_pseries_crypto_alloc_ctx(void)
{
- return nx842_crypto_init(tfm, &nx842_pseries_driver);
+ return nx842_crypto_alloc_ctx(&nx842_pseries_driver);
}
-static struct crypto_alg nx842_pseries_alg = {
- .cra_name = "842",
- .cra_driver_name = "842-nx",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
- .cra_ctxsize = sizeof(struct nx842_crypto_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = nx842_pseries_crypto_init,
- .cra_exit = nx842_crypto_exit,
- .cra_u = { .compress = {
- .coa_compress = nx842_crypto_compress,
- .coa_decompress = nx842_crypto_decompress } }
+static struct scomp_alg nx842_pseries_alg = {
+ .base.cra_name = "842",
+ .base.cra_driver_name = "842-nx",
+ .base.cra_priority = 300,
+ .base.cra_module = THIS_MODULE,
+
+ .alloc_ctx = nx842_pseries_crypto_alloc_ctx,
+ .free_ctx = nx842_crypto_free_ctx,
+ .compress = nx842_crypto_compress,
+ .decompress = nx842_crypto_decompress,
};
static int nx842_probe(struct vio_dev *viodev,
@@ -1072,7 +1071,7 @@ static int nx842_probe(struct vio_dev *viodev,
if (ret)
goto error;
- ret = crypto_register_alg(&nx842_pseries_alg);
+ ret = crypto_register_scomp(&nx842_pseries_alg);
if (ret) {
dev_err(&viodev->dev, "could not register comp alg: %d\n", ret);
goto error;
@@ -1120,7 +1119,7 @@ static void nx842_remove(struct vio_dev *viodev)
if (caps_feat)
sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group);
- crypto_unregister_alg(&nx842_pseries_alg);
+ crypto_unregister_scomp(&nx842_pseries_alg);
spin_lock_irqsave(&devdata_mutex, flags);
old_devdata = rcu_dereference_check(devdata,
@@ -1252,7 +1251,7 @@ static void __exit nx842_pseries_exit(void)
vas_unregister_api_pseries();
- crypto_unregister_alg(&nx842_pseries_alg);
+ crypto_unregister_scomp(&nx842_pseries_alg);
spin_lock_irqsave(&devdata_mutex, flags);
old_devdata = rcu_dereference_check(devdata,
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 4ca4fbd227bc..347483f6fc5d 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -12,6 +12,7 @@
* All rights reserved.
*/
+#include <linux/workqueue.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -868,20 +869,28 @@ struct talitos_ahash_req_ctx {
u8 buf[2][HASH_MAX_BLOCK_SIZE];
int buf_idx;
unsigned int swinit;
- unsigned int first;
- unsigned int last;
+ unsigned int first_desc;
+ unsigned int last_desc;
+ unsigned int last_request;
unsigned int to_hash_later;
unsigned int nbuf;
struct scatterlist bufsl[2];
struct scatterlist *psrc;
+
+ struct scatterlist request_bufsl[2];
+ struct ahash_request *areq;
+ struct scatterlist *request_sl;
+ unsigned int remaining_ahash_request_bytes;
+ unsigned int current_ahash_request_bytes;
+ struct work_struct sec1_ahash_process_remaining;
};
struct talitos_export_state {
u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
u8 buf[HASH_MAX_BLOCK_SIZE];
unsigned int swinit;
- unsigned int first;
- unsigned int last;
+ unsigned int first_desc;
+ unsigned int last_desc;
unsigned int to_hash_later;
unsigned int nbuf;
};
@@ -1713,7 +1722,7 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
if (desc->next_desc &&
desc->ptr[5].ptr != desc2->ptr[5].ptr)
unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
- if (req_ctx->last)
+ if (req_ctx->last_desc)
memcpy(areq->result, req_ctx->hw_context,
crypto_ahash_digestsize(tfm));
@@ -1750,7 +1759,7 @@ static void ahash_done(struct device *dev,
container_of(desc, struct talitos_edesc, desc);
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- if (!req_ctx->last && req_ctx->to_hash_later) {
+ if (!req_ctx->last_desc && req_ctx->to_hash_later) {
/* Position any partial block for next update/final/finup */
req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
req_ctx->nbuf = req_ctx->to_hash_later;
@@ -1759,7 +1768,20 @@ static void ahash_done(struct device *dev,
kfree(edesc);
- ahash_request_complete(areq, err);
+ if (err) {
+ ahash_request_complete(areq, err);
+ return;
+ }
+
+ req_ctx->remaining_ahash_request_bytes -=
+ req_ctx->current_ahash_request_bytes;
+
+ if (!req_ctx->remaining_ahash_request_bytes) {
+ ahash_request_complete(areq, 0);
+ return;
+ }
+
+ schedule_work(&req_ctx->sec1_ahash_process_remaining);
}
/*
@@ -1803,7 +1825,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* first DWORD empty */
/* hash context in */
- if (!req_ctx->first || req_ctx->swinit) {
+ if (!req_ctx->first_desc || req_ctx->swinit) {
map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
req_ctx->hw_context_size,
req_ctx->hw_context,
@@ -1811,7 +1833,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
req_ctx->swinit = 0;
}
/* Indicate next op is not the first. */
- req_ctx->first = 0;
+ req_ctx->first_desc = 0;
/* HMAC key */
if (ctx->keylen)
@@ -1844,7 +1866,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* fifth DWORD empty */
/* hash/HMAC out -or- hash context out */
- if (req_ctx->last)
+ if (req_ctx->last_desc)
map_single_talitos_ptr(dev, &desc->ptr[5],
crypto_ahash_digestsize(tfm),
req_ctx->hw_context, DMA_FROM_DEVICE);
@@ -1886,7 +1908,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
if (sg_count > 1)
sync_needed = true;
copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
- if (req_ctx->last)
+ if (req_ctx->last_desc)
map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
req_ctx->hw_context_size,
req_ctx->hw_context,
@@ -1925,60 +1947,7 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
nbytes, 0, 0, 0, areq->base.flags, false);
}
-static int ahash_init(struct ahash_request *areq)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
- struct device *dev = ctx->dev;
- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- unsigned int size;
- dma_addr_t dma;
-
- /* Initialize the context */
- req_ctx->buf_idx = 0;
- req_ctx->nbuf = 0;
- req_ctx->first = 1; /* first indicates h/w must init its context */
- req_ctx->swinit = 0; /* assume h/w init of context */
- size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
- ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
- : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
- req_ctx->hw_context_size = size;
-
- dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
- DMA_TO_DEVICE);
- dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
-
- return 0;
-}
-
-/*
- * on h/w without explicit sha224 support, we initialize h/w context
- * manually with sha224 constants, and tell it to run sha256.
- */
-static int ahash_init_sha224_swinit(struct ahash_request *areq)
-{
- struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
-
- req_ctx->hw_context[0] = SHA224_H0;
- req_ctx->hw_context[1] = SHA224_H1;
- req_ctx->hw_context[2] = SHA224_H2;
- req_ctx->hw_context[3] = SHA224_H3;
- req_ctx->hw_context[4] = SHA224_H4;
- req_ctx->hw_context[5] = SHA224_H5;
- req_ctx->hw_context[6] = SHA224_H6;
- req_ctx->hw_context[7] = SHA224_H7;
-
- /* init 64-bit count */
- req_ctx->hw_context[8] = 0;
- req_ctx->hw_context[9] = 0;
-
- ahash_init(areq);
- req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
-
- return 0;
-}
-
-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
@@ -1995,14 +1964,14 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
bool is_sec1 = has_ftr_sec1(priv);
u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
- if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+ if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
/* Buffer up to one whole block */
- nents = sg_nents_for_len(areq->src, nbytes);
+ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
if (nents < 0) {
dev_err(dev, "Invalid number of src SG.\n");
return nents;
}
- sg_copy_to_buffer(areq->src, nents,
+ sg_copy_to_buffer(req_ctx->request_sl, nents,
ctx_buf + req_ctx->nbuf, nbytes);
req_ctx->nbuf += nbytes;
return 0;
@@ -2012,7 +1981,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
nbytes_to_hash = nbytes + req_ctx->nbuf;
to_hash_later = nbytes_to_hash & (blocksize - 1);
- if (req_ctx->last)
+ if (req_ctx->last_desc)
to_hash_later = 0;
else if (to_hash_later)
/* There is a partial block. Hash the full block(s) now */
@@ -2029,7 +1998,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
sg_init_table(req_ctx->bufsl, nsg);
sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
if (nsg > 1)
- sg_chain(req_ctx->bufsl, 2, areq->src);
+ sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
req_ctx->psrc = req_ctx->bufsl;
} else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
int offset;
@@ -2038,26 +2007,26 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
offset = blocksize - req_ctx->nbuf;
else
offset = nbytes_to_hash - req_ctx->nbuf;
- nents = sg_nents_for_len(areq->src, offset);
+ nents = sg_nents_for_len(req_ctx->request_sl, offset);
if (nents < 0) {
dev_err(dev, "Invalid number of src SG.\n");
return nents;
}
- sg_copy_to_buffer(areq->src, nents,
+ sg_copy_to_buffer(req_ctx->request_sl, nents,
ctx_buf + req_ctx->nbuf, offset);
req_ctx->nbuf += offset;
- req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
+ req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
offset);
} else
- req_ctx->psrc = areq->src;
+ req_ctx->psrc = req_ctx->request_sl;
if (to_hash_later) {
- nents = sg_nents_for_len(areq->src, nbytes);
+ nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
if (nents < 0) {
dev_err(dev, "Invalid number of src SG.\n");
return nents;
}
- sg_pcopy_to_buffer(areq->src, nents,
+ sg_pcopy_to_buffer(req_ctx->request_sl, nents,
req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
to_hash_later,
nbytes - to_hash_later);
@@ -2065,36 +2034,145 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
req_ctx->to_hash_later = to_hash_later;
/* Allocate extended descriptor */
- edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
+ edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
edesc->desc.hdr = ctx->desc_hdr_template;
/* On last one, request SEC to pad; otherwise continue */
- if (req_ctx->last)
+ if (req_ctx->last_desc)
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
else
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
/* request SEC to INIT hash. */
- if (req_ctx->first && !req_ctx->swinit)
+ if (req_ctx->first_desc && !req_ctx->swinit)
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
/* When the tfm context has a keylen, it's an HMAC.
* A first or last (ie. not middle) descriptor must request HMAC.
*/
- if (ctx->keylen && (req_ctx->first || req_ctx->last))
+ if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
- return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
+ return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+}
+
+static void sec1_ahash_process_remaining(struct work_struct *work)
+{
+ struct talitos_ahash_req_ctx *req_ctx =
+ container_of(work, struct talitos_ahash_req_ctx,
+ sec1_ahash_process_remaining);
+ int err = 0;
+
+ req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
+ req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
+
+ if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
+ req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
+ else {
+ req_ctx->current_ahash_request_bytes =
+ req_ctx->remaining_ahash_request_bytes;
+
+ if (req_ctx->last_request)
+ req_ctx->last_desc = 1;
+ }
+
+ err = ahash_process_req_one(req_ctx->areq,
+ req_ctx->current_ahash_request_bytes);
+
+ if (err != -EINPROGRESS)
+ ahash_request_complete(req_ctx->areq, err);
+}
+
+static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = ctx->dev;
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ req_ctx->areq = areq;
+ req_ctx->request_sl = areq->src;
+ req_ctx->remaining_ahash_request_bytes = nbytes;
+
+ if (is_sec1) {
+ if (nbytes > TALITOS1_MAX_DATA_LEN)
+ nbytes = TALITOS1_MAX_DATA_LEN;
+ else if (req_ctx->last_request)
+ req_ctx->last_desc = 1;
+ }
+
+ req_ctx->current_ahash_request_bytes = nbytes;
+
+ return ahash_process_req_one(req_ctx->areq,
+ req_ctx->current_ahash_request_bytes);
+}
+
+static int ahash_init(struct ahash_request *areq)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = ctx->dev;
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+ unsigned int size;
+ dma_addr_t dma;
+
+ /* Initialize the context */
+ req_ctx->buf_idx = 0;
+ req_ctx->nbuf = 0;
+ req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
+ req_ctx->swinit = 0; /* assume h/w init of context */
+ size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+ req_ctx->hw_context_size = size;
+ req_ctx->last_request = 0;
+ req_ctx->last_desc = 0;
+ INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+ DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+/*
+ * on h/w without explicit sha224 support, we initialize h/w context
+ * manually with sha224 constants, and tell it to run sha256.
+ */
+static int ahash_init_sha224_swinit(struct ahash_request *areq)
+{
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+
+ req_ctx->hw_context[0] = SHA224_H0;
+ req_ctx->hw_context[1] = SHA224_H1;
+ req_ctx->hw_context[2] = SHA224_H2;
+ req_ctx->hw_context[3] = SHA224_H3;
+ req_ctx->hw_context[4] = SHA224_H4;
+ req_ctx->hw_context[5] = SHA224_H5;
+ req_ctx->hw_context[6] = SHA224_H6;
+ req_ctx->hw_context[7] = SHA224_H7;
+
+ /* init 64-bit count */
+ req_ctx->hw_context[8] = 0;
+ req_ctx->hw_context[9] = 0;
+
+ ahash_init(areq);
+ req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+
+ return 0;
}
static int ahash_update(struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- req_ctx->last = 0;
+ req_ctx->last_request = 0;
return ahash_process_req(areq, areq->nbytes);
}
@@ -2103,7 +2181,7 @@ static int ahash_final(struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- req_ctx->last = 1;
+ req_ctx->last_request = 1;
return ahash_process_req(areq, 0);
}
@@ -2112,7 +2190,7 @@ static int ahash_finup(struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- req_ctx->last = 1;
+ req_ctx->last_request = 1;
return ahash_process_req(areq, areq->nbytes);
}
@@ -2145,8 +2223,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
req_ctx->hw_context_size);
memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
export->swinit = req_ctx->swinit;
- export->first = req_ctx->first;
- export->last = req_ctx->last;
+ export->first_desc = req_ctx->first_desc;
+ export->last_desc = req_ctx->last_desc;
export->to_hash_later = req_ctx->to_hash_later;
export->nbuf = req_ctx->nbuf;
@@ -2171,8 +2249,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
memcpy(req_ctx->hw_context, export->hw_context, size);
memcpy(req_ctx->buf[0], export->buf, export->nbuf);
req_ctx->swinit = export->swinit;
- req_ctx->first = export->first;
- req_ctx->last = export->last;
+ req_ctx->first_desc = export->first_desc;
+ req_ctx->last_desc = export->last_desc;
req_ctx->to_hash_later = export->to_hash_later;
req_ctx->nbuf = export->nbuf;
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 44bbeb3acd14..13af4ef2f43f 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -810,8 +810,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
struct device *dev = &idxd->pdev->dev;
struct idxd_evl *evl = idxd->evl;
- gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
- if (!gencfg.evl_en)
+ if (!evl)
return;
mutex_lock(&evl->lock);
diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c
index 4616da7e5430..4e69982e0345 100644
--- a/drivers/extcon/extcon-ptn5150.c
+++ b/drivers/extcon/extcon-ptn5150.c
@@ -331,6 +331,19 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c)
return 0;
}
+static int ptn5150_resume(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct ptn5150_info *info = i2c_get_clientdata(i2c);
+
+ /* Need to check possible pending interrupt events */
+ schedule_work(&info->irq_work);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ptn5150_pm_ops, NULL, ptn5150_resume);
+
static const struct of_device_id ptn5150_dt_match[] = {
{ .compatible = "nxp,ptn5150" },
{ },
@@ -346,6 +359,7 @@ MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id);
static struct i2c_driver ptn5150_i2c_driver = {
.driver = {
.name = "ptn5150",
+ .pm = pm_sleep_ptr(&ptn5150_pm_ops),
.of_match_table = ptn5150_dt_match,
},
.probe = ptn5150_i2c_probe,
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
index c323a818805c..b626b11ebf85 100644
--- a/drivers/firmware/google/framebuffer-coreboot.c
+++ b/drivers/firmware/google/framebuffer-coreboot.c
@@ -50,7 +50,7 @@ static int framebuffer_probe(struct coreboot_device *dev)
return -ENODEV;
memset(&res, 0, sizeof(res));
- res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ res.flags = IORESOURCE_MEM;
res.name = "Coreboot Framebuffer";
res.start = fb->physical_address;
length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);
@@ -64,22 +64,12 @@ static int framebuffer_probe(struct coreboot_device *dev)
sizeof(pdata));
if (IS_ERR(pdev))
pr_warn("coreboot: could not register framebuffer\n");
- else
- dev_set_drvdata(&dev->dev, pdev);
return PTR_ERR_OR_ZERO(pdev);
}
-static void framebuffer_remove(struct coreboot_device *dev)
-{
- struct platform_device *pdev = dev_get_drvdata(&dev->dev);
-
- platform_device_unregister(pdev);
-}
-
static struct coreboot_driver framebuffer_driver = {
.probe = framebuffer_probe,
- .remove = framebuffer_remove,
.drv = {
.name = "framebuffer",
},
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index c1e83b2926ae..4da0798ccd12 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -1136,5 +1136,12 @@ int of_gpiochip_add(struct gpio_chip *chip)
void of_gpiochip_remove(struct gpio_chip *chip)
{
- of_node_put(dev_of_node(&chip->gpiodev->dev));
+ struct device_node *np = dev_of_node(&chip->gpiodev->dev);
+
+ for_each_child_of_node_scoped(np, child) {
+ if (of_property_present(child, "gpio-hog"))
+ of_node_clear_flag(child, OF_POPULATED);
+ }
+
+ of_node_put(np);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index b2d86ffc626c..9c0e4e4bf3f6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1665,7 +1665,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
alloc_domain = AMDGPU_GEM_DOMAIN_GTT;
alloc_flags = 0;
} else {
- alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE;
+ alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE |
+ AMDGPU_GEM_CREATE_VRAM_CLEARED;
alloc_flags |= (flags & KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC) ?
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED : 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 9a53ca555e70..4efdc49d1015 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -36,6 +36,7 @@
#define AMDGPU_BO_LIST_MAX_PRIORITY 32u
#define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1)
+#define AMDGPU_BO_LIST_MAX_ENTRIES (128 * 1024)
static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
{
@@ -195,43 +196,39 @@ void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
struct drm_amdgpu_bo_list_entry **info_param)
{
- const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
+ const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
+ const uint32_t bo_info_size = in->bo_info_size;
+ const uint32_t bo_number = in->bo_number;
struct drm_amdgpu_bo_list_entry *info;
- int r;
- info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL);
- if (!info)
- return -ENOMEM;
+ if (bo_number > AMDGPU_BO_LIST_MAX_ENTRIES)
+ return -EINVAL;
/* copy the handle array from userspace to a kernel buffer */
- r = -EFAULT;
- if (likely(info_size == in->bo_info_size)) {
- unsigned long bytes = in->bo_number *
- in->bo_info_size;
-
- if (copy_from_user(info, uptr, bytes))
- goto error_free;
-
+ if (likely(info_size == bo_info_size)) {
+ info = vmemdup_array_user(uptr, bo_number, info_size);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
} else {
- unsigned long bytes = min(in->bo_info_size, info_size);
+ const uint32_t bytes = min(bo_info_size, info_size);
unsigned i;
- memset(info, 0, in->bo_number * info_size);
- for (i = 0; i < in->bo_number; ++i) {
- if (copy_from_user(&info[i], uptr, bytes))
- goto error_free;
+ info = kvmalloc_array(bo_number, info_size, GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
- uptr += in->bo_info_size;
+ memset(info, 0, bo_number * info_size);
+ for (i = 0; i < bo_number; ++i, uptr += bo_info_size) {
+ if (copy_from_user(&info[i], uptr, bytes)) {
+ kvfree(info);
+ return -EFAULT;
+ }
}
}
*info_param = info;
return 0;
-
-error_free:
- kvfree(info);
- return r;
}
int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
index eace2c9d0c36..ea75c2b2bbb1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -252,12 +252,19 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
*/
int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
{
+ int r;
+
if (adev->gart.bo != NULL)
return 0;
- return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
- NULL, (void *)&adev->gart.ptr);
+ r = amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
+ NULL, (void *)&adev->gart.ptr);
+ if (r)
+ return r;
+
+ memset_io(adev->gart.ptr, adev->gart.gart_pte_flags, adev->gart.table_size);
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index 60f770b99c2c..dc17e2ce84d0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -440,15 +440,18 @@ void amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
int amdgpu_ring_init_mqd(struct amdgpu_ring *ring);
-static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, int idx)
+static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, uint32_t idx)
{
- return ib->ptr[idx];
+ if (idx < ib->length_dw)
+ return ib->ptr[idx];
+ return 0;
}
-static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, int idx,
+static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, uint32_t idx,
uint32_t value)
{
- ib->ptr[idx] = value;
+ if (idx < ib->length_dw)
+ ib->ptr[idx] = value;
}
int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index c56405b49050..96c98417c29d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -75,6 +75,9 @@ static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
unsigned int type,
uint64_t size_in_page)
{
+ if (!size_in_page)
+ return 0;
+
return ttm_range_man_init(&adev->mman.bdev, type,
false, size_in_page);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 8e91355ad42c..d25d444984b3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -654,6 +654,9 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib,
uint64_t addr;
int r;
+ if (lo >= ib->length_dw || hi >= ib->length_dw)
+ return -EINVAL;
+
if (index == 0xffffffff)
index = 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 895060f6948f..f923aaa6104a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -5388,9 +5388,6 @@ static void gfx_v9_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
{
struct amdgpu_device *adev = ring->adev;
- /* we only allocate 32bit for each seq wb address */
- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
-
/* write fence seq to the "addr" */
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 0ba9a3d3312f..6a26428572ec 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -841,7 +841,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
/* write the fence */
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
- BUG_ON(addr & 0x3);
+ WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, lower_32_bits(seq));
@@ -851,7 +851,7 @@ static void sdma_v4_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
addr += 4;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
/* zero in first two bits */
- BUG_ON(addr & 0x3);
+ WARN_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(seq));
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 710328f12194..c9345da548a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -1789,7 +1789,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
{
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_bo_va_mapping *map;
- uint32_t *msg, num_buffers;
+ uint32_t *msg, num_buffers, len_dw;
struct amdgpu_bo *bo;
uint64_t start, end;
unsigned int i;
@@ -1810,6 +1810,11 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
return -EINVAL;
}
+ if (end - addr < 16) {
+ DRM_ERROR("VCN messages must be at least 4 DWORDs!\n");
+ return -EINVAL;
+ }
+
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
@@ -1826,8 +1831,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
msg = ptr + addr - start;
- /* Check length */
if (msg[1] > end - addr) {
+ DRM_ERROR("VCN message header does not fit in BO!\n");
r = -EINVAL;
goto out;
}
@@ -1835,9 +1840,19 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
if (msg[3] != RDECODE_MSG_CREATE)
goto out;
+ len_dw = msg[1] / 4;
num_buffers = msg[2];
+
+ /* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
+ if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
+ DRM_ERROR("VCN message has too many buffers!\n");
+ r = -EINVAL;
+ goto out;
+ }
+
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
uint32_t offset, size, *create;
+ uint64_t buf_end;
if (msg[0] != RDECODE_MESSAGE_CREATE)
continue;
@@ -1845,14 +1860,16 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
offset = msg[1];
size = msg[2];
- if (offset + size > end) {
+ if (size < 4 || check_add_overflow(offset, size, &buf_end) ||
+ buf_end > end - addr) {
+ DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
r = -EINVAL;
goto out;
}
create = ptr + addr + offset - start;
- /* H246, HEVC and VP9 can run on any instance */
+ /* H264, HEVC and VP9 can run on any instance */
if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11)
continue;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 43249e9f66d7..d35bc5d01b44 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1668,7 +1668,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
{
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_bo_va_mapping *map;
- uint32_t *msg, num_buffers;
+ uint32_t *msg, num_buffers, len_dw;
struct amdgpu_bo *bo;
uint64_t start, end;
unsigned int i;
@@ -1689,6 +1689,11 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
return -EINVAL;
}
+ if (end - addr < 16) {
+ DRM_ERROR("VCN messages must be at least 4 DWORDs!\n");
+ return -EINVAL;
+ }
+
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
@@ -1705,8 +1710,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
msg = ptr + addr - start;
- /* Check length */
if (msg[1] > end - addr) {
+ DRM_ERROR("VCN message header does not fit in BO!\n");
r = -EINVAL;
goto out;
}
@@ -1714,9 +1719,19 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
if (msg[3] != RDECODE_MSG_CREATE)
goto out;
+ len_dw = msg[1] / 4;
num_buffers = msg[2];
+
+ /* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
+ if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
+ DRM_ERROR("VCN message has too many buffers!\n");
+ r = -EINVAL;
+ goto out;
+ }
+
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
uint32_t offset, size, *create;
+ uint64_t buf_end;
if (msg[0] != RDECODE_MESSAGE_CREATE)
continue;
@@ -1724,7 +1739,9 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
offset = msg[1];
size = msg[2];
- if (offset + size > end) {
+ if (size < 4 || check_add_overflow(offset, size, &buf_end) ||
+ buf_end > end - addr) {
+ DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
r = -EINVAL;
goto out;
}
@@ -1755,9 +1772,10 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start)
{
int i;
+ uint32_t len;
- for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) {
- if (ib->ptr[i + 1] == id)
+ for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) {
+ if (amdgpu_ib_get_value(ib, i + 1) == id)
return i;
}
return -1;
@@ -1768,8 +1786,6 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
struct amdgpu_ib *ib)
{
struct amdgpu_ring *ring = amdgpu_job_ring(job);
- struct amdgpu_vcn_decode_buffer *decode_buffer;
- uint64_t addr;
uint32_t val;
int idx = 0, sidx;
@@ -1780,20 +1796,22 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) {
val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
- decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
+ uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6);
+ uint64_t msg_buffer_addr;
- if (!(decode_buffer->valid_buf_flag & 0x1))
+ if (!(valid_buf_flag & 0x1))
return 0;
- addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
- decode_buffer->msg_buffer_address_lo;
- return vcn_v4_0_dec_msg(p, job, addr);
+ msg_buffer_addr = ((u64)amdgpu_ib_get_value(ib, idx + 7)) << 32 |
+ amdgpu_ib_get_value(ib, idx + 8);
+ return vcn_v4_0_dec_msg(p, job, msg_buffer_addr);
} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx);
- if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1)
+ if (sidx >= 0 &&
+ amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1)
return vcn_v4_0_limit_sched(p, job);
}
- idx += ib->ptr[idx] / 4;
+ idx += amdgpu_ib_get_value(ib, idx) / 4;
}
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 2e194aa60848..d8544c766125 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -26,6 +26,7 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/overflow.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -784,6 +785,9 @@ static int kfd_ioctl_get_process_apertures_new(struct file *filp,
goto out_unlock;
}
+ if (args->num_of_nodes > kfd_topology_get_num_devices())
+ return -EINVAL;
+
/* Fill in process-aperture information for all available
* nodes, but not more than args->num_of_nodes as that is
* the amount of memory allocated by user
@@ -1702,6 +1706,16 @@ static int kfd_ioctl_smi_events(struct file *filep,
return kfd_smi_event_open(pdd->dev, &args->anon_fd);
}
+static int kfd_ioctl_svm_validate(void *kdata, unsigned int usize)
+{
+ struct kfd_ioctl_svm_args *args = kdata;
+ size_t expected = struct_size(args, attrs, args->nattr);
+
+ if (expected == SIZE_MAX || usize < expected)
+ return -EINVAL;
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_HSA_AMD_SVM)
static int kfd_ioctl_set_xnack_mode(struct file *filep,
@@ -3125,7 +3139,11 @@ static int kfd_ioctl_set_debug_trap(struct file *filep, struct kfd_process *p, v
#define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
[_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \
- .cmd_drv = 0, .name = #ioctl}
+ .validate = NULL, .cmd_drv = 0, .name = #ioctl}
+
+#define AMDKFD_IOCTL_DEF_V(ioctl, _func, _validate, _flags) \
+ [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \
+ .validate = _validate, .cmd_drv = 0, .name = #ioctl}
/** Ioctl table */
static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
@@ -3222,7 +3240,8 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
AMDKFD_IOCTL_DEF(AMDKFD_IOC_SMI_EVENTS,
kfd_ioctl_smi_events, 0),
- AMDKFD_IOCTL_DEF(AMDKFD_IOC_SVM, kfd_ioctl_svm, 0),
+ AMDKFD_IOCTL_DEF_V(AMDKFD_IOC_SVM, kfd_ioctl_svm,
+ kfd_ioctl_svm_validate, 0),
AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_XNACK_MODE,
kfd_ioctl_set_xnack_mode, 0),
@@ -3344,6 +3363,12 @@ static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
memset(kdata, 0, usize);
}
+ if (ioctl->validate) {
+ retcode = ioctl->validate(kdata, usize);
+ if (retcode)
+ goto err_i1;
+ }
+
retcode = func(filep, process, kdata);
if (cmd & IOC_OUT)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 0b69ff5375c5..12de27f58edf 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -1006,10 +1006,13 @@ extern struct srcu_struct kfd_processes_srcu;
typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p,
void *data);
+typedef int amdkfd_ioctl_validate_t(void *kdata, unsigned int usize);
+
struct amdkfd_ioctl_desc {
unsigned int cmd;
int flags;
amdkfd_ioctl_t *func;
+ amdkfd_ioctl_validate_t *validate;
unsigned int cmd_drv;
const char *name;
};
@@ -1145,6 +1148,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev,
return NULL;
}
int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_node **kdev);
+uint32_t kfd_topology_get_num_devices(void);
int kfd_numa_node_to_apic_id(int numa_node_id);
/* Interrupts */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index 3885bb53f019..556883e6a509 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -2177,6 +2177,17 @@ int kfd_topology_remove_device(struct kfd_node *gpu)
return res;
}
+uint32_t kfd_topology_get_num_devices(void)
+{
+ uint32_t num_devices;
+
+ down_read(&topology_lock);
+ num_devices = sys_props.num_devices;
+ up_read(&topology_lock);
+
+ return num_devices;
+}
+
/* kfd_topology_enum_kfd_devices - Enumerate through all devices in KFD
* topology. If GPU device is found @idx, then valid kfd_dev pointer is
* returned through @kdev
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index f51c3921cbc2..12f75b2ad664 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10152,6 +10152,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
}
if (dc_resource_is_dsc_encoding_supported(dc)) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed;
+ }
+
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = add_affected_mst_dsc_crtcs(state, crtc);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 88606b805330..8d4f2cadb915 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -737,6 +737,7 @@ struct dm_crtc_state {
bool freesync_vrr_info_changed;
+ bool mode_changed_independent_from_dsc;
bool dsc_force_changed;
bool vrr_supported;
struct mod_freesync_config freesync_config;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 2698e5c74ddf..ab6924d3046b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1587,8 +1587,11 @@ int pre_validate_dsc(struct drm_atomic_state *state,
} else {
int ind = find_crtc_index_in_state_by_stream(state, stream);
- if (ind >= 0)
- state->crtcs[ind].new_state->mode_changed = 0;
+ if (ind >= 0) {
+ struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state);
+
+ dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc;
+ }
}
}
clean_exit:
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
index 9e4228232f02..23f991dd065f 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
@@ -1326,12 +1326,13 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
dev_id = adev->pdev->device;
- if ((dpm_table->mclk_table.count >= 2)
- && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) {
- smu_data->smc_state_table.MemoryLevel[1].MinVddci =
- smu_data->smc_state_table.MemoryLevel[0].MinVddci;
- smu_data->smc_state_table.MemoryLevel[1].MinMvdd =
- smu_data->smc_state_table.MemoryLevel[0].MinMvdd;
+ if ((dpm_table->mclk_table.count >= 2) &&
+ ((dev_id == 0x67B0) || (dev_id == 0x67B1)) &&
+ (adev->pdev->revision == 0)) {
+ smu_data->smc_state_table.MemoryLevel[1].MinVddc =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddc;
+ smu_data->smc_state_table.MemoryLevel[1].MinVddcPhases =
+ smu_data->smc_state_table.MemoryLevel[0].MinVddcPhases;
}
smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F;
CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel);
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 3bdb6ba37ff4..2383ebb5e435 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -174,8 +174,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
}
for (i = 0; i < info->num_planes; i++) {
- unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
- unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
+ unsigned int width = drm_format_info_plane_width(info, mode_cmd->width, i);
+ unsigned int height = drm_format_info_plane_height(info, mode_cmd->height, i);
unsigned int min_size;
objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index cd97df690335..e8ce33c89548 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -679,7 +679,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
}
nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv;
- if (unlikely(r->reloc_bo_offset + 4 >
+ if (unlikely((u64)r->reloc_bo_offset + 4 >
nvbo->bo.base.size)) {
NV_PRINTK(err, cli, "reloc outside of bo\n");
ret = -EINVAL;
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index b8f4dac68d85..63c4d99a1aac 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -2466,7 +2466,8 @@ static void ci_register_patching_mc_arb(struct radeon_device *rdev,
if (patch &&
((rdev->pdev->device == 0x67B0) ||
- (rdev->pdev->device == 0x67B1))) {
+ (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
if ((memory_clock > 100000) && (memory_clock <= 125000)) {
tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
*dram_timimg2 &= ~0x00ff0000;
@@ -3307,7 +3308,8 @@ static int ci_populate_all_memory_levels(struct radeon_device *rdev)
pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
if ((dpm_table->mclk_table.count >= 2) &&
- ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) {
+ ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
pi->smc_state_table.MemoryLevel[1].MinVddc =
pi->smc_state_table.MemoryLevel[0].MinVddc;
pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
@@ -4504,7 +4506,8 @@ static int ci_register_patching_mc_seq(struct radeon_device *rdev,
if (patch &&
((rdev->pdev->device == 0x67B0) ||
- (rdev->pdev->device == 0x67B1))) {
+ (rdev->pdev->device == 0x67B1)) &&
+ (rdev->pdev->revision == 0)) {
for (i = 0; i < table->last; i++) {
if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
return -EINVAL;
diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c
index e5b10e41554a..b6218567f5a4 100644
--- a/drivers/gpu/drm/tiny/arcpgu.c
+++ b/drivers/gpu/drm/tiny/arcpgu.c
@@ -248,7 +248,8 @@ DEFINE_DRM_GEM_DMA_FOPS(arcpgu_drm_ops);
static int arcpgu_load(struct arcpgu_drm_private *arcpgu)
{
struct platform_device *pdev = to_platform_device(arcpgu->drm.dev);
- struct device_node *encoder_node = NULL, *endpoint_node = NULL;
+ struct device_node *encoder_node __free(device_node) = NULL;
+ struct device_node *endpoint_node = NULL;
struct drm_connector *connector = NULL;
struct drm_device *drm = &arcpgu->drm;
struct resource *res;
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index 199f76988bae..4db50cacbf9a 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -2200,7 +2200,8 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
struct dualshock4_input_report_usb *usb = (struct dualshock4_input_report_usb *)data;
ds4_report = &usb->common;
- num_touch_reports = usb->num_touch_reports;
+ num_touch_reports = min_t(u8, usb->num_touch_reports,
+ ARRAY_SIZE(usb->touch_reports));
touch_reports = usb->touch_reports;
} else if (hdev->bus == BUS_BLUETOOTH && report->id == DS4_INPUT_REPORT_BT &&
size == DS4_INPUT_REPORT_BT_SIZE) {
@@ -2214,7 +2215,8 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
}
ds4_report = &bt->common;
- num_touch_reports = bt->num_touch_reports;
+ num_touch_reports = min_t(u8, bt->num_touch_reports,
+ ARRAY_SIZE(bt->touch_reports));
touch_reports = bt->touch_reports;
} else {
hid_err(hdev, "Unhandled reportID=%d\n", report->id);
diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
index f8f22b8a67cd..93937e1bce19 100644
--- a/drivers/hwmon/corsair-psu.c
+++ b/drivers/hwmon/corsair-psu.c
@@ -805,13 +805,13 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
ret = corsairpsu_init(priv);
if (ret < 0) {
dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
- goto fail_and_stop;
+ goto fail_and_close;
}
ret = corsairpsu_fwinfo(priv);
if (ret < 0) {
dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
- goto fail_and_stop;
+ goto fail_and_close;
}
corsairpsu_get_criticals(priv);
diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c
index b8548105cd67..5ce1699da71d 100644
--- a/drivers/hwmon/ltc2992.c
+++ b/drivers/hwmon/ltc2992.c
@@ -421,10 +421,16 @@ static int ltc2992_get_voltage(struct ltc2992_state *st, u32 reg, u32 scale, lon
static int ltc2992_set_voltage(struct ltc2992_state *st, u32 reg, u32 scale, long val)
{
- val = DIV_ROUND_CLOSEST(val * 1000, scale);
- val = val << 4;
+ u32 reg_val;
+ long vmax;
+
+ vmax = DIV_ROUND_CLOSEST_ULL(0xFFFULL * scale, 1000);
+ val = max(val, 0L);
+ val = min(val, vmax);
+ reg_val = min(DIV_ROUND_CLOSEST_ULL((u64)val * 1000, scale),
+ 0xFFFULL) << 4;
- return ltc2992_write_reg(st, reg, 2, val);
+ return ltc2992_write_reg(st, reg, 2, reg_val);
}
static int ltc2992_read_gpio_alarm(struct ltc2992_state *st, int nr_gpio, u32 attr, long *val)
@@ -549,9 +555,15 @@ static int ltc2992_get_current(struct ltc2992_state *st, u32 reg, u32 channel, l
static int ltc2992_set_current(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{
u32 reg_val;
+ long cmax;
- reg_val = DIV_ROUND_CLOSEST(val * st->r_sense_uohm[channel], LTC2992_IADC_NANOV_LSB);
- reg_val = reg_val << 4;
+ cmax = DIV_ROUND_CLOSEST_ULL(0xFFFULL * LTC2992_IADC_NANOV_LSB,
+ st->r_sense_uohm[channel]);
+ val = max(val, 0L);
+ val = min(val, cmax);
+ reg_val = min(DIV_ROUND_CLOSEST_ULL((u64)val * st->r_sense_uohm[channel],
+ LTC2992_IADC_NANOV_LSB),
+ 0xFFFULL) << 4;
return ltc2992_write_reg(st, reg, 2, reg_val);
}
@@ -615,8 +627,10 @@ static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, lon
if (reg_val < 0)
return reg_val;
- *val = mul_u64_u32_div(reg_val, LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB,
- st->r_sense_uohm[channel] * 1000);
+ *val = mul_u64_u32_div(reg_val,
+ LTC2992_VADC_UV_LSB / 1000 *
+ LTC2992_IADC_NANOV_LSB,
+ st->r_sense_uohm[channel]);
return 0;
}
@@ -624,9 +638,18 @@ static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, lon
static int ltc2992_set_power(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{
u32 reg_val;
-
- reg_val = mul_u64_u32_div(val, st->r_sense_uohm[channel] * 1000,
- LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB);
+ u64 pmax, uval;
+
+ uval = max(val, 0L);
+ pmax = mul_u64_u32_div(0xFFFFFFULL,
+ LTC2992_VADC_UV_LSB / 1000 *
+ LTC2992_IADC_NANOV_LSB,
+ st->r_sense_uohm[channel]);
+ uval = min(uval, pmax);
+ reg_val = min(mul_u64_u32_div(uval, st->r_sense_uohm[channel],
+ LTC2992_VADC_UV_LSB / 1000 *
+ LTC2992_IADC_NANOV_LSB),
+ 0xFFFFFFULL);
return ltc2992_write_reg(st, reg, 3, reg_val);
}
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index a6c407d36800..50e97e2ed2cf 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -182,7 +182,7 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
* Clear the flag before adding the device so that fw_devlink
* doesn't skip adding consumers to this device.
*/
- rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
+ fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
client = of_i2c_register_device(adap, rd->dn);
if (IS_ERR(client)) {
dev_err(&adap->dev, "failed to create client for '%pOF'\n",
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index e147eaf1a3b1..0f1361bbafa3 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -241,12 +241,17 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
struct ad7768_state *st = iio_priv(indio_dev);
int readval, ret;
- reinit_completion(&st->completion);
-
ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
if (ret < 0)
return ret;
+ reinit_completion(&st->completion);
+
+ /* One-shot mode requires a SYNC pulse to generate a new sample */
+ ret = ad7768_send_sync_pulse(st);
+ if (ret)
+ return ret;
+
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000));
if (!ret)
diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
index 263fc3a1b87e..8856d85db4bb 100644
--- a/drivers/iio/adc/ti-ads7950.c
+++ b/drivers/iio/adc/ti-ads7950.c
@@ -47,8 +47,6 @@
#define TI_ADS7950_MAX_CHAN 16
#define TI_ADS7950_NUM_GPIOS 4
-#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
-
/* val = value, dec = left shift, bits = number of bits of the mask */
#define TI_ADS7950_EXTRACT(val, dec, bits) \
(((val) >> (dec)) & ((1 << (bits)) - 1))
@@ -105,8 +103,7 @@ struct ti_ads7950_state {
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
*/
- u16 rx_buf[TI_ADS7950_MAX_CHAN + 2 + TI_ADS7950_TIMESTAMP_SIZE]
- __aligned(IIO_DMA_MINALIGN);
+ u16 rx_buf[TI_ADS7950_MAX_CHAN + 2] __aligned(IIO_DMA_MINALIGN);
u16 tx_buf[TI_ADS7950_MAX_CHAN + 2];
u16 single_tx;
u16 single_rx;
@@ -313,8 +310,10 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
if (ret < 0)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->rx_buf[2],
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2],
+ sizeof(*st->rx_buf) *
+ TI_ADS7950_MAX_CHAN,
+ iio_get_time_ns(indio_dev));
out:
mutex_unlock(&st->slock);
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index e95745710610..579fd879716d 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -321,11 +321,14 @@ static int dst_fetch_ha(const struct dst_entry *dst,
if (!n)
return -ENODATA;
+ read_lock_bh(&n->lock);
if (!(n->nud_state & NUD_VALID)) {
+ read_unlock_bh(&n->lock);
neigh_event_send(n, NULL);
ret = -ENODATA;
} else {
neigh_ha_snapshot(dev_addr->dst_dev_addr, n, dst->dev);
+ read_unlock_bh(&n->lock);
}
neigh_release(n);
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 26784b296ffa..64516f898f80 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -1082,6 +1082,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
struct hns_roce_ib_create_qp_resp resp = {};
struct ib_device *ibdev = &hr_dev->ib_dev;
struct hns_roce_ib_create_qp ucmd = {};
+ unsigned long flags;
int ret;
mutex_init(&hr_qp->mutex);
@@ -1165,7 +1166,13 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
return 0;
err_flow_ctrl:
+ spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
+ hns_roce_lock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
+ init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
hns_roce_qp_remove(hr_dev, hr_qp);
+ hns_roce_unlock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
+ init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
+ spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
err_store:
free_qpc(hr_dev, hr_qp);
err_qpc:
diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 4b3b5b274e84..8009a339bf9c 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -449,6 +449,21 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp,
ndev = mc->ports[qp->port - 1];
mpc = netdev_priv(ndev);
+ /* Disable vPort RX steering before destroying RX WQ objects.
+ * Otherwise firmware still routes traffic to the destroyed queues,
+ * which can cause bogus completions on reused CQ IDs when the
+ * ethernet driver later creates new queues on mana_open().
+ *
+ * Unlike the ethernet teardown path, mana_fence_rqs() cannot be
+ * used here because the fence completion CQE is delivered on the
+ * CQ which is polled by userspace (e.g. DPDK), so there is no way
+ * for the kernel to wait for fence completion.
+ *
+ * This is best effort — if it fails there is not much we can do,
+ * and mana_cfg_vport_steering() already logs the error.
+ */
+ mana_disable_vport_rx(mpc);
+
for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) {
ibwq = ind_tbl->ind_tbl[i];
wq = container_of(ibwq, struct mana_ib_wq, ibwq);
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index c4cf91235eee..68e8b04c5388 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -193,13 +193,15 @@ int mlx4_ib_create_srq(struct ib_srq *ib_srq,
if (udata)
if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
err = -EFAULT;
- goto err_wrid;
+ goto err_srq;
}
init_attr->attr.max_wr = srq->msrq.max - 1;
return 0;
+err_srq:
+ mlx4_srq_free(dev->dev, &srq->msrq);
err_wrid:
if (udata)
mlx4_ib_db_unmap_user(ucontext, &srq->db);
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 0adb98b8dacc..5408ee2b33ec 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -2924,6 +2924,7 @@ int mlx5_ib_dev_res_srq_init(struct mlx5_ib_dev *dev)
ret = PTR_ERR(s1);
mlx5_ib_err(dev, "Couldn't create SRQ 1 for res init, err=%d\n", ret);
ib_destroy_srq(s0);
+ goto unlock;
}
devr->s0 = s0;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index c849fdbd4c99..c47ecb1c08bf 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -620,9 +620,9 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_dev *dev, struct ocrdma_pd *pd,
ucopy_err:
if (pd->dpp_enabled)
- ocrdma_del_mmap(pd->uctx, dpp_page_addr, PAGE_SIZE);
+ ocrdma_del_mmap(uctx, dpp_page_addr, PAGE_SIZE);
dpp_map_err:
- ocrdma_del_mmap(pd->uctx, db_page_addr, db_page_size);
+ ocrdma_del_mmap(uctx, db_page_addr, db_page_size);
return status;
}
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
index 9f54aa90a35a..dde1910dd8b1 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
@@ -350,7 +350,7 @@ int pvrdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
uresp.qp_tab_size = vdev->dsr->caps.max_qp;
ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
if (ret) {
- pvrdma_uar_free(vdev, &context->uar);
+ /* pvrdma_dealloc_ucontext() also frees the UAR */
pvrdma_dealloc_ucontext(&context->ibucontext);
return -EFAULT;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
index 5861e4244049..2d5e701ff961 100644
--- a/drivers/infiniband/sw/rxe/rxe_recv.c
+++ b/drivers/infiniband/sw/rxe/rxe_recv.c
@@ -330,7 +330,19 @@ void rxe_rcv(struct sk_buff *skb)
pkt->qp = NULL;
pkt->mask |= rxe_opcode[pkt->opcode].mask;
- if (unlikely(skb->len < header_size(pkt)))
+ /*
+ * Unknown opcodes have a zero-initialized rxe_opcode[] entry, so
+ * both mask and length are 0. Reject them before any length math:
+ * rxe_icrc_hdr() would otherwise compute length - RXE_BTH_BYTES
+ * and pass the underflowed value to rxe_crc32(), producing an
+ * out-of-bounds read.
+ */
+ if (unlikely(!rxe_opcode[pkt->opcode].mask ||
+ !rxe_opcode[pkt->opcode].length))
+ goto drop;
+
+ if (unlikely(pkt->paylen < header_size(pkt) + bth_pad(pkt) +
+ RXE_ICRC_SIZE))
goto drop;
err = hdr_check(pkt);
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index fa2b87c74929..70e9bf3a7042 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -536,7 +536,19 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
}
skip_check_range:
- if (pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) {
+ if (pkt->mask & RXE_ATOMIC_WRITE_MASK) {
+ /* IBA oA19-28: ATOMIC_WRITE payload is exactly 8 bytes.
+ * Reject any other length before the responder reads
+ * sizeof(u64) bytes from payload_addr(pkt); a shorter
+ * payload would read past the logical end of the packet
+ * into skb->head tailroom.
+ */
+ if (resid != sizeof(u64) || pktlen != sizeof(u64) ||
+ bth_pad(pkt)) {
+ state = RESPST_ERR_LENGTH;
+ goto err;
+ }
+ } else if (pkt->mask & RXE_WRITE_MASK) {
if (resid > mtu) {
if (pktlen != mtu || bth_pad(pkt)) {
state = RESPST_ERR_LENGTH;
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index d872054b874f..2571a782b7b6 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -765,7 +765,7 @@ struct amd_iommu {
u32 flags;
volatile u64 *cmd_sem;
- atomic64_t cmd_sem_val;
+ u64 cmd_sem_val;
#ifdef CONFIG_AMD_IOMMU_DEBUGFS
/* DebugFS Info */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 6261bc7304e9..e5fee1aae587 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1805,7 +1805,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
iommu->pci_seg = pci_seg;
raw_spin_lock_init(&iommu->lock);
- atomic64_set(&iommu->cmd_sem_val, 0);
+ iommu->cmd_sem_val = 0;
/* Add IOMMU to internal data structures */
list_add_tail(&iommu->list, &amd_iommu_list);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index d119a104a343..48cf9e9e1597 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1195,6 +1195,12 @@ static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
return iommu_queue_command_sync(iommu, cmd, true);
}
+static u64 get_cmdsem_val(struct amd_iommu *iommu)
+{
+ lockdep_assert_held(&iommu->lock);
+ return ++iommu->cmd_sem_val;
+}
+
/*
* This function queues a completion wait command into the command
* buffer of an IOMMU
@@ -1209,11 +1215,11 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
if (!iommu->need_sync)
return 0;
- data = atomic64_add_return(1, &iommu->cmd_sem_val);
- build_completion_wait(&cmd, iommu, data);
-
raw_spin_lock_irqsave(&iommu->lock, flags);
+ data = get_cmdsem_val(iommu);
+ build_completion_wait(&cmd, iommu, data);
+
ret = __iommu_queue_command_sync(iommu, &cmd, false);
raw_spin_unlock_irqrestore(&iommu->lock, flags);
@@ -2877,10 +2883,11 @@ static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
return;
build_inv_irt(&cmd, devid);
- data = atomic64_add_return(1, &iommu->cmd_sem_val);
- build_completion_wait(&cmd2, iommu, data);
raw_spin_lock_irqsave(&iommu->lock, flags);
+ data = get_cmdsem_val(iommu);
+ build_completion_wait(&cmd2, iommu, data);
+
ret = __iommu_queue_command_sync(iommu, &cmd, true);
if (ret)
goto out_err;
@@ -2894,7 +2901,6 @@ static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
out_err:
raw_spin_unlock_irqrestore(&iommu->lock, flags);
- return;
}
static void set_dte_irq_entry(struct amd_iommu *iommu, u16 devid,
diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c
index 6bd37343061e..d1300774cc2b 100644
--- a/drivers/iommu/iommufd/io_pagetable.c
+++ b/drivers/iommu/iommufd/io_pagetable.c
@@ -552,6 +552,16 @@ static int iopt_unmap_iova_range(struct io_pagetable *iopt, unsigned long start,
unmapped_bytes += area_last - area_first + 1;
down_write(&iopt->iova_rwsem);
+
+ /*
+ * After releasing the iova_rwsem concurrent allocation could
+ * place new areas at IOVAs we have already unmapped. Keep
+ * moving the start of the search forward to ignore the area
+ * already unmapped.
+ */
+ if (area_last >= last)
+ break;
+ start = area_last + 1;
}
out_unlock_iova:
diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c
index 9843fe2e5f9e..d94c5dd91bdf 100644
--- a/drivers/leds/rgb/leds-qcom-lpg.c
+++ b/drivers/leds/rgb/leds-qcom-lpg.c
@@ -1043,7 +1043,12 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) {
- refclk = lpg_clk_rates_hi_res[FIELD_GET(PWM_CLK_SELECT_HI_RES_MASK, val)];
+ unsigned int clk_idx = FIELD_GET(PWM_CLK_SELECT_HI_RES_MASK, val);
+
+ if (clk_idx >= ARRAY_SIZE(lpg_clk_rates_hi_res))
+ return -EINVAL;
+
+ refclk = lpg_clk_rates_hi_res[clk_idx];
resolution = lpg_pwm_resolution_hi_res[FIELD_GET(PWM_SIZE_HI_RES_MASK, val)];
} else {
refclk = lpg_clk_rates[FIELD_GET(PWM_CLK_SELECT_MASK, val)];
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 5bb76aab7755..a9cde9fe8fa3 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -384,7 +384,7 @@ static void dm_hash_remove_all(bool keep_open_devices, bool mark_deferred, bool
up_write(&_hash_lock);
- if (dev_skipped)
+ if (dev_skipped && !only_deferred)
DMWARN("remove_all left %d open device(s)", dev_skipped);
}
@@ -1341,6 +1341,10 @@ static void retrieve_status(struct dm_table *table,
used = param->data_start + (outptr - outbuf);
outptr = align_ptr(outptr);
+ if (!outptr || outptr > outbuf + len) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
spec->next = outptr - outbuf;
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 94b6c43dfa5c..93e3470a701c 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -993,13 +993,13 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
return NULL;
}
- *args_used = 2 + param_count;
-
- if (argc < *args_used) {
+ if (param_count > argc - 2) {
ti->error = "Insufficient mirror log arguments";
return NULL;
}
+ *args_used = 2 + param_count;
+
dl = dm_dirty_log_create(argv[0], ti, mirror_flush, param_count,
argv + 2);
if (!dl) {
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index c9a5bbb6202f..5f646c4bb98a 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -688,7 +688,7 @@ int verity_fec_ctr(struct dm_verity *v)
{
struct dm_verity_fec *f = v->fec;
struct dm_target *ti = v->ti;
- u64 hash_blocks, fec_blocks;
+ u64 hash_blocks;
int ret;
if (!verity_fec_is_enabled(v)) {
@@ -751,7 +751,8 @@ int verity_fec_ctr(struct dm_verity *v)
* it to be large enough.
*/
f->hash_blocks = f->blocks - v->data_blocks;
- if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) {
+ if (dm_bufio_get_device_size(v->bufio) <
+ v->hash_start + f->hash_blocks) {
ti->error = "Hash device is too small for "
DM_VERITY_OPT_FEC_BLOCKS;
return -E2BIG;
@@ -769,8 +770,7 @@ int verity_fec_ctr(struct dm_verity *v)
dm_bufio_set_sector_offset(f->bufio, f->start << (v->data_dev_block_bits - SECTOR_SHIFT));
- fec_blocks = div64_u64(f->rounds * f->roots, v->fec->roots << SECTOR_SHIFT);
- if (dm_bufio_get_device_size(f->bufio) < fec_blocks) {
+ if (dm_bufio_get_device_size(f->bufio) < f->rounds * f->roots) {
ti->error = "FEC device is too small";
return -E2BIG;
}
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index 942cd47eb52d..aeec5b9a1dd5 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s,
if (le32_to_cpu(n->header.nr_entries) == 1) {
struct dm_block *child;
+ int is_shared;
dm_block_t b = value64(n, 0);
+ r = dm_tm_block_is_shared(info->tm, b, &is_shared);
+ if (r)
+ return r;
+
r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child);
if (r)
return r;
+ if (is_shared)
+ inc_children(info->tm, dm_block_data(child), vt);
+
memcpy(n, dm_block_data(child),
dm_bm_block_size(dm_tm_get_bm(info->tm)));
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 6bcf6852c200..fd03c01bcf25 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1204,7 +1204,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
- raid_end_bio_io(r10_bio);
+ free_r10bio(r10_bio);
return;
}
@@ -1425,7 +1425,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
sectors = r10_bio->sectors;
if (!regular_request_wait(mddev, conf, bio, sectors)) {
- raid_end_bio_io(r10_bio);
+ free_r10bio(r10_bio);
return;
}
@@ -3986,6 +3986,8 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
nc = layout & 255;
fc = (layout >> 8) & 255;
fo = layout & (1<<16);
+ if (!nc || !fc)
+ return -1;
geo->raid_disks = disks;
geo->near_copies = nc;
geo->far_copies = fc;
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
index 53f3718c01eb..eac024485791 100644
--- a/drivers/md/raid5-cache.c
+++ b/drivers/md/raid5-cache.c
@@ -2010,15 +2010,27 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
return -ENOMEM;
while (mb_offset < le32_to_cpu(mb->meta_size)) {
+ sector_t payload_len;
+
payload = (void *)mb + mb_offset;
payload_flush = (void *)mb + mb_offset;
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) {
+ payload_len = sizeof(struct r5l_payload_data_parity) +
+ (sector_t)sizeof(__le32) *
+ (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
+ if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
+ goto mismatch;
if (r5l_recovery_verify_data_checksum(
log, ctx, page, log_offset,
payload->checksum[0]) < 0)
goto mismatch;
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_PARITY) {
+ payload_len = sizeof(struct r5l_payload_data_parity) +
+ (sector_t)sizeof(__le32) *
+ (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
+ if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
+ goto mismatch;
if (r5l_recovery_verify_data_checksum(
log, ctx, page, log_offset,
payload->checksum[0]) < 0)
@@ -2031,22 +2043,18 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
payload->checksum[1]) < 0)
goto mismatch;
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
- /* nothing to do for R5LOG_PAYLOAD_FLUSH here */
+ payload_len = sizeof(struct r5l_payload_flush) +
+ (sector_t)le32_to_cpu(payload_flush->size);
+ if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
+ goto mismatch;
} else /* not R5LOG_PAYLOAD_DATA/PARITY/FLUSH */
goto mismatch;
- if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
- mb_offset += sizeof(struct r5l_payload_flush) +
- le32_to_cpu(payload_flush->size);
- } else {
- /* DATA or PARITY payload */
+ if (le16_to_cpu(payload->header.type) != R5LOG_PAYLOAD_FLUSH) {
log_offset = r5l_ring_add(log, log_offset,
le32_to_cpu(payload->size));
- mb_offset += sizeof(struct r5l_payload_data_parity) +
- sizeof(__le32) *
- (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
}
-
+ mb_offset += payload_len;
}
put_page(page);
@@ -2097,6 +2105,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
log_offset = r5l_ring_add(log, ctx->pos, BLOCK_SECTORS);
while (mb_offset < le32_to_cpu(mb->meta_size)) {
+ sector_t payload_len;
int dd;
payload = (void *)mb + mb_offset;
@@ -2105,6 +2114,12 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
int i, count;
+ payload_len = sizeof(struct r5l_payload_flush) +
+ (sector_t)le32_to_cpu(payload_flush->size);
+ if (mb_offset + payload_len >
+ le32_to_cpu(mb->meta_size))
+ return -EINVAL;
+
count = le32_to_cpu(payload_flush->size) / sizeof(__le64);
for (i = 0; i < count; ++i) {
stripe_sect = le64_to_cpu(payload_flush->flush_stripes[i]);
@@ -2118,12 +2133,17 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
}
}
- mb_offset += sizeof(struct r5l_payload_flush) +
- le32_to_cpu(payload_flush->size);
+ mb_offset += payload_len;
continue;
}
/* DATA or PARITY payload */
+ payload_len = sizeof(struct r5l_payload_data_parity) +
+ (sector_t)sizeof(__le32) *
+ (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
+ if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
+ return -EINVAL;
+
stripe_sect = (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) ?
raid5_compute_sector(
conf, le64_to_cpu(payload->location), 0, &dd,
@@ -2188,9 +2208,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
log_offset = r5l_ring_add(log, log_offset,
le32_to_cpu(payload->size));
- mb_offset += sizeof(struct r5l_payload_data_parity) +
- sizeof(__le32) *
- (le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
+ mb_offset += payload_len;
}
return 0;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index aad2b8c0c541..6eb94e466f90 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6691,7 +6691,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio,
}
if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) {
- raid5_release_stripe(sh);
+ int hash;
+
+ spin_lock_irq(&conf->device_lock);
+ hash = sh->hash_lock_index;
+ __release_stripe(conf, sh,
+ &conf->temp_inactive_list[hash]);
+ spin_unlock_irq(&conf->device_lock);
conf->retry_read_aligned = raid_bio;
conf->retry_read_offset = scnt;
return handled;
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index a5aa6a2a028c..94239f914120 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -345,6 +345,7 @@ static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)
return err;
}
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
/*
* Use common vm_area operations to track buffer refcount.
*/
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index cfe59c3255f7..a2e63296be5d 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -2694,7 +2694,7 @@ static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
{
- s16 unit_khz_dds_val;
+ s32 unit_khz_dds_val;
u32 abs_offset_khz = abs(offset_khz);
u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
@@ -2715,7 +2715,7 @@ static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
dds = (1<<26) - dds;
} else {
ratio = 2;
- unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
+ unit_khz_dds_val = 67108864 / state->cfg.pll->internal;
if (offset_khz < 0)
unit_khz_dds_val *= -1;
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index a3d5a8a7c660..03cbacd77a80 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -1274,6 +1274,9 @@ static int imx219_probe(struct i2c_client *client)
/* Request optional enable pin */
imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
+ if (IS_ERR(imx219->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx219->reset_gpio),
+ "failed to get reset gpio\n");
/*
* The sensor must be powered for imx219_identify_module()
diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c
index 90fc8eea171f..63c1a727d5be 100644
--- a/drivers/media/i2c/imx412.c
+++ b/drivers/media/i2c/imx412.c
@@ -934,7 +934,7 @@ static int imx412_parse_hw_config(struct imx412 *imx412)
/* Request optional reset pin */
imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset",
- GPIOD_OUT_LOW);
+ GPIOD_OUT_HIGH);
if (IS_ERR(imx412->reset_gpio)) {
dev_err(imx412->dev, "failed to get reset gpio %ld\n",
PTR_ERR(imx412->reset_gpio));
diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c
index 7d55d4ca24de..e265cc78542e 100644
--- a/drivers/media/i2c/ov08d10.c
+++ b/drivers/media/i2c/ov08d10.c
@@ -217,7 +217,7 @@ static const struct ov08d10_reg lane_2_mode_3280x2460[] = {
{0x9a, 0x30},
{0xa8, 0x02},
{0xfd, 0x02},
- {0xa1, 0x01},
+ {0xa1, 0x00},
{0xa2, 0x09},
{0xa3, 0x9c},
{0xa5, 0x00},
@@ -335,7 +335,7 @@ static const struct ov08d10_reg lane_2_mode_3264x2448[] = {
{0x9a, 0x30},
{0xa8, 0x02},
{0xfd, 0x02},
- {0xa1, 0x09},
+ {0xa1, 0x08},
{0xa2, 0x09},
{0xa3, 0x90},
{0xa5, 0x08},
@@ -467,7 +467,7 @@ static const struct ov08d10_reg lane_2_mode_1632x1224[] = {
{0xaa, 0xd0},
{0xab, 0x06},
{0xac, 0x68},
- {0xa1, 0x09},
+ {0xa1, 0x04},
{0xa2, 0x04},
{0xa3, 0xc8},
{0xa5, 0x04},
@@ -615,8 +615,8 @@ static const struct ov08d10_lane_cfg lane_cfg_2 = {
static u32 ov08d10_get_format_code(struct ov08d10 *ov08d10)
{
static const u32 codes[2][2] = {
- { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10},
- { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10 },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10 },
};
return codes[ov08d10->vflip->val][ov08d10->hflip->val];
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index 8c93fe6285f8..91981437c572 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -1954,12 +1954,18 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- if (ctrl_hdlr->error)
- return ctrl_hdlr->error;
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ goto err_ctrl_handler_free;
+ }
ov8856->sd.ctrl_handler = ctrl_hdlr;
return 0;
+
+err_ctrl_handler_free:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ return ret;
}
static void ov8856_update_pad_format(struct ov8856 *ov8856,
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index a8a004f28ca0..ac290f546413 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -888,6 +888,15 @@ static int get_resources(struct saa7164_dev *dev)
return -EBUSY;
}
+static void release_resources(struct saa7164_dev *dev)
+{
+ release_mem_region(pci_resource_start(dev->pci, 0),
+ pci_resource_len(dev->pci, 0));
+
+ release_mem_region(pci_resource_start(dev->pci, 2),
+ pci_resource_len(dev->pci, 2));
+}
+
static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
{
struct saa7164_port *port = NULL;
@@ -947,9 +956,9 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
- mutex_lock(&devlist);
- list_add_tail(&dev->devlist, &saa7164_devlist);
- mutex_unlock(&devlist);
+ scoped_guard(mutex, &devlist) {
+ list_add_tail(&dev->devlist, &saa7164_devlist);
+ }
/* board config */
dev->board = UNSET;
@@ -996,11 +1005,17 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
}
/* PCI/e allocations */
- dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
- pci_resource_len(dev->pci, 0));
+ dev->lmmio = pci_ioremap_bar(dev->pci, 0);
+ if (!dev->lmmio) {
+ dev_err(&dev->pci->dev, "Failed to remap MMIO BAR 0\n");
+ goto err_ioremap_bar0;
+ }
- dev->lmmio2 = ioremap(pci_resource_start(dev->pci, 2),
- pci_resource_len(dev->pci, 2));
+ dev->lmmio2 = pci_ioremap_bar(dev->pci, 2);
+ if (!dev->lmmio2) {
+ dev_err(&dev->pci->dev, "Failed to remap MMIO BAR 2\n");
+ goto err_ioremap_bar2;
+ }
dev->bmmio = (u8 __iomem *)dev->lmmio;
dev->bmmio2 = (u8 __iomem *)dev->lmmio2;
@@ -1019,17 +1034,25 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
saa7164_pci_quirks(dev);
return 0;
+
+err_ioremap_bar2:
+ iounmap(dev->lmmio);
+err_ioremap_bar0:
+ release_resources(dev);
+
+ scoped_guard(mutex, &devlist) {
+ list_del(&dev->devlist);
+ }
+ saa7164_devcount--;
+
+ return -ENODEV;
}
static void saa7164_dev_unregister(struct saa7164_dev *dev)
{
dprintk(1, "%s()\n", __func__);
- release_mem_region(pci_resource_start(dev->pci, 0),
- pci_resource_len(dev->pci, 0));
-
- release_mem_region(pci_resource_start(dev->pci, 2),
- pci_resource_len(dev->pci, 2));
+ release_resources(dev);
if (!atomic_dec_and_test(&dev->refcount))
return;
diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
index 3975fc1b2ee3..38a083ffe6c3 100644
--- a/drivers/media/pci/zoran/zoran_card.c
+++ b/drivers/media/pci/zoran/zoran_card.c
@@ -1377,7 +1377,7 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
if (zr->codec->type != zr->card.video_codec) {
pci_err(pdev, "%s - wrong codec\n", __func__);
- goto zr_unreg_videocodec;
+ goto zr_detach_codec;
}
}
if (zr->card.video_vfe != 0) {
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 27c99f5c5b71..8ce105847501 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -441,17 +441,14 @@ static void vpu_m2m_device_run(void *priv)
{
}
-static void vpu_m2m_job_abort(void *priv)
+static int vpu_m2m_job_ready(void *priv)
{
- struct vpu_inst *inst = priv;
- struct v4l2_m2m_ctx *m2m_ctx = inst->fh.m2m_ctx;
-
- v4l2_m2m_job_finish(m2m_ctx->m2m_dev, m2m_ctx);
+ return 0;
}
static const struct v4l2_m2m_ops vpu_m2m_ops = {
.device_run = vpu_m2m_device_run,
- .job_abort = vpu_m2m_job_abort
+ .job_ready = vpu_m2m_job_ready,
};
static int vpu_vb2_queue_setup(struct vb2_queue *vq,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 4c7b46f5a7dd..5c513916cf72 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1214,6 +1214,7 @@ static int mtk_jpeg_release(struct file *file)
struct mtk_jpeg_dev *jpeg = video_drvdata(file);
struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data);
+ cancel_work_sync(&ctx->jpeg_work);
mutex_lock(&jpeg->lock);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index b9e0b6215fa0..ef369d486141 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -1324,6 +1324,7 @@ static int isp_video_open(struct file *file)
ret = vb2_queue_init(&handle->queue);
if (ret < 0) {
+ v4l2_pipeline_pm_put(&video->video.entity);
omap3isp_put(video->isp);
goto done;
}
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index 1464ef9c55bc..f3616607d4f5 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -34,7 +34,7 @@ struct igorplugusb {
struct device *dev;
struct urb *urb;
- struct usb_ctrlrequest request;
+ struct usb_ctrlrequest *request;
struct timer_list timer;
@@ -122,7 +122,7 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd)
{
int ret;
- ir->request.bRequest = cmd;
+ ir->request->bRequest = cmd;
ir->urb->transfer_flags = 0;
ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
if (ret && ret != -EPERM)
@@ -164,13 +164,17 @@ static int igorplugusb_probe(struct usb_interface *intf,
if (!ir)
return -ENOMEM;
+ ir->request = kzalloc(sizeof(*ir->request), GFP_KERNEL);
+ if (!ir->request)
+ goto fail;
+
ir->dev = &intf->dev;
timer_setup(&ir->timer, igorplugusb_timer, 0);
- ir->request.bRequest = GET_INFRACODE;
- ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
- ir->request.wLength = cpu_to_le16(MAX_PACKET);
+ ir->request->bRequest = GET_INFRACODE;
+ ir->request->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
+ ir->request->wLength = cpu_to_le16(MAX_PACKET);
ir->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ir->urb)
@@ -228,6 +232,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
usb_free_urb(ir->urb);
rc_free_device(ir->rc);
kfree(ir->buf_in);
+ kfree(ir->request);
return ret;
}
@@ -243,6 +248,7 @@ static void igorplugusb_disconnect(struct usb_interface *intf)
usb_unpoison_urb(ir->urb);
usb_free_urb(ir->urb);
kfree(ir->buf_in);
+ kfree(ir->request);
}
static const struct usb_device_id igorplugusb_table[] = {
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index d3b48a0dd1f4..8e9b156e4300 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -219,9 +219,8 @@ static void streamzap_callback(struct urb *urb)
case -ESHUTDOWN:
/*
* this urb is terminated, clean up.
- * sz might already be invalid at this point
*/
- dev_err(sz->dev, "urb terminated, status: %d\n", urb->status);
+ dev_dbg(sz->dev, "urb terminated, status: %d\n", urb->status);
return;
default:
break;
@@ -358,11 +357,16 @@ static int streamzap_probe(struct usb_interface *intf,
usb_set_intfdata(intf, sz);
- if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+ retval = usb_submit_urb(sz->urb_in, GFP_ATOMIC);
+ if (retval < 0) {
dev_err(sz->dev, "urb submit failed\n");
+ goto rc_submit_fail;
+ }
return 0;
-
+rc_submit_fail:
+ rc_free_device(sz->rdev);
+ usb_set_intfdata(intf, NULL);
rc_dev_fail:
usb_free_urb(sz->urb_in);
free_buf_in:
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 560a26f3965c..dde446a95eaa 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -32,7 +32,7 @@ struct ttusbir {
struct led_classdev led;
struct urb *bulk_urb;
- uint8_t bulk_buffer[5];
+ u8 *bulk_buffer;
int bulk_out_endp, iso_in_endp;
bool led_on, is_led_on;
atomic_t led_complete;
@@ -186,13 +186,16 @@ static int ttusbir_probe(struct usb_interface *intf,
struct rc_dev *rc;
int i, j, ret;
int altsetting = -1;
+ u8 *buffer;
tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+ buffer = kzalloc(5, GFP_KERNEL);
rc = rc_allocate_device(RC_DRIVER_IR_RAW);
- if (!tt || !rc) {
+ if (!tt || !rc || buffer) {
ret = -ENOMEM;
goto out;
}
+ tt->bulk_buffer = buffer;
/* find the correct alt setting */
for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
@@ -281,8 +284,8 @@ static int ttusbir_probe(struct usb_interface *intf,
tt->bulk_buffer[3] = 0x01;
usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
- tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
- ttusbir_bulk_complete, tt);
+ tt->bulk_out_endp), tt->bulk_buffer, 5,
+ ttusbir_bulk_complete, tt);
tt->led.name = "ttusbir:green:power";
tt->led.default_trigger = "rc-feedback";
@@ -351,6 +354,7 @@ static int ttusbir_probe(struct usb_interface *intf,
kfree(tt);
}
rc_free_device(rc);
+ kfree(buffer);
return ret;
}
@@ -373,6 +377,7 @@ static void ttusbir_disconnect(struct usb_interface *intf)
}
usb_kill_urb(tt->bulk_urb);
usb_free_urb(tt->bulk_urb);
+ kfree(tt->bulk_buffer);
usb_set_intfdata(intf, NULL);
kfree(tt);
}
diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c
index a1572381d097..0c9c855ced72 100644
--- a/drivers/media/rc/xbox_remote.c
+++ b/drivers/media/rc/xbox_remote.c
@@ -55,7 +55,7 @@ struct xbox_remote {
struct usb_interface *interface;
struct urb *irq_urb;
- unsigned char inbuf[DATA_BUFSIZE] __aligned(sizeof(u16));
+ u8 *inbuf;
char rc_name[NAME_BUFSIZE];
char rc_phys[NAME_BUFSIZE];
@@ -218,6 +218,10 @@ static int xbox_remote_probe(struct usb_interface *interface,
if (!xbox_remote || !rc_dev)
goto exit_free_dev_rdev;
+ xbox_remote->inbuf = kzalloc(DATA_BUFSIZE, GFP_KERNEL);
+ if (!xbox_remote->inbuf)
+ goto exit_free_inbuf;
+
/* Allocate URB buffer */
xbox_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!xbox_remote->irq_urb)
@@ -262,6 +266,8 @@ static int xbox_remote_probe(struct usb_interface *interface,
usb_kill_urb(xbox_remote->irq_urb);
exit_free_buffers:
usb_free_urb(xbox_remote->irq_urb);
+exit_free_inbuf:
+ kfree(xbox_remote->inbuf);
exit_free_dev_rdev:
rc_free_device(rc_dev);
kfree(xbox_remote);
@@ -286,6 +292,7 @@ static void xbox_remote_disconnect(struct usb_interface *interface)
usb_kill_urb(xbox_remote->irq_urb);
rc_unregister_device(xbox_remote->rdev);
usb_free_urb(xbox_remote->irq_urb);
+ kfree(xbox_remote->inbuf);
kfree(xbox_remote);
}
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 83ed7821fa2a..ac108330cdad 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -218,7 +218,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
int ret;
queue->queue.type = type;
- queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
queue->queue.drv_priv = queue;
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.mem_ops = &vb2_vmalloc_memops;
@@ -231,7 +231,6 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.ops = &uvc_meta_queue_qops;
break;
default:
- queue->queue.io_modes |= VB2_DMABUF;
queue->queue.ops = &uvc_queue_qops;
break;
}
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
index c5128fe96cc7..27497f0db5cc 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -16,6 +16,8 @@
#include <dt-bindings/mfd/st,stpmic1.h>
+#define STPMIC1_MAX_RETRIES 2
+
#define STPMIC1_MAIN_IRQ 0
static const struct regmap_range stpmic1_readable_ranges[] = {
@@ -121,9 +123,23 @@ static const struct regmap_irq_chip stpmic1_regmap_irq_chip = {
static int stpmic1_power_off(struct sys_off_data *data)
{
struct stpmic1 *ddata = data->cb_data;
+ int ret;
+
+ /*
+ * Attempt to shut down again, in case the first attempt failed.
+ * The STPMIC1 might get confused and the first regmap_update_bits()
+ * returns with -ETIMEDOUT / -110 . If that or similar transient
+ * failure occurs, try to shut down again. If the second attempt
+ * fails, there is some bigger problem, report it to user.
+ */
+ for (int retries = 0; retries < STPMIC1_MAX_RETRIES; retries++) {
+ ret = regmap_update_bits(ddata->regmap, MAIN_CR, SOFTWARE_SWITCH_OFF,
+ SOFTWARE_SWITCH_OFF);
+ if (!ret)
+ return NOTIFY_DONE;
+ }
- regmap_update_bits(ddata->regmap, MAIN_CR,
- SOFTWARE_SWITCH_OFF, SOFTWARE_SWITCH_OFF);
+ dev_err(ddata->dev, "Failed to access PMIC I2C bus (%d)\n", ret);
return NOTIFY_DONE;
}
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 5867af9f592c..93dba0d79b5a 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -303,6 +303,8 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
return -EINVAL;
if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
return 0;
+ if (count < sizeof(struct dot_command_header))
+ return -EINVAL;
if (*offset != 0)
return 0;
@@ -319,6 +321,11 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
return -EFAULT;
}
+ if (count < get_dot_command_size(cmd->buffer)) {
+ command_put(cmd);
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&command_data->sp->lock, flags);
if (command_data->command) {
spin_unlock_irqrestore(&command_data->sp->lock, flags);
diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c
index 6922dc6c10db..5313230f36ad 100644
--- a/drivers/misc/ibmasm/lowlevel.c
+++ b/drivers/misc/ibmasm/lowlevel.c
@@ -19,17 +19,21 @@ static struct i2o_header header = I2O_HEADER_TEMPLATE;
int ibmasm_send_i2o_message(struct service_processor *sp)
{
u32 mfa;
- unsigned int command_size;
+ size_t command_size;
struct i2o_message *message;
struct command *command = sp->current_command;
+ command_size = get_dot_command_size(command->buffer);
+ if (command_size > command->buffer_size)
+ return 1;
+ if (command_size > I2O_COMMAND_SIZE)
+ command_size = I2O_COMMAND_SIZE;
+
mfa = get_mfa_inbound(sp->base_address);
if (!mfa)
return 1;
- command_size = get_dot_command_size(command->buffer);
- header.message_size = outgoing_message_size(command_size);
-
+ header.message_size = outgoing_message_size((unsigned int)command_size);
message = get_i2o_message(sp->base_address, mfa);
memcpy_toio(&message->header, &header, sizeof(struct i2o_header));
diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
index ec816d3b38cb..521531738c9a 100644
--- a/drivers/misc/ibmasm/remote.c
+++ b/drivers/misc/ibmasm/remote.c
@@ -177,6 +177,11 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp)
writer = get_queue_writer(sp);
while (reader != writer) {
+ if (reader >= REMOTE_QUEUE_SIZE || writer >= REMOTE_QUEUE_SIZE) {
+ set_queue_reader(sp, 0);
+ break;
+ }
+
memcpy_fromio(&input, get_queue_entry(sp, reader),
sizeof(struct remote_input));
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 3564a0f63c9c..f53f0bf4ae60 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1378,6 +1378,9 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
rq_data_dir(req) == WRITE &&
(md->flags & MMC_BLK_REL_WR);
+ if (mqrq->flags & MQRQ_XFER_SINGLE_BLOCK)
+ recovery_mode = 1;
+
memset(brq, 0, sizeof(struct mmc_blk_request));
mmc_crypto_prepare_req(mqrq);
@@ -1517,10 +1520,13 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
err = 0;
if (err) {
- if (mqrq->retries++ < MMC_CQE_RETRIES)
+ if (mqrq->retries++ < MMC_CQE_RETRIES) {
+ if (rq_data_dir(req) == WRITE)
+ mqrq->flags |= MQRQ_XFER_SINGLE_BLOCK;
blk_mq_requeue_request(req, true);
- else
+ } else {
blk_mq_end_request(req, BLK_STS_IOERR);
+ }
} else if (mrq->data) {
if (blk_update_request(req, BLK_STS_OK, mrq->data->bytes_xfered))
blk_mq_requeue_request(req, true);
@@ -2058,6 +2064,8 @@ static void mmc_blk_mq_complete_rq(struct mmc_queue *mq, struct request *req)
} else if (!blk_rq_bytes(req)) {
__blk_mq_end_request(req, BLK_STS_IOERR);
} else if (mqrq->retries++ < MMC_MAX_RETRIES) {
+ if (rq_data_dir(req) == WRITE)
+ mqrq->flags |= MQRQ_XFER_SINGLE_BLOCK;
blk_mq_requeue_request(req, true);
} else {
if (mmc_card_removed(mq->card))
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index fe0b2fa3bb89..4af43f9f1476 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -297,4 +297,9 @@ static inline int mmc_card_no_uhs_ddr50_tuning(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_NO_UHS_DDR50_TUNING;
}
+static inline int mmc_card_fixed_secure_erase_trim_time(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_FIXED_SECURE_ERASE_TRIM_TIME;
+}
+
#endif
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index b396e3900717..9eed7562e267 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -188,8 +188,12 @@ static void mmc_queue_setup_discard(struct request_queue *q,
/* granularity must not be greater than max. discard */
if (card->pref_erase > max_discard)
q->limits.discard_granularity = SECTOR_SIZE;
- if (mmc_can_secure_erase_trim(card))
- blk_queue_max_secure_erase_sectors(q, max_discard);
+ if (mmc_can_secure_erase_trim(card)) {
+ if (mmc_card_fixed_secure_erase_trim_time(card))
+ blk_queue_max_secure_erase_sectors(q, UINT_MAX >> card->erase_shift);
+ else
+ blk_queue_max_secure_erase_sectors(q, max_discard);
+ }
if (mmc_can_trim(card) && card->erased_byte == 0)
blk_queue_max_write_zeroes_sectors(q, max_discard);
}
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
index 9ade3bcbb714..c30e4065c9ba 100644
--- a/drivers/mmc/core/queue.h
+++ b/drivers/mmc/core/queue.h
@@ -61,6 +61,8 @@ enum mmc_drv_op {
MMC_DRV_OP_GET_EXT_CSD,
};
+#define MQRQ_XFER_SINGLE_BLOCK BIT(0)
+
struct mmc_queue_req {
struct mmc_blk_request brq;
struct scatterlist *sg;
@@ -69,6 +71,7 @@ struct mmc_queue_req {
void *drv_op_data;
unsigned int ioc_count;
int retries;
+ u32 flags;
};
struct mmc_queue {
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index c417ed34c057..1f7406c0ab03 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -153,6 +153,15 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
+ /*
+ * On Some Kingston eMMCs, secure erase/trim time is independent
+ * of erase size, fixed at approximately 2 seconds.
+ */
+ MMC_FIXUP("IY2964", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
+ MMC_QUIRK_FIXED_SECURE_ERASE_TRIM_TIME),
+ MMC_FIXUP("IB2932", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
+ MMC_QUIRK_FIXED_SECURE_ERASE_TRIM_TIME),
+
END_FIXUP
};
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index def7997f340a..99a618884df5 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -243,12 +243,15 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
extra &= ~BIT(0);
sdhci_writel(host, extra, reg);
+ /* Disable clock while config DLL */
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
if (clock <= 52000000) {
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
dev_err(mmc_dev(host->mmc),
"Can't reduce the clock below 52MHz in HS200/HS400 mode");
- return;
+ goto enable_clk;
}
/*
@@ -268,7 +271,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
DLL_STRBIN_DELAY_NUM_SEL |
DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
- return;
+ goto enable_clk;
}
/* Reset DLL */
@@ -295,7 +298,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
500 * USEC_PER_MSEC);
if (err) {
dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
- return;
+ goto enable_clk;
}
extra = 0x1 << 16 | /* tune clock stop en */
@@ -328,6 +331,16 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
DLL_STRBIN_TAPNUM_DEFAULT |
DLL_STRBIN_TAPNUM_FROM_SW;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
+
+enable_clk:
+ /*
+ * The sdclk frequency select bits in SDHCI_CLOCK_CONTROL are not functional
+ * on Rockchip's SDHCI implementation. Instead, the clock frequency is fully
+ * controlled via external clk provider by calling clk_set_rate(). Consequently,
+ * passing 0 to sdhci_enable_clk() only re-enables the already-configured clock,
+ * which matches the hardware's actual behavior.
+ */
+ sdhci_enable_clk(host, 0);
}
static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 22e73dd6118b..e37fb1155647 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -2046,10 +2046,9 @@ static int __init docg3_probe(struct platform_device *pdev)
*
* Returns 0
*/
-static int docg3_release(struct platform_device *pdev)
+static void docg3_release(struct platform_device *pdev)
{
struct docg3_cascade *cascade = platform_get_drvdata(pdev);
- struct docg3 *docg3 = cascade->floors[0]->priv;
int floor;
doc_unregister_sysfs(pdev, cascade);
@@ -2057,8 +2056,7 @@ static int docg3_release(struct platform_device *pdev)
if (cascade->floors[floor])
doc_release_device(cascade->floors[floor]);
- bch_free(docg3->cascade->bch);
- return 0;
+ bch_free(cascade->bch);
}
#ifdef CONFIG_OF
@@ -2076,7 +2074,7 @@ static struct platform_driver g3_driver = {
},
.suspend = docg3_suspend,
.resume = docg3_resume,
- .remove = docg3_release,
+ .remove_new = docg3_release,
};
module_platform_driver_probe(g3_driver, docg3_probe);
diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c
index 6e163cb5b478..2f6098e47119 100644
--- a/drivers/mtd/spi-nor/debugfs.c
+++ b/drivers/mtd/spi-nor/debugfs.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/array_size.h>
#include <linux/debugfs.h>
#include <linux/mtd/spi-nor.h>
#include <linux/spi/spi.h>
@@ -92,7 +93,8 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes);
seq_puts(s, "flags\t\t");
- spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names));
+ spi_nor_print_flags(s, nor->flags, snor_f_names,
+ ARRAY_SIZE(snor_f_names));
seq_puts(s, "\n");
seq_puts(s, "\nopcodes\n");
diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c
index 197d2c1101ed..eb3f95231cd0 100644
--- a/drivers/mtd/spi-nor/sst.c
+++ b/drivers/mtd/spi-nor/sst.c
@@ -123,6 +123,21 @@ static const struct flash_info sst_nor_parts[] = {
.fixups = &sst26vf_nor_fixups },
};
+static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
+ const u_char *buf)
+{
+ u8 op = (len == 1) ? SPINOR_OP_BP : SPINOR_OP_AAI_WP;
+ int ret;
+
+ nor->program_opcode = op;
+ ret = spi_nor_write_data(nor, to, len, buf);
+ if (ret < 0)
+ return ret;
+ WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret);
+
+ return spi_nor_wait_till_ready(nor);
+}
+
static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -144,33 +159,35 @@ static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Start write from odd address. */
if (to % 2) {
- nor->program_opcode = SPINOR_OP_BP;
+ bool needs_write_enable = (len > 1);
/* write one byte. */
- ret = spi_nor_write_data(nor, to, 1, buf);
+ ret = sst_nor_write_data(nor, to, 1, buf);
if (ret < 0)
goto out;
- WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
- ret = spi_nor_wait_till_ready(nor);
- if (ret)
- goto out;
to++;
actual++;
+
+ /*
+ * Byte program clears the write enable latch. If more
+ * data needs to be written using the AAI sequence,
+ * re-enable writes.
+ */
+ if (needs_write_enable) {
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ goto out;
+ }
}
/* Write out most of the data here. */
for (; actual < len - 1; actual += 2) {
- nor->program_opcode = SPINOR_OP_AAI_WP;
-
/* write two bytes. */
- ret = spi_nor_write_data(nor, to, 2, buf + actual);
+ ret = sst_nor_write_data(nor, to, 2, buf + actual);
if (ret < 0)
goto out;
- WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
- ret = spi_nor_wait_till_ready(nor);
- if (ret)
- goto out;
+
to += 2;
nor->sst_write_second = true;
}
@@ -190,14 +207,9 @@ static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
if (ret)
goto out;
- nor->program_opcode = SPINOR_OP_BP;
- ret = spi_nor_write_data(nor, to, 1, buf + actual);
+ ret = sst_nor_write_data(nor, to, 1, buf + actual);
if (ret < 0)
goto out;
- WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
- ret = spi_nor_wait_till_ready(nor);
- if (ret)
- goto out;
actual += 1;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 114ebaa284da..8d481a6495e8 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2309,9 +2309,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
unblock_netpoll_tx();
}
- if (bond_mode_can_use_xmit_hash(bond))
- bond_update_slave_arr(bond, NULL);
-
if (!slave_dev->netdev_ops->ndo_bpf ||
!slave_dev->netdev_ops->ndo_xdp_xmit) {
if (bond->xdp_prog) {
@@ -2345,6 +2342,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
bpf_prog_inc(bond->xdp_prog);
}
+ if (bond_mode_can_use_xmit_hash(bond))
+ bond_update_slave_arr(bond, NULL);
+
bond_xdp_set_features(bond_dev);
slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n",
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index 6c90b4a7d955..c3ebb648d8b0 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -1399,7 +1399,7 @@ static int ucan_probe(struct usb_interface *intf,
*/
/* Prepare Memory for control transfers */
- ctl_msg_buffer = devm_kzalloc(&udev->dev,
+ ctl_msg_buffer = devm_kzalloc(&intf->dev,
sizeof(union ucan_ctl_payload),
GFP_KERNEL);
if (!ctl_msg_buffer) {
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index a332a0e3154a..be12eaf080e9 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1630,6 +1630,27 @@ static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
return 0;
}
+static netdev_features_t ibmveth_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ /* Some physical adapters do not support segmentation offload with
+ * MSS < 224. Disable GSO for such packets to avoid adapter freeze.
+ * Note: Single-segment packets (gso_segs == 1) don't need this check
+ * as they bypass the LSO path and are transmitted without segmentation.
+ */
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_size < IBMVETH_MIN_LSO_MSS) {
+ netdev_warn_once(dev,
+ "MSS %u too small for LSO, disabling GSO\n",
+ skb_shinfo(skb)->gso_size);
+ features &= ~NETIF_F_GSO_MASK;
+ }
+ }
+
+ return vlan_features_check(skb, features);
+}
+
static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_open = ibmveth_open,
.ndo_stop = ibmveth_close,
@@ -1641,6 +1662,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_set_features = ibmveth_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ibmveth_set_mac_addr,
+ .ndo_features_check = ibmveth_features_check,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ibmveth_poll_controller,
#endif
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 8468e2c59d7a..bc1c1bb83c40 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -36,6 +36,7 @@
#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL
#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL
+#define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h
index 31f75b4a67fd..b795a3a60571 100644
--- a/drivers/net/ethernet/micrel/ks8851.h
+++ b/drivers/net/ethernet/micrel/ks8851.h
@@ -408,10 +408,8 @@ struct ks8851_net {
struct gpio_desc *gpio;
struct mii_bus *mii_bus;
- void (*lock)(struct ks8851_net *ks,
- unsigned long *flags);
- void (*unlock)(struct ks8851_net *ks,
- unsigned long *flags);
+ void (*lock)(struct ks8851_net *ks);
+ void (*unlock)(struct ks8851_net *ks);
unsigned int (*rdreg16)(struct ks8851_net *ks,
unsigned int reg);
void (*wrreg16)(struct ks8851_net *ks,
diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c
index 7fa1820db9cc..b1e9d1495c01 100644
--- a/drivers/net/ethernet/micrel/ks8851_common.c
+++ b/drivers/net/ethernet/micrel/ks8851_common.c
@@ -28,25 +28,23 @@
/**
* ks8851_lock - register access lock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Claim chip register access lock
*/
-static void ks8851_lock(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_lock(struct ks8851_net *ks)
{
- ks->lock(ks, flags);
+ ks->lock(ks);
}
/**
* ks8851_unlock - register access unlock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Release chip register access lock
*/
-static void ks8851_unlock(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_unlock(struct ks8851_net *ks)
{
- ks->unlock(ks, flags);
+ ks->unlock(ks);
}
/**
@@ -129,11 +127,10 @@ static void ks8851_set_powermode(struct ks8851_net *ks, unsigned pwrmode)
static int ks8851_write_mac_addr(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
u16 val;
int i;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
/*
* Wake up chip in case it was powered off when stopped; otherwise,
@@ -149,7 +146,7 @@ static int ks8851_write_mac_addr(struct net_device *dev)
if (!netif_running(dev))
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
return 0;
}
@@ -163,12 +160,11 @@ static int ks8851_write_mac_addr(struct net_device *dev)
static void ks8851_read_mac_addr(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
u8 addr[ETH_ALEN];
u16 reg;
int i;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
for (i = 0; i < ETH_ALEN; i += 2) {
reg = ks8851_rdreg16(ks, KS_MAR(i));
@@ -177,7 +173,7 @@ static void ks8851_read_mac_addr(struct net_device *dev)
}
eth_hw_addr_set(dev, addr);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
}
/**
@@ -328,11 +324,10 @@ static irqreturn_t ks8851_irq(int irq, void *_ks)
{
struct ks8851_net *ks = _ks;
struct sk_buff_head rxq;
- unsigned long flags;
unsigned int status;
struct sk_buff *skb;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
status = ks8851_rdreg16(ks, KS_ISR);
ks8851_wrreg16(ks, KS_ISR, status);
@@ -389,14 +384,17 @@ static irqreturn_t ks8851_irq(int irq, void *_ks)
ks8851_wrreg16(ks, KS_RXCR1, rxc->rxcr1);
}
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
if (status & IRQ_LCI)
mii_check_link(&ks->mii);
- if (status & IRQ_RXI)
+ if (status & IRQ_RXI) {
+ local_bh_disable();
while ((skb = __skb_dequeue(&rxq)))
netif_rx(skb);
+ local_bh_enable();
+ }
return IRQ_HANDLED;
}
@@ -421,7 +419,6 @@ static void ks8851_flush_tx_work(struct ks8851_net *ks)
static int ks8851_net_open(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
int ret;
ret = request_threaded_irq(dev->irq, NULL, ks8851_irq,
@@ -434,7 +431,7 @@ static int ks8851_net_open(struct net_device *dev)
/* lock the card, even if we may not actually be doing anything
* else at the moment */
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
netif_dbg(ks, ifup, ks->netdev, "opening\n");
@@ -487,7 +484,7 @@ static int ks8851_net_open(struct net_device *dev)
netif_dbg(ks, ifup, ks->netdev, "network device up\n");
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
mii_check_link(&ks->mii);
return 0;
}
@@ -503,23 +500,22 @@ static int ks8851_net_open(struct net_device *dev)
static int ks8851_net_stop(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
netif_info(ks, ifdown, dev, "shutting down\n");
netif_stop_queue(dev);
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
/* turn off the IRQs and ack any outstanding */
ks8851_wrreg16(ks, KS_IER, 0x0000);
ks8851_wrreg16(ks, KS_ISR, 0xffff);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
/* stop any outstanding work */
ks8851_flush_tx_work(ks);
flush_work(&ks->rxctrl_work);
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
/* shutdown RX process */
ks8851_wrreg16(ks, KS_RXCR1, 0x0000);
@@ -528,7 +524,7 @@ static int ks8851_net_stop(struct net_device *dev)
/* set powermode to soft power down to save power */
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
/* ensure any queued tx buffers are dumped */
while (!skb_queue_empty(&ks->txq)) {
@@ -582,14 +578,13 @@ static netdev_tx_t ks8851_start_xmit(struct sk_buff *skb,
static void ks8851_rxctrl_work(struct work_struct *work)
{
struct ks8851_net *ks = container_of(work, struct ks8851_net, rxctrl_work);
- unsigned long flags;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
/* need to shutdown RXQ before modifying filter parameters */
ks8851_wrreg16(ks, KS_RXCR1, 0x00);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
}
static void ks8851_set_rx_mode(struct net_device *dev)
@@ -796,7 +791,6 @@ static int ks8851_set_eeprom(struct net_device *dev,
{
struct ks8851_net *ks = netdev_priv(dev);
int offset = ee->offset;
- unsigned long flags;
int len = ee->len;
u16 tmp;
@@ -810,7 +804,7 @@ static int ks8851_set_eeprom(struct net_device *dev,
if (!(ks->rc_ccr & CCR_EEPROM))
return -ENOENT;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
ks8851_eeprom_claim(ks);
@@ -833,7 +827,7 @@ static int ks8851_set_eeprom(struct net_device *dev,
eeprom_93cx6_wren(&ks->eeprom, false);
ks8851_eeprom_release(ks);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
return 0;
}
@@ -843,7 +837,6 @@ static int ks8851_get_eeprom(struct net_device *dev,
{
struct ks8851_net *ks = netdev_priv(dev);
int offset = ee->offset;
- unsigned long flags;
int len = ee->len;
/* must be 2 byte aligned */
@@ -853,7 +846,7 @@ static int ks8851_get_eeprom(struct net_device *dev,
if (!(ks->rc_ccr & CCR_EEPROM))
return -ENOENT;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
ks8851_eeprom_claim(ks);
@@ -861,7 +854,7 @@ static int ks8851_get_eeprom(struct net_device *dev,
eeprom_93cx6_multiread(&ks->eeprom, offset/2, (__le16 *)data, len/2);
ks8851_eeprom_release(ks);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
return 0;
}
@@ -920,7 +913,6 @@ static int ks8851_phy_reg(int reg)
static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
int result;
int ksreg;
@@ -928,9 +920,9 @@ static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg)
if (ksreg < 0)
return ksreg;
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
result = ks8851_rdreg16(ks, ksreg);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
return result;
}
@@ -965,14 +957,13 @@ static void ks8851_phy_write(struct net_device *dev,
int phy, int reg, int value)
{
struct ks8851_net *ks = netdev_priv(dev);
- unsigned long flags;
int ksreg;
ksreg = ks8851_phy_reg(reg);
if (ksreg >= 0) {
- ks8851_lock(ks, &flags);
+ ks8851_lock(ks);
ks8851_wrreg16(ks, ksreg, value);
- ks8851_unlock(ks, &flags);
+ ks8851_unlock(ks);
}
}
diff --git a/drivers/net/ethernet/micrel/ks8851_par.c b/drivers/net/ethernet/micrel/ks8851_par.c
index 96fb0ffcedb9..7f16ee5a91e2 100644
--- a/drivers/net/ethernet/micrel/ks8851_par.c
+++ b/drivers/net/ethernet/micrel/ks8851_par.c
@@ -55,29 +55,27 @@ struct ks8851_net_par {
/**
* ks8851_lock_par - register access lock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Claim chip register access lock
*/
-static void ks8851_lock_par(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_lock_par(struct ks8851_net *ks)
{
struct ks8851_net_par *ksp = to_ks8851_par(ks);
- spin_lock_irqsave(&ksp->lock, *flags);
+ spin_lock_bh(&ksp->lock);
}
/**
* ks8851_unlock_par - register access unlock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Release chip register access lock
*/
-static void ks8851_unlock_par(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_unlock_par(struct ks8851_net *ks)
{
struct ks8851_net_par *ksp = to_ks8851_par(ks);
- spin_unlock_irqrestore(&ksp->lock, *flags);
+ spin_unlock_bh(&ksp->lock);
}
/**
@@ -233,7 +231,6 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
{
struct ks8851_net *ks = netdev_priv(dev);
netdev_tx_t ret = NETDEV_TX_OK;
- unsigned long flags;
unsigned int txqcr;
u16 txmir;
int err;
@@ -241,7 +238,7 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
netif_dbg(ks, tx_queued, ks->netdev,
"%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
- ks8851_lock_par(ks, &flags);
+ ks8851_lock_par(ks);
txmir = ks8851_rdreg16_par(ks, KS_TXMIR) & 0x1fff;
@@ -262,7 +259,7 @@ static netdev_tx_t ks8851_start_xmit_par(struct sk_buff *skb,
ret = NETDEV_TX_BUSY;
}
- ks8851_unlock_par(ks, &flags);
+ ks8851_unlock_par(ks);
return ret;
}
diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c
index e33a5e7beb39..50afe8c11178 100644
--- a/drivers/net/ethernet/micrel/ks8851_spi.c
+++ b/drivers/net/ethernet/micrel/ks8851_spi.c
@@ -73,11 +73,10 @@ struct ks8851_net_spi {
/**
* ks8851_lock_spi - register access lock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Claim chip register access lock
*/
-static void ks8851_lock_spi(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_lock_spi(struct ks8851_net *ks)
{
struct ks8851_net_spi *kss = to_ks8851_spi(ks);
@@ -87,11 +86,10 @@ static void ks8851_lock_spi(struct ks8851_net *ks, unsigned long *flags)
/**
* ks8851_unlock_spi - register access unlock
* @ks: The chip state
- * @flags: Spinlock flags
*
* Release chip register access lock
*/
-static void ks8851_unlock_spi(struct ks8851_net *ks, unsigned long *flags)
+static void ks8851_unlock_spi(struct ks8851_net *ks)
{
struct ks8851_net_spi *kss = to_ks8851_spi(ks);
@@ -311,7 +309,6 @@ static void ks8851_tx_work(struct work_struct *work)
struct ks8851_net_spi *kss;
unsigned short tx_space;
struct ks8851_net *ks;
- unsigned long flags;
struct sk_buff *txb;
bool last;
@@ -319,7 +316,7 @@ static void ks8851_tx_work(struct work_struct *work)
ks = &kss->ks8851;
last = skb_queue_empty(&ks->txq);
- ks8851_lock_spi(ks, &flags);
+ ks8851_lock_spi(ks);
while (!last) {
txb = skb_dequeue(&ks->txq);
@@ -345,7 +342,7 @@ static void ks8851_tx_work(struct work_struct *work)
ks->tx_space = tx_space;
spin_unlock_bh(&ks->statelock);
- ks8851_unlock_spi(ks, &flags);
+ ks8851_unlock_spi(ks);
}
/**
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index b56a337b1e21..343f6e879af3 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2380,6 +2380,13 @@ static void mana_rss_table_init(struct mana_port_context *apc)
ethtool_rxfh_indir_default(i, apc->num_queues);
}
+int mana_disable_vport_rx(struct mana_port_context *apc)
+{
+ return mana_cfg_vport_steering(apc, TRI_STATE_FALSE, false, false,
+ false);
+}
+EXPORT_SYMBOL_NS(mana_disable_vport_rx, NET_MANA);
+
int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
bool update_hash, bool update_tab)
{
@@ -2620,12 +2627,14 @@ static int mana_dealloc_queues(struct net_device *ndev)
*/
apc->rss_state = TRI_STATE_FALSE;
- err = mana_config_rss(apc, TRI_STATE_FALSE, false, false);
+ err = mana_disable_vport_rx(apc);
if (err) {
netdev_err(ndev, "Failed to disable vPort: %d\n", err);
return err;
}
+ mana_fence_rqs(apc);
+
mana_destroy_vport(apc);
return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 1c01e3c640ce..251560887823 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -47,7 +47,7 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
while (len != 0) {
tx_q->tx_skbuff[entry] = NULL;
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
desc = tx_q->dma_tx + entry;
if (len > bmax) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index c74de09181c6..5cecbe0e3b6a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -54,7 +54,7 @@
#define DMA_MIN_RX_SIZE 64
#define DMA_MAX_RX_SIZE 1024
#define DMA_DEFAULT_RX_SIZE 512
-#define STMMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1))
+#define STMMAC_NEXT_ENTRY(x, size) ((x + 1) & (size - 1))
#undef FRAME_FILTER_DEBUG
/* #define FRAME_FILTER_DEBUG */
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index d218412ca832..45c14c1bb0ea 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -51,7 +51,7 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum,
STMMAC_RING_MODE, 0, false, skb->len);
tx_q->tx_skbuff[entry] = NULL;
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
if (priv->extend_desc)
desc = (struct dma_desc *)(tx_q->dma_etx + entry);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 4c672e1db52e..dea3d66619ce 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
stmmac_enable_dma_transmission(priv, priv->ioaddr);
- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
+ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
entry = tx_q->cur_tx;
}
u64_stats_update_begin(&txq_stats->napi_syncp);
@@ -2659,7 +2659,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
stmmac_release_tx_desc(priv, p, priv->mode);
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
}
tx_q->dirty_tx = entry;
@@ -3973,7 +3973,7 @@ static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb,
return false;
stmmac_set_tx_owner(priv, p);
- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
+ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
return true;
}
@@ -4001,7 +4001,7 @@ static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des,
while (tmp_len > 0) {
dma_addr_t curr_addr;
- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx,
+ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx,
priv->dma_conf.dma_tx_size);
WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]);
@@ -4133,7 +4133,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
stmmac_set_mss(priv, mss_desc, mss);
tx_q->mss = mss;
- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx,
+ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx,
priv->dma_conf.dma_tx_size);
WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]);
}
@@ -4258,7 +4258,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
* ndo_start_xmit will fill this descriptor the next time it's
* called and stmmac_tx_clean may clean up to this descriptor.
*/
- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
+ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
@@ -4451,7 +4451,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int len = skb_frag_size(frag);
bool last_segment = (i == (nfrags - 1));
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
WARN_ON(tx_q->tx_skbuff[entry]);
if (likely(priv->extend_desc))
@@ -4521,7 +4521,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
* ndo_start_xmit will fill this descriptor the next time it's
* called and stmmac_tx_clean may clean up to this descriptor.
*/
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
tx_q->cur_tx = entry;
if (netif_msg_pktdata(priv)) {
@@ -4691,7 +4691,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
dma_wmb();
stmmac_set_rx_owner(priv, p, use_rx_wd);
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size);
}
rx_q->dirty_rx = entry;
rx_q->rx_tail_addr = rx_q->dma_rx_phy +
@@ -4818,7 +4818,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
stmmac_enable_dma_transmission(priv, priv->ioaddr);
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size);
tx_q->cur_tx = entry;
return STMMAC_XDP_TX;
@@ -5048,7 +5048,7 @@ static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
dma_wmb();
stmmac_set_rx_owner(priv, rx_desc, use_rx_wd);
- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size);
+ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size);
}
if (rx_desc) {
@@ -5143,9 +5143,12 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
break;
/* Prefetch the next RX descriptor */
- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx,
- priv->dma_conf.dma_rx_size);
- next_entry = rx_q->cur_rx;
+ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
+ priv->dma_conf.dma_rx_size);
+ if (unlikely(next_entry == rx_q->dirty_rx))
+ break;
+
+ rx_q->cur_rx = next_entry;
if (priv->extend_desc)
np = (struct dma_desc *)(rx_q->dma_erx + next_entry);
@@ -5279,11 +5282,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
int xdp_status = 0;
- int buf_sz;
+ int bufsz;
dma_dir = page_pool_get_dma_dir(rx_q->page_pool);
- buf_sz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
- limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit);
+ bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
if (netif_msg_rx_status(priv)) {
void *rx_head;
@@ -5339,9 +5341,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
if (unlikely(status & dma_own))
break;
- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx,
- priv->dma_conf.dma_rx_size);
- next_entry = rx_q->cur_rx;
+ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
+ priv->dma_conf.dma_rx_size);
+ if (unlikely(next_entry == rx_q->dirty_rx))
+ break;
+
+ rx_q->cur_rx = next_entry;
if (priv->extend_desc)
np = (struct dma_desc *)(rx_q->dma_erx + next_entry);
@@ -5397,7 +5402,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
dma_sync_single_for_cpu(priv->device, buf->addr,
buf1_len, dma_dir);
- xdp_init_buff(&ctx.xdp, buf_sz, &rx_q->xdp_rxq);
+ xdp_init_buff(&ctx.xdp, bufsz, &rx_q->xdp_rxq);
xdp_prepare_buff(&ctx.xdp, page_address(buf->page),
buf->page_offset, buf1_len, true);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 7feb991a9592..e6320da3e594 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -1667,8 +1667,11 @@ int wx_sw_init(struct wx *wx)
wx->oem_svid = pdev->subsystem_vendor;
wx->oem_ssid = pdev->subsystem_device;
wx->bus.device = PCI_SLOT(pdev->devfn);
- wx->bus.func = FIELD_GET(WX_CFG_PORT_ST_LANID,
- rd32(wx, WX_CFG_PORT_ST));
+ if (pdev->is_virtfn)
+ wx->bus.func = PCI_FUNC(pdev->devfn);
+ else
+ wx->bus.func = FIELD_GET(WX_CFG_PORT_ST_LANID,
+ rd32(wx, WX_CFG_PORT_ST));
if (wx->oem_svid == PCI_VENDOR_ID_WANGXUN) {
wx->subsystem_vendor_id = pdev->subsystem_vendor;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index d60c26ba0ba4..d0d955467aef 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -696,7 +696,8 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
- if (etrack_id < 0x20010)
+ if (wx->mac.type == wx_mac_sp &&
+ ((etrack_id & 0xfffff) < 0x20010))
dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 4159c84035fd..2494a3a171fd 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -820,7 +820,9 @@ int txgbe_init_phy(struct txgbe *txgbe)
void txgbe_remove_phy(struct txgbe *txgbe)
{
if (txgbe->wx->media_type == sp_media_copper) {
+ rtnl_lock();
phylink_disconnect_phy(txgbe->phylink);
+ rtnl_unlock();
phylink_destroy(txgbe->phylink);
return;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 7da30a6752be..08b32b45126d 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -675,8 +675,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
return -EINVAL;
if (bus->parent && bus->parent->of_node)
- bus->parent->of_node->fwnode.flags |=
- FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD;
+ fwnode_set_flag(&bus->parent->of_node->fwnode,
+ FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD);
WARN(bus->state != MDIOBUS_ALLOCATED &&
bus->state != MDIOBUS_UNREGISTERED,
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index c59c14483177..04558fff0a99 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1738,7 +1738,8 @@ ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb,
}
info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
- info->status.rates[ts->ts_final_idx + 1].idx = -1;
+ if (ts->ts_final_idx + 1 < IEEE80211_TX_MAX_RATES)
+ info->status.rates[ts->ts_final_idx + 1].idx = -1;
if (unlikely(ts->ts_status)) {
ah->stats.ack_fail++;
diff --git a/drivers/net/wireless/broadcom/b43/xmit.c b/drivers/net/wireless/broadcom/b43/xmit.c
index 7651b1bdb592..f0b082596637 100644
--- a/drivers/net/wireless/broadcom/b43/xmit.c
+++ b/drivers/net/wireless/broadcom/b43/xmit.c
@@ -702,7 +702,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
* key index, but the ucode passed it slightly different.
*/
keyidx = b43_kidx_to_raw(dev, keyidx);
- B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key));
+ if (B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key)))
+ goto drop;
if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
wlhdr_len = ieee80211_hdrlen(fctl);
diff --git a/drivers/net/wireless/broadcom/b43legacy/xmit.c b/drivers/net/wireless/broadcom/b43legacy/xmit.c
index efd63f4ce74f..ee199d4eaf03 100644
--- a/drivers/net/wireless/broadcom/b43legacy/xmit.c
+++ b/drivers/net/wireless/broadcom/b43legacy/xmit.c
@@ -476,7 +476,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
* key index, but the ucode passed it slightly different.
*/
keyidx = b43legacy_kidx_to_raw(dev, keyidx);
- B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
+ if (B43legacy_WARN_ON(keyidx >= dev->max_nr_keys))
+ goto drop;
if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
/* Remove PROTECTED flag to mark it as decrypted. */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 6b38d9de71af..a4d0db371c89 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -2475,8 +2475,9 @@ static void brcmf_sdio_bus_stop(struct device *dev)
brcmf_dbg(TRACE, "Enter\n");
if (bus->watchdog_tsk) {
+ get_task_struct(bus->watchdog_tsk);
send_sig(SIGTERM, bus->watchdog_tsk, 1);
- kthread_stop(bus->watchdog_tsk);
+ kthread_stop_put(bus->watchdog_tsk);
bus->watchdog_tsk = NULL;
}
@@ -4557,8 +4558,9 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
if (bus) {
/* Stop watchdog task */
if (bus->watchdog_tsk) {
+ get_task_struct(bus->watchdog_tsk);
send_sig(SIGTERM, bus->watchdog_tsk, 1);
- kthread_stop(bus->watchdog_tsk);
+ kthread_stop_put(bus->watchdog_tsk);
bus->watchdog_tsk = NULL;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index c9c58419c37b..64d651c78570 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -386,7 +386,7 @@ static void mwifiex_invalidate_lists(struct mwifiex_adapter *adapter)
static void
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
{
- del_timer(&adapter->wakeup_timer);
+ del_timer_sync(&adapter->wakeup_timer);
cancel_delayed_work_sync(&adapter->devdump_work);
mwifiex_cancel_all_pending_cmd(adapter);
wake_up_interruptible(&adapter->cmd_wait_q.wait);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 22878f088804..1f29d8cd900c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -172,6 +172,11 @@ struct mt76_connac_tx_free {
extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;
+static inline bool is_mt7925(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7925;
+}
+
static inline bool is_mt7922(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7922;
@@ -245,6 +250,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
switch (mt76_chip(dev)) {
case 0x7961:
case 0x7922:
+ case 0x7925:
case 0x7663:
case 0x7622:
return false;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 570c9dcbc505..6a637d4f4236 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -170,7 +170,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev,
txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
- if (is_mt7663(dev) || is_mt7921(dev))
+ if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_AMSDU_LAST |
@@ -214,7 +214,7 @@ mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev,
u32 last_mask;
int i;
- if (is_mt7663(dev) || is_mt7921(dev))
+ if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_MSDU_LAST;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 7420d91bef0d..a388078cdaa2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -66,6 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,
if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) ||
(is_mt7921(dev) && addr == 0x900000) ||
+ (is_mt7925(dev) && addr == 0x900000) ||
(is_mt7996(dev) && addr == 0x900000))
cmd = MCU_CMD(PATCH_START_REQ);
else
@@ -3080,7 +3081,7 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info)
{
u32 mode = DL_MODE_NEED_RSP;
- if (!is_mt7921(dev) || info == PATCH_SEC_NOT_SUPPORT)
+ if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)
return mode;
switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 27391ee3564a..4740c6dc3108 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1739,7 +1739,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa)
ret |= feature_set & FW_FEATURE_SET_ENCRYPT ?
DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0;
- if (is_mt7921(dev))
+ if (is_mt7921(dev) || is_mt7925(dev))
ret |= feature_set & FW_FEATURE_ENCRY_MODE ?
DL_CONFIG_ENCRY_MODE_SEL : 0;
ret |= FIELD_PREP(DL_MODE_KEY_IDX,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index ae7a01c7ce36..5ffe08b8b85c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -361,10 +361,11 @@ void mt7921_roc_work(struct work_struct *work)
phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
roc_work);
- if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
- return;
-
mt792x_mutex_acquire(phy->dev);
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) {
+ mt792x_mutex_release(phy->dev);
+ return;
+ }
ieee80211_iterate_active_interfaces(phy->mt76->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, phy);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index d1b1b8f767fc..80a07e5f3a27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1155,6 +1155,9 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
u16 len = le16_to_cpu(rule->len);
u16 offset = len + sizeof(*rule);
+ if (buf_len < offset)
+ break;
+
pos += offset;
buf_len -= offset;
if (rule->alpha2[0] != alpha2[0] ||
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
index a99af23e4b56..ae33ac34e3cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
@@ -385,6 +385,10 @@
#define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
#define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
+#define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600
+#define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604
+#define MT7925_WFSYS_INIT_DONE 0x00001d1e
+
#define MT_HW_BOUND 0x70010020
#define MT_HW_CHIPID 0x70010200
#define MT_HW_REV 0x70010204
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 20e7f9c7c88c..5d10d981b33f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -208,6 +208,33 @@ static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset)
mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val);
}
+struct mt792xu_wfsys_desc {
+ u32 rst_reg;
+ u32 done_reg;
+ u32 done_mask;
+ u32 done_val;
+ u32 delay_ms;
+ bool need_status_sel;
+};
+
+static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = {
+ .rst_reg = MT_CBTOP_RGU_WF_SUBSYS_RST,
+ .done_reg = MT_UDMA_CONN_INFRA_STATUS,
+ .done_mask = MT_UDMA_CONN_WFSYS_INIT_DONE,
+ .done_val = MT_UDMA_CONN_WFSYS_INIT_DONE,
+ .delay_ms = 0,
+ .need_status_sel = true,
+};
+
+static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = {
+ .rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST,
+ .done_reg = MT7925_WFSYS_INIT_DONE_ADDR,
+ .done_mask = U32_MAX,
+ .done_val = MT7925_WFSYS_INIT_DONE,
+ .delay_ms = 20,
+ .need_status_sel = false,
+};
+
int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
{
int err;
@@ -238,25 +265,33 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init);
int mt792xu_wfsys_reset(struct mt792x_dev *dev)
{
+ const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ?
+ &mt7925_wfsys_desc :
+ &mt7921_wfsys_desc;
u32 val;
int i;
mt792xu_epctl_rst_opt(dev, false);
- val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
+ val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
- mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
+ mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val);
- usleep_range(10, 20);
+ if (desc->delay_ms)
+ msleep(desc->delay_ms);
+ else
+ usleep_range(10, 20);
- val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
+ val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg);
val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
- mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
+ mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val);
+
+ if (desc->need_status_sel)
+ mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
- mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) {
- val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS);
- if (val & MT_UDMA_CONN_WFSYS_INIT_DONE)
+ val = mt792xu_uhw_rr(&dev->mt76, desc->done_reg);
+ if ((val & desc->done_mask) == desc->done_val)
break;
msleep(100);
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 03aacb7a4317..5a57ffb53ace 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -4809,20 +4809,6 @@ static const struct ieee80211_rate rtl8xxxu_legacy_ratetable[] = {
{.bitrate = 540, .hw_value = 0x0b,},
};
-static void rtl8xxxu_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
-{
- if (rate <= DESC_RATE_54M)
- return;
-
- if (rate >= DESC_RATE_MCS0 && rate <= DESC_RATE_MCS15) {
- if (rate < DESC_RATE_MCS8)
- *nss = 1;
- else
- *nss = 2;
- *mcs = rate - DESC_RATE_MCS0;
- }
-}
-
static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
{
struct ieee80211_hw *hw = priv->hw;
@@ -4927,23 +4913,25 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time)
void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
u8 rate, u8 sgi, u8 bw)
{
- u8 mcs, nss;
-
rarpt->txrate.flags = 0;
if (rate <= DESC_RATE_54M) {
rarpt->txrate.legacy = rtl8xxxu_legacy_ratetable[rate].bitrate;
- } else {
- rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss);
+ } else if (rate >= DESC_RATE_MCS0 && rate <= DESC_RATE_MCS15) {
rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ if (rate < DESC_RATE_MCS8)
+ rarpt->txrate.nss = 1;
+ else
+ rarpt->txrate.nss = 2;
- rarpt->txrate.mcs = mcs;
- rarpt->txrate.nss = nss;
+ rarpt->txrate.mcs = rate - DESC_RATE_MCS0;
if (sgi)
rarpt->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
rarpt->txrate.bw = bw;
+ } else {
+ return;
}
rarpt->bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 2bfc0e822b8d..bd6d8b2af242 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1749,7 +1749,8 @@ int rtw_pci_probe(struct pci_dev *pdev,
}
/* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
- if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C &&
+ bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
rtwpci->rx_no_aspm = true;
rtw_pci_phy_cfg(rtwdev);
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 7aa5124575cf..c40f8101febc 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -70,12 +70,11 @@ static inline int rsi_create_kthread(struct rsi_common *common,
return 0;
}
-static inline int rsi_kill_thread(struct rsi_thread *handle)
+static inline void rsi_kill_thread(struct rsi_thread *handle)
{
atomic_inc(&handle->thread_done);
rsi_set_event(&handle->event);
-
- return kthread_stop(handle->task);
+ wait_for_completion(&handle->completion);
}
void rsi_mac80211_detach(struct rsi_hw *hw);
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index 24e7d491468e..6e319f1ac6dc 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -417,8 +417,20 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
offset = sizeof(struct feature_query);
for (i = 0; i < FEATURE_COUNT && offset < data_length; i++) {
+ size_t remaining = data_length - offset;
+ size_t feat_data_len, feat_total;
+
+ if (remaining < sizeof(*rt_feature))
+ break;
+
rt_feature = data + offset;
- offset += sizeof(*rt_feature) + le32_to_cpu(rt_feature->data_len);
+ feat_data_len = le32_to_cpu(rt_feature->data_len);
+
+ if (feat_data_len > remaining - sizeof(*rt_feature))
+ break;
+
+ feat_total = sizeof(*rt_feature) + feat_data_len;
+ offset += feat_total;
ft_spt_cfg = FIELD_GET(FEATURE_MSK, core->feature_set[i]);
if (ft_spt_cfg != MTK_FEATURE_MUST_BE_SUPPORTED)
@@ -428,8 +440,10 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
if (ft_spt_st != MTK_FEATURE_MUST_BE_SUPPORTED)
return -EINVAL;
- if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM)
- t7xx_port_enum_msg_handler(ctl->md, rt_feature->data);
+ if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM) {
+ t7xx_port_enum_msg_handler(ctl->md, rt_feature->data,
+ feat_data_len);
+ }
}
return 0;
diff --git a/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c b/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
index ae632ef96698..f869e4ed9ee9 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
@@ -117,6 +117,7 @@ static int fsm_ee_message_handler(struct t7xx_port *port, struct t7xx_fsm_ctl *c
* t7xx_port_enum_msg_handler() - Parse the port enumeration message to create/remove nodes.
* @md: Modem context.
* @msg: Message.
+ * @msg_len: Length of @msg in bytes.
*
* Used to control create/remove device node.
*
@@ -124,12 +125,18 @@ static int fsm_ee_message_handler(struct t7xx_port *port, struct t7xx_fsm_ctl *c
* * 0 - Success.
* * -EFAULT - Message check failure.
*/
-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg)
+int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len)
{
struct device *dev = &md->t7xx_dev->pdev->dev;
unsigned int version, port_count, i;
struct port_msg *port_msg = msg;
+ if (msg_len < sizeof(*port_msg)) {
+ dev_err(dev, "Port enum msg too short for header: need %zu, have %zu\n",
+ sizeof(*port_msg), msg_len);
+ return -EINVAL;
+ }
+
version = FIELD_GET(PORT_MSG_VERSION, le32_to_cpu(port_msg->info));
if (version != PORT_ENUM_VER ||
le32_to_cpu(port_msg->head_pattern) != PORT_ENUM_HEAD_PATTERN ||
@@ -141,6 +148,13 @@ int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg)
}
port_count = FIELD_GET(PORT_MSG_PRT_CNT, le32_to_cpu(port_msg->info));
+
+ if (msg_len < struct_size(port_msg, data, port_count)) {
+ dev_err(dev, "Port enum msg too short: need %zu, have %zu\n",
+ struct_size(port_msg, data, port_count), msg_len);
+ return -EINVAL;
+ }
+
for (i = 0; i < port_count; i++) {
u32 port_info = le32_to_cpu(port_msg->data[i]);
unsigned int ch_id;
@@ -191,7 +205,7 @@ static int control_msg_handler(struct t7xx_port *port, struct sk_buff *skb)
case CTL_ID_PORT_ENUM:
skb_pull(skb, sizeof(*ctrl_msg_h));
- ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data);
+ ret = t7xx_port_enum_msg_handler(ctl->md, (struct port_msg *)skb->data, skb->len);
if (!ret)
ret = port_ctl_send_msg_to_md(port, CTL_ID_PORT_ENUM, 0);
else
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index 81d059fbc0fb..6784c6b783a4 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -95,7 +95,7 @@ void t7xx_port_proxy_reset(struct port_proxy *port_prox);
void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
int t7xx_port_proxy_init(struct t7xx_modem *md);
void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state);
-int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg);
+int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg, size_t msg_len);
int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
bool en_flag);
diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c
index 9b1019ee7478..04bb23757a52 100644
--- a/drivers/nvme/host/apple.c
+++ b/drivers/nvme/host/apple.c
@@ -1208,11 +1208,7 @@ static int apple_nvme_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl)
{
- struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl);
-
- if (anv->ctrl.admin_q)
- blk_put_queue(anv->ctrl.admin_q);
- put_device(anv->dev);
+ put_device(ctrl->dev);
}
static const struct nvme_ctrl_ops nvme_ctrl_ops = {
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 215aa871092d..48c46c942253 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2943,7 +2943,7 @@ static int nvme_init_non_mdts_limits(struct nvme_ctrl *ctrl)
if (id->dmrl)
ctrl->max_discard_segments = id->dmrl;
ctrl->dmrsl = le32_to_cpu(id->dmrsl);
- if (id->wzsl)
+ if (id->wzsl && !(ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
ctrl->max_zeroes_sectors = nvme_mps_to_sectors(ctrl, id->wzsl);
free_data:
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 6f78577fb70d..40d9be6468b5 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3589,6 +3589,8 @@ static const struct pci_device_id nvme_id_table[] = {
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
{ PCI_DEVICE(0x2646, 0x501E), /* KINGSTON OM3PGP4xxxxQ OS21011 NVMe SSD */
.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+ { PCI_DEVICE(0x2646, 0x502F), /* KINGSTON OM3SGP4xxxxK NVMe SSD */
+ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
{ PCI_DEVICE(0x1f40, 0x1202), /* Netac Technologies Co. NV3000 NVMe SSD */
.driver_data = NVME_QUIRK_BOGUS_NID, },
{ PCI_DEVICE(0x1f40, 0x5236), /* Netac Technologies Co. NV7000 NVMe SSD */
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 1cf6dfac1836..5a2adfc7c796 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1497,7 +1497,7 @@ static void nvmet_ctrl_free(struct kref *ref)
nvmet_stop_keep_alive_timer(ctrl);
- flush_work(&ctrl->async_event_work);
+ cancel_work_sync(&ctrl->async_event_work);
cancel_work_sync(&ctrl->fatal_err_work);
nvmet_destroy_auth(ctrl);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index d10248a5c0a5..04c6a3b40429 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1759,7 +1759,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
if (of_stdout)
- of_stdout->fwnode.flags |= FWNODE_FLAG_BEST_EFFORT;
+ fwnode_set_flag(&of_stdout->fwnode, FWNODE_FLAG_BEST_EFFORT);
}
if (!of_aliases)
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 18393800546c..ab109bb92cf4 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -224,7 +224,7 @@ static void __of_attach_node(struct device_node *np)
np->sibling = np->parent->child;
np->parent->child = np;
of_node_clear_flag(np, OF_DETACHED);
- np->fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
+ fwnode_set_flag(&np->fwnode, FWNODE_FLAG_NOT_DEVICE);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index ccf7f0ffa67f..18b72f891c5b 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -774,7 +774,7 @@ static int of_platform_notify(struct notifier_block *nb,
* Clear the flag before adding the device so that fw_devlink
* doesn't skip adding consumers to this device.
*/
- rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
+ fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
/* pdev_parent may be NULL when no bus platform device */
pdev_parent = of_find_device_by_node(rd->dn->parent);
pdev = of_platform_device_create(rd->dn, NULL,
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 4b7e663feee3..9af9d3f7418f 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -3862,7 +3862,6 @@ static int testdrv_probe(struct pci_dev *pdev, const struct pci_device_id *id)
size = info->dtbo_end - info->dtbo_begin;
ret = of_overlay_fdt_apply(info->dtbo_begin, size, &ovcs_id, dn);
- of_node_put(dn);
if (ret)
return ret;
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index 73c93e9cfa51..86ef05fba217 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -193,8 +193,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
ret = request_irq(lasi->gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
if (ret < 0) {
- kfree(lasi);
- return ret;
+ goto err_free;
}
/* enable IRQ's for devices below LASI */
@@ -203,8 +202,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
/* Done init'ing, register this driver */
ret = gsc_common_setup(dev, lasi);
if (ret) {
- kfree(lasi);
- return ret;
+ goto err_irq;
}
gsc_fixup_irqs(dev, lasi, lasi_choose_irq);
@@ -214,6 +212,12 @@ static int __init lasi_init_chip(struct parisc_device *dev)
SYS_OFF_PRIO_DEFAULT, lasi_power_off, lasi);
return ret;
+
+err_irq:
+ free_irq(lasi->gsc_irq.irq, lasi);
+err_free:
+ kfree(lasi);
+ return ret;
}
static struct parisc_device_id lasi_tbl[] __initdata = {
diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
index 87154992ea11..e5a7d1735649 100644
--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
+++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
@@ -331,6 +331,8 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
dev_err(dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(chan);
ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
}
err_unmap:
@@ -402,6 +404,8 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
dev_err(dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(chan);
ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
}
err_unmap:
diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c
index 9aac2c6f3bb9..b759b4e0bfb5 100644
--- a/drivers/pci/endpoint/functions/pci-epf-ntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c
@@ -1494,47 +1494,6 @@ static int epf_ntb_db_mw_bar_init(struct epf_ntb *ntb,
return ret;
}
-/**
- * epf_ntb_epc_destroy_interface() - Cleanup NTB EPC interface
- * @ntb: NTB device that facilitates communication between HOST1 and HOST2
- * @type: PRIMARY interface or SECONDARY interface
- *
- * Unbind NTB function device from EPC and relinquish reference to pci_epc
- * for each of the interface.
- */
-static void epf_ntb_epc_destroy_interface(struct epf_ntb *ntb,
- enum pci_epc_interface_type type)
-{
- struct epf_ntb_epc *ntb_epc;
- struct pci_epc *epc;
- struct pci_epf *epf;
-
- if (type < 0)
- return;
-
- epf = ntb->epf;
- ntb_epc = ntb->epc[type];
- if (!ntb_epc)
- return;
- epc = ntb_epc->epc;
- pci_epc_remove_epf(epc, epf, type);
- pci_epc_put(epc);
-}
-
-/**
- * epf_ntb_epc_destroy() - Cleanup NTB EPC interface
- * @ntb: NTB device that facilitates communication between HOST1 and HOST2
- *
- * Wrapper for epf_ntb_epc_destroy_interface() to cleanup all the NTB interfaces
- */
-static void epf_ntb_epc_destroy(struct epf_ntb *ntb)
-{
- enum pci_epc_interface_type type;
-
- for (type = PRIMARY_INTERFACE; type <= SECONDARY_INTERFACE; type++)
- epf_ntb_epc_destroy_interface(ntb, type);
-}
-
/**
* epf_ntb_epc_create_interface() - Create and initialize NTB EPC interface
* @ntb: NTB device that facilitates communication between HOST1 and HOST2
@@ -1614,15 +1573,8 @@ static int epf_ntb_epc_create(struct epf_ntb *ntb)
ret = epf_ntb_epc_create_interface(ntb, epf->sec_epc,
SECONDARY_INTERFACE);
- if (ret) {
+ if (ret)
dev_err(dev, "SECONDARY intf: Fail to create NTB EPC\n");
- goto err_epc_create;
- }
-
- return 0;
-
-err_epc_create:
- epf_ntb_epc_destroy_interface(ntb, PRIMARY_INTERFACE);
return ret;
}
@@ -1887,7 +1839,7 @@ static int epf_ntb_bind(struct pci_epf *epf)
ret = epf_ntb_init_epc_bar(ntb);
if (ret) {
dev_err(dev, "Failed to create NTB EPC\n");
- goto err_bar_init;
+ return ret;
}
ret = epf_ntb_config_spad_bar_alloc_interface(ntb);
@@ -1909,9 +1861,6 @@ static int epf_ntb_bind(struct pci_epf *epf)
err_bar_alloc:
epf_ntb_config_spad_bar_free(ntb);
-err_bar_init:
- epf_ntb_epc_destroy(ntb);
-
return ret;
}
@@ -1927,7 +1876,6 @@ static void epf_ntb_unbind(struct pci_epf *epf)
epf_ntb_epc_cleanup(ntb);
epf_ntb_config_spad_bar_free(ntb);
- epf_ntb_epc_destroy(ntb);
}
#define EPF_NTB_R(_name) \
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b82927905968..a21192ec5689 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2426,10 +2426,9 @@ EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
#ifdef CONFIG_PCIEAER
void pcie_clear_device_status(struct pci_dev *dev)
{
- u16 sta;
-
- pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
- pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
+ pcie_capability_write_word(dev, PCI_EXP_DEVSTA,
+ PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED |
+ PCI_EXP_DEVSTA_FED | PCI_EXP_DEVSTA_URD);
}
#endif
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 42a0f86b72fa..608908552daf 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -849,8 +849,6 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
* 3) There are multiple errors and prior ID comparing fails;
* We check AER status registers to find possible reporter.
*/
- if (atomic_read(&dev->enable_cnt) == 0)
- return false;
/* Check if AER is enabled */
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16);
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 8ebb7be52ee7..9ac5ecc9833a 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -238,6 +238,11 @@ static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
{ KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
{ KE_KEY, 0x231b, { KEY_HELP } },
+ { KE_IGNORE, 0x21ab, }, /* FnLock on */
+ { KE_IGNORE, 0x121ab, }, /* FnLock off */
+ { KE_IGNORE, 0x30021aa, }, /* kbd backlight: level 2 -> off */
+ { KE_IGNORE, 0x33221aa, }, /* kbd backlight: off -> level 1 */
+ { KE_IGNORE, 0x36421aa, }, /* kbd backlight: level 1 -> level 2*/
{ KE_END, 0 }
};
diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c
index ac05942e4e6a..ca52c2c82b2c 100644
--- a/drivers/power/supply/axp288_charger.c
+++ b/drivers/power/supply/axp288_charger.c
@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/module.h>
+#include <linux/devm-helpers.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/workqueue.h>
@@ -821,14 +822,6 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info)
return 0;
}
-static void axp288_charger_cancel_work(void *data)
-{
- struct axp288_chrg_info *info = data;
-
- cancel_work_sync(&info->otg.work);
- cancel_work_sync(&info->cable.work);
-}
-
static int axp288_charger_probe(struct platform_device *pdev)
{
int ret, i, pirq;
@@ -911,12 +904,12 @@ static int axp288_charger_probe(struct platform_device *pdev)
}
/* Cancel our work on cleanup, register this before the notifiers */
- ret = devm_add_action(dev, axp288_charger_cancel_work, info);
+ ret = devm_work_autocancel(dev, &info->cable.work,
+ axp288_charger_extcon_evt_worker);
if (ret)
return ret;
/* Register for extcon notification */
- INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker);
info->cable.nb.notifier_call = axp288_charger_handle_cable_evt;
ret = devm_extcon_register_notifier_all(dev, info->cable.edev,
&info->cable.nb);
@@ -926,8 +919,12 @@ static int axp288_charger_probe(struct platform_device *pdev)
}
schedule_work(&info->cable.work);
+ ret = devm_work_autocancel(dev, &info->otg.work,
+ axp288_charger_otg_evt_worker);
+ if (ret)
+ return ret;
+
/* Register for OTG notification */
- INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
if (info->otg.cable) {
ret = devm_extcon_register_notifier(dev, info->otg.cable,
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index ab97dd7ca5cb..32a0a05a15e2 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -199,7 +199,7 @@ static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
goto out;
}
- if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) {
+ if (vbatt > size_add(chip->pdata->vmax, MAX17042_VMAX_TOLERANCE)) {
*health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
goto out;
}
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index 6591f8f84ce8..7a46bb49d51b 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -350,6 +350,7 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
{
struct imx_tpm_pwm_chip *tpm;
int ret;
+ unsigned int i;
u32 val;
tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
@@ -383,6 +384,13 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
mutex_init(&tpm->lock);
+ /* count the enabled channels */
+ for (i = 0; i < tpm->chip.npwm; ++i) {
+ val = readl(tpm->base + PWM_IMX_TPM_CnSC(i));
+ if (FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val))
+ ++tpm->enable_count;
+ }
+
ret = pwmchip_add(&tpm->chip);
if (ret) {
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c
index 24cbdd833863..5bbe2bce740e 100644
--- a/drivers/regulator/act8945a-regulator.c
+++ b/drivers/regulator/act8945a-regulator.c
@@ -302,8 +302,9 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
num_regulators = ARRAY_SIZE(act8945a_regulators);
}
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
config.dev = &pdev->dev;
- config.dev->of_node = pdev->dev.parent->of_node;
config.driver_data = act8945a;
for (i = 0; i < num_regulators; i++) {
rdev = devm_regulator_register(&pdev->dev, ®ulators[i],
diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c
index d469481d8442..21b07ad7afe6 100644
--- a/drivers/regulator/bd9571mwv-regulator.c
+++ b/drivers/regulator/bd9571mwv-regulator.c
@@ -288,8 +288,9 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bdreg);
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
config.dev = &pdev->dev;
- config.dev->of_node = pdev->dev.parent->of_node;
config.driver_data = bdreg;
config.regmap = bdreg->regmap;
diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c
index 94abfbb2bc1e..16e9f85442c6 100644
--- a/drivers/regulator/max77650-regulator.c
+++ b/drivers/regulator/max77650-regulator.c
@@ -339,7 +339,7 @@ static int max77650_regulator_probe(struct platform_device *pdev)
parent = dev->parent;
if (!dev->of_node)
- dev->of_node = parent->of_node;
+ device_set_of_node_from_dev(dev, parent);
rdescs = devm_kcalloc(dev, MAX77650_REGULATOR_NUM_REGULATORS,
sizeof(*rdescs), GFP_KERNEL);
diff --git a/drivers/regulator/mt6357-regulator.c b/drivers/regulator/mt6357-regulator.c
index c0439a4e0b50..01af473d515e 100644
--- a/drivers/regulator/mt6357-regulator.c
+++ b/drivers/regulator/mt6357-regulator.c
@@ -410,7 +410,7 @@ static int mt6357_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
int i;
- pdev->dev.of_node = pdev->dev.parent->of_node;
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
for (i = 0; i < MT6357_MAX_REGULATOR; i++) {
config.dev = &pdev->dev;
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index bec22a001a5d..56edf81e57fd 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -1674,8 +1674,7 @@ static int rk808_regulator_probe(struct platform_device *pdev)
struct regmap *regmap;
int ret, i, nregulators;
- pdev->dev.of_node = pdev->dev.parent->of_node;
- pdev->dev.of_node_reused = true;
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap)
diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c
index feca6de68da2..425b905dc86d 100644
--- a/drivers/remoteproc/xlnx_r5_remoteproc.c
+++ b/drivers/remoteproc/xlnx_r5_remoteproc.c
@@ -179,17 +179,19 @@ static void zynqmp_r5_mb_rx_cb(struct mbox_client *cl, void *msg)
ipi = container_of(cl, struct mbox_info, mbox_cl);
- /* copy data from ipi buffer to r5_core */
+ /* copy data from ipi buffer to r5_core if IPI is buffered. */
ipi_msg = (struct zynqmp_ipi_message *)msg;
- buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf;
- len = ipi_msg->len;
- if (len > IPI_BUF_LEN_MAX) {
- dev_warn(cl->dev, "msg size exceeded than %d\n",
- IPI_BUF_LEN_MAX);
- len = IPI_BUF_LEN_MAX;
+ if (ipi_msg) {
+ buf_msg = (struct zynqmp_ipi_message *)ipi->rx_mc_buf;
+ len = ipi_msg->len;
+ if (len > IPI_BUF_LEN_MAX) {
+ dev_warn(cl->dev, "msg size exceeded than %d\n",
+ IPI_BUF_LEN_MAX);
+ len = IPI_BUF_LEN_MAX;
+ }
+ buf_msg->len = len;
+ memcpy(buf_msg->data, ipi_msg->data, len);
}
- buf_msg->len = len;
- memcpy(buf_msg->data, ipi_msg->data, len);
/* received and processed interrupt ack */
if (mbox_send_message(ipi->rx_chan, NULL) < 0)
diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c
index 850ca49186fd..d28ddb34e19e 100644
--- a/drivers/rtc/rtc-ntxec.c
+++ b/drivers/rtc/rtc-ntxec.c
@@ -110,7 +110,7 @@ static int ntxec_rtc_probe(struct platform_device *pdev)
struct rtc_device *dev;
struct ntxec_rtc *rtc;
- pdev->dev.of_node = pdev->dev.parent->of_node;
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 873c920eb0cf..8cb10cb78b1d 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3727,6 +3727,7 @@ static int sd_probe(struct device *dev)
error = device_add(&sdkp->disk_dev);
if (error) {
put_device(&sdkp->disk_dev);
+ put_disk(gd);
goto out;
}
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
index b11d0f993cc7..8719d1a99189 100644
--- a/drivers/spi/spi-at91-usart.c
+++ b/drivers/spi/spi-at91-usart.c
@@ -570,7 +570,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
spin_lock_init(&aus->lock);
init_completion(&aus->xfer_completion);
- ret = devm_spi_register_controller(&pdev->dev, controller);
+ ret = spi_register_controller(controller);
if (ret)
goto at91_usart_fail_register_controller;
@@ -648,8 +648,14 @@ static void at91_usart_spi_remove(struct platform_device *pdev)
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
+ spi_controller_get(ctlr);
+
+ spi_unregister_controller(ctlr);
+
at91_usart_spi_release_dma(ctlr);
clk_disable_unprepare(aus->clk);
+
+ spi_controller_put(ctlr);
}
static const struct dev_pm_ops at91_usart_spi_pm_ops = {
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index e073d54873b1..c9666be85f53 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1647,7 +1647,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_controller(&pdev->dev, host);
+ ret = spi_register_controller(host);
if (ret)
goto out_free_dma;
@@ -1679,8 +1679,12 @@ static void atmel_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
pm_runtime_get_sync(&pdev->dev);
+ spi_unregister_controller(host);
+
/* reset the hardware and block queue progress */
if (as->use_dma) {
atmel_spi_stop_dma(host);
@@ -1705,6 +1709,8 @@ static void atmel_spi_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+
+ spi_controller_put(host);
}
static int atmel_spi_runtime_suspend(struct device *dev)
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index ba66fe9f1f54..746a61095ad4 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -603,7 +603,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
goto out_clk_disable;
/* register and we are done */
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret) {
dev_err(dev, "spi register failed\n");
goto out_clk_disable;
@@ -626,11 +626,17 @@ static void bcm63xx_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
/* reset spi block */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
/* HW shutdown */
clk_disable_unprepare(bs->clk);
+
+ spi_controller_put(host);
}
static int bcm63xx_spi_suspend(struct device *dev)
diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c
index 4965bc86d7f5..6f71639aea03 100644
--- a/drivers/spi/spi-bcmbca-hsspi.c
+++ b/drivers/spi/spi-bcmbca-hsspi.c
@@ -557,7 +557,7 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
}
/* register and we are done */
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret)
goto out_sysgroup_disable;
@@ -581,6 +581,8 @@ static void bcmbca_hsspi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
+ spi_unregister_controller(host);
+
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
clk_disable_unprepare(bs->pll_clk);
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 81edf0a3ddf8..c6579db42eff 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -685,15 +685,26 @@ static void cdns_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
+ int ret = 0;
- cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
+ if (!spi_controller_is_target(ctlr))
+ ret = pm_runtime_get_sync(&pdev->dev);
+
+ spi_controller_get(ctlr);
+
+ spi_unregister_controller(ctlr);
+
+ if (ret >= 0)
+ cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
if (!spi_controller_is_target(ctlr)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
}
- spi_unregister_controller(ctlr);
+ spi_controller_put(ctlr);
}
/**
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index b341b6908df0..d6725a587483 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -410,9 +410,9 @@ static int mcfqspi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
pm_runtime_enable(&pdev->dev);
- status = devm_spi_register_controller(&pdev->dev, host);
+ status = spi_register_controller(host);
if (status) {
- dev_dbg(&pdev->dev, "devm_spi_register_controller failed\n");
+ dev_dbg(&pdev->dev, "failed to register controller\n");
goto fail1;
}
@@ -436,11 +436,17 @@ static void mcfqspi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
mcfqspi_cs_teardown(mcfqspi);
+
+ spi_controller_put(host);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c
index d319dc357fef..29720f8959dc 100644
--- a/drivers/spi/spi-dln2.c
+++ b/drivers/spi/spi-dln2.c
@@ -761,7 +761,7 @@ static int dln2_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_controller(&pdev->dev, host);
+ ret = spi_register_controller(host);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register host\n");
goto exit_register;
@@ -786,10 +786,16 @@ static void dln2_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct dln2_spi *dln2 = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
pm_runtime_disable(&pdev->dev);
if (dln2_spi_enable(dln2, false) < 0)
dev_err(&pdev->dev, "Failed to disable SPI module\n");
+
+ spi_controller_put(host);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index ea647ee94da8..c77b5b28ff50 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -720,7 +720,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret < 0)
goto err_pm;
@@ -785,7 +785,15 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
static void of_fsl_espi_remove(struct platform_device *dev)
{
+ struct spi_controller *host = platform_get_drvdata(dev);
+
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
pm_runtime_disable(&dev->dev);
+
+ spi_controller_put(host);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 750e2cd2594d..8c4db3537790 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -615,7 +615,7 @@ static struct spi_controller *fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(®_base->mode, regval);
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret < 0)
goto err_probe;
@@ -706,7 +706,13 @@ static void of_fsl_spi_remove(struct platform_device *ofdev)
struct spi_controller *host = platform_get_drvdata(ofdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
fsl_spi_cpm_free(mpc8xxx_spi);
+
+ spi_controller_put(host);
}
static struct platform_driver of_fsl_spi_driver = {
@@ -752,7 +758,13 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
fsl_spi_cpm_free(mpc8xxx_spi);
+
+ spi_controller_put(host);
}
MODULE_ALIAS("platform:mpc8xxx_spi");
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index d8360f94d3b7..1e2a8cf9290f 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -644,7 +644,7 @@ static int img_spfi_probe(struct platform_device *pdev)
pm_runtime_set_active(spfi->dev);
pm_runtime_enable(spfi->dev);
- ret = devm_spi_register_controller(spfi->dev, host);
+ ret = spi_register_controller(host);
if (ret)
goto disable_pm;
@@ -670,6 +670,10 @@ static void img_spfi_remove(struct platform_device *pdev)
struct spi_controller *host = platform_get_drvdata(pdev);
struct img_spfi *spfi = spi_controller_get_devdata(host);
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
if (spfi->tx_ch)
dma_release_channel(spfi->tx_ch);
if (spfi->rx_ch)
@@ -680,6 +684,8 @@ static void img_spfi_remove(struct platform_device *pdev)
clk_disable_unprepare(spfi->spfi_clk);
clk_disable_unprepare(spfi->sys_clk);
}
+
+ spi_controller_put(host);
}
#ifdef CONFIG_PM
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 76f8747c2943..8b5da079d684 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1881,6 +1881,7 @@ static int spi_imx_probe(struct platform_device *pdev)
out_runtime_pm_put:
pm_runtime_dont_use_autosuspend(spi_imx->dev);
pm_runtime_disable(spi_imx->dev);
+ pm_runtime_put_noidle(spi_imx->dev);
pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(spi_imx->clk_ipg);
@@ -1898,6 +1899,8 @@ static void spi_imx_remove(struct platform_device *pdev)
struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
int ret;
+ spi_controller_get(controller);
+
spi_unregister_controller(controller);
ret = pm_runtime_get_sync(spi_imx->dev);
@@ -1911,6 +1914,8 @@ static void spi_imx_remove(struct platform_device *pdev)
pm_runtime_disable(spi_imx->dev);
spi_imx_sdma_exit(spi_imx);
+
+ spi_controller_put(controller);
}
static int __maybe_unused spi_imx_runtime_resume(struct device *dev)
diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c
index 938e9e577e4f..a852d23caa4d 100644
--- a/drivers/spi/spi-lantiq-ssc.c
+++ b/drivers/spi/spi-lantiq-ssc.c
@@ -998,7 +998,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
"Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
- err = devm_spi_register_controller(dev, host);
+ err = spi_register_controller(host);
if (err) {
dev_err(dev, "failed to register spi host\n");
goto err_wq_destroy;
@@ -1022,6 +1022,10 @@ static void lantiq_ssc_remove(struct platform_device *pdev)
{
struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
+ spi_controller_get(spi->host);
+
+ spi_unregister_controller(spi->host);
+
lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN);
lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC);
rx_fifo_flush(spi);
@@ -1031,6 +1035,8 @@ static void lantiq_ssc_remove(struct platform_device *pdev)
destroy_workqueue(spi->wq);
clk_disable_unprepare(spi->spi_clk);
clk_put(spi->fpi_clk);
+
+ spi_controller_put(spi->host);
}
static struct platform_driver lantiq_ssc_driver = {
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index 43d134f4b42b..de8cf91658fd 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -918,8 +918,6 @@ static void meson_spicc_remove(struct platform_device *pdev)
clk_disable_unprepare(spicc->core);
clk_disable_unprepare(spicc->pclk);
-
- spi_master_put(spicc->master);
}
static const struct meson_spicc_data meson_spicc_gx_data = {
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index 32a0fa4ba50f..160861891b46 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -512,37 +512,30 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
"unable to allocate master for QSPI controller\n");
qspi = spi_controller_get_devdata(ctlr);
- platform_set_drvdata(pdev, qspi);
+ platform_set_drvdata(pdev, ctlr);
qspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(qspi->regs))
return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs),
"failed to map registers\n");
- qspi->clk = devm_clk_get(&pdev->dev, NULL);
+ qspi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(qspi->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk),
"could not get clock\n");
- ret = clk_prepare_enable(qspi->clk);
- if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to enable clock\n");
-
init_completion(&qspi->data_completion);
mutex_init(&qspi->op_lock);
qspi->irq = platform_get_irq(pdev, 0);
- if (qspi->irq < 0) {
- ret = qspi->irq;
- goto out;
- }
+ if (qspi->irq < 0)
+ return qspi->irq;
ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr,
IRQF_SHARED, pdev->name, qspi);
if (ret) {
dev_err(&pdev->dev, "request_irq failed %d\n", ret);
- goto out;
+ return ret;
}
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
@@ -552,30 +545,26 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
- if (ret) {
- dev_err_probe(&pdev->dev, ret,
- "spi_register_controller failed\n");
- goto out;
- }
+ ret = spi_register_controller(ctlr);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "spi_register_controller failed\n");
return 0;
-
-out:
- clk_disable_unprepare(qspi->clk);
-
- return ret;
}
static void mchp_coreqspi_remove(struct platform_device *pdev)
{
- struct mchp_coreqspi *qspi = platform_get_drvdata(pdev);
- u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
+ u32 control;
+ spi_unregister_controller(ctlr);
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
mchp_coreqspi_disable_ints(qspi);
control &= ~CONTROL_ENABLE;
writel_relaxed(control, qspi->regs + REG_CONTROL);
- clk_disable_unprepare(qspi->clk);
}
static const struct of_device_id mchp_coreqspi_of_match[] = {
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index b8e2d9263fc8..16ab333af009 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -519,10 +519,11 @@ static void mpc52xx_spi_remove(struct platform_device *op)
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
int i;
- cancel_work_sync(&ms->work);
free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);
+ cancel_work_sync(&ms->work);
+
for (i = 0; i < ms->gpio_cs_count; i++)
gpiod_put(ms->gpio_cs[i]);
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index cf4ee8b19e42..d20c3984f2a0 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -914,7 +914,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret < 0)
goto err_probe;
@@ -940,6 +940,8 @@ static void mtk_nor_remove(struct platform_device *pdev)
struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
+ spi_unregister_controller(ctlr);
+
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 35ca8fda45aa..c955741f0c73 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -1541,7 +1541,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
if (status < 0)
goto disable_pm;
- status = devm_spi_register_controller(&pdev->dev, ctlr);
+ status = spi_register_controller(ctlr);
if (status < 0)
goto disable_pm;
@@ -1562,11 +1562,17 @@ static void omap2_mcspi_remove(struct platform_device *pdev)
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
+ spi_controller_get(ctlr);
+
+ spi_unregister_controller(ctlr);
+
omap2_mcspi_release_dma(ctlr);
pm_runtime_dont_use_autosuspend(mcspi->dev);
pm_runtime_put_sync(mcspi->dev);
pm_runtime_disable(&pdev->dev);
+
+ spi_controller_put(ctlr);
}
/* work with hotplug and coldplug */
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 1f10f5c8e34d..77dc56ac6dfa 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -778,6 +778,7 @@ static int orion_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
status = orion_spi_reset(spi);
@@ -789,10 +790,15 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
goto out_rel_pm;
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return status;
out_rel_pm:
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
out_rel_axi_clk:
clk_disable_unprepare(spi->axi_clk);
out_rel_clk:
@@ -814,6 +820,9 @@ static void orion_spi_remove(struct platform_device *pdev)
spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
}
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 4b6f6b25219b..1e9cd86d9dcc 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -1149,7 +1149,7 @@ static int spi_qup_probe(struct platform_device *pdev)
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret)
goto disable_pm;
@@ -1274,6 +1274,10 @@ static void spi_qup_remove(struct platform_device *pdev)
struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
ret = pm_runtime_get_sync(&pdev->dev);
if (ret >= 0) {
@@ -1293,6 +1297,8 @@ static void spi_qup_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+
+ spi_controller_put(host);
}
static const struct of_device_id spi_qup_dt_match[] = {
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1615f935c8f0..9e160cba1ff3 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -921,7 +921,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
break;
}
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register controller\n");
goto err_free_dma_rx;
@@ -957,6 +957,8 @@ static void rockchip_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(rs->spiclk);
clk_disable_unprepare(rs->apb_pclk);
+ spi_unregister_controller(ctlr);
+
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 8e81f1a8623f..3a4f9a276cf5 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1176,8 +1176,14 @@ static void rspi_remove(struct platform_device *pdev)
{
struct rspi_data *rspi = platform_get_drvdata(pdev);
+ spi_controller_get(rspi->ctlr);
+
+ spi_unregister_controller(rspi->ctlr);
+
rspi_release_dma(rspi->ctlr);
pm_runtime_disable(&pdev->dev);
+
+ spi_controller_put(rspi->ctlr);
}
static const struct spi_ops rspi_ops = {
@@ -1387,9 +1393,9 @@ static int rspi_probe(struct platform_device *pdev)
if (ret < 0)
dev_warn(&pdev->dev, "DMA not available, using PIO\n");
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret < 0) {
- dev_err(&pdev->dev, "devm_spi_register_controller error.\n");
+ dev_err(&pdev->dev, "failed to register controller\n");
goto error3;
}
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index f699ce1b4025..4d50d3bf721b 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1305,7 +1305,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
sdd->regs + S3C64XX_SPI_INT_EN);
- ret = devm_spi_register_controller(&pdev->dev, host);
+ ret = spi_register_controller(host);
if (ret != 0) {
dev_err(&pdev->dev, "cannot register SPI host: %d\n", ret);
goto err_pm_put;
@@ -1336,12 +1336,9 @@ static void s3c64xx_spi_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
- writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
+ spi_unregister_controller(host);
- if (!is_polling(sdd)) {
- dma_release_channel(sdd->rx_dma.ch);
- dma_release_channel(sdd->tx_dma.ch);
- }
+ writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 5d63aa1d28e2..00b1b2099d15 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -258,9 +258,9 @@ static int hspi_probe(struct platform_device *pdev)
ctlr->transfer_one_message = hspi_transfer_one_message;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret < 0) {
- dev_err(&pdev->dev, "devm_spi_register_controller error.\n");
+ dev_err(&pdev->dev, "failed to register controller\n");
goto error2;
}
@@ -280,9 +280,15 @@ static void hspi_remove(struct platform_device *pdev)
{
struct hspi_priv *hspi = platform_get_drvdata(pdev);
+ spi_controller_get(hspi->ctlr);
+
+ spi_unregister_controller(hspi->ctlr);
+
pm_runtime_disable(&pdev->dev);
clk_put(hspi->clk);
+
+ spi_controller_put(hspi->ctlr);
}
static const struct of_device_id hspi_of_match[] = {
diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c
index 95377cf748c0..4ba822ee491a 100644
--- a/drivers/spi/spi-sprd.c
+++ b/drivers/spi/spi-sprd.c
@@ -978,7 +978,7 @@ static int sprd_spi_probe(struct platform_device *pdev)
goto err_rpm_put;
}
- ret = devm_spi_register_controller(&pdev->dev, sctlr);
+ ret = spi_register_controller(sctlr);
if (ret)
goto err_rpm_put;
@@ -1010,7 +1010,9 @@ static void sprd_spi_remove(struct platform_device *pdev)
if (ret < 0)
dev_err(ss->dev, "failed to resume SPI controller\n");
- spi_controller_suspend(sctlr);
+ spi_controller_get(sctlr);
+
+ spi_unregister_controller(sctlr);
if (ret >= 0) {
if (ss->dma.enable)
@@ -1019,6 +1021,8 @@ static void sprd_spi_remove(struct platform_device *pdev)
}
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+
+ spi_controller_put(sctlr);
}
static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev)
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 5b2cb225a419..365651504212 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -75,7 +75,7 @@
#define SUN4I_FIFO_STA_TF_CNT_BITS 16
struct sun4i_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base_addr;
struct clk *hclk;
struct clk *mclk;
@@ -161,7 +161,7 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
@@ -201,11 +201,11 @@ static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
return SUN4I_MAX_XFER_SIZE - 1;
}
-static int sun4i_spi_transfer_one(struct spi_master *master,
+static int sun4i_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
unsigned int tx_len = 0;
@@ -334,7 +334,7 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
msecs_to_jiffies(tx_time));
end = jiffies;
if (!timeout) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
@@ -389,8 +389,8 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
static int sun4i_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(sspi->hclk);
@@ -418,8 +418,8 @@ static int sun4i_spi_runtime_resume(struct device *dev)
static int sun4i_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
clk_disable_unprepare(sspi->mclk);
clk_disable_unprepare(sspi->hclk);
@@ -429,62 +429,62 @@ static int sun4i_spi_runtime_suspend(struct device *dev)
static int sun4i_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct sun4i_spi *sspi;
int ret = 0, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
- if (!master) {
- dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi));
+ if (!host) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Host\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, master);
- sspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ sspi = spi_controller_get_devdata(host);
sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
- goto err_free_master;
+ goto err_free_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto err_free_master;
+ goto err_free_host;
}
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
0, "sun4i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
- goto err_free_master;
+ goto err_free_host;
}
- sspi->master = master;
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
- master->set_cs = sun4i_spi_set_cs;
- master->transfer_one = sun4i_spi_transfer_one;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->max_transfer_size = sun4i_spi_max_transfer_size;
+ sspi->host = host;
+ host->max_speed_hz = 100 * 1000 * 1000;
+ host->min_speed_hz = 3 * 1000;
+ host->set_cs = sun4i_spi_set_cs;
+ host->transfer_one = sun4i_spi_transfer_one;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->max_transfer_size = sun4i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
- goto err_free_master;
+ goto err_free_host;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sspi->done);
@@ -496,16 +496,16 @@ static int sun4i_spi_probe(struct platform_device *pdev)
ret = sun4i_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't resume the device\n");
- goto err_free_master;
+ goto err_free_host;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err(&pdev->dev, "cannot register SPI master\n");
+ dev_err(&pdev->dev, "cannot register SPI host\n");
goto err_pm_disable;
}
@@ -514,14 +514,22 @@ static int sun4i_spi_probe(struct platform_device *pdev)
err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun4i_spi_runtime_suspend(&pdev->dev);
-err_free_master:
- spi_master_put(master);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
static void sun4i_spi_remove(struct platform_device *pdev)
{
+ struct spi_controller *host = platform_get_drvdata(pdev);
+
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
+
pm_runtime_force_suspend(&pdev->dev);
+
+ spi_controller_put(host);
}
static const struct of_device_id sun4i_spi_match[] = {
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index fddc63309773..c5655e3438c6 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -97,7 +97,7 @@ struct sun6i_spi_cfg {
};
struct sun6i_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base_addr;
dma_addr_t dma_addr_rx;
dma_addr_t dma_addr_tx;
@@ -181,7 +181,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -212,7 +212,7 @@ static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
struct spi_transfer *tfr)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;
- struct spi_master *master = sspi->master;
+ struct spi_controller *host = sspi->host;
rxdesc = NULL;
if (tfr->rx_buf) {
@@ -223,9 +223,9 @@ static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
.src_maxburst = 8,
};
- dmaengine_slave_config(master->dma_rx, &rxconf);
+ dmaengine_slave_config(host->dma_rx, &rxconf);
- rxdesc = dmaengine_prep_slave_sg(master->dma_rx,
+ rxdesc = dmaengine_prep_slave_sg(host->dma_rx,
tfr->rx_sg.sgl,
tfr->rx_sg.nents,
DMA_DEV_TO_MEM,
@@ -245,38 +245,38 @@ static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
.dst_maxburst = 8,
};
- dmaengine_slave_config(master->dma_tx, &txconf);
+ dmaengine_slave_config(host->dma_tx, &txconf);
- txdesc = dmaengine_prep_slave_sg(master->dma_tx,
+ txdesc = dmaengine_prep_slave_sg(host->dma_tx,
tfr->tx_sg.sgl,
tfr->tx_sg.nents,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
- dmaengine_terminate_sync(master->dma_rx);
+ dmaengine_terminate_sync(host->dma_rx);
return -EINVAL;
}
}
if (tfr->rx_buf) {
dmaengine_submit(rxdesc);
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (tfr->tx_buf) {
dmaengine_submit(txdesc);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
return 0;
}
-static int sun6i_spi_transfer_one(struct spi_master *master,
+static int sun6i_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
unsigned int div, div_cdr1, div_cdr2, timeout;
unsigned int start, end, tx_time;
unsigned int trig_level;
@@ -293,7 +293,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
- use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false;
+ use_dma = host->can_dma ? host->can_dma(host, spi, tfr) : false;
/* Clear pending interrupts */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
@@ -463,7 +463,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
} else {
ret = sun6i_spi_prepare_dma(sspi, tfr);
if (ret) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"%s: prepare DMA failed, ret=%d",
dev_name(&spi->dev), ret);
return ret;
@@ -486,7 +486,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
- tx_time = spi_controller_xfer_timeout(master, tfr);
+ tx_time = spi_controller_xfer_timeout(host, tfr);
start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(tx_time));
@@ -502,13 +502,13 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
timeout = wait_for_completion_timeout(&sspi->dma_rx_done,
timeout);
if (!timeout)
- dev_warn(&master->dev, "RX DMA timeout\n");
+ dev_warn(&host->dev, "RX DMA timeout\n");
}
}
end = jiffies;
if (!timeout) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
@@ -518,8 +518,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
if (ret && use_dma) {
- dmaengine_terminate_sync(master->dma_rx);
- dmaengine_terminate_sync(master->dma_tx);
+ dmaengine_terminate_sync(host->dma_rx);
+ dmaengine_terminate_sync(host->dma_tx);
}
return ret;
@@ -564,8 +564,8 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
static int sun6i_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(sspi->hclk);
@@ -601,8 +601,8 @@ static int sun6i_spi_runtime_resume(struct device *dev)
static int sun6i_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
reset_control_assert(sspi->rstc);
clk_disable_unprepare(sspi->mclk);
@@ -611,11 +611,11 @@ static int sun6i_spi_runtime_suspend(struct device *dev)
return 0;
}
-static bool sun6i_spi_can_dma(struct spi_master *master,
+static bool sun6i_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
/*
* If the number of spi words to transfer is less or equal than
@@ -627,67 +627,67 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
static int sun6i_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct sun6i_spi *sspi;
struct resource *mem;
int ret = 0, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
- if (!master) {
- dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!host) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Host\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, master);
- sspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ sspi = spi_controller_get_devdata(host);
sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
- goto err_free_master;
+ goto err_free_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto err_free_master;
+ goto err_free_host;
}
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
0, "sun6i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
- goto err_free_master;
+ goto err_free_host;
}
- sspi->master = master;
+ sspi->host = host;
sspi->cfg = of_device_get_match_data(&pdev->dev);
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
- master->use_gpio_descriptors = true;
- master->set_cs = sun6i_spi_set_cs;
- master->transfer_one = sun6i_spi_transfer_one;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
- sspi->cfg->mode_bits;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->max_transfer_size = sun6i_spi_max_transfer_size;
+ host->max_speed_hz = 100 * 1000 * 1000;
+ host->min_speed_hz = 3 * 1000;
+ host->use_gpio_descriptors = true;
+ host->set_cs = sun6i_spi_set_cs;
+ host->transfer_one = sun6i_spi_transfer_one;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ sspi->cfg->mode_bits;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->max_transfer_size = sun6i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
- goto err_free_master;
+ goto err_free_host;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sspi->done);
@@ -697,34 +697,34 @@ static int sun6i_spi_probe(struct platform_device *pdev)
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
ret = PTR_ERR(sspi->rstc);
- goto err_free_master;
+ goto err_free_host;
}
- master->dma_tx = dma_request_chan(&pdev->dev, "tx");
- if (IS_ERR(master->dma_tx)) {
+ host->dma_tx = dma_request_chan(&pdev->dev, "tx");
+ if (IS_ERR(host->dma_tx)) {
/* Check tx to see if we need defer probing driver */
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_free_master;
+ goto err_free_host;
}
dev_warn(&pdev->dev, "Failed to request TX DMA channel\n");
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
}
- master->dma_rx = dma_request_chan(&pdev->dev, "rx");
- if (IS_ERR(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
+ host->dma_rx = dma_request_chan(&pdev->dev, "rx");
+ if (IS_ERR(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_free_dma_tx;
}
dev_warn(&pdev->dev, "Failed to request RX DMA channel\n");
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
}
- if (master->dma_tx && master->dma_rx) {
+ if (host->dma_tx && host->dma_rx) {
sspi->dma_addr_tx = mem->start + SUN6I_TXDATA_REG;
sspi->dma_addr_rx = mem->start + SUN6I_RXDATA_REG;
- master->can_dma = sun6i_spi_can_dma;
+ host->can_dma = sun6i_spi_can_dma;
}
/*
@@ -742,9 +742,9 @@ static int sun6i_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err(&pdev->dev, "cannot register SPI master\n");
+ dev_err(&pdev->dev, "cannot register SPI host\n");
goto err_pm_disable;
}
@@ -754,26 +754,32 @@ static int sun6i_spi_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
sun6i_spi_runtime_suspend(&pdev->dev);
err_free_dma_rx:
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
err_free_dma_tx:
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
-err_free_master:
- spi_master_put(master);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
static void sun6i_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
pm_runtime_force_suspend(&pdev->dev);
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
+
+ spi_controller_put(host);
}
static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index aeaf7db022f0..0986c728c0f2 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -225,11 +225,11 @@ static int write_fifo(struct synquacer_spi *sspi)
return 0;
}
-static int synquacer_spi_config(struct spi_master *master,
+static int synquacer_spi_config(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
u32 rate, val, div;
@@ -263,7 +263,7 @@ static int synquacer_spi_config(struct spi_master *master,
}
sspi->transfer_mode = transfer_mode;
- rate = master->max_speed_hz;
+ rate = host->max_speed_hz;
div = DIV_ROUND_UP(rate, speed);
if (div > 254) {
@@ -350,11 +350,11 @@ static int synquacer_spi_config(struct spi_master *master,
return 0;
}
-static int synquacer_spi_transfer_one(struct spi_master *master,
+static int synquacer_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
int status = 0;
u32 words;
@@ -378,7 +378,7 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST))
xfer->bits_per_word = 32;
- ret = synquacer_spi_config(master, spi, xfer);
+ ret = synquacer_spi_config(host, spi, xfer);
/* restore */
xfer->bits_per_word = bpw;
@@ -482,7 +482,7 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
@@ -517,11 +517,11 @@ static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
return -EBUSY;
}
-static int synquacer_spi_enable(struct spi_master *master)
+static int synquacer_spi_enable(struct spi_controller *host)
{
u32 val;
int status;
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
/* Disable module */
writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
@@ -601,18 +601,18 @@ static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
static int synquacer_spi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct synquacer_spi *sspi;
int ret;
int rx_irq, tx_irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*sspi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- sspi = spi_master_get_devdata(master);
+ sspi = spi_controller_get_devdata(host);
sspi->dev = &pdev->dev;
init_completion(&sspi->transfer_done);
@@ -625,7 +625,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
- &master->max_speed_hz); /* for ACPI */
+ &host->max_speed_hz); /* for ACPI */
if (dev_of_node(&pdev->dev)) {
if (device_property_match_string(&pdev->dev,
@@ -655,21 +655,21 @@ static int synquacer_spi_probe(struct platform_device *pdev)
goto put_spi;
}
- master->max_speed_hz = clk_get_rate(sspi->clk);
+ host->max_speed_hz = clk_get_rate(sspi->clk);
}
- if (!master->max_speed_hz) {
+ if (!host->max_speed_hz) {
dev_err(&pdev->dev, "missing clock source\n");
ret = -EINVAL;
goto disable_clk;
}
- master->min_speed_hz = master->max_speed_hz / 254;
+ host->min_speed_hz = host->max_speed_hz / 254;
sspi->aces = device_property_read_bool(&pdev->dev,
"socionext,set-aces");
sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
- master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
+ host->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
rx_irq = platform_get_irq(pdev, 0);
if (rx_irq <= 0) {
@@ -699,27 +699,27 @@ static int synquacer_spi_probe(struct platform_device *pdev)
goto disable_clk;
}
- master->dev.of_node = np;
- master->dev.fwnode = pdev->dev.fwnode;
- master->auto_runtime_pm = true;
- master->bus_num = pdev->id;
+ host->dev.of_node = np;
+ host->dev.fwnode = pdev->dev.fwnode;
+ host->auto_runtime_pm = true;
+ host->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
- SPI_TX_QUAD | SPI_RX_QUAD;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
- SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
+ SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
- master->set_cs = synquacer_spi_set_cs;
- master->transfer_one = synquacer_spi_transfer_one;
+ host->set_cs = synquacer_spi_set_cs;
+ host->transfer_one = synquacer_spi_transfer_one;
- ret = synquacer_spi_enable(master);
+ ret = synquacer_spi_enable(host);
if (ret)
goto disable_clk;
pm_runtime_set_active(sspi->dev);
pm_runtime_enable(sspi->dev);
- ret = devm_spi_register_master(sspi->dev, master);
+ ret = spi_register_controller(host);
if (ret)
goto disable_pm;
@@ -730,28 +730,34 @@ static int synquacer_spi_probe(struct platform_device *pdev)
disable_clk:
clk_disable_unprepare(sspi->clk);
put_spi:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void synquacer_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
+
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
pm_runtime_disable(sspi->dev);
clk_disable_unprepare(sspi->clk);
+
+ spi_controller_put(host);
}
static int __maybe_unused synquacer_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -763,8 +769,8 @@ static int __maybe_unused synquacer_spi_suspend(struct device *dev)
static int __maybe_unused synquacer_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
if (!pm_runtime_suspended(dev)) {
@@ -778,7 +784,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
return ret;
}
- ret = synquacer_spi_enable(master);
+ ret = synquacer_spi_enable(host);
if (ret) {
clk_disable_unprepare(sspi->clk);
dev_err(dev, "failed to enable spi (%d)\n", ret);
@@ -786,7 +792,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
}
}
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret < 0)
clk_disable_unprepare(sspi->clk);
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index c99f72c9ab17..ba2c9feab1cd 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1416,7 +1416,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
}
master->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
goto exit_free_irq;
@@ -1442,6 +1442,10 @@ static void tegra_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ spi_master_get(master);
+
+ spi_unregister_master(master);
+
free_irq(tspi->irq, tspi);
if (tspi->tx_dma_chan)
@@ -1453,6 +1457,8 @@ static void tegra_spi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
tegra_spi_runtime_suspend(&pdev->dev);
+
+ spi_master_put(master);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 0c5507473f97..956178f7dd86 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -506,7 +506,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
master->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
goto exit_pm_disable;
@@ -529,11 +529,17 @@ static void tegra_sflash_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ spi_master_get(master);
+
+ spi_unregister_master(master);
+
free_irq(tsd->irq, tsd);
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
tegra_sflash_runtime_suspend(&pdev->dev);
+
+ spi_master_put(master);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 4c81516b67db..e0459fd4d549 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -40,7 +40,7 @@ struct ti_qspi {
/* list synchronization */
struct mutex list_lock;
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
void __iomem *mmap_base;
size_t mmap_size;
@@ -137,20 +137,20 @@ static inline void ti_qspi_write(struct ti_qspi *qspi,
static int ti_qspi_setup(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
int ret;
- if (spi->master->busy) {
- dev_dbg(qspi->dev, "master busy doing other transfers\n");
+ if (spi->controller->busy) {
+ dev_dbg(qspi->dev, "host busy doing other transfers\n");
return -EBUSY;
}
- if (!qspi->master->max_speed_hz) {
+ if (!qspi->host->max_speed_hz) {
dev_err(qspi->dev, "spi max frequency not defined\n");
return -EINVAL;
}
- spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
+ spi->max_speed_hz = min(spi->max_speed_hz, qspi->host->max_speed_hz);
ret = pm_runtime_resume_and_get(qspi->dev);
if (ret < 0) {
@@ -526,7 +526,7 @@ static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
static void ti_qspi_enable_memory_map(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
if (qspi->ctrl_base) {
@@ -540,7 +540,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
static void ti_qspi_disable_memory_map(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
if (qspi->ctrl_base)
@@ -554,7 +554,7 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
u8 data_nbits, u8 addr_width,
u8 dummy_bytes)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
u32 memval = opcode;
switch (data_nbits) {
@@ -576,7 +576,7 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
size_t max_len;
if (op->data.dir == SPI_MEM_DATA_IN) {
@@ -606,7 +606,7 @@ static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
static int ti_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
u32 from = 0;
int ret = 0;
@@ -633,10 +633,10 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
struct sg_table sgt;
if (virt_addr_valid(op->data.buf.in) &&
- !spi_controller_dma_map_mem_op_data(mem->spi->master, op,
+ !spi_controller_dma_map_mem_op_data(mem->spi->controller, op,
&sgt)) {
ret = ti_qspi_dma_xfer_sg(qspi, sgt, from);
- spi_controller_dma_unmap_mem_op_data(mem->spi->master,
+ spi_controller_dma_unmap_mem_op_data(mem->spi->controller,
op, &sgt);
} else {
ret = ti_qspi_dma_bounce_buffer(qspi, from,
@@ -658,10 +658,10 @@ static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
.adjust_op_size = ti_qspi_adjust_op_size,
};
-static int ti_qspi_start_transfer_one(struct spi_master *master,
+static int ti_qspi_start_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct ti_qspi *qspi = spi_master_get_devdata(master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
struct spi_transfer *t;
int status = 0, ret;
@@ -720,7 +720,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,
ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
@@ -756,33 +756,33 @@ MODULE_DEVICE_TABLE(of, ti_qspi_match);
static int ti_qspi_probe(struct platform_device *pdev)
{
struct ti_qspi *qspi;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *r, *res_mmap;
struct device_node *np = pdev->dev.of_node;
u32 max_freq;
int ret = 0, num_cs, irq;
dma_cap_mask_t mask;
- master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*qspi));
+ if (!host)
return -ENOMEM;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- master->flags = SPI_CONTROLLER_HALF_DUPLEX;
- master->setup = ti_qspi_setup;
- master->auto_runtime_pm = true;
- master->transfer_one_message = ti_qspi_start_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
- SPI_BPW_MASK(8);
- master->mem_ops = &ti_qspi_mem_ops;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = ti_qspi_setup;
+ host->auto_runtime_pm = true;
+ host->transfer_one_message = ti_qspi_start_transfer_one;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
+ host->mem_ops = &ti_qspi_mem_ops;
if (!of_property_read_u32(np, "num-cs", &num_cs))
- master->num_chipselect = num_cs;
+ host->num_chipselect = num_cs;
- qspi = spi_master_get_devdata(master);
- qspi->master = master;
+ qspi = spi_controller_get_devdata(host);
+ qspi->host = host;
qspi->dev = &pdev->dev;
platform_set_drvdata(pdev, qspi);
@@ -792,7 +792,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (r == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
}
@@ -812,7 +812,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto free_master;
+ goto free_host;
}
mutex_init(&qspi->list_lock);
@@ -820,7 +820,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
qspi->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(qspi->base)) {
ret = PTR_ERR(qspi->base);
- goto free_master;
+ goto free_host;
}
@@ -830,7 +830,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
"syscon-chipselects");
if (IS_ERR(qspi->ctrl_base)) {
ret = PTR_ERR(qspi->ctrl_base);
- goto free_master;
+ goto free_host;
}
ret = of_property_read_u32_index(np,
"syscon-chipselects",
@@ -838,7 +838,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"couldn't get ctrl_mod reg index\n");
- goto free_master;
+ goto free_host;
}
}
@@ -853,7 +853,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
- master->max_speed_hz = max_freq;
+ host->max_speed_hz = max_freq;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
@@ -876,7 +876,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
dma_release_channel(qspi->rx_chan);
goto no_dma;
}
- master->dma_rx = qspi->rx_chan;
+ host->dma_rx = qspi->rx_chan;
init_completion(&qspi->transfer_complete);
if (res_mmap)
qspi->mmap_phys_base = (dma_addr_t)res_mmap->start;
@@ -889,39 +889,38 @@ static int ti_qspi_probe(struct platform_device *pdev)
"mmap failed with error %ld using PIO mode\n",
PTR_ERR(qspi->mmap_base));
qspi->mmap_base = NULL;
- master->mem_ops = NULL;
+ host->mem_ops = NULL;
}
}
qspi->mmap_enabled = false;
qspi->current_cs = -1;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_controller(host);
if (!ret)
return 0;
ti_qspi_dma_cleanup(qspi);
pm_runtime_disable(&pdev->dev);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
return ret;
}
-static int ti_qspi_remove(struct platform_device *pdev)
+static void ti_qspi_remove(struct platform_device *pdev)
{
struct ti_qspi *qspi = platform_get_drvdata(pdev);
- int rc;
- rc = spi_master_suspend(qspi->master);
- if (rc)
- return rc;
+ spi_controller_get(qspi->host);
+
+ spi_unregister_controller(qspi->host);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
ti_qspi_dma_cleanup(qspi);
- return 0;
+ spi_controller_put(qspi->host);
}
static const struct dev_pm_ops ti_qspi_pm_ops = {
@@ -930,7 +929,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = {
static struct platform_driver ti_qspi_driver = {
.probe = ti_qspi_probe,
- .remove = ti_qspi_remove,
+ .remove_new = ti_qspi_remove,
.driver = {
.name = "ti-qspi",
.pm = &ti_qspi_pm_ops,
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index af5846cfe5e9..f34603df0114 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1406,9 +1406,6 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev)
dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d\n",
__func__, plat_dev->id, board_dat->pdev->irq);
- if (use_dma)
- pch_free_dma_buf(board_dat, data);
-
/* check for any pending messages; no action is taken if the queue
* is still full; but at least we tried. Unload anyway */
count = 500;
@@ -1432,6 +1429,9 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev)
free_irq(board_dat->pdev->irq, data);
}
+ if (use_dma)
+ pch_free_dma_buf(board_dat, data);
+
pci_iounmap(board_dat->pdev, data->io_remap_addr);
spi_unregister_master(data->master);
}
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
index f5344527af0b..bf6fcfda3c65 100644
--- a/drivers/spi/spi-uniphier.c
+++ b/drivers/spi/spi-uniphier.c
@@ -26,7 +26,7 @@ struct uniphier_spi_priv {
void __iomem *base;
dma_addr_t base_dma_addr;
struct clk *clk;
- struct spi_master *master;
+ struct spi_controller *host;
struct completion xfer_done;
int error;
@@ -127,7 +127,7 @@ static inline void uniphier_spi_irq_disable(struct uniphier_spi_priv *priv,
static void uniphier_spi_set_mode(struct spi_device *spi)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val1, val2;
/*
@@ -180,7 +180,7 @@ static void uniphier_spi_set_mode(struct spi_device *spi)
static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(priv->base + SSI_TXWDS);
@@ -198,7 +198,7 @@ static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
static void uniphier_spi_set_baudrate(struct spi_device *spi,
unsigned int speed)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val, ckdiv;
/*
@@ -217,7 +217,7 @@ static void uniphier_spi_set_baudrate(struct spi_device *spi,
static void uniphier_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
priv->error = 0;
@@ -333,7 +333,7 @@ static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(priv->base + SSI_FPS);
@@ -346,16 +346,16 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
writel(val, priv->base + SSI_FPS);
}
-static bool uniphier_spi_can_dma(struct spi_master *master,
+static bool uniphier_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
unsigned int bpw = bytes_per_word(priv->bits_per_word);
- if ((!master->dma_tx && !master->dma_rx)
- || (!master->dma_tx && t->tx_buf)
- || (!master->dma_rx && t->rx_buf))
+ if ((!host->dma_tx && !host->dma_rx)
+ || (!host->dma_tx && t->tx_buf)
+ || (!host->dma_rx && t->rx_buf))
return false;
return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH;
@@ -363,33 +363,33 @@ static bool uniphier_spi_can_dma(struct spi_master *master,
static void uniphier_spi_dma_rxcb(void *data)
{
- struct spi_master *master = data;
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = data;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy);
uniphier_spi_irq_disable(priv, SSI_IE_RXRE);
if (!(state & SSI_DMA_TX_BUSY))
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
static void uniphier_spi_dma_txcb(void *data)
{
- struct spi_master *master = data;
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = data;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy);
uniphier_spi_irq_disable(priv, SSI_IE_TXRE);
if (!(state & SSI_DMA_RX_BUSY))
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
-static int uniphier_spi_transfer_one_dma(struct spi_master *master,
+static int uniphier_spi_transfer_one_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
int buswidth;
@@ -412,23 +412,23 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
.src_maxburst = SSI_FIFO_BURST_NUM,
};
- dmaengine_slave_config(master->dma_rx, &rxconf);
+ dmaengine_slave_config(host->dma_rx, &rxconf);
rxdesc = dmaengine_prep_slave_sg(
- master->dma_rx,
+ host->dma_rx,
t->rx_sg.sgl, t->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc)
goto out_err_prep;
rxdesc->callback = uniphier_spi_dma_rxcb;
- rxdesc->callback_param = master;
+ rxdesc->callback_param = host;
uniphier_spi_irq_enable(priv, SSI_IE_RXRE);
atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy);
dmaengine_submit(rxdesc);
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (priv->tx_buf) {
@@ -439,23 +439,23 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
.dst_maxburst = SSI_FIFO_BURST_NUM,
};
- dmaengine_slave_config(master->dma_tx, &txconf);
+ dmaengine_slave_config(host->dma_tx, &txconf);
txdesc = dmaengine_prep_slave_sg(
- master->dma_tx,
+ host->dma_tx,
t->tx_sg.sgl, t->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc)
goto out_err_prep;
txdesc->callback = uniphier_spi_dma_txcb;
- txdesc->callback_param = master;
+ txdesc->callback_param = host;
uniphier_spi_irq_enable(priv, SSI_IE_TXRE);
atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy);
dmaengine_submit(txdesc);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
/* signal that we need to wait for completion */
@@ -463,17 +463,17 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
out_err_prep:
if (rxdesc)
- dmaengine_terminate_sync(master->dma_rx);
+ dmaengine_terminate_sync(host->dma_rx);
return -EINVAL;
}
-static int uniphier_spi_transfer_one_irq(struct spi_master *master,
+static int uniphier_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
- struct device *dev = master->dev.parent;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
+ struct device *dev = host->dev.parent;
unsigned long time_left;
reinit_completion(&priv->xfer_done);
@@ -495,11 +495,11 @@ static int uniphier_spi_transfer_one_irq(struct spi_master *master,
return priv->error;
}
-static int uniphier_spi_transfer_one_poll(struct spi_master *master,
+static int uniphier_spi_transfer_one_poll(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int loop = SSI_POLL_TIMEOUT_US * 10;
while (priv->tx_bytes) {
@@ -520,14 +520,14 @@ static int uniphier_spi_transfer_one_poll(struct spi_master *master,
return 0;
irq_transfer:
- return uniphier_spi_transfer_one_irq(master, spi, t);
+ return uniphier_spi_transfer_one_irq(host, spi, t);
}
-static int uniphier_spi_transfer_one(struct spi_master *master,
+static int uniphier_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
unsigned long threshold;
bool use_dma;
@@ -537,9 +537,9 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
uniphier_spi_setup_transfer(spi, t);
- use_dma = master->can_dma ? master->can_dma(master, spi, t) : false;
+ use_dma = host->can_dma ? host->can_dma(host, spi, t) : false;
if (use_dma)
- return uniphier_spi_transfer_one_dma(master, spi, t);
+ return uniphier_spi_transfer_one_dma(host, spi, t);
/*
* If the transfer operation will take longer than
@@ -548,33 +548,33 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz,
USEC_PER_SEC * BITS_PER_BYTE);
if (t->len > threshold)
- return uniphier_spi_transfer_one_irq(master, spi, t);
+ return uniphier_spi_transfer_one_irq(host, spi, t);
else
- return uniphier_spi_transfer_one_poll(master, spi, t);
+ return uniphier_spi_transfer_one_poll(host, spi, t);
}
-static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
+static int uniphier_spi_prepare_transfer_hardware(struct spi_controller *host)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
writel(SSI_CTL_EN, priv->base + SSI_CTL);
return 0;
}
-static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master)
+static int uniphier_spi_unprepare_transfer_hardware(struct spi_controller *host)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
writel(0, priv->base + SSI_CTL);
return 0;
}
-static void uniphier_spi_handle_err(struct spi_master *master,
+static void uniphier_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
u32 val;
/* stop running spi transfer */
@@ -587,12 +587,12 @@ static void uniphier_spi_handle_err(struct spi_master *master,
uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK);
if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) {
- dmaengine_terminate_async(master->dma_tx);
+ dmaengine_terminate_async(host->dma_tx);
atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy);
}
if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) {
- dmaengine_terminate_async(master->dma_rx);
+ dmaengine_terminate_async(host->dma_rx);
atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy);
}
}
@@ -641,7 +641,7 @@ static irqreturn_t uniphier_spi_handler(int irq, void *dev_id)
static int uniphier_spi_probe(struct platform_device *pdev)
{
struct uniphier_spi_priv *priv;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
struct dma_slave_caps caps;
u32 dma_tx_burst = 0, dma_rx_burst = 0;
@@ -649,80 +649,76 @@ static int uniphier_spi_probe(struct platform_device *pdev)
int irq;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*priv));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- priv = spi_master_get_devdata(master);
- priv->master = master;
+ priv = spi_controller_get_devdata(host);
+ priv->host = host;
priv->is_save_param = false;
priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
- goto out_master_put;
+ goto out_host_put;
}
priv->base_dma_addr = res->start;
- priv->clk = devm_clk_get(&pdev->dev, NULL);
+ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(priv->clk);
- goto out_master_put;
+ goto out_host_put;
}
- ret = clk_prepare_enable(priv->clk);
- if (ret)
- goto out_master_put;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_disable_clk;
+ goto out_host_put;
}
ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler,
0, "uniphier-spi", priv);
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ\n");
- goto out_disable_clk;
+ goto out_host_put;
}
init_completion(&priv->xfer_done);
clk_rate = clk_get_rate(priv->clk);
- master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
- master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
+ host->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->set_cs = uniphier_spi_set_cs;
- master->transfer_one = uniphier_spi_transfer_one;
- master->prepare_transfer_hardware
+ host->set_cs = uniphier_spi_set_cs;
+ host->transfer_one = uniphier_spi_transfer_one;
+ host->prepare_transfer_hardware
= uniphier_spi_prepare_transfer_hardware;
- master->unprepare_transfer_hardware
+ host->unprepare_transfer_hardware
= uniphier_spi_unprepare_transfer_hardware;
- master->handle_err = uniphier_spi_handle_err;
- master->can_dma = uniphier_spi_can_dma;
+ host->handle_err = uniphier_spi_handle_err;
+ host->can_dma = uniphier_spi_can_dma;
- master->num_chipselect = 1;
- master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+ host->num_chipselect = 1;
+ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
- master->dma_tx = dma_request_chan(&pdev->dev, "tx");
- if (IS_ERR_OR_NULL(master->dma_tx)) {
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
+ host->dma_tx = dma_request_chan(&pdev->dev, "tx");
+ if (IS_ERR_OR_NULL(host->dma_tx)) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto out_disable_clk;
+ goto out_host_put;
}
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
dma_tx_burst = INT_MAX;
} else {
- ret = dma_get_slave_caps(master->dma_tx, &caps);
+ ret = dma_get_slave_caps(host->dma_tx, &caps);
if (ret) {
dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n",
ret);
@@ -731,16 +727,16 @@ static int uniphier_spi_probe(struct platform_device *pdev)
dma_tx_burst = caps.max_burst;
}
- master->dma_rx = dma_request_chan(&pdev->dev, "rx");
- if (IS_ERR_OR_NULL(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
+ host->dma_rx = dma_request_chan(&pdev->dev, "rx");
+ if (IS_ERR_OR_NULL(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_release_dma;
}
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
dma_rx_burst = INT_MAX;
} else {
- ret = dma_get_slave_caps(master->dma_rx, &caps);
+ ret = dma_get_slave_caps(host->dma_rx, &caps);
if (ret) {
dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n",
ret);
@@ -749,43 +745,43 @@ static int uniphier_spi_probe(struct platform_device *pdev)
dma_rx_burst = caps.max_burst;
}
- master->max_dma_len = min(dma_tx_burst, dma_rx_burst);
+ host->max_dma_len = min(dma_tx_burst, dma_rx_burst);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = spi_register_controller(host);
if (ret)
goto out_release_dma;
return 0;
out_release_dma:
- if (!IS_ERR_OR_NULL(master->dma_rx)) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (!IS_ERR_OR_NULL(host->dma_rx)) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
}
- if (!IS_ERR_OR_NULL(master->dma_tx)) {
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (!IS_ERR_OR_NULL(host->dma_tx)) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
}
-out_disable_clk:
- clk_disable_unprepare(priv->clk);
-
-out_master_put:
- spi_master_put(master);
+out_host_put:
+ spi_controller_put(host);
return ret;
}
static void uniphier_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+
+ spi_controller_get(host);
+
+ spi_unregister_controller(host);
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
- clk_disable_unprepare(priv->clk);
+ spi_controller_put(host);
}
static const struct of_device_id uniphier_spi_match[] = {
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index 9358c75a30f4..3c537b1c0e22 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -54,10 +54,10 @@
#define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */
/*
- * QSPI Configuration Register - Baud rate and slave select
+ * QSPI Configuration Register - Baud rate and target select
*
* These are the values used in the calculation of baud rate divisor and
- * setting the slave select.
+ * setting the target select.
*/
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */
@@ -164,14 +164,14 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
*
* The default settings of the QSPI controller's configurable parameters on
* reset are
- * - Master mode
+ * - Host mode
* - Baud rate divisor is set to 2
* - Tx threshold set to 1l Rx threshold set to 32
* - Flash memory interface mode enabled
* - Size of the word to be transferred as 8 bit
* This function performs the following actions
* - Disable and clear all the interrupts
- * - Enable manual slave select
+ * - Enable manual target select
* - Enable manual start
* - Deselect all the chip select lines
* - Set the size of the word to be transferred as 32 bit
@@ -289,7 +289,7 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
*/
static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
{
- struct spi_controller *ctlr = spi->master;
+ struct spi_controller *ctlr = spi->controller;
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
u32 config_reg;
@@ -377,23 +377,12 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
*/
static int zynq_qspi_setup_op(struct spi_device *spi)
{
- struct spi_controller *ctlr = spi->master;
+ struct spi_controller *ctlr = spi->controller;
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
- int ret;
if (ctlr->busy)
return -EBUSY;
- ret = clk_enable(qspi->refclk);
- if (ret)
- return ret;
-
- ret = clk_enable(qspi->pclk);
- if (ret) {
- clk_disable(qspi->refclk);
- return ret;
- }
-
zynq_qspi_write(qspi, ZYNQ_QSPI_ENABLE_OFFSET,
ZYNQ_QSPI_ENABLE_ENABLE_MASK);
@@ -534,7 +523,7 @@ static irqreturn_t zynq_qspi_irq(int irq, void *dev_id)
static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master);
+ struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller);
int err = 0, i;
u8 *tmpbuf;
@@ -646,58 +635,46 @@ static int zynq_qspi_probe(struct platform_device *pdev)
struct zynq_qspi *xqspi;
u32 num_cs;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi));
if (!ctlr)
return -ENOMEM;
xqspi = spi_controller_get_devdata(ctlr);
xqspi->dev = dev;
- platform_set_drvdata(pdev, xqspi);
+ platform_set_drvdata(pdev, ctlr);
xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xqspi->regs)) {
ret = PTR_ERR(xqspi->regs);
- goto remove_master;
+ goto remove_ctlr;
}
- xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
+ xqspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(xqspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
ret = PTR_ERR(xqspi->pclk);
- goto remove_master;
+ goto remove_ctlr;
}
init_completion(&xqspi->data_completion);
- xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk");
+ xqspi->refclk = devm_clk_get_enabled(&pdev->dev, "ref_clk");
if (IS_ERR(xqspi->refclk)) {
dev_err(&pdev->dev, "ref_clk clock not found.\n");
ret = PTR_ERR(xqspi->refclk);
- goto remove_master;
- }
-
- ret = clk_prepare_enable(xqspi->pclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable APB clock.\n");
- goto remove_master;
- }
-
- ret = clk_prepare_enable(xqspi->refclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable device clock.\n");
- goto clk_dis_pclk;
+ goto remove_ctlr;
}
xqspi->irq = platform_get_irq(pdev, 0);
if (xqspi->irq < 0) {
ret = xqspi->irq;
- goto clk_dis_all;
+ goto remove_ctlr;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq,
0, pdev->name, xqspi);
if (ret != 0) {
ret = -ENXIO;
dev_err(&pdev->dev, "request_irq failed\n");
- goto clk_dis_all;
+ goto remove_ctlr;
}
ret = of_property_read_u32(np, "num-cs",
@@ -707,7 +684,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
} else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) {
ret = -EINVAL;
dev_err(&pdev->dev, "only 2 chip selects are available\n");
- goto clk_dis_all;
+ goto remove_ctlr;
} else {
ctlr->num_chipselect = num_cs;
}
@@ -722,19 +699,15 @@ static int zynq_qspi_probe(struct platform_device *pdev)
/* QSPI controller initializations */
zynq_qspi_init_hw(xqspi, ctlr->num_chipselect);
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret) {
- dev_err(&pdev->dev, "spi_register_master failed\n");
- goto clk_dis_all;
+ dev_err(&pdev->dev, "failed to register controller\n");
+ goto remove_ctlr;
}
return ret;
-clk_dis_all:
- clk_disable_unprepare(xqspi->refclk);
-clk_dis_pclk:
- clk_disable_unprepare(xqspi->pclk);
-remove_master:
+remove_ctlr:
spi_controller_put(ctlr);
return ret;
@@ -752,12 +725,16 @@ static int zynq_qspi_probe(struct platform_device *pdev)
*/
static void zynq_qspi_remove(struct platform_device *pdev)
{
- struct zynq_qspi *xqspi = platform_get_drvdata(pdev);
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
+
+ spi_controller_get(ctlr);
+
+ spi_unregister_controller(ctlr);
zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0);
- clk_disable_unprepare(xqspi->refclk);
- clk_disable_unprepare(xqspi->pclk);
+ spi_controller_put(ctlr);
}
static const struct of_device_id zynq_qspi_of_match[] = {
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index b5deb4fe3b83..b9ed6d6824b2 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -1324,7 +1324,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
ctlr->dev.of_node = np;
ctlr->auto_runtime_pm = true;
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = spi_register_controller(ctlr);
if (ret) {
dev_err(&pdev->dev, "spi_register_controller failed\n");
goto clk_dis_all;
@@ -1365,6 +1365,8 @@ static void zynqmp_qspi_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
+ spi_unregister_controller(xqspi->ctlr);
+
zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 91da4cae011c..bb7e5e56f6dc 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -42,6 +42,8 @@ EXPORT_TRACEPOINT_SYMBOL(spi_transfer_stop);
#include "internals.h"
+static int __spi_setup(struct spi_device *spi, bool initial_setup);
+
static DEFINE_IDR(spi_master_idr);
static void spidev_release(struct device *dev)
@@ -677,7 +679,7 @@ static int __spi_add_device(struct spi_device *spi)
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
- status = spi_setup(spi);
+ status = __spi_setup(spi, true);
if (status < 0) {
dev_err(dev, "can't setup %s, status %d\n",
dev_name(&spi->dev), status);
@@ -3734,27 +3736,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
return status;
}
-/**
- * spi_setup - setup SPI mode and clock rate
- * @spi: the device whose settings are being modified
- * Context: can sleep, and no requests are queued to the device
- *
- * SPI protocol drivers may need to update the transfer mode if the
- * device doesn't work with its default. They may likewise need
- * to update clock rates or word sizes from initial values. This function
- * changes those settings, and must be called from a context that can sleep.
- * Except for SPI_CS_HIGH, which takes effect immediately, the changes take
- * effect the next time the device is selected and data is transferred to
- * or from it. When this function returns, the SPI device is deselected.
- *
- * Note that this call will fail if the protocol driver specifies an option
- * that the underlying controller or its driver does not support. For
- * example, not all hardware supports wire transfers using nine bit words,
- * LSB-first wire encoding, or active-high chipselects.
- *
- * Return: zero on success, else a negative error code.
- */
-int spi_setup(struct spi_device *spi)
+static int __spi_setup(struct spi_device *spi, bool initial_setup)
{
unsigned bad_bits, ugly_bits;
int status = 0;
@@ -3833,7 +3815,7 @@ int spi_setup(struct spi_device *spi)
status = spi_set_cs_timing(spi);
if (status) {
mutex_unlock(&spi->controller->io_mutex);
- return status;
+ goto err_cleanup;
}
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
@@ -3842,7 +3824,7 @@ int spi_setup(struct spi_device *spi)
mutex_unlock(&spi->controller->io_mutex);
dev_err(&spi->controller->dev, "Failed to power device: %d\n",
status);
- return status;
+ goto err_cleanup;
}
/*
@@ -3879,6 +3861,37 @@ int spi_setup(struct spi_device *spi)
status);
return status;
+
+err_cleanup:
+ if (initial_setup)
+ spi_cleanup(spi);
+
+ return status;
+}
+
+/**
+ * spi_setup - setup SPI mode and clock rate
+ * @spi: the device whose settings are being modified
+ * Context: can sleep, and no requests are queued to the device
+ *
+ * SPI protocol drivers may need to update the transfer mode if the
+ * device doesn't work with its default. They may likewise need
+ * to update clock rates or word sizes from initial values. This function
+ * changes those settings, and must be called from a context that can sleep.
+ * Except for SPI_CS_HIGH, which takes effect immediately, the changes take
+ * effect the next time the device is selected and data is transferred to
+ * or from it. When this function returns, the SPI device is deselected.
+ *
+ * Note that this call will fail if the protocol driver specifies an option
+ * that the underlying controller or its driver does not support. For
+ * example, not all hardware supports wire transfers using nine bit words,
+ * LSB-first wire encoding, or active-high chipselects.
+ *
+ * Return: zero on success, else a negative error code.
+ */
+int spi_setup(struct spi_device *spi)
+{
+ return __spi_setup(spi, false);
}
EXPORT_SYMBOL_GPL(spi_setup);
@@ -4532,7 +4545,7 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
* Clear the flag before adding the device so that fw_devlink
* doesn't skip adding consumers to this device.
*/
- rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
+ fwnode_clear_flag(&rd->dn->fwnode, FWNODE_FLAG_NOT_DEVICE);
spi = of_register_spi_device(ctlr, rd->dn);
put_device(&ctlr->dev);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index d2174156573a..de37bb15c856 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -1780,6 +1780,10 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
int err;
+ /* Disable all private IOCTLs for now! */
+ if (cmd)
+ return -EINVAL;
+
switch (cmd) {
case ATOMISP_IOC_S_SENSOR_RUNMODE:
if (IS_ISP2401)
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index dda1ebc34692..2c78b08749a8 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -97,9 +97,6 @@ struct csi_priv {
/* the mipi virtual channel number at link validate */
int vc_num;
- /* media bus config of the upstream subdevice CSI is receiving from */
- struct v4l2_mbus_config mbus_cfg;
-
spinlock_t irqlock; /* protect eof_irq handler */
struct timer_list eof_timeout_timer;
int eof_irq;
@@ -403,7 +400,8 @@ static void csi_idmac_unsetup_vb2_buf(struct csi_priv *priv,
}
/* init the SMFC IDMAC channel */
-static int csi_idmac_setup_channel(struct csi_priv *priv)
+static int csi_idmac_setup_channel(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
{
struct imx_media_video_dev *vdev = priv->vdev;
const struct imx_media_pixfmt *incc;
@@ -432,7 +430,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
image.phys0 = phys[0];
image.phys1 = phys[1];
- passthrough = requires_passthrough(&priv->mbus_cfg, infmt, incc);
+ passthrough = requires_passthrough(mbus_cfg, infmt, incc);
passthrough_cycles = 1;
/*
@@ -572,11 +570,12 @@ static void csi_idmac_unsetup(struct csi_priv *priv,
csi_idmac_unsetup_vb2_buf(priv, state);
}
-static int csi_idmac_setup(struct csi_priv *priv)
+static int csi_idmac_setup(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
{
int ret;
- ret = csi_idmac_setup_channel(priv);
+ ret = csi_idmac_setup_channel(priv, mbus_cfg);
if (ret)
return ret;
@@ -595,7 +594,8 @@ static int csi_idmac_setup(struct csi_priv *priv)
return 0;
}
-static int csi_idmac_start(struct csi_priv *priv)
+static int csi_idmac_start(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
{
struct imx_media_video_dev *vdev = priv->vdev;
int ret;
@@ -619,7 +619,7 @@ static int csi_idmac_start(struct csi_priv *priv)
priv->last_eof = false;
priv->nfb4eof = false;
- ret = csi_idmac_setup(priv);
+ ret = csi_idmac_setup(priv, mbus_cfg);
if (ret) {
v4l2_err(&priv->sd, "csi_idmac_setup failed: %d\n", ret);
goto out_free_dma_buf;
@@ -701,7 +701,8 @@ static void csi_idmac_stop(struct csi_priv *priv)
}
/* Update the CSI whole sensor and active windows */
-static int csi_setup(struct csi_priv *priv)
+static int csi_setup(struct csi_priv *priv,
+ struct v4l2_mbus_config *mbus_cfg)
{
struct v4l2_mbus_framefmt *infmt, *outfmt;
const struct imx_media_pixfmt *incc;
@@ -719,7 +720,7 @@ static int csi_setup(struct csi_priv *priv)
* if cycles is set, we need to handle this over multiple cycles as
* generic/bayer data
*/
- if (is_parallel_bus(&priv->mbus_cfg) && incc->cycles) {
+ if (is_parallel_bus(mbus_cfg) && incc->cycles) {
if_fmt.width *= incc->cycles;
crop.width *= incc->cycles;
}
@@ -730,7 +731,7 @@ static int csi_setup(struct csi_priv *priv)
priv->crop.width == 2 * priv->compose.width,
priv->crop.height == 2 * priv->compose.height);
- ipu_csi_init_interface(priv->csi, &priv->mbus_cfg, &if_fmt, outfmt);
+ ipu_csi_init_interface(priv->csi, mbus_cfg, &if_fmt, outfmt);
ipu_csi_set_dest(priv->csi, priv->dest);
@@ -745,9 +746,17 @@ static int csi_setup(struct csi_priv *priv)
static int csi_start(struct csi_priv *priv)
{
+ struct v4l2_mbus_config mbus_cfg = { .type = 0 };
struct v4l2_fract *input_fi, *output_fi;
int ret;
+ ret = csi_get_upstream_mbus_config(priv, &mbus_cfg);
+ if (ret) {
+ v4l2_err(&priv->sd,
+ "failed to get upstream media bus configuration\n");
+ return ret;
+ }
+
input_fi = &priv->frame_interval[CSI_SINK_PAD];
output_fi = &priv->frame_interval[priv->active_output_pad];
@@ -758,7 +767,7 @@ static int csi_start(struct csi_priv *priv)
return ret;
/* Skip first few frames from a BT.656 source */
- if (priv->mbus_cfg.type == V4L2_MBUS_BT656) {
+ if (mbus_cfg.type == V4L2_MBUS_BT656) {
u32 delay_usec, bad_frames = 20;
delay_usec = DIV_ROUND_UP_ULL((u64)USEC_PER_SEC *
@@ -769,12 +778,12 @@ static int csi_start(struct csi_priv *priv)
}
if (priv->dest == IPU_CSI_DEST_IDMAC) {
- ret = csi_idmac_start(priv);
+ ret = csi_idmac_start(priv, &mbus_cfg);
if (ret)
goto stop_upstream;
}
- ret = csi_setup(priv);
+ ret = csi_setup(priv, &mbus_cfg);
if (ret)
goto idmac_stop;
@@ -1122,7 +1131,6 @@ static int csi_link_validate(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- priv->mbus_cfg = mbus_cfg;
is_csi2 = !is_parallel_bus(&mbus_cfg);
if (is_csi2) {
/*
diff --git a/drivers/staging/vme_user/vme_fake.c b/drivers/staging/vme_user/vme_fake.c
index 95730d1270af..c70aec959f4d 100644
--- a/drivers/staging/vme_user/vme_fake.c
+++ b/drivers/staging/vme_user/vme_fake.c
@@ -1235,6 +1235,8 @@ static int __init fake_init(void)
err_driver:
kfree(fake_bridge);
err_struct:
+ root_device_unregister(vme_root);
+
return retval;
}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index a52a4ac735e1..74a71c8d7ac1 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3134,7 +3134,7 @@ static ssize_t target_tg_pt_gp_members_show(struct config_item *item,
config_item_name(&lun->lun_group.cg_item));
cur_len++; /* Extra byte for NULL terminator */
- if ((cur_len + len) > PAGE_SIZE) {
+ if (cur_len > TG_PT_GROUP_NAME_BUF || (cur_len + len) > PAGE_SIZE) {
pr_warn("Ran out of lu_gp_show_attr"
"_members buffer\n");
break;
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index e27c4bdc8912..6e40288bcae9 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -178,7 +178,7 @@ static int sprd_thm_sensor_calibration(struct device_node *np,
static int sprd_thm_rawdata_to_temp(struct sprd_thermal_sensor *sen,
u32 rawdata)
{
- clamp(rawdata, (u32)SPRD_THM_RAW_DATA_LOW, (u32)SPRD_THM_RAW_DATA_HIGH);
+ rawdata = clamp(rawdata, SPRD_THM_RAW_DATA_LOW, SPRD_THM_RAW_DATA_HIGH);
/*
* According to the thermal datasheet, the formula of converting
@@ -192,7 +192,7 @@ static int sprd_thm_temp_to_rawdata(int temp, struct sprd_thermal_sensor *sen)
{
u32 val;
- clamp(temp, (int)SPRD_THM_TEMP_LOW, (int)SPRD_THM_TEMP_HIGH);
+ temp = clamp(temp, SPRD_THM_TEMP_LOW, SPRD_THM_TEMP_HIGH);
/*
* According to the thermal datasheet, the formula of converting
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 660a8d6f3567..3efdd2ae6dcb 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -804,6 +804,7 @@ static void thermal_release(struct device *dev)
sizeof("thermal_zone") - 1)) {
tz = to_thermal_zone(dev);
thermal_zone_destroy_device_groups(tz);
+ thermal_set_governor(tz, NULL);
mutex_destroy(&tz->lock);
complete(&tz->removal);
} else if (!strncmp(dev_name(dev), "cooling_device",
@@ -1325,8 +1326,10 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
/* sys I/F */
/* Add nodes that are always present via .groups */
result = thermal_zone_create_device_groups(tz, mask);
- if (result)
+ if (result) {
+ thermal_set_governor(tz, NULL);
goto remove_id;
+ }
/* A new thermal zone needs to be updated anyway. */
atomic_set(&tz->need_update, 1);
@@ -1478,8 +1481,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
cancel_delayed_work_sync(&tz->poll_queue);
- thermal_set_governor(tz, NULL);
-
thermal_remove_hwmon_sysfs(tz);
ida_free(&thermal_tz_ida, tz->id);
ida_destroy(&tz->ida);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index c161a4ee5290..87991d9d2f2f 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -543,30 +543,31 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
if (ret == IRQ_HANDLED)
return ret;
}
- }
- /*
- * Handle id change interrupt, it indicates device/host function
- * switch.
- */
- if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
- ci->id_event = true;
- /* Clear ID change irq status */
- hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
- ci_otg_queue_work(ci);
- return IRQ_HANDLED;
- }
+ /*
+ * Handle id change interrupt, it indicates device/host function
+ * switch.
+ */
+ if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
+ ci->id_event = true;
+ /* Clear ID change irq status */
+ hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
+ }
- /*
- * Handle vbus change interrupt, it indicates device connection
- * and disconnection events.
- */
- if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
- ci->b_sess_valid_event = true;
- /* Clear BSV irq */
- hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
- ci_otg_queue_work(ci);
- return IRQ_HANDLED;
+ /*
+ * Handle vbus change interrupt, it indicates device connection
+ * and disconnection events.
+ */
+ if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+ ci->b_sess_valid_event = true;
+ /* Clear BSV irq */
+ hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
+ }
+
+ if (ci->id_event || ci->b_sess_valid_event) {
+ ci_otg_queue_work(ci);
+ return IRQ_HANDLED;
+ }
}
/* Handle device/host interrupt */
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 647e98f4e351..fecc7d7e2f0d 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -130,6 +130,9 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
void ci_handle_vbus_change(struct ci_hdrc *ci)
{
+ if (ci->role != CI_ROLE_GADGET)
+ return;
+
if (!ci->is_otg) {
if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS)
usb_gadget_vbus_connect(&ci->gadget);
@@ -187,8 +190,8 @@ void ci_handle_id_switch(struct ci_hdrc *ci)
ci_role_stop(ci);
- if (role == CI_ROLE_GADGET &&
- IS_ERR(ci->platdata->vbus_extcon.edev))
+ if (role == CI_ROLE_GADGET && !ci->role_switch &&
+ IS_ERR(ci->platdata->vbus_extcon.edev))
/*
* Wait vbus lower than OTGSC_BSV before connecting
* to host. If connecting status is from an external
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index ff1a941fd2ed..7424052a1fa9 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -1166,7 +1166,7 @@ static int usblp_probe(struct usb_interface *intf,
}
/* Allocate buffer for printer status */
- usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
+ usblp->statusbuf = kzalloc(STATUS_BUF_SIZE, GFP_KERNEL);
if (!usblp->statusbuf) {
retval = -ENOMEM;
goto abort;
@@ -1365,6 +1365,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
{
int err, length;
+ memset(usblp->device_id_string, 0, USBLP_DEVICE_ID_SIZE);
err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
if (err < 0) {
dev_dbg(&usblp->intf->dev,
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index c9f52cd1cfb2..b1957dc687a8 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -286,12 +286,15 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
ret = ulpi_of_register(ulpi);
- if (ret)
+ if (ret) {
+ kfree(ulpi);
return ret;
+ }
ret = ulpi_read_id(ulpi);
if (ret) {
of_node_put(ulpi->dev.of_node);
+ kfree(ulpi);
return ret;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 11b938fd9de0..3ac0de8351f5 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1240,12 +1240,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
- /*
- * Write Linux Version Code to our GUID register so it's easy to figure
- * out which kernel version a bug was found.
- */
- dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
-
ret = dwc3_phy_setup(dwc);
if (ret)
return ret;
@@ -1277,6 +1271,12 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err_exit_phy;
+ /*
+ * Write Linux Version Code to our GUID register so it's easy to figure
+ * out which kernel version a bug was found.
+ */
+ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+
dwc3_core_setup_global_control(dwc);
dwc3_core_num_eps(dwc);
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index f90eeecf27de..895d5c5df1ae 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -734,8 +734,6 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
if (status == 0) {
omap_writew(reg, UDC_TXDMA_CFG);
/* EMIFF or SDRC */
- omap_set_dma_src_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
omap_set_dma_src_data_pack(ep->lch, 1);
/* TIPB */
omap_set_dma_dest_params(ep->lch,
@@ -757,8 +755,6 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
UDC_DATA_DMA,
0, 0);
/* EMIFF or SDRC */
- omap_set_dma_dest_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
omap_set_dma_dest_data_pack(ep->lch, 1);
}
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0fdb0780d19c..9243eff82817 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3102,7 +3102,6 @@ static void xhci_endpoint_disable(struct usb_hcd *hcd,
xhci_dbg(xhci, "endpoint disable with ep_state 0x%x\n",
ep->ep_state);
done:
- host_ep->hcpriv = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 4027d81e8932..835727335c73 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1513,7 +1513,11 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1231, 0xff), /* Telit LE910Cx (RNDIS) */
.driver_info = NCTRL(2) | RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x1250, 0xff, 0x00, 0x00) }, /* Telit LE910Cx (rmnet) */
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1251, 0xff) }, /* Telit LE910Cx (RNDIS) */
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1252, 0xff) }, /* Telit LE910Cx (MBIM) */
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1253, 0xff) }, /* Telit LE910Cx (ECM) */
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1254, 0xff) }, /* Telit LE910Cx */
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1255, 0xff) }, /* Telit LE910Cx */
{ USB_DEVICE(TELIT_VENDOR_ID, 0x1260),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, 0x1261),
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 2e39686e01c9..c6330084d4f6 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -4610,6 +4610,8 @@ static void run_state_machine(struct tcpm_port *port)
usb_power_delivery_unregister_capabilities(port->partner_source_caps);
port->partner_source_caps = NULL;
tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ port->vdm_sm_running = false;
+ port->explicit_contract = false;
tcpm_ams_finish(port);
if (port->pwr_role == TYPEC_SOURCE) {
port->upcoming_state = SRC_SEND_CAPABILITIES;
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index b9607d5a370d..f4812a76c3cc 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -23,6 +23,75 @@
#include <linux/rmap.h>
#include <linux/pagemap.h>
+/*
+ * struct fb_deferred_io_state
+ */
+
+struct fb_deferred_io_state {
+ struct kref ref;
+
+ struct mutex lock; /* mutex that protects the pageref list */
+ /* fields protected by lock */
+ struct fb_info *info;
+};
+
+static struct fb_deferred_io_state *fb_deferred_io_state_alloc(void)
+{
+ struct fb_deferred_io_state *fbdefio_state;
+
+ fbdefio_state = kzalloc(sizeof(*fbdefio_state), GFP_KERNEL);
+ if (!fbdefio_state)
+ return NULL;
+
+ kref_init(&fbdefio_state->ref);
+ mutex_init(&fbdefio_state->lock);
+
+ return fbdefio_state;
+}
+
+static void fb_deferred_io_state_release(struct fb_deferred_io_state *fbdefio_state)
+{
+ mutex_destroy(&fbdefio_state->lock);
+
+ kfree(fbdefio_state);
+}
+
+static void fb_deferred_io_state_get(struct fb_deferred_io_state *fbdefio_state)
+{
+ kref_get(&fbdefio_state->ref);
+}
+
+static void __fb_deferred_io_state_release(struct kref *ref)
+{
+ struct fb_deferred_io_state *fbdefio_state =
+ container_of(ref, struct fb_deferred_io_state, ref);
+
+ fb_deferred_io_state_release(fbdefio_state);
+}
+
+static void fb_deferred_io_state_put(struct fb_deferred_io_state *fbdefio_state)
+{
+ kref_put(&fbdefio_state->ref, __fb_deferred_io_state_release);
+}
+
+/*
+ * struct vm_operations_struct
+ */
+
+static void fb_deferred_io_vm_open(struct vm_area_struct *vma)
+{
+ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
+
+ fb_deferred_io_state_get(fbdefio_state);
+}
+
+static void fb_deferred_io_vm_close(struct vm_area_struct *vma)
+{
+ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
+
+ fb_deferred_io_state_put(fbdefio_state);
+}
+
static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
{
void *screen_base = (void __force *) info->screen_base;
@@ -93,17 +162,31 @@ static void fb_deferred_io_pageref_put(struct fb_deferred_io_pageref *pageref,
/* this is to find and return the vmalloc-ed fb pages */
static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
{
+ struct fb_info *info;
unsigned long offset;
struct page *page;
- struct fb_info *info = vmf->vma->vm_private_data;
+ vm_fault_t ret;
+ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
+
+ mutex_lock(&fbdefio_state->lock);
+
+ info = fbdefio_state->info;
+ if (!info) {
+ ret = VM_FAULT_SIGBUS; /* our device is gone */
+ goto err_mutex_unlock;
+ }
offset = vmf->pgoff << PAGE_SHIFT;
- if (offset >= info->fix.smem_len)
- return VM_FAULT_SIGBUS;
+ if (offset >= info->fix.smem_len) {
+ ret = VM_FAULT_SIGBUS;
+ goto err_mutex_unlock;
+ }
page = fb_deferred_io_page(info, offset);
- if (!page)
- return VM_FAULT_SIGBUS;
+ if (!page) {
+ ret = VM_FAULT_SIGBUS;
+ goto err_mutex_unlock;
+ }
get_page(page);
@@ -115,8 +198,15 @@ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
BUG_ON(!page->mapping);
page->index = vmf->pgoff; /* for page_mkclean() */
+ mutex_unlock(&fbdefio_state->lock);
+
vmf->page = page;
+
return 0;
+
+err_mutex_unlock:
+ mutex_unlock(&fbdefio_state->lock);
+ return ret;
}
int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
@@ -143,15 +233,24 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
* Adds a page to the dirty list. Call this from struct
* vm_operations_struct.page_mkwrite.
*/
-static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long offset,
- struct page *page)
+static vm_fault_t fb_deferred_io_track_page(struct fb_deferred_io_state *fbdefio_state,
+ unsigned long offset, struct page *page)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_info *info;
+ struct fb_deferred_io *fbdefio;
struct fb_deferred_io_pageref *pageref;
vm_fault_t ret;
/* protect against the workqueue changing the page list */
- mutex_lock(&fbdefio->lock);
+ mutex_lock(&fbdefio_state->lock);
+
+ info = fbdefio_state->info;
+ if (!info) {
+ ret = VM_FAULT_SIGBUS; /* our device is gone */
+ goto err_mutex_unlock;
+ }
+
+ fbdefio = info->fbdefio;
pageref = fb_deferred_io_pageref_get(info, offset, page);
if (WARN_ON_ONCE(!pageref)) {
@@ -169,50 +268,38 @@ static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long
*/
lock_page(pageref->page);
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
/* come back after delay to process the deferred IO */
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
return VM_FAULT_LOCKED;
err_mutex_unlock:
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
return ret;
}
-/*
- * fb_deferred_io_page_mkwrite - Mark a page as written for deferred I/O
- * @fb_info: The fbdev info structure
- * @vmf: The VM fault
- *
- * This is a callback we get when userspace first tries to
- * write to the page. We schedule a workqueue. That workqueue
- * will eventually mkclean the touched pages and execute the
- * deferred framebuffer IO. Then if userspace touches a page
- * again, we repeat the same scheme.
- *
- * Returns:
- * VM_FAULT_LOCKED on success, or a VM_FAULT error otherwise.
- */
-static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf)
+static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_deferred_io_state *fbdefio_state,
+ struct vm_fault *vmf)
{
unsigned long offset = vmf->pgoff << PAGE_SHIFT;
struct page *page = vmf->page;
file_update_time(vmf->vma->vm_file);
- return fb_deferred_io_track_page(info, offset, page);
+ return fb_deferred_io_track_page(fbdefio_state, offset, page);
}
-/* vm_ops->page_mkwrite handler */
static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf)
{
- struct fb_info *info = vmf->vma->vm_private_data;
+ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
- return fb_deferred_io_page_mkwrite(info, vmf);
+ return fb_deferred_io_page_mkwrite(fbdefio_state, vmf);
}
static const struct vm_operations_struct fb_deferred_io_vm_ops = {
+ .open = fb_deferred_io_vm_open,
+ .close = fb_deferred_io_vm_close,
.fault = fb_deferred_io_fault,
.page_mkwrite = fb_deferred_io_mkwrite,
};
@@ -227,7 +314,10 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
if (!(info->flags & FBINFO_VIRTFB))
vm_flags_set(vma, VM_IO);
- vma->vm_private_data = info;
+ vma->vm_private_data = info->fbdefio_state;
+
+ fb_deferred_io_state_get(info->fbdefio_state); /* released in vma->vm_ops->close() */
+
return 0;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_mmap);
@@ -238,9 +328,10 @@ static void fb_deferred_io_work(struct work_struct *work)
struct fb_info *info = container_of(work, struct fb_info, deferred_work.work);
struct fb_deferred_io_pageref *pageref, *next;
struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
/* here we mkclean the pages, then do all deferred IO */
- mutex_lock(&fbdefio->lock);
+ mutex_lock(&fbdefio_state->lock);
list_for_each_entry(pageref, &fbdefio->pagereflist, list) {
struct page *cur = pageref->page;
lock_page(cur);
@@ -255,12 +346,13 @@ static void fb_deferred_io_work(struct work_struct *work)
list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list)
fb_deferred_io_pageref_put(pageref, info);
- mutex_unlock(&fbdefio->lock);
+ mutex_unlock(&fbdefio_state->lock);
}
int fb_deferred_io_init(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state;
struct fb_deferred_io_pageref *pagerefs;
unsigned long npagerefs, i;
int ret;
@@ -270,7 +362,11 @@ int fb_deferred_io_init(struct fb_info *info)
if (WARN_ON(!info->fix.smem_len))
return -EINVAL;
- mutex_init(&fbdefio->lock);
+ fbdefio_state = fb_deferred_io_state_alloc();
+ if (!fbdefio_state)
+ return -ENOMEM;
+ fbdefio_state->info = info;
+
INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
INIT_LIST_HEAD(&fbdefio->pagereflist);
if (fbdefio->delay == 0) /* set a default of 1 s */
@@ -289,10 +385,12 @@ int fb_deferred_io_init(struct fb_info *info)
info->npagerefs = npagerefs;
info->pagerefs = pagerefs;
+ info->fbdefio_state = fbdefio_state;
+
return 0;
err:
- mutex_destroy(&fbdefio->lock);
+ fb_deferred_io_state_release(fbdefio_state);
return ret;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_init);
@@ -333,11 +431,18 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_release);
void fb_deferred_io_cleanup(struct fb_info *info)
{
- struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
fb_deferred_io_lastclose(info);
+ info->fbdefio_state = NULL;
+
+ mutex_lock(&fbdefio_state->lock);
+ fbdefio_state->info = NULL;
+ mutex_unlock(&fbdefio_state->lock);
+
+ fb_deferred_io_state_put(fbdefio_state);
+
kvfree(info->pagerefs);
- mutex_destroy(&fbdefio->lock);
}
EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
index ec3c883400f7..4a06e71ae443 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.c
+++ b/drivers/video/fbdev/core/fbcon_rotate.c
@@ -46,6 +46,10 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
info->fbops->fb_sync(info);
if (ops->fd_size < d_cellsize * len) {
+ kfree(ops->fontbuffer);
+ ops->fontbuffer = NULL;
+ ops->fd_size = 0;
+
dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
if (dst == NULL) {
@@ -54,7 +58,6 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
}
ops->fd_size = d_cellsize * len;
- kfree(ops->fontbuffer);
ops->fontbuffer = dst;
}
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 077f064ddd48..80b36f4caf0c 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -321,12 +321,32 @@ static int dlfb_set_video_mode(struct dlfb_data *dlfb,
return retval;
}
+static void dlfb_vm_open(struct vm_area_struct *vma)
+{
+ struct dlfb_data *dlfb = vma->vm_private_data;
+
+ atomic_inc(&dlfb->mmap_count);
+}
+
+static void dlfb_vm_close(struct vm_area_struct *vma)
+{
+ struct dlfb_data *dlfb = vma->vm_private_data;
+
+ atomic_dec(&dlfb->mmap_count);
+}
+
+static const struct vm_operations_struct dlfb_vm_ops = {
+ .open = dlfb_vm_open,
+ .close = dlfb_vm_close,
+};
+
static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
+ struct dlfb_data *dlfb = info->par;
if (info->fbdefio)
return fb_deferred_io_mmap(info, vma);
@@ -356,6 +376,9 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
size = 0;
}
+ vma->vm_ops = &dlfb_vm_ops;
+ vma->vm_private_data = dlfb;
+ atomic_inc(&dlfb->mmap_count);
return 0;
}
@@ -1219,7 +1242,6 @@ static void dlfb_deferred_vfree(struct dlfb_data *dlfb, void *mem)
/*
* Assumes &info->lock held by caller
- * Assumes no active clients have framebuffer open
*/
static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len)
{
@@ -1231,6 +1253,13 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info
new_len = PAGE_ALIGN(new_len);
if (new_len > old_len) {
+ if (atomic_read(&dlfb->mmap_count) > 0) {
+ dev_warn(info->dev,
+ "refusing realloc: %d active mmaps\n",
+ atomic_read(&dlfb->mmap_count));
+ return -EBUSY;
+ }
+
/*
* Alloc system memory for virtual framebuffer
*/
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 3ff7d2e47c7e..e4348dd76658 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2035,7 +2035,7 @@ static void free_note_info(struct elf_note_info *info)
threads = t->next;
WARN_ON(t->notes[0].data && t->notes[0].data != &t->prstatus);
for (i = 1; i < info->thread_notes; ++i)
- kfree(t->notes[i].data);
+ kvfree(t->notes[i].data);
kfree(t);
}
kfree(info->psinfo.data);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4723013995f5..d17d1eff8eff 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3087,7 +3087,7 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
return -ENOMEM;
space_args.total_spaces = 0;
- dest = kmalloc(alloc_size, GFP_KERNEL);
+ dest = kzalloc(alloc_size, GFP_KERNEL);
if (!dest)
return -ENOMEM;
dest_orig = dest;
@@ -3143,7 +3143,8 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
user_dest = (struct btrfs_ioctl_space_info __user *)
(arg + sizeof(struct btrfs_ioctl_space_args));
- if (copy_to_user(user_dest, dest_orig, alloc_size))
+ if (copy_to_user(user_dest, dest_orig,
+ space_args.total_spaces * sizeof(*dest_orig)))
ret = -EFAULT;
kfree(dest_orig);
diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
index 12f8f55bb993..0a960b6c866e 100644
--- a/fs/btrfs/space-info.c
+++ b/fs/btrfs/space-info.c
@@ -293,7 +293,7 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags)
ret = btrfs_sysfs_add_space_info_type(info, space_info);
if (ret)
- goto out_free;
+ return ret;
list_add(&space_info->list, &info->space_info);
if (flags & BTRFS_BLOCK_GROUP_DATA)
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index cc448470fd9b..d3bb28939194 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -745,7 +745,8 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
d_drop(dentry);
err = -ENOENT;
} else {
- d_add(dentry, NULL);
+ if (d_unhashed(dentry))
+ d_add(dentry, NULL);
}
}
}
@@ -813,7 +814,8 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
__ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
spin_unlock(&ci->i_ceph_lock);
dout(" dir %p complete, -ENOENT\n", dir);
- d_add(dentry, NULL);
+ if (d_unhashed(dentry))
+ d_add(dentry, NULL);
di->lease_shared_gen = atomic_read(&ci->i_shared_gen);
return NULL;
}
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 86e088fd386e..18e4da98309d 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -133,6 +133,7 @@ static void *z_erofs_lz4_handle_overlap(struct z_erofs_lz4_decompress_ctx *ctx,
if (rq->inplace_io) {
omargin = PAGE_ALIGN(ctx->oend) - ctx->oend;
if (rq->partial_decoding || !may_inplace ||
+ ctx->outpages < ctx->inpages ||
omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize))
goto docopy;
diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c
index b80abec0531a..c5a965c5c8f8 100644
--- a/fs/erofs/dir.c
+++ b/fs/erofs/dir.c
@@ -22,20 +22,18 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
nameoff = le16_to_cpu(de->nameoff);
de_name = (char *)dentry_blk + nameoff;
- /* the last dirent in the block? */
- if (de + 1 >= end)
- de_namelen = strnlen(de_name, maxsize - nameoff);
- else
+ /* non-trailing dirent in the directory block? */
+ if (de + 1 < end)
de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+ else if (maxsize <= nameoff)
+ goto err_bogus;
+ else
+ de_namelen = strnlen(de_name, maxsize - nameoff);
- /* a corrupted entry is found */
- if (nameoff + de_namelen > maxsize ||
- de_namelen > EROFS_NAME_LEN) {
- erofs_err(dir->i_sb, "bogus dirent @ nid %llu",
- EROFS_I(dir)->nid);
- DBG_BUGON(1);
- return -EFSCORRUPTED;
- }
+ /* a corrupted entry is found (including negative namelen) */
+ if (!in_range32(de_namelen, 1, EROFS_NAME_LEN) ||
+ nameoff + de_namelen > maxsize)
+ goto err_bogus;
if (!dir_emit(ctx, de_name, de_namelen,
le64_to_cpu(de->nid), d_type))
@@ -44,6 +42,10 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
ctx->pos += sizeof(struct erofs_dirent);
}
return 0;
+err_bogus:
+ erofs_err(dir->i_sb, "bogus dirent @ nid %llu", EROFS_I(dir)->nid);
+ DBG_BUGON(1);
+ return -EFSCORRUPTED;
}
static int erofs_readdir(struct file *f, struct dir_context *ctx)
@@ -72,7 +74,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
}
nameoff = le16_to_cpu(de->nameoff);
- if (nameoff < sizeof(struct erofs_dirent) || nameoff >= bsz) {
+ if (!nameoff || nameoff >= bsz || (nameoff % sizeof(*de))) {
erofs_err(sb, "invalid de[0].nameoff %u @ nid %llu",
nameoff, EROFS_I(dir)->nid);
err = -EFSCORRUPTED;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 6ff1f8f29a3c..6eccee033617 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1432,9 +1432,17 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
* the test is that same one that e2fsck uses
* NeilBrown 1999oct15
*/
- if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
- /* this inode is deleted */
- ret = -ESTALE;
+ if (inode->i_nlink == 0) {
+ if (inode->i_mode == 0 || ei->i_dtime) {
+ /* this inode is deleted */
+ ret = -ESTALE;
+ } else {
+ ext2_error(sb, __func__,
+ "inode %lu has zero i_nlink with mode 0%o and no dtime, "
+ "filesystem may be corrupt",
+ ino, inode->i_mode);
+ ret = -EFSCORRUPTED;
+ }
goto bad_inode;
}
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7626cf2b07f1..a94798e23c1a 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1743,6 +1743,13 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode, path + k);
if (err)
return err;
+ if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
+ EXT4_ERROR_INODE(inode,
+ "path[%d].p_idx %p > EXT_LAST_INDEX %p",
+ k, path[k].p_idx,
+ EXT_LAST_INDEX(path[k].p_hdr));
+ return -EFSCORRUPTED;
+ }
path[k].p_idx->ei_block = border;
err = ext4_ext_dirty(handle, inode, path + k);
if (err)
@@ -1755,6 +1762,14 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode, path + k);
if (err)
break;
+ if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
+ EXT4_ERROR_INODE(inode,
+ "path[%d].p_idx %p > EXT_LAST_INDEX %p",
+ k, path[k].p_idx,
+ EXT_LAST_INDEX(path[k].p_hdr));
+ err = -EFSCORRUPTED;
+ break;
+ }
path[k].p_idx->ei_block = border;
err = ext4_ext_dirty(handle, inode, path + k);
if (err)
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index bb4b7f280267..5b5c3ce7719d 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -226,7 +226,7 @@ check_xattrs(struct inode *inode, struct buffer_head *bh,
/* Find the end of the names list */
while (!IS_LAST_ENTRY(e)) {
struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
- if ((void *)next >= end) {
+ if ((void *)next + sizeof(u32) > end) {
err_str = "e_name out of bounds";
goto errout;
}
@@ -1165,7 +1165,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
{
struct inode *ea_inode;
struct ext4_xattr_entry *entry;
- struct ext4_iloc iloc;
+ struct ext4_iloc iloc = { .bh = NULL };
bool dirty = false;
unsigned int ea_ino;
int err;
@@ -1260,6 +1260,8 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
ext4_warning_inode(parent,
"handle dirty metadata err=%d", err);
}
+
+ brelse(iloc.bh);
}
/*
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 44f6be3ea11a..7643c1d7dbb2 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -356,6 +356,8 @@ static void f2fs_write_end_io(struct bio *bio)
f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
page->index != nid_of_node(page));
+ if (f2fs_in_warm_node_list(sbi, page))
+ f2fs_del_fsync_node_entry(sbi, page);
dec_page_count(sbi, type);
@@ -367,8 +369,6 @@ static void f2fs_write_end_io(struct bio *bio)
wq_has_sleeper(&sbi->cp_wait))
wake_up(&sbi->cp_wait);
- if (f2fs_in_warm_node_list(sbi, page))
- f2fs_del_fsync_node_entry(sbi, page);
clear_page_private_gcing(page);
end_page_writeback(page);
}
@@ -1507,7 +1507,8 @@ static bool f2fs_map_blocks_cached(struct inode *inode,
f2fs_wait_on_block_writeback_range(inode,
map->m_pblk, map->m_len);
- if (f2fs_allow_multi_device_dio(sbi, flag)) {
+ map->m_multidev_dio = f2fs_allow_multi_device_dio(sbi, flag);
+ if (map->m_multidev_dio) {
int bidx = f2fs_target_device_index(sbi, map->m_pblk);
struct f2fs_dev_info *dev = &sbi->devs[bidx];
@@ -1543,8 +1544,26 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
if (!maxblocks)
return 0;
- if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag))
- goto out;
+ if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) {
+ struct extent_info ei;
+
+ /*
+ * 1. If map->m_multidev_dio is true, map->m_pblk cannot be
+ * waitted by f2fs_wait_on_block_writeback_range() and are not
+ * mergeable.
+ * 2. If pgofs hits the read extent cache, it means the mapping
+ * is already cached in the extent cache, but it is not
+ * mergeable, and there is no need to query the mapping again
+ * via f2fs_get_dnode_of_data().
+ */
+ pgofs = (pgoff_t)map->m_lblk + map->m_len;
+ if (map->m_len == maxblocks ||
+ map->m_multidev_dio ||
+ f2fs_lookup_read_extent_cache(inode, pgofs, &ei))
+ goto out;
+ ofs = map->m_len;
+ goto map_more;
+ }
map->m_bdev = inode->i_sb->s_bdev;
map->m_multidev_dio =
@@ -1555,7 +1574,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
/* it only supports block size == page size */
pgofs = (pgoff_t)map->m_lblk;
- end = pgofs + maxblocks;
+map_more:
+ end = (pgoff_t)map->m_lblk + maxblocks;
next_dnode:
if (map->m_may_create) {
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index 847c50e40c22..09fd0cbd8f77 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -87,9 +87,10 @@ static bool __may_extent_tree(struct inode *inode, enum extent_type type)
if (!__init_may_extent_tree(inode, type))
return false;
+ if (is_inode_flag_set(inode, FI_NO_EXTENT))
+ return false;
+
if (type == EX_READ) {
- if (is_inode_flag_set(inode, FI_NO_EXTENT))
- return false;
if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) &&
!f2fs_sb_has_readonly(F2FS_I_SB(inode)))
return false;
@@ -602,6 +603,8 @@ static unsigned int __destroy_extent_node(struct inode *inode,
while (atomic_read(&et->node_cnt)) {
write_lock(&et->lock);
+ if (!is_inode_flag_set(inode, FI_NO_EXTENT))
+ set_inode_flag(inode, FI_NO_EXTENT);
node_cnt += __free_extent_tree(sbi, et, nr_shrink);
write_unlock(&et->lock);
}
@@ -637,12 +640,12 @@ static void __update_extent_tree_range(struct inode *inode,
write_lock(&et->lock);
- if (type == EX_READ) {
- if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
- write_unlock(&et->lock);
- return;
- }
+ if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
+ write_unlock(&et->lock);
+ return;
+ }
+ if (type == EX_READ) {
prev = et->largest;
dei.len = 0;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index d7afa8bc0ff8..fb35f78e60bb 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3722,7 +3722,7 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
int f2fs_start_discard_thread(struct f2fs_sb_info *sbi);
void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi);
-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi);
+bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check);
void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
struct cp_control *cpc);
void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 4ba5642148b5..db80b6cad325 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -665,7 +665,7 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
ri->i_uid = cpu_to_le32(i_uid_read(inode));
ri->i_gid = cpu_to_le32(i_gid_read(inode));
ri->i_links = cpu_to_le32(inode->i_nlink);
- ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1);
+ ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(READ_ONCE(inode->i_blocks)) + 1);
if (!f2fs_is_atomic_file(inode) ||
is_inode_flag_set(inode, FI_ATOMIC_COMMITTED))
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 133141f10d94..586a90643ddd 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -27,12 +27,17 @@ static struct kmem_cache *free_nid_slab;
static struct kmem_cache *nat_entry_set_slab;
static struct kmem_cache *fsync_node_entry_slab;
+static inline bool is_invalid_nid(struct f2fs_sb_info *sbi, nid_t nid)
+{
+ return nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid;
+}
+
/*
* Check whether the given nid is within node id range.
*/
int f2fs_check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
{
- if (unlikely(nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid)) {
+ if (unlikely(is_invalid_nid(sbi, nid))) {
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_warn(sbi, "%s: out-of-range nid=%x, run fsck to fix.",
__func__, nid);
@@ -2603,6 +2608,16 @@ bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list));
i = list_first_entry(&nm_i->free_nid_list,
struct free_nid, list);
+
+ if (unlikely(is_invalid_nid(sbi, i->nid))) {
+ spin_unlock(&nm_i->nid_list_lock);
+ f2fs_err(sbi, "Corrupted nid %u in free_nid_list",
+ i->nid);
+ f2fs_stop_checkpoint(sbi, false,
+ STOP_CP_REASON_CORRUPTED_NID);
+ return false;
+ }
+
*nid = i->nid;
__move_free_nid(sbi, i, FREE_NID, PREALLOC_NID);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 764a3d084e4c..8791aba087cd 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1873,7 +1873,7 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
*
* Return true if issued all discard cmd or no discard cmd need issue, otherwise return false.
*/
-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
+bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check)
{
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
struct discard_policy dpolicy;
@@ -1890,7 +1890,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
/* just to make sure there is no pending discard commands */
__wait_all_discard_cmd(sbi, NULL);
- f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt));
+ f2fs_bug_on(sbi, need_check && atomic_read(&dcc->discard_cmd_cnt));
return !dropped;
}
@@ -2349,7 +2349,7 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
* Recovery can cache discard commands, so in error path of
* fill_super(), it needs to give a chance to handle them.
*/
- f2fs_issue_discard_timeout(sbi);
+ f2fs_issue_discard_timeout(sbi, true);
kfree(dcc);
SM_I(sbi)->dcc_info = NULL;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 9bd71d68cd95..7614d93bd67f 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1612,7 +1612,7 @@ static void f2fs_put_super(struct super_block *sb)
}
/* be sure to wait for any on-going discard commands */
- done = f2fs_issue_discard_timeout(sbi);
+ done = f2fs_issue_discard_timeout(sbi, true);
if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) {
struct cp_control cpc = {
.reason = CP_UMOUNT | CP_TRIMMED,
@@ -1754,7 +1754,7 @@ static int f2fs_unfreeze(struct super_block *sb)
* will recover after removal of snapshot.
*/
if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi))
- f2fs_issue_discard_timeout(sbi);
+ f2fs_issue_discard_timeout(sbi, true);
clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
return 0;
@@ -2515,7 +2515,12 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
need_stop_discard = true;
} else {
f2fs_stop_discard_thread(sbi);
- f2fs_issue_discard_timeout(sbi);
+ /*
+ * f2fs_ioc_fitrim() won't race w/ "remount ro"
+ * so it's safe to check discard_cmd_cnt in
+ * f2fs_issue_discard_timeout().
+ */
+ f2fs_issue_discard_timeout(sbi, *flags & SB_RDONLY);
need_restart_discard = true;
}
}
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
index 26ebac4c6042..41f4f56f90fa 100644
--- a/fs/hfsplus/bfind.c
+++ b/fs/hfsplus/bfind.c
@@ -287,3 +287,54 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
fd->bnode = bnode;
return res;
}
+
+/**
+ * hfsplus_brec_read_cat - read and validate a catalog record
+ * @fd: find data structure
+ * @entry: pointer to catalog entry to read into
+ *
+ * Reads a catalog record and validates its size matches the expected
+ * size based on the record type.
+ *
+ * Returns 0 on success, or negative error code on failure.
+ */
+int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry)
+{
+ int res;
+ u32 expected_size;
+
+ res = hfs_brec_read(fd, entry, sizeof(hfsplus_cat_entry));
+ if (res)
+ return res;
+
+ /* Validate catalog record size based on type */
+ switch (be16_to_cpu(entry->type)) {
+ case HFSPLUS_FOLDER:
+ expected_size = sizeof(struct hfsplus_cat_folder);
+ break;
+ case HFSPLUS_FILE:
+ expected_size = sizeof(struct hfsplus_cat_file);
+ break;
+ case HFSPLUS_FOLDER_THREAD:
+ case HFSPLUS_FILE_THREAD:
+ /* Ensure we have at least the fixed fields before reading nodeName.length */
+ if (fd->entrylength < HFSPLUS_MIN_THREAD_SZ) {
+ pr_err("thread record too short (got %u)\n", fd->entrylength);
+ return -EIO;
+ }
+ expected_size = hfsplus_cat_thread_size(&entry->thread);
+ break;
+ default:
+ pr_err("unknown catalog record type %d\n",
+ be16_to_cpu(entry->type));
+ return -EIO;
+ }
+
+ if (fd->entrylength != expected_size) {
+ pr_err("catalog record size mismatch (type %d, got %u, expected %u)\n",
+ be16_to_cpu(entry->type), fd->entrylength, expected_size);
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index e71ae2537eaa..34e19f6c3468 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -194,12 +194,12 @@ static int hfsplus_fill_cat_thread(struct super_block *sb,
int hfsplus_find_cat(struct super_block *sb, u32 cnid,
struct hfs_find_data *fd)
{
- hfsplus_cat_entry tmp;
+ hfsplus_cat_entry tmp = {0};
int err;
u16 type;
hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid);
- err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
+ err = hfsplus_brec_read_cat(fd, &tmp);
if (err)
return err;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index d23f8c4cd717..eecb72c800d0 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -49,7 +49,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
if (unlikely(err < 0))
goto fail;
again:
- err = hfs_brec_read(&fd, &entry, sizeof(entry));
+ err = hfsplus_brec_read_cat(&fd, &entry);
if (err) {
if (err == -ENOENT) {
hfs_find_exit(&fd);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 595e5fd4dfdd..52be0d59e532 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -535,6 +535,15 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, void *buf,
void **data, blk_opf_t opf);
int hfsplus_read_wrapper(struct super_block *sb);
+static inline u32 hfsplus_cat_thread_size(const struct hfsplus_cat_thread *thread)
+{
+ return offsetof(struct hfsplus_cat_thread, nodeName) +
+ offsetof(struct hfsplus_unistr, unicode) +
+ be16_to_cpu(thread->nodeName.length) * sizeof(hfsplus_unichr);
+}
+
+int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry);
+
/*
* time helpers: convert between 1904-base and 1970-base timestamps
*
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 954ceaa748e6..0d15e440d686 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -539,9 +539,11 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if (err)
goto out_put_root;
err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
- if (unlikely(err < 0))
+ if (unlikely(err < 0)) {
+ hfs_find_exit(&fd);
goto out_put_root;
- if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
+ }
+ if (!hfsplus_brec_read_cat(&fd, &entry)) {
hfs_find_exit(&fd);
if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
err = -EIO;
diff --git a/fs/isofs/export.c b/fs/isofs/export.c
index 421d247fae52..78f80c1a5c54 100644
--- a/fs/isofs/export.c
+++ b/fs/isofs/export.c
@@ -24,7 +24,7 @@ isofs_export_iget(struct super_block *sb,
{
struct inode *inode;
- if (block == 0)
+ if (block == 0 || block >= ISOFS_SB(sb)->s_nzones)
return ERR_PTR(-ESTALE);
inode = isofs_iget(sb, block, offset);
if (IS_ERR(inode))
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 348783a70f57..4a791011cb09 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -101,6 +101,15 @@ static int rock_continue(struct rock_state *rs)
goto out;
}
+ if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) {
+ printk(KERN_NOTICE "rock: corrupted directory entry. "
+ "extent=%u out of volume (nzones=%lu)\n",
+ (unsigned)rs->cont_extent,
+ ISOFS_SB(rs->inode->i_sb)->s_nzones);
+ ret = -EIO;
+ goto out;
+ }
+
if (rs->cont_extent) {
struct buffer_head *bh;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 82602157bcc0..7da224a0ae7c 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -398,7 +398,7 @@ static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector
return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
}
-static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
+struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
{
struct hlist_node *node = NULL;
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 1c4bfdab008d..804af9d6078b 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -622,6 +622,7 @@ static int inotify_new_watch(struct fsnotify_group *group,
if (ret) {
/* we failed to get on the inode, get off the idr */
inotify_remove_from_idr(group, tmp_i_mark);
+ dec_inotify_watches(group->inotify_data.ucounts);
goto out_err;
}
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 4be6e883d492..b419a5ccf192 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -380,9 +380,6 @@ EXPORT_SYMBOL_GPL(fsnotify_put_mark);
*/
static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
{
- if (!mark)
- return true;
-
if (refcount_inc_not_zero(&mark->refcnt)) {
spin_lock(&mark->lock);
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
@@ -423,15 +420,22 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
int type;
fsnotify_foreach_iter_type(type) {
+ struct fsnotify_mark *mark = iter_info->marks[type];
+
/* This can fail if mark is being removed */
- if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
- __release(&fsnotify_mark_srcu);
- goto fail;
+ while (mark && !fsnotify_get_mark_safe(mark)) {
+ if (mark->group == iter_info->current_group) {
+ __release(&fsnotify_mark_srcu);
+ goto fail;
+ }
+ /* This is a mark in an unrelated group, skip */
+ mark = fsnotify_next_mark(mark);
+ iter_info->marks[type] = mark;
}
}
/*
- * Now that both marks are pinned by refcount in the inode / vfsmount
+ * Now that all marks are pinned by refcount in the inode / vfsmount / etc
* lists, we can drop SRCU lock, and safely resume the list iteration
* once userspace returns.
*/
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c
index 0256fa7c879f..f2451eaf928a 100644
--- a/fs/ntfs3/run.c
+++ b/fs/ntfs3/run.c
@@ -963,6 +963,9 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
if (size_size > 8)
return -EINVAL;
+ if (run_buf + size_size > run_last)
+ return -EINVAL;
+
len = run_unpack_s64(run_buf, size_size, 0);
/* Skip size_size. */
run_buf += size_size;
@@ -975,6 +978,9 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
else if (offset_size <= 8) {
s64 dlcn;
+ if (run_buf + offset_size > run_last)
+ return -EINVAL;
+
/* Initial value of dlcn is -1 or 0. */
dlcn = (run_buf[offset_size - 1] & 0x80) ? (s64)-1 : 0;
dlcn = run_unpack_s64(run_buf, offset_size, dlcn);
@@ -1012,9 +1018,15 @@ int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
return -EOPNOTSUPP;
}
#endif
- if (lcn != SPARSE_LCN64 && lcn + len > sbi->used.bitmap.nbits) {
- /* LCN range is out of volume. */
- return -EINVAL;
+ if (lcn != SPARSE_LCN64) {
+ u64 lcn_end;
+
+ if (check_add_overflow(lcn, len, &lcn_end))
+ return -EINVAL;
+ if (lcn_end > sbi->used.bitmap.nbits) {
+ /* LCN range is out of volume. */
+ return -EINVAL;
+ }
}
if (!run)
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 0d147f2b4e9f..5365fc7675de 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -37,6 +37,8 @@
#include "namei.h"
#include "sysfile.h"
+#define OCFS2_DIO_MARK_EXTENT_BATCH 200
+
static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
@@ -2305,7 +2307,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
struct ocfs2_alloc_context *meta_ac = NULL;
handle_t *handle = NULL;
loff_t end = offset + bytes;
- int ret = 0, credits = 0;
+ int ret = 0, credits = 0, batch = 0;
ocfs2_init_dealloc_ctxt(&dealloc);
@@ -2322,18 +2324,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
goto out;
}
- /* Delete orphan before acquire i_rwsem. */
- if (dwc->dw_orphaned) {
- BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
-
- end = end > i_size_read(inode) ? end : 0;
-
- ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
- !!end, end);
- if (ret < 0)
- mlog_errno(ret);
- }
-
down_write(&oi->ip_alloc_sem);
di = (struct ocfs2_dinode *)di_bh->b_data;
@@ -2354,24 +2344,25 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list);
- handle = ocfs2_start_trans(osb, credits);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- mlog_errno(ret);
- goto unlock;
- }
- ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (ret) {
- mlog_errno(ret);
- goto commit;
- }
-
list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
+ if (!handle) {
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto unlock;
+ }
+ ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto commit;
+ }
+ }
ret = ocfs2_assure_trans_credits(handle, credits);
if (ret < 0) {
mlog_errno(ret);
- break;
+ goto commit;
}
ret = ocfs2_mark_extent_written(inode, &et, handle,
ue->ue_cpos, 1,
@@ -2379,19 +2370,44 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
meta_ac, &dealloc);
if (ret < 0) {
mlog_errno(ret);
- break;
+ goto commit;
+ }
+
+ if (++batch == OCFS2_DIO_MARK_EXTENT_BATCH) {
+ ocfs2_commit_trans(osb, handle);
+ handle = NULL;
+ batch = 0;
}
}
if (end > i_size_read(inode)) {
+ if (!handle) {
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto unlock;
+ }
+ }
ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
if (ret < 0)
mlog_errno(ret);
}
+
commit:
- ocfs2_commit_trans(osb, handle);
+ if (handle)
+ ocfs2_commit_trans(osb, handle);
unlock:
up_write(&oi->ip_alloc_sem);
+
+ /* everything looks good, let's start the cleanup */
+ if (!ret && dwc->dw_orphaned) {
+ BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
+
+ ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
+ if (ret < 0)
+ mlog_errno(ret);
+ }
ocfs2_inode_unlock(inode, 1);
brelse(di_bh);
out:
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index d83161285a17..fbc746813a6f 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -261,6 +261,14 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
&rqst[0], &oplock, &oparms, utf16_path);
if (rc)
goto oshr_free;
+
+ if (oplock != SMB2_OPLOCK_LEVEL_II) {
+ rc = -EINVAL;
+ cifs_dbg(FYI, "%s: Oplock level %d not suitable for cached directory\n",
+ __func__, oplock);
+ goto oshr_free;
+ }
+
smb2_set_next_command(tcon, &rqst[0]);
memset(&qi_iov, 0, sizeof(qi_iov));
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index fb090e001e44..2422ac371262 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -758,14 +758,85 @@ static void dump_ace(struct smb_ace *pace, char *end_of_acl)
}
#endif
+static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl)
+{
+ int i, ace_hdr_size, ace_size, min_ace_size;
+ u16 dacl_size, num_aces;
+ char *acl_base, *end_of_dacl;
+ struct smb_ace *pace;
+
+ if (!pdacl)
+ return 0;
+
+ if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ dacl_size = le16_to_cpu(pdacl->size);
+ if (dacl_size < sizeof(struct smb_acl) ||
+ end_of_acl < (char *)pdacl + dacl_size) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ num_aces = le16_to_cpu(pdacl->num_aces);
+ if (!num_aces)
+ return 0;
+
+ ace_hdr_size = offsetof(struct smb_ace, sid) +
+ offsetof(struct smb_sid, sub_auth);
+ min_ace_size = ace_hdr_size + sizeof(__le32);
+ if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ return -EINVAL;
+ }
+
+ end_of_dacl = (char *)pdacl + dacl_size;
+ acl_base = (char *)pdacl;
+ ace_size = sizeof(struct smb_acl);
+
+ for (i = 0; i < num_aces; ++i) {
+ if (end_of_dacl - acl_base < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ pace = (struct smb_ace *)(acl_base + ace_size);
+ acl_base = (char *)pace;
+
+ if (end_of_dacl - acl_base < ace_hdr_size ||
+ pace->sid.num_subauth == 0 ||
+ pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
+ if (end_of_dacl - acl_base < ace_size ||
+ le16_to_cpu(pace->size) < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+
+ ace_size = le16_to_cpu(pace->size);
+ if (end_of_dacl - acl_base < ace_size) {
+ cifs_dbg(VFS, "ACL too small to parse ACE\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct cifs_fattr *fattr, bool mode_from_special_sid)
{
int i;
- int num_aces = 0;
+ u16 num_aces = 0;
int acl_size;
- char *acl_base;
+ char *acl_base, *end_of_dacl;
struct smb_ace **ppace;
/* BB need to add parm so we can store the SID BB */
@@ -777,59 +848,36 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
return;
}
- /* validate that we do not go past end of acl */
- if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
- end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
- cifs_dbg(VFS, "ACL too small to parse DACL\n");
+ if (validate_dacl(pdacl, end_of_acl))
return;
- }
cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
- le32_to_cpu(pdacl->num_aces));
+ le16_to_cpu(pdacl->num_aces));
/* reset rwx permissions for user/group/other.
Also, if num_aces is 0 i.e. DACL has no ACEs,
user/group/other have no permissions */
fattr->cf_mode &= ~(0777);
+ end_of_dacl = (char *)pdacl + le16_to_cpu(pdacl->size);
acl_base = (char *)pdacl;
acl_size = sizeof(struct smb_acl);
- num_aces = le32_to_cpu(pdacl->num_aces);
+ num_aces = le16_to_cpu(pdacl->num_aces);
if (num_aces > 0) {
umode_t denied_mode = 0;
- if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
- (offsetof(struct smb_ace, sid) +
- offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
- return;
-
ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *),
GFP_KERNEL);
if (!ppace)
return;
for (i = 0; i < num_aces; ++i) {
- if (end_of_acl - acl_base < acl_size)
- break;
-
ppace[i] = (struct smb_ace *) (acl_base + acl_size);
- acl_base = (char *)ppace[i];
- acl_size = offsetof(struct smb_ace, sid) +
- offsetof(struct smb_sid, sub_auth);
-
- if (end_of_acl - acl_base < acl_size ||
- ppace[i]->sid.num_subauth == 0 ||
- ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
- (end_of_acl - acl_base <
- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
- (le16_to_cpu(ppace[i]->size) <
- acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
- break;
#ifdef CONFIG_CIFS_DEBUG2
- dump_ace(ppace[i], end_of_acl);
+ dump_ace(ppace[i], end_of_dacl);
#endif
if (mode_from_special_sid &&
ppace[i]->sid.num_subauth >= 3 &&
@@ -872,6 +920,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
(void *)ppace[i],
sizeof(struct smb_ace)); */
+ acl_base = (char *)ppace[i];
acl_size = le16_to_cpu(ppace[i]->size);
}
@@ -957,12 +1006,12 @@ unsigned int setup_special_user_owner_ACE(struct smb_ace *pntace)
static void populate_new_aces(char *nacl_base,
struct smb_sid *pownersid,
struct smb_sid *pgrpsid,
- __u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
+ __u64 *pnmode, u16 *pnum_aces, u16 *pnsize,
bool modefromsid,
bool posix)
{
__u64 nmode;
- u32 num_aces = 0;
+ u16 num_aces = 0;
u16 nsize = 0;
__u64 user_mode;
__u64 group_mode;
@@ -1070,7 +1119,7 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
u16 size = 0;
struct smb_ace *pntace = NULL;
char *acl_base = NULL;
- u32 src_num_aces = 0;
+ u16 src_num_aces = 0;
u16 nsize = 0;
struct smb_ace *pnntace = NULL;
char *nacl_base = NULL;
@@ -1078,7 +1127,7 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
acl_base = (char *)pdacl;
size = sizeof(struct smb_acl);
- src_num_aces = le32_to_cpu(pdacl->num_aces);
+ src_num_aces = le16_to_cpu(pdacl->num_aces);
nacl_base = (char *)pndacl;
nsize = sizeof(struct smb_acl);
@@ -1110,11 +1159,11 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
u16 size = 0;
struct smb_ace *pntace = NULL;
char *acl_base = NULL;
- u32 src_num_aces = 0;
+ u16 src_num_aces = 0;
u16 nsize = 0;
struct smb_ace *pnntace = NULL;
char *nacl_base = NULL;
- u32 num_aces = 0;
+ u16 num_aces = 0;
bool new_aces_set = false;
/* Assuming that pndacl and pnmode are never NULL */
@@ -1132,7 +1181,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
acl_base = (char *)pdacl;
size = sizeof(struct smb_acl);
- src_num_aces = le32_to_cpu(pdacl->num_aces);
+ src_num_aces = le16_to_cpu(pdacl->num_aces);
/* Retain old ACEs which we can retain */
for (i = 0; i < src_num_aces; ++i) {
@@ -1178,7 +1227,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
}
finalize_dacl:
- pndacl->num_aces = cpu_to_le32(num_aces);
+ pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(nsize);
return 0;
@@ -1216,6 +1265,17 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl)
return 0;
}
+static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
+{
+ if (acl_len < sizeof(struct smb_acl))
+ return false;
+
+ if (dacloffset < sizeof(struct smb_ntsd))
+ return false;
+
+ return dacloffset <= acl_len - sizeof(struct smb_acl);
+}
+
/* Convert CIFS ACL to POSIX form */
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
@@ -1236,7 +1296,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
group_sid_ptr = (struct smb_sid *)((char *)pntsd +
le32_to_cpu(pntsd->gsidoffset));
dacloffset = le32_to_cpu(pntsd->dacloffset);
- dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
le32_to_cpu(pntsd->gsidoffset),
@@ -1267,11 +1326,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
return rc;
}
- if (dacloffset)
+ if (dacloffset) {
+ if (!dacl_offset_valid(acl_len, dacloffset)) {
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
+ return -EINVAL;
+ }
+
+ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
group_sid_ptr, fattr, get_mode_from_special_sid);
- else
+ } else {
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
+ }
return rc;
}
@@ -1294,11 +1360,15 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
dacloffset = le32_to_cpu(pntsd->dacloffset);
if (dacloffset) {
- dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
- if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
- cifs_dbg(VFS, "Server returned illegal ACL size\n");
+ if (!dacl_offset_valid(secdesclen, dacloffset)) {
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
return -EINVAL;
}
+
+ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ rc = validate_dacl(dacl_ptr, end_of_acl);
+ if (rc)
+ return rc;
}
owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1313,7 +1383,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
ndacl_ptr->size = cpu_to_le16(0);
- ndacl_ptr->num_aces = cpu_to_le32(0);
+ ndacl_ptr->num_aces = cpu_to_le16(0);
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
pnmode, mode_from_sid, posix);
@@ -1668,10 +1738,22 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
dacloffset = le32_to_cpu(pntsd->dacloffset);
if (dacloffset) {
+ if (!dacl_offset_valid(secdesclen, dacloffset)) {
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
+ rc = -EINVAL;
+ goto id_mode_to_cifs_acl_exit;
+ }
+
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
+ if (rc) {
+ kfree(pntsd);
+ cifs_put_tlink(tlink);
+ return rc;
+ }
if (mode_from_sid)
nsecdesclen +=
- le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
+ le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
else /* cifsacl */
nsecdesclen += le16_to_cpu(dacl_ptr->size);
}
@@ -1684,7 +1766,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
* descriptor parameters, and security descriptor itself
*/
nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN);
- pnntsd = kmalloc(nsecdesclen, GFP_KERNEL);
+ pnntsd = kzalloc(nsecdesclen, GFP_KERNEL);
if (!pnntsd) {
kfree(pntsd);
cifs_put_tlink(tlink);
@@ -1704,6 +1786,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
}
+id_mode_to_cifs_acl_exit:
cifs_put_tlink(tlink);
kfree(pnntsd);
diff --git a/fs/smb/client/cifsacl.h b/fs/smb/client/cifsacl.h
index 05b3650ba0ae..31b51a8fc256 100644
--- a/fs/smb/client/cifsacl.h
+++ b/fs/smb/client/cifsacl.h
@@ -9,8 +9,7 @@
#ifndef _CIFSACL_H
#define _CIFSACL_H
-#define NUM_AUTHS (6) /* number of authority fields */
-#define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */
+#include "../common/smbacl.h"
#define READ_BIT 0x4
#define WRITE_BIT 0x2
@@ -23,12 +22,6 @@
#define UBITSHIFT 6
#define GBITSHIFT 3
-#define ACCESS_ALLOWED 0
-#define ACCESS_DENIED 1
-
-#define SIDOWNER 1
-#define SIDGROUP 2
-
/*
* Security Descriptor length containing DACL with 3 ACEs (one each for
* owner, group and world).
@@ -37,88 +30,6 @@
sizeof(struct smb_acl) + \
(sizeof(struct smb_ace) * 4))
-/*
- * Maximum size of a string representation of a SID:
- *
- * The fields are unsigned values in decimal. So:
- *
- * u8: max 3 bytes in decimal
- * u32: max 10 bytes in decimal
- *
- * "S-" + 3 bytes for version field + 15 for authority field + NULL terminator
- *
- * For authority field, max is when all 6 values are non-zero and it must be
- * represented in hex. So "-0x" + 12 hex digits.
- *
- * Add 11 bytes for each subauthority field (10 bytes each + 1 for '-')
- */
-#define SID_STRING_BASE_SIZE (2 + 3 + 15 + 1)
-#define SID_STRING_SUBAUTH_SIZE (11) /* size of a single subauth string */
-
-struct smb_ntsd {
- __le16 revision; /* revision level */
- __le16 type;
- __le32 osidoffset;
- __le32 gsidoffset;
- __le32 sacloffset;
- __le32 dacloffset;
-} __attribute__((packed));
-
-struct smb_sid {
- __u8 revision; /* revision level */
- __u8 num_subauth;
- __u8 authority[NUM_AUTHS];
- __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
-} __attribute__((packed));
-
-/* size of a struct smb_sid, sans sub_auth array */
-#define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS)
-
-struct smb_acl {
- __le16 revision; /* revision level */
- __le16 size;
- __le32 num_aces;
-} __attribute__((packed));
-
-/* ACE types - see MS-DTYP 2.4.4.1 */
-#define ACCESS_ALLOWED_ACE_TYPE 0x00
-#define ACCESS_DENIED_ACE_TYPE 0x01
-#define SYSTEM_AUDIT_ACE_TYPE 0x02
-#define SYSTEM_ALARM_ACE_TYPE 0x03
-#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
-#define ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
-#define ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
-#define SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
-#define SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
-#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09
-#define ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A
-#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B
-#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C
-#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D
-#define SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E /* Reserved */
-#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F
-#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 /* reserved */
-#define SYSTEM_MANDATORY_LABEL_ACE_TYPE 0x11
-#define SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE 0x12
-#define SYSTEM_SCOPED_POLICY_ID_ACE_TYPE 0x13
-
-/* ACE flags */
-#define OBJECT_INHERIT_ACE 0x01
-#define CONTAINER_INHERIT_ACE 0x02
-#define NO_PROPAGATE_INHERIT_ACE 0x04
-#define INHERIT_ONLY_ACE 0x08
-#define INHERITED_ACE 0x10
-#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40
-#define FAILED_ACCESS_ACE_FLAG 0x80
-
-struct smb_ace {
- __u8 type; /* see above and MS-DTYP 2.4.4.1 */
- __u8 flags;
- __le16 size;
- __le32 access_req;
- struct smb_sid sid; /* ie UUID of user or group who gets these perms */
-} __attribute__((packed));
-
/*
* The current SMB3 form of security descriptor is similar to what was used for
* cifs (see above) but some fields are split, and fields in the struct below
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index aae486771ccb..540f4ba81b6c 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -108,7 +108,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
u32 outlen, next;
u16 vlen;
u8 nlen;
- u8 *end;
+ u8 *ea_end, *iov_end;
outlen = le32_to_cpu(rsp->OutputBufferLength);
if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
@@ -117,15 +117,19 @@ static int check_wsl_eas(struct kvec *rsp_iov)
ea = (void *)((u8 *)rsp_iov->iov_base +
le16_to_cpu(rsp->OutputBufferOffset));
- end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
+ ea_end = (u8 *)ea + outlen;
+ iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
+ if (ea_end > iov_end)
+ return -EINVAL;
+
for (;;) {
- if ((u8 *)ea > end - sizeof(*ea))
+ if ((u8 *)ea > ea_end - sizeof(*ea))
return -EINVAL;
nlen = ea->ea_name_length;
vlen = le16_to_cpu(ea->ea_value_length);
if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
- (u8 *)ea->ea_data + nlen + 1 + vlen > end)
+ (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
return -EINVAL;
switch (vlen) {
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 70a9536b03c6..dc0a441371be 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -239,7 +239,8 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
if (len != calc_len) {
/* create failed on symlink */
if (command == SMB2_CREATE_HE &&
- shdr->Status == STATUS_STOPPED_ON_SYMLINK)
+ shdr->Status == STATUS_STOPPED_ON_SYMLINK &&
+ len > calc_len)
return 0;
/* Windows 7 server returns 24 bytes more */
if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index bedca306cc82..c16ed08d62af 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -96,10 +96,21 @@ smb2_add_credits(struct TCP_Server_Info *server,
}
WARN_ON_ONCE(server->in_flight == 0);
server->in_flight--;
+
+ /*
+ * Rebalance credits when an op drains in_flight. For session setup,
+ * do this only when the total accumulated credits are high enough (>2)
+ * so that a newly established secondary channel can reserve credits for
+ * echoes and oplocks. We expect this to happen at the end of the final
+ * session setup response.
+ */
if (server->in_flight == 0 &&
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
((optype & CIFS_OP_MASK) != CIFS_SESS_OP))
rc = change_conf(server);
+ else if (server->in_flight == 0 &&
+ ((optype & CIFS_OP_MASK) == CIFS_SESS_OP) && *val > 2)
+ rc = change_conf(server);
/*
* Sometimes server returns 0 credits on oplock break ack - we need to
* rebalance credits in this case.
diff --git a/fs/smb/common/smbacl.h b/fs/smb/common/smbacl.h
new file mode 100644
index 000000000000..a624ec9e4a14
--- /dev/null
+++ b/fs/smb/common/smbacl.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ * Modified by Namjae Jeon (linkinjeon@kernel.org)
+ */
+
+#ifndef _COMMON_SMBACL_H
+#define _COMMON_SMBACL_H
+
+#define NUM_AUTHS (6) /* number of authority fields */
+#define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */
+
+/* ACE types - see MS-DTYP 2.4.4.1 */
+#define ACCESS_ALLOWED_ACE_TYPE 0x00
+#define ACCESS_DENIED_ACE_TYPE 0x01
+#define SYSTEM_AUDIT_ACE_TYPE 0x02
+#define SYSTEM_ALARM_ACE_TYPE 0x03
+#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
+#define ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
+#define ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
+#define SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
+#define SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
+#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09
+#define ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A
+#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B
+#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C
+#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D
+#define SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E /* Reserved */
+#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F
+#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 /* reserved */
+#define SYSTEM_MANDATORY_LABEL_ACE_TYPE 0x11
+#define SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE 0x12
+#define SYSTEM_SCOPED_POLICY_ID_ACE_TYPE 0x13
+
+/* ACE flags */
+#define OBJECT_INHERIT_ACE 0x01
+#define CONTAINER_INHERIT_ACE 0x02
+#define NO_PROPAGATE_INHERIT_ACE 0x04
+#define INHERIT_ONLY_ACE 0x08
+#define INHERITED_ACE 0x10
+#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40
+#define FAILED_ACCESS_ACE_FLAG 0x80
+
+/*
+ * Maximum size of a string representation of a SID:
+ *
+ * The fields are unsigned values in decimal. So:
+ *
+ * u8: max 3 bytes in decimal
+ * u32: max 10 bytes in decimal
+ *
+ * "S-" + 3 bytes for version field + 15 for authority field + NULL terminator
+ *
+ * For authority field, max is when all 6 values are non-zero and it must be
+ * represented in hex. So "-0x" + 12 hex digits.
+ *
+ * Add 11 bytes for each subauthority field (10 bytes each + 1 for '-')
+ */
+#define SID_STRING_BASE_SIZE (2 + 3 + 15 + 1)
+#define SID_STRING_SUBAUTH_SIZE (11) /* size of a single subauth string */
+
+#define DOMAIN_USER_RID_LE cpu_to_le32(513)
+
+/*
+ * ACE types - see MS-DTYP 2.4.4.1
+ */
+enum {
+ ACCESS_ALLOWED,
+ ACCESS_DENIED,
+};
+
+/*
+ * Security ID types
+ */
+enum {
+ SIDOWNER = 1,
+ SIDGROUP,
+ SIDCREATOR_OWNER,
+ SIDCREATOR_GROUP,
+ SIDUNIX_USER,
+ SIDUNIX_GROUP,
+ SIDNFS_USER,
+ SIDNFS_GROUP,
+ SIDNFS_MODE,
+};
+
+struct smb_ntsd {
+ __le16 revision; /* revision level */
+ __le16 type;
+ __le32 osidoffset;
+ __le32 gsidoffset;
+ __le32 sacloffset;
+ __le32 dacloffset;
+} __attribute__((packed));
+
+struct smb_sid {
+ __u8 revision; /* revision level */
+ __u8 num_subauth;
+ __u8 authority[NUM_AUTHS];
+ __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
+} __attribute__((packed));
+
+/* size of a struct smb_sid, sans sub_auth array */
+#define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS)
+
+struct smb_acl {
+ __le16 revision; /* revision level */
+ __le16 size;
+ __le16 num_aces;
+ __le16 reserved;
+} __attribute__((packed));
+
+struct smb_ace {
+ __u8 type; /* see above and MS-DTYP 2.4.4.1 */
+ __u8 flags;
+ __le16 size;
+ __le32 access_req;
+ struct smb_sid sid; /* ie UUID of user or group who gets these perms */
+} __attribute__((packed));
+
+#endif /* _COMMON_SMBACL_H */
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index 907ddfc2c2c1..a5209abb004a 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -19,7 +19,7 @@ static DEFINE_MUTEX(init_lock);
static struct ksmbd_conn_ops default_conn_ops;
-LIST_HEAD(conn_list);
+DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS);
DECLARE_RWSEM(conn_list_lock);
/**
@@ -33,7 +33,7 @@ DECLARE_RWSEM(conn_list_lock);
void ksmbd_conn_free(struct ksmbd_conn *conn)
{
down_write(&conn_list_lock);
- list_del(&conn->conns_list);
+ hash_del(&conn->hlist);
up_write(&conn_list_lock);
xa_destroy(&conn->sessions);
@@ -78,7 +78,6 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
init_waitqueue_head(&conn->req_running_q);
init_waitqueue_head(&conn->r_count_q);
- INIT_LIST_HEAD(&conn->conns_list);
INIT_LIST_HEAD(&conn->requests);
INIT_LIST_HEAD(&conn->async_requests);
spin_lock_init(&conn->request_lock);
@@ -91,19 +90,17 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
init_rwsem(&conn->session_lock);
- down_write(&conn_list_lock);
- list_add(&conn->conns_list, &conn_list);
- up_write(&conn_list_lock);
return conn;
}
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
{
struct ksmbd_conn *t;
+ int bkt;
bool ret = false;
down_read(&conn_list_lock);
- list_for_each_entry(t, &conn_list, conns_list) {
+ hash_for_each(conn_list, bkt, t, hlist) {
if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
continue;
@@ -164,9 +161,10 @@ void ksmbd_conn_unlock(struct ksmbd_conn *conn)
void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
{
struct ksmbd_conn *conn;
+ int bkt;
down_read(&conn_list_lock);
- list_for_each_entry(conn, &conn_list, conns_list) {
+ hash_for_each(conn_list, bkt, conn, hlist) {
if (conn->binding || xa_load(&conn->sessions, sess_id))
WRITE_ONCE(conn->status, status);
}
@@ -182,17 +180,16 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
{
struct ksmbd_conn *conn;
int rc, retry_count = 0, max_timeout = 120;
- int rcount = 1;
+ int rcount, bkt;
retry_idle:
if (retry_count >= max_timeout)
return -EIO;
down_read(&conn_list_lock);
- list_for_each_entry(conn, &conn_list, conns_list) {
+ hash_for_each(conn_list, bkt, conn, hlist) {
if (conn->binding || xa_load(&conn->sessions, sess_id)) {
- if (conn == curr_conn)
- rcount = 2;
+ rcount = (conn == curr_conn) ? 2 : 1;
if (atomic_read(&conn->req_running) >= rcount) {
rc = wait_event_timeout(conn->req_running_q,
atomic_read(&conn->req_running) < rcount,
@@ -480,10 +477,11 @@ static void stop_sessions(void)
{
struct ksmbd_conn *conn;
struct ksmbd_transport *t;
+ int bkt;
again:
down_read(&conn_list_lock);
- list_for_each_entry(conn, &conn_list, conns_list) {
+ hash_for_each(conn_list, bkt, conn, hlist) {
t = conn->transport;
ksmbd_conn_set_exiting(conn);
if (t->ops->shutdown) {
@@ -494,8 +492,8 @@ static void stop_sessions(void)
}
up_read(&conn_list_lock);
- if (!list_empty(&conn_list)) {
- schedule_timeout_interruptible(HZ / 10); /* 100ms */
+ if (!hash_empty(conn_list)) {
+ msleep(100);
goto again;
}
}
diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
index 45421269ddd8..2a4b0141ab45 100644
--- a/fs/smb/server/connection.h
+++ b/fs/smb/server/connection.h
@@ -52,11 +52,12 @@ struct ksmbd_conn {
u8 inet6_addr[16];
#endif
};
+ unsigned int inet_hash;
char *request_buf;
struct ksmbd_transport *transport;
struct nls_table *local_nls;
struct unicode_map *um;
- struct list_head conns_list;
+ struct hlist_node hlist;
struct rw_semaphore session_lock;
/* smb session 1 per user */
struct xarray sessions;
@@ -151,7 +152,8 @@ struct ksmbd_transport {
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
-extern struct list_head conn_list;
+#define CONN_HASH_BITS 12
+extern DECLARE_HASHTABLE(conn_list, CONN_HASH_BITS);
extern struct rw_semaphore conn_list_lock;
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 0ead29d69259..6c41a67be725 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7348,7 +7348,7 @@ int smb2_lock(struct ksmbd_work *work)
int nolock = 0;
LIST_HEAD(lock_list);
LIST_HEAD(rollback_list);
- int prior_lock = 0;
+ int prior_lock = 0, bkt;
WORK_BUFFERS(work, req, rsp);
@@ -7458,7 +7458,7 @@ int smb2_lock(struct ksmbd_work *work)
nolock = 1;
/* check locks in connection list */
down_read(&conn_list_lock);
- list_for_each_entry(conn, &conn_list, conns_list) {
+ hash_for_each(conn_list, bkt, conn, hlist) {
spin_lock(&conn->llist_lock);
list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
if (file_inode(cmp_lock->fl->fl_file) !=
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 0c768761a731..0a3a26e63ebc 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -338,7 +338,7 @@ void posix_state_to_acl(struct posix_acl_state *state,
pace->e_perm = state->other.allow;
}
-int init_acl_state(struct posix_acl_state *state, int cnt)
+int init_acl_state(struct posix_acl_state *state, u16 cnt)
{
int alloc;
@@ -373,7 +373,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
struct smb_fattr *fattr)
{
int i, ret;
- int num_aces = 0;
+ u16 num_aces = 0;
unsigned int acl_size;
char *acl_base;
struct smb_ace **ppace;
@@ -394,12 +394,12 @@ static void parse_dacl(struct mnt_idmap *idmap,
ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n",
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
- le32_to_cpu(pdacl->num_aces));
+ le16_to_cpu(pdacl->num_aces));
acl_base = (char *)pdacl;
acl_size = sizeof(struct smb_acl);
- num_aces = le32_to_cpu(pdacl->num_aces);
+ num_aces = le16_to_cpu(pdacl->num_aces);
if (num_aces <= 0)
return;
@@ -589,7 +589,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
struct smb_ace *pndace,
- struct smb_fattr *fattr, u32 *num_aces,
+ struct smb_fattr *fattr, u16 *num_aces,
u16 *size, u32 nt_aces_num)
{
struct posix_acl_entry *pace;
@@ -717,7 +717,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
struct smb_fattr *fattr)
{
struct smb_ace *ntace, *pndace;
- int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
unsigned short size = 0;
int i;
@@ -745,7 +745,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
set_posix_acl_entries_dacl(idmap, pndace, fattr,
&num_aces, &size, nt_num_aces);
- pndacl->num_aces = cpu_to_le32(num_aces);
+ pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
}
@@ -753,7 +753,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
struct smb_acl *pndacl, struct smb_fattr *fattr)
{
struct smb_ace *pace, *pndace;
- u32 num_aces = 0;
+ u16 num_aces = 0;
u16 size = 0, ace_size = 0;
uid_t uid;
const struct smb_sid *sid;
@@ -809,7 +809,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
fattr->cf_mode, 0007);
out:
- pndacl->num_aces = cpu_to_le32(num_aces);
+ pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
}
@@ -1039,8 +1039,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
struct smb_sid owner_sid, group_sid;
struct dentry *parent = path->dentry->d_parent;
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
- int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
- int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
+ int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
+ int rc = 0, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
+ u16 num_aces, ace_cnt = 0;
char *aces_base;
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
@@ -1056,7 +1057,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
acl_len = pntsd_size - dacloffset;
- num_aces = le32_to_cpu(parent_pdacl->num_aces);
+ num_aces = le16_to_cpu(parent_pdacl->num_aces);
pntsd_type = le16_to_cpu(parent_pntsd->type);
pdacl_size = le16_to_cpu(parent_pdacl->size);
@@ -1215,7 +1216,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
pdacl->revision = cpu_to_le16(2);
pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size);
- pdacl->num_aces = cpu_to_le32(ace_cnt);
+ pdacl->num_aces = cpu_to_le16(ace_cnt);
pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
memcpy(pace, aces_base, nt_size);
pntsd_size += sizeof(struct smb_acl) + nt_size;
@@ -1296,11 +1297,14 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = acl_size - sizeof(struct smb_acl);
- for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
- if (offsetof(struct smb_ace, access_req) > aces_size)
+ for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
+ if (offsetof(struct smb_ace, sid) +
+ aces_size < CIFS_SID_BASE_SIZE)
break;
ace_size = le16_to_cpu(ace->size);
- if (ace_size > aces_size)
+ if (ace_size > aces_size ||
+ ace_size < offsetof(struct smb_ace, sid) +
+ CIFS_SID_BASE_SIZE)
break;
aces_size -= ace_size;
granted |= le32_to_cpu(ace->access_req);
@@ -1317,14 +1321,20 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = acl_size - sizeof(struct smb_acl);
- for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
- if (offsetof(struct smb_ace, access_req) > aces_size)
+ for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
+ if (offsetof(struct smb_ace, sid) +
+ aces_size < CIFS_SID_BASE_SIZE)
break;
ace_size = le16_to_cpu(ace->size);
- if (ace_size > aces_size)
+ if (ace_size > aces_size ||
+ ace_size < offsetof(struct smb_ace, sid) +
+ CIFS_SID_BASE_SIZE)
break;
aces_size -= ace_size;
+ if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
+ break;
+
if (!compare_sids(&sid, &ace->sid) ||
!compare_sids(&sid_unix_NFS_mode, &ace->sid)) {
found = 1;
diff --git a/fs/smb/server/smbacl.h b/fs/smb/server/smbacl.h
index 2b52861707d8..355adaee39b8 100644
--- a/fs/smb/server/smbacl.h
+++ b/fs/smb/server/smbacl.h
@@ -8,6 +8,7 @@
#ifndef _SMBACL_H
#define _SMBACL_H
+#include "../common/smbacl.h"
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/posix_acl.h>
@@ -15,32 +16,6 @@
#include "mgmt/tree_connect.h"
-#define NUM_AUTHS (6) /* number of authority fields */
-#define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */
-
-/*
- * ACE types - see MS-DTYP 2.4.4.1
- */
-enum {
- ACCESS_ALLOWED,
- ACCESS_DENIED,
-};
-
-/*
- * Security ID types
- */
-enum {
- SIDOWNER = 1,
- SIDGROUP,
- SIDCREATOR_OWNER,
- SIDCREATOR_GROUP,
- SIDUNIX_USER,
- SIDUNIX_GROUP,
- SIDNFS_USER,
- SIDNFS_GROUP,
- SIDNFS_MODE,
-};
-
/* Revision for ACLs */
#define SD_REVISION 1
@@ -62,92 +37,8 @@ enum {
#define RM_CONTROL_VALID 0x4000
#define SELF_RELATIVE 0x8000
-/* ACE types - see MS-DTYP 2.4.4.1 */
-#define ACCESS_ALLOWED_ACE_TYPE 0x00
-#define ACCESS_DENIED_ACE_TYPE 0x01
-#define SYSTEM_AUDIT_ACE_TYPE 0x02
-#define SYSTEM_ALARM_ACE_TYPE 0x03
-#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
-#define ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
-#define ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
-#define SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
-#define SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
-#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09
-#define ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A
-#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B
-#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C
-#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D
-#define SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E /* Reserved */
-#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F
-#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 /* reserved */
-#define SYSTEM_MANDATORY_LABEL_ACE_TYPE 0x11
-#define SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE 0x12
-#define SYSTEM_SCOPED_POLICY_ID_ACE_TYPE 0x13
-
-/* ACE flags */
-#define OBJECT_INHERIT_ACE 0x01
-#define CONTAINER_INHERIT_ACE 0x02
-#define NO_PROPAGATE_INHERIT_ACE 0x04
-#define INHERIT_ONLY_ACE 0x08
-#define INHERITED_ACE 0x10
-#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40
-#define FAILED_ACCESS_ACE_FLAG 0x80
-
-/*
- * Maximum size of a string representation of a SID:
- *
- * The fields are unsigned values in decimal. So:
- *
- * u8: max 3 bytes in decimal
- * u32: max 10 bytes in decimal
- *
- * "S-" + 3 bytes for version field + 15 for authority field + NULL terminator
- *
- * For authority field, max is when all 6 values are non-zero and it must be
- * represented in hex. So "-0x" + 12 hex digits.
- *
- * Add 11 bytes for each subauthority field (10 bytes each + 1 for '-')
- */
-#define SID_STRING_BASE_SIZE (2 + 3 + 15 + 1)
-#define SID_STRING_SUBAUTH_SIZE (11) /* size of a single subauth string */
-
-#define DOMAIN_USER_RID_LE cpu_to_le32(513)
-
struct ksmbd_conn;
-struct smb_ntsd {
- __le16 revision; /* revision level */
- __le16 type;
- __le32 osidoffset;
- __le32 gsidoffset;
- __le32 sacloffset;
- __le32 dacloffset;
-} __packed;
-
-struct smb_sid {
- __u8 revision; /* revision level */
- __u8 num_subauth;
- __u8 authority[NUM_AUTHS];
- __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
-} __packed;
-
-/* size of a struct cifs_sid, sans sub_auth array */
-#define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS)
-
-struct smb_acl {
- __le16 revision; /* revision level */
- __le16 size;
- __le32 num_aces;
-} __packed;
-
-struct smb_ace {
- __u8 type;
- __u8 flags;
- __le16 size;
- __le32 access_req;
- struct smb_sid sid; /* ie UUID of user or group who gets these perms */
-} __packed;
-
struct smb_fattr {
kuid_t cf_uid;
kgid_t cf_gid;
@@ -195,7 +86,7 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
int build_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
__u32 *secdesclen, struct smb_fattr *fattr);
-int init_acl_state(struct posix_acl_state *state, int cnt);
+int init_acl_state(struct posix_acl_state *state, u16 cnt);
void free_acl_state(struct posix_acl_state *state);
void posix_state_to_acl(struct posix_acl_state *state,
struct posix_acl_entry *pace);
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 4bab3f89d2c8..3528ec33919d 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -381,6 +381,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id)
conn = ksmbd_conn_alloc();
if (!conn)
goto err;
+
+ down_write(&conn_list_lock);
+ hash_add(conn_list, &conn->hlist, 0);
+ up_write(&conn_list_lock);
+
conn->transport = KSMBD_TRANS(t);
KSMBD_TRANS(t)->conn = conn;
KSMBD_TRANS(t)->ops = &ksmbd_smb_direct_transport_ops;
diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c
index e55afd0c9bf4..b3a1df597d50 100644
--- a/fs/smb/server/transport_tcp.c
+++ b/fs/smb/server/transport_tcp.c
@@ -89,13 +89,21 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk)
}
#if IS_ENABLED(CONFIG_IPV6)
- if (client_sk->sk->sk_family == AF_INET6)
+ if (client_sk->sk->sk_family == AF_INET6) {
memcpy(&conn->inet6_addr, &client_sk->sk->sk_v6_daddr, 16);
- else
+ conn->inet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr);
+ } else {
conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;
+ conn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);
+ }
#else
conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;
+ conn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);
#endif
+ down_write(&conn_list_lock);
+ hash_add(conn_list, &conn->hlist, conn->inet_hash);
+ up_write(&conn_list_lock);
+
conn->transport = KSMBD_TRANS(t);
KSMBD_TRANS(t)->conn = conn;
KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops;
@@ -242,7 +250,7 @@ static int ksmbd_kthread_fn(void *p)
struct socket *client_sk = NULL;
struct interface *iface = (struct interface *)p;
struct ksmbd_conn *conn;
- int ret;
+ int ret, inet_hash;
unsigned int max_ip_conns;
while (!kthread_should_stop()) {
@@ -267,9 +275,18 @@ static int ksmbd_kthread_fn(void *p)
/*
* Limits repeated connections from clients with the same IP.
*/
+#if IS_ENABLED(CONFIG_IPV6)
+ if (client_sk->sk->sk_family == AF_INET6)
+ inet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr);
+ else
+ inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);
+#else
+ inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);
+#endif
+
max_ip_conns = 0;
down_read(&conn_list_lock);
- list_for_each_entry(conn, &conn_list, conns_list) {
+ hash_for_each_possible(conn_list, conn, hlist, inet_hash) {
#if IS_ENABLED(CONFIG_IPV6)
if (client_sk->sk->sk_family == AF_INET6) {
if (memcmp(&client_sk->sk->sk_v6_daddr,
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 2fcb7ca33a63..eacc6ef41db0 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -356,9 +356,11 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
* there are not accesses to fp->lock_list.
*/
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
- spin_lock(&fp->conn->llist_lock);
- list_del(&smb_lock->clist);
- spin_unlock(&fp->conn->llist_lock);
+ if (!list_empty(&smb_lock->clist) && fp->conn) {
+ spin_lock(&fp->conn->llist_lock);
+ list_del(&smb_lock->clist);
+ spin_unlock(&fp->conn->llist_lock);
+ }
list_del(&smb_lock->flist);
locks_free_lock(smb_lock->fl);
@@ -755,6 +757,7 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
struct ksmbd_inode *ci;
struct oplock_info *op;
struct ksmbd_conn *conn;
+ struct ksmbd_lock *smb_lock, *tmp_lock;
if (!is_reconnectable(fp))
return false;
@@ -771,6 +774,12 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
}
up_write(&ci->m_lock);
+ list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
+ spin_lock(&fp->conn->llist_lock);
+ list_del_init(&smb_lock->clist);
+ spin_unlock(&fp->conn->llist_lock);
+ }
+
fp->conn = NULL;
fp->tcon = NULL;
fp->volatile_id = KSMBD_NO_FID;
@@ -844,6 +853,9 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
{
struct ksmbd_inode *ci;
struct oplock_info *op;
+ struct ksmbd_conn *conn = work->conn;
+ struct ksmbd_lock *smb_lock;
+ unsigned int old_f_state;
if (!fp->is_durable || fp->conn || fp->tcon) {
pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon);
@@ -855,9 +867,23 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
return -EBADF;
}
- fp->conn = work->conn;
+ old_f_state = fp->f_state;
+ fp->f_state = FP_NEW;
+ __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
+ if (!has_file_id(fp->volatile_id)) {
+ fp->f_state = old_f_state;
+ return -EBADF;
+ }
+
+ fp->conn = conn;
fp->tcon = work->tcon;
+ list_for_each_entry(smb_lock, &fp->lock_list, flist) {
+ spin_lock(&conn->llist_lock);
+ list_add_tail(&smb_lock->clist, &conn->lock_list);
+ spin_unlock(&conn->llist_lock);
+ }
+
ci = fp->f_ci;
down_write(&ci->m_lock);
list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
@@ -868,12 +894,6 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
}
up_write(&ci->m_lock);
- __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
- if (!has_file_id(fp->volatile_id)) {
- fp->conn = NULL;
- fp->tcon = NULL;
- return -EBADF;
- }
return 0;
}
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index 4190e6155044..f98315e91e99 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c
@@ -310,6 +310,8 @@ static void eventfs_set_attrs(struct eventfs_inode *ei, bool update_uid, kuid_t
{
struct eventfs_inode *ei_child;
+ lockdep_assert_held(&eventfs_mutex);
+
/* Update events/<system>/<event> */
if (WARN_ON_ONCE(level > 3))
return;
@@ -985,3 +987,15 @@ void eventfs_remove_events_dir(struct eventfs_inode *ei)
d_invalidate(dentry);
dput(dentry);
}
+
+int eventfs_remount_lock(void)
+{
+ mutex_lock(&eventfs_mutex);
+ return srcu_read_lock(&eventfs_srcu);
+}
+
+void eventfs_remount_unlock(int srcu_idx)
+{
+ srcu_read_unlock(&eventfs_srcu, srcu_idx);
+ mutex_unlock(&eventfs_mutex);
+}
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 6b70965063d7..6c7b48770948 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -362,6 +362,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
struct tracefs_mount_opts *opts = &fsi->mount_opts;
struct tracefs_inode *ti;
bool update_uid, update_gid;
+ int srcu_idx;
umode_t tmp_mode;
/*
@@ -386,6 +387,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
update_uid = opts->opts & BIT(Opt_uid);
update_gid = opts->opts & BIT(Opt_gid);
+ srcu_idx = eventfs_remount_lock();
rcu_read_lock();
list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
if (update_uid)
@@ -398,6 +400,7 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
eventfs_remount(ti, update_uid, update_gid);
}
rcu_read_unlock();
+ eventfs_remount_unlock(srcu_idx);
}
return 0;
@@ -444,7 +447,7 @@ static int tracefs_drop_inode(struct inode *inode)
* This inode is being freed and cannot be used for
* eventfs. Clear the flag so that it doesn't call into
* eventfs during the remount flag updates. The eventfs_inode
- * gets freed after an RCU cycle, so the content will still
+ * gets freed after an SRCU cycle, so the content will still
* be safe if the iteration is going on now.
*/
ti->flags &= ~TRACEFS_EVENT_INODE;
diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h
index d83c2a25f288..a4a7f8431aff 100644
--- a/fs/tracefs/internal.h
+++ b/fs/tracefs/internal.h
@@ -76,4 +76,7 @@ struct inode *tracefs_get_inode(struct super_block *sb);
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid);
void eventfs_d_release(struct dentry *dentry);
+int eventfs_remount_lock(void);
+void eventfs_remount_unlock(int srcu_idx);
+
#endif /* _TRACEFS_INTERNAL_H */
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index 0788593b6a1d..6928e378fbbd 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -230,8 +230,12 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
}
/* Verify the descriptor CRC */
- if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
- le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
+ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize) {
+ udf_err(sb, "block %u: CRC length %u exceeds block size\n",
+ block, le16_to_cpu(tag_p->descCRCLength));
+ goto error_out;
+ }
+ if (le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
bh->b_data + sizeof(struct tag),
le16_to_cpu(tag_p->descCRCLength)))
return bh;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index cb13a07a4aa8..dbf5faf07912 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1656,8 +1656,9 @@ static struct udf_vds_record *handle_partition_descriptor(
return &(data->part_descs_loc[i].rec);
if (data->num_part_descs >= data->size_part_descs) {
struct part_desc_seq_scan_data *new_loc;
- unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
+ unsigned int new_size;
+ new_size = data->num_part_descs + PART_DESC_ALLOC_STEP;
new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL);
if (!new_loc)
return ERR_PTR(-ENOMEM);
@@ -1667,6 +1668,7 @@ static struct udf_vds_record *handle_partition_descriptor(
data->part_descs_loc = new_loc;
data->size_part_descs = new_size;
}
+ data->part_descs_loc[data->num_part_descs].partnum = partnum;
return &(data->part_descs_loc[data->num_part_descs++].rec);
}
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 5ceb1fa8eb11..74c468cc432e 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1295,8 +1295,6 @@ static __always_inline int validate_unaligned_range(
return -EINVAL;
if (!len)
return -EINVAL;
- if (start < mmap_min_addr)
- return -EINVAL;
if (start >= task_size)
return -EINVAL;
if (len > task_size - start)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 20c1d146af1d..1181108f8074 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -2045,6 +2045,7 @@ xfs_alloc_buftarg(
error_lru:
list_lru_destroy(&btp->bt_lru);
error_free:
+ fs_put_dax(btp->bt_daxdev, mp);
kmem_free(btp);
return NULL;
}
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 32e89758176b..dba211d3bb9a 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -319,12 +319,34 @@ struct bpf_func_state {
struct bpf_stack_state *stack;
};
-struct bpf_idx_pair {
- u32 prev_idx;
+#define MAX_CALL_FRAMES 8
+
+/* instruction history flags, used in bpf_jmp_history_entry.flags field */
+enum {
+ /* instruction references stack slot through PTR_TO_STACK register;
+ * we also store stack's frame number in lower 3 bits (MAX_CALL_FRAMES is 8)
+ * and accessed stack slot's index in next 6 bits (MAX_BPF_STACK is 512,
+ * 8 bytes per slot, so slot index (spi) is [0, 63])
+ */
+ INSN_F_FRAMENO_MASK = 0x7, /* 3 bits */
+
+ INSN_F_SPI_MASK = 0x3f, /* 6 bits */
+ INSN_F_SPI_SHIFT = 3, /* shifted 3 bits to the left */
+
+ INSN_F_STACK_ACCESS = BIT(9), /* we need 10 bits total */
+};
+
+static_assert(INSN_F_FRAMENO_MASK + 1 >= MAX_CALL_FRAMES);
+static_assert(INSN_F_SPI_MASK + 1 >= MAX_BPF_STACK / 8);
+
+struct bpf_jmp_history_entry {
u32 idx;
+ /* insn idx can't be bigger than 1 million */
+ u32 prev_idx : 22;
+ /* special flags, e.g., whether insn is doing register stack spill/load */
+ u32 flags : 10;
};
-#define MAX_CALL_FRAMES 8
/* Maximum number of register states that can exist at once */
#define BPF_ID_MAP_SIZE ((MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) * MAX_CALL_FRAMES)
struct bpf_verifier_state {
@@ -407,7 +429,7 @@ struct bpf_verifier_state {
* For most states jmp_history_cnt is [0-3].
* For loops can go up to ~40.
*/
- struct bpf_idx_pair *jmp_history;
+ struct bpf_jmp_history_entry *jmp_history;
u32 jmp_history_cnt;
u32 dfs_depth;
u32 callback_unroll_depth;
@@ -641,6 +663,7 @@ struct bpf_verifier_env {
int cur_stack;
} cfg;
struct backtrack_state bt;
+ struct bpf_jmp_history_entry *cur_hist_ent;
u32 pass_cnt; /* number of times do_check() was called */
u32 subprog_cnt;
/* number of instructions analyzed by the verifier */
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 343132a146cf..8d88ac52a72d 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -677,6 +677,8 @@ static inline unsigned int damon_max_nr_accesses(const struct damon_attrs *attrs
int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive);
int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
+bool damon_is_running(struct damon_ctx *ctx);
+int damon_kdamond_pid(struct damon_ctx *ctx);
int damon_set_region_biggest_system_ram_default(struct damon_target *t,
unsigned long *start, unsigned long *end);
diff --git a/include/linux/device.h b/include/linux/device.h
index e5f1a773dc54..8fb9bd71fcd0 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -602,6 +602,22 @@ struct device_physical_location {
bool lid;
};
+/**
+ * enum struct_device_flags - Flags in struct device
+ *
+ * Each flag should have a set of accessor functions created via
+ * __create_dev_flag_accessors() for each access.
+ *
+ * @DEV_FLAG_READY_TO_PROBE: If set then device_add() has finished enough
+ * initialization that probe could be called.
+ * @DEV_FLAG_COUNT: Number of defined struct_device_flags.
+ */
+enum struct_device_flags {
+ DEV_FLAG_READY_TO_PROBE = 0,
+
+ DEV_FLAG_COUNT
+};
+
/**
* struct device - The basic device structure
* @parent: The device's "parent" device, the device to which it is attached.
@@ -693,6 +709,7 @@ struct device_physical_location {
* and optionall (if the coherent mask is large enough) also
* for dma allocations. This flag is managed by the dma ops
* instance from ->dma_supported.
+ * @flags: DEV_FLAG_XXX flags. Use atomic bitfield operations to modify.
*
* At the lowest level, every device in a Linux system is represented by an
* instance of struct device. The device structure contains the information
@@ -805,8 +822,36 @@ struct device {
#ifdef CONFIG_DMA_OPS_BYPASS
bool dma_ops_bypass : 1;
#endif
+
+ DECLARE_BITMAP(flags, DEV_FLAG_COUNT);
};
+#define __create_dev_flag_accessors(accessor_name, flag_name) \
+static inline bool dev_##accessor_name(const struct device *dev) \
+{ \
+ return test_bit(flag_name, dev->flags); \
+} \
+static inline void dev_set_##accessor_name(struct device *dev) \
+{ \
+ set_bit(flag_name, dev->flags); \
+} \
+static inline void dev_clear_##accessor_name(struct device *dev) \
+{ \
+ clear_bit(flag_name, dev->flags); \
+} \
+static inline void dev_assign_##accessor_name(struct device *dev, bool value) \
+{ \
+ assign_bit(flag_name, dev->flags, value); \
+} \
+static inline bool dev_test_and_set_##accessor_name(struct device *dev) \
+{ \
+ return test_and_set_bit(flag_name, dev->flags); \
+}
+
+__create_dev_flag_accessors(ready_to_probe, DEV_FLAG_READY_TO_PROBE);
+
+#undef __create_dev_flag_accessors
+
/**
* struct device_link - Device link representation.
* @supplier: The device on the supplier end of the link.
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index b9affa64b7fa..fed8bec024db 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -77,6 +77,7 @@ enum stop_cp_reason {
STOP_CP_REASON_UPDATE_INODE,
STOP_CP_REASON_FLUSH_FAIL,
STOP_CP_REASON_NO_SEGMENT,
+ STOP_CP_REASON_CORRUPTED_NID,
STOP_CP_REASON_MAX,
};
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 322b4d20afa5..8a9d949cc7e2 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -214,11 +214,12 @@ struct fb_deferred_io {
unsigned long delay;
bool sort_pagereflist; /* sort pagelist by offset */
int open_count; /* number of opened files; protected by fb_info lock */
- struct mutex lock; /* mutex that protects the pageref list */
struct list_head pagereflist; /* list of pagerefs for touched pages */
/* callback */
void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
};
+
+struct fb_deferred_io_state;
#endif
/*
@@ -476,6 +477,7 @@ struct fb_info {
unsigned long npagerefs;
struct fb_deferred_io_pageref *pagerefs;
struct fb_deferred_io *fbdefio;
+ struct fb_deferred_io_state *fbdefio_state;
#endif
const struct fb_ops *fbops;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 575415b51349..9bc585a29b78 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -817,6 +817,7 @@ static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group
}
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
+struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark);
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 7efb4493e51c..76680d583852 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/bits.h>
+#include <linux/bitops.h>
#include <linux/err.h>
struct fwnode_operations;
@@ -31,12 +32,12 @@ struct device;
* suppliers. Only enforce ordering with suppliers that have
* drivers.
*/
-#define FWNODE_FLAG_LINKS_ADDED BIT(0)
-#define FWNODE_FLAG_NOT_DEVICE BIT(1)
-#define FWNODE_FLAG_INITIALIZED BIT(2)
-#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD BIT(3)
-#define FWNODE_FLAG_BEST_EFFORT BIT(4)
-#define FWNODE_FLAG_VISITED BIT(5)
+#define FWNODE_FLAG_LINKS_ADDED 0
+#define FWNODE_FLAG_NOT_DEVICE 1
+#define FWNODE_FLAG_INITIALIZED 2
+#define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD 3
+#define FWNODE_FLAG_BEST_EFFORT 4
+#define FWNODE_FLAG_VISITED 5
struct fwnode_handle {
struct fwnode_handle *secondary;
@@ -44,7 +45,7 @@ struct fwnode_handle {
struct device *dev;
struct list_head suppliers;
struct list_head consumers;
- u8 flags;
+ unsigned long flags;
};
/*
@@ -197,16 +198,37 @@ static inline void fwnode_init(struct fwnode_handle *fwnode,
INIT_LIST_HEAD(&fwnode->suppliers);
}
+static inline void fwnode_set_flag(struct fwnode_handle *fwnode,
+ unsigned int bit)
+{
+ set_bit(bit, &fwnode->flags);
+}
+
+static inline void fwnode_clear_flag(struct fwnode_handle *fwnode,
+ unsigned int bit)
+{
+ clear_bit(bit, &fwnode->flags);
+}
+
+static inline void fwnode_assign_flag(struct fwnode_handle *fwnode,
+ unsigned int bit, bool value)
+{
+ assign_bit(bit, &fwnode->flags, value);
+}
+
+static inline bool fwnode_test_flag(struct fwnode_handle *fwnode,
+ unsigned int bit)
+{
+ return test_bit(bit, &fwnode->flags);
+}
+
static inline void fwnode_dev_initialized(struct fwnode_handle *fwnode,
bool initialized)
{
if (IS_ERR_OR_NULL(fwnode))
return;
- if (initialized)
- fwnode->flags |= FWNODE_FLAG_INITIALIZED;
- else
- fwnode->flags &= ~FWNODE_FLAG_INITIALIZED;
+ fwnode_assign_flag(fwnode, FWNODE_FLAG_INITIALIZED, initialized);
}
extern bool fw_devlink_is_strict(void);
diff --git a/include/linux/mmap_lock.h b/include/linux/mmap_lock.h
index 8d38dcb6d044..153e01867790 100644
--- a/include/linux/mmap_lock.h
+++ b/include/linux/mmap_lock.h
@@ -116,7 +116,7 @@ static inline void mmap_write_lock_nested(struct mm_struct *mm, int subclass)
__mmap_lock_trace_acquire_returned(mm, true, true);
}
-static inline int mmap_write_lock_killable(struct mm_struct *mm)
+static inline int __must_check mmap_write_lock_killable(struct mm_struct *mm)
{
int ret;
@@ -147,7 +147,7 @@ static inline void mmap_read_lock(struct mm_struct *mm)
__mmap_lock_trace_acquire_returned(mm, false, true);
}
-static inline int mmap_read_lock_killable(struct mm_struct *mm)
+static inline int __must_check mmap_read_lock_killable(struct mm_struct *mm)
{
int ret;
@@ -157,7 +157,7 @@ static inline int mmap_read_lock_killable(struct mm_struct *mm)
return ret;
}
-static inline bool mmap_read_trylock(struct mm_struct *mm)
+static inline bool __must_check mmap_read_trylock(struct mm_struct *mm)
{
bool ret;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 7c6da19fff9f..d9fbd389dce2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -298,6 +298,7 @@ struct mmc_card {
#define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */
#define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */
#define MMC_QUIRK_NO_UHS_DDR50_TUNING (1<<18) /* Disable DDR50 tuning */
+#define MMC_QUIRK_FIXED_SECURE_ERASE_TRIM_TIME (1<<20) /* Secure erase/trim time is fixed regardless of size */
bool written_flag; /* Indicates eMMC has been written since power on */
bool reenable_cmdq; /* Re-enable Command Queue */
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 495b16b6b4d7..6f07e12a4381 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -90,8 +90,6 @@ struct padata_cpumask {
* @processed: Number of already processed objects.
* @cpu: Next CPU to be processed.
* @cpumask: The cpumasks in use for parallel and serial workers.
- * @reorder_work: work struct for reordering.
- * @lock: Reorder lock.
*/
struct parallel_data {
struct padata_shell *ps;
@@ -102,8 +100,6 @@ struct parallel_data {
unsigned int processed;
int cpu;
struct padata_cpumask cpumask;
- struct work_struct reorder_work;
- spinlock_t ____cacheline_aligned lock;
};
/**
diff --git a/include/linux/printk.h b/include/linux/printk.h
index e4878bb58f66..478203bb2369 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -745,6 +745,19 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type,
}
#endif
+#if defined(DEBUG)
+#define print_hex_dump_devel(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii) \
+ print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
+#else
+static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type,
+ int rowsize, int groupsize,
+ const void *buf, size_t len, bool ascii)
+{
+}
+#endif
+
/**
* print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
* @prefix_str: string to prefix each line with;
diff --git a/include/linux/randomize_kstack.h b/include/linux/randomize_kstack.h
index 6d92b68efbf6..7792ee5e509f 100644
--- a/include/linux/randomize_kstack.h
+++ b/include/linux/randomize_kstack.h
@@ -9,7 +9,6 @@
DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
randomize_kstack_offset);
-DECLARE_PER_CPU(u32, kstack_offset);
/*
* Do not use this anywhere else in the kernel. This is used here because
@@ -44,15 +43,14 @@ DECLARE_PER_CPU(u32, kstack_offset);
* add_random_kstack_offset - Increase stack utilization by previously
* chosen random offset
*
- * This should be used in the syscall entry path when interrupts and
- * preempt are disabled, and after user registers have been stored to
- * the stack. For testing the resulting entropy, please see:
- * tools/testing/selftests/lkdtm/stack-entropy.sh
+ * This should be used in the syscall entry path after user registers have been
+ * stored to the stack. Preemption may be enabled. For testing the resulting
+ * entropy, please see: tools/testing/selftests/lkdtm/stack-entropy.sh
*/
#define add_random_kstack_offset() do { \
if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
&randomize_kstack_offset)) { \
- u32 offset = raw_cpu_read(kstack_offset); \
+ u32 offset = current->kstack_offset; \
u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset)); \
/* Keep allocation even after "ptr" loses scope. */ \
asm volatile("" :: "r"(ptr) : "memory"); \
@@ -63,9 +61,9 @@ DECLARE_PER_CPU(u32, kstack_offset);
* choose_random_kstack_offset - Choose the random offset for the next
* add_random_kstack_offset()
*
- * This should only be used during syscall exit when interrupts and
- * preempt are disabled. This position in the syscall flow is done to
- * frustrate attacks from userspace attempting to learn the next offset:
+ * This should only be used during syscall exit. Preemption may be enabled. This
+ * position in the syscall flow is done to frustrate attacks from userspace
+ * attempting to learn the next offset:
* - Maximize the timing uncertainty visible from userspace: if the
* offset is chosen at syscall entry, userspace has much more control
* over the timing between choosing offsets. "How long will we be in
@@ -79,14 +77,20 @@ DECLARE_PER_CPU(u32, kstack_offset);
#define choose_random_kstack_offset(rand) do { \
if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
&randomize_kstack_offset)) { \
- u32 offset = raw_cpu_read(kstack_offset); \
+ u32 offset = current->kstack_offset; \
offset = ror32(offset, 5) ^ (rand); \
- raw_cpu_write(kstack_offset, offset); \
+ current->kstack_offset = offset; \
} \
} while (0)
+
+static inline void random_kstack_task_init(struct task_struct *tsk)
+{
+ tsk->kstack_offset = 0;
+}
#else /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
#define add_random_kstack_offset() do { } while (0)
#define choose_random_kstack_offset(rand) do { } while (0)
+#define random_kstack_task_init(tsk) do { } while (0)
#endif /* CONFIG_RANDOMIZE_KSTACK_OFFSET */
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 856a560100c2..fad3aad97c7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1501,6 +1501,10 @@ struct task_struct {
unsigned long prev_lowest_stack;
#endif
+#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
+ u32 kstack_offset;
+#endif
+
#ifdef CONFIG_X86_MCE
void __user *mce_vaddr;
__u64 mce_kflags;
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
index 7d68a5cc5881..6e5be15029fb 100644
--- a/include/linux/tpm_eventlog.h
+++ b/include/linux/tpm_eventlog.h
@@ -131,11 +131,16 @@ struct tcg_algorithm_info {
};
#ifndef TPM_MEMREMAP
-#define TPM_MEMREMAP(start, size) NULL
+static inline void *TPM_MEMREMAP(unsigned long start, size_t size)
+{
+ return NULL;
+}
#endif
#ifndef TPM_MEMUNMAP
-#define TPM_MEMUNMAP(start, size) do{} while(0)
+static inline void TPM_MEMUNMAP(void *mapping, size_t size)
+{
+}
#endif
/**
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 6e6e32067148..e49e5ab57813 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -53,7 +53,8 @@ struct ep_device;
* @ssp_isoc_ep_comp: SuperSpeedPlus isoc companion descriptor for this endpoint
* @urb_list: urbs queued to this endpoint; maintained by usbcore
* @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
- * with one or more transfer descriptors (TDs) per urb
+ * with one or more transfer descriptors (TDs) per urb; must be preserved
+ * by core while BW is allocated for the endpoint
* @ep_dev: ep_device for sysfs info
* @extra: descriptors following this endpoint in the configuration
* @extralen: how many bytes of "extra" are valid
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 7892b79854f6..d716771a7262 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -437,6 +437,7 @@ struct mana_port_context {
netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int mana_config_rss(struct mana_port_context *ac, enum TRI_STATE rx,
bool update_hash, bool update_tab);
+int mana_disable_vport_rx(struct mana_port_context *apc);
int mana_alloc_queues(struct net_device *ndev);
int mana_attach(struct net_device *ndev);
diff --git a/include/net/mctp.h b/include/net/mctp.h
index 1eb1b4393e46..6dbed4ca2220 100644
--- a/include/net/mctp.h
+++ b/include/net/mctp.h
@@ -26,6 +26,9 @@ struct mctp_hdr {
#define MCTP_VER_MIN 1
#define MCTP_VER_MAX 1
+/* Definitions for ver field */
+#define MCTP_HDR_VER_MASK GENMASK(3, 0)
+
/* Definitions for flags_seq_tag field */
#define MCTP_HDR_FLAG_SOM BIT(7)
#define MCTP_HDR_FLAG_EOM BIT(6)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 6965099dda89..f0560087637e 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -36,6 +36,7 @@
EM(rxkad_abort_1_short_encdata, "rxkad1-short-encdata") \
EM(rxkad_abort_1_short_header, "rxkad1-short-hdr") \
EM(rxkad_abort_2_short_check, "rxkad2-short-check") \
+ EM(rxkad_abort_2_crypto_unaligned, "rxkad2-crypto-unaligned") \
EM(rxkad_abort_2_short_data, "rxkad2-short-data") \
EM(rxkad_abort_2_short_header, "rxkad2-short-hdr") \
EM(rxkad_abort_2_short_len, "rxkad2-short-len") \
@@ -125,8 +126,6 @@
E_(rxrpc_call_poke_timer_now, "Timer-now")
#define rxrpc_skb_traces \
- EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \
- EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \
EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \
EM(rxrpc_skb_get_conn_work, "GET conn-work") \
EM(rxrpc_skb_get_last_nack, "GET last-nack") \
@@ -145,12 +144,14 @@
EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \
EM(rxrpc_skb_put_last_nack, "PUT last-nack") \
EM(rxrpc_skb_put_purge, "PUT purge ") \
+ EM(rxrpc_skb_put_response_copy, "PUT resp-cpy ") \
EM(rxrpc_skb_put_rotate, "PUT rotate ") \
EM(rxrpc_skb_put_unknown, "PUT unknown ") \
EM(rxrpc_skb_see_conn_work, "SEE conn-work") \
EM(rxrpc_skb_see_recvmsg, "SEE recvmsg ") \
EM(rxrpc_skb_see_reject, "SEE reject ") \
EM(rxrpc_skb_see_rotate, "SEE rotate ") \
+ EM(rxrpc_skb_see_unshare_nomem, "SEE unshar-nm") \
E_(rxrpc_skb_see_version, "SEE version ")
#define rxrpc_local_traces \
@@ -231,7 +232,6 @@
EM(rxrpc_conn_put_unidle, "PUT unidle ") \
EM(rxrpc_conn_put_work, "PUT work ") \
EM(rxrpc_conn_queue_challenge, "QUE chall ") \
- EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \
EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \
EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \
EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \
diff --git a/include/video/udlfb.h b/include/video/udlfb.h
index 58fb5732831a..ab34790d57ec 100644
--- a/include/video/udlfb.h
+++ b/include/video/udlfb.h
@@ -56,6 +56,7 @@ struct dlfb_data {
spinlock_t damage_lock;
struct work_struct damage_work;
struct fb_ops ops;
+ atomic_t mmap_count;
/* blit-only rendering path metrics, exposed through sysfs */
atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
atomic_t bytes_identical; /* saved effort with backbuffer comparison */
diff --git a/init/main.c b/init/main.c
index 20d2dd4d9b40..eac47a2beb7e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -816,7 +816,6 @@ static inline void initcall_debug_enable(void)
#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
randomize_kstack_offset);
-DEFINE_PER_CPU(u32, kstack_offset);
static int __init early_randomize_kstack_offset(char *buf)
{
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 64835d692c37..66a0a9b9950b 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -91,7 +91,7 @@ static bool io_poll_get_ownership_slowpath(struct io_kiocb *req)
*/
static inline bool io_poll_get_ownership(struct io_kiocb *req)
{
- if (unlikely(atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
+ if (unlikely((unsigned int)atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
return io_poll_get_ownership_slowpath(req);
return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
}
@@ -321,7 +321,13 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
return IOU_POLL_REMOVE_POLL_USE_RES;
}
} else {
- int ret = io_poll_issue(req, ts);
+ int ret;
+
+ /* multiple refs and HUP, ensure we loop once more */
+ if ((req->cqe.res & (POLLHUP | POLLRDHUP)) &&
+ (v & IO_POLL_REF_MASK) != 1)
+ v--;
+ ret = io_poll_issue(req, ts);
if (ret == IOU_STOP_MULTISHOT)
return IOU_POLL_REMOVE_POLL_USE_RES;
else if (ret == IOU_REQUEUE)
@@ -441,8 +447,10 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
* disable multishot as there is a circular dependency between
* CQ posting and triggering the event.
*/
- if (mask & EPOLL_URING_WAKE)
+ if (mask & EPOLL_URING_WAKE) {
poll->events |= EPOLLONESHOT;
+ req->apoll_events |= EPOLLONESHOT;
+ }
/* optional, saves extra locking for removal in tw handler */
if (mask && poll->events & EPOLLONESHOT) {
diff --git a/io_uring/timeout.c b/io_uring/timeout.c
index be2a0f6c209b..edf4b2455c48 100644
--- a/io_uring/timeout.c
+++ b/io_uring/timeout.c
@@ -428,6 +428,8 @@ int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
return -EINVAL;
+ if (sqe->addr3 || sqe->__pad2[0])
+ return -EINVAL;
if (sqe->buf_index || sqe->len || sqe->splice_fd_in)
return -EINVAL;
@@ -500,6 +502,8 @@ static int __io_timeout_prep(struct io_kiocb *req,
unsigned flags;
u32 off = READ_ONCE(sqe->off);
+ if (sqe->addr3 || sqe->__pad2[0])
+ return -EINVAL;
if (sqe->buf_index || sqe->len != 1 || sqe->splice_fd_in)
return -EINVAL;
if (off && is_timeout_link)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 45eb795c8c04..b7fd3995538b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1347,6 +1347,24 @@ static bool is_spilled_scalar_reg(const struct bpf_stack_state *stack)
stack->spilled_ptr.type == SCALAR_VALUE;
}
+/* Mark stack slot as STACK_MISC, unless it is already STACK_INVALID, in which
+ * case they are equivalent, or it's STACK_ZERO, in which case we preserve
+ * more precise STACK_ZERO.
+ * Regardless of allow_ptr_leaks setting (i.e., privileged or unprivileged
+ * mode), we won't promote STACK_INVALID to STACK_MISC. In privileged case it is
+ * unnecessary as both are considered equivalent when loading data and pruning,
+ * in case of unprivileged mode it will be incorrect to allow reads of invalid
+ * slots.
+ */
+static void mark_stack_slot_misc(struct bpf_verifier_env *env, u8 *stype)
+{
+ if (*stype == STACK_ZERO)
+ return;
+ if (*stype == STACK_INVALID)
+ return;
+ *stype = STACK_MISC;
+}
+
static void scrub_spilled_slot(u8 *stype)
{
if (*stype != STACK_INVALID)
@@ -1763,8 +1781,8 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
int i, err;
dst_state->jmp_history = copy_array(dst_state->jmp_history, src->jmp_history,
- src->jmp_history_cnt, sizeof(struct bpf_idx_pair),
- GFP_USER);
+ src->jmp_history_cnt, sizeof(*dst_state->jmp_history),
+ GFP_USER);
if (!dst_state->jmp_history)
return -ENOMEM;
dst_state->jmp_history_cnt = src->jmp_history_cnt;
@@ -3418,6 +3436,21 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno,
return __check_reg_arg(env, state->regs, regno, t);
}
+static int insn_stack_access_flags(int frameno, int spi)
+{
+ return INSN_F_STACK_ACCESS | (spi << INSN_F_SPI_SHIFT) | frameno;
+}
+
+static int insn_stack_access_spi(int insn_flags)
+{
+ return (insn_flags >> INSN_F_SPI_SHIFT) & INSN_F_SPI_MASK;
+}
+
+static int insn_stack_access_frameno(int insn_flags)
+{
+ return insn_flags & INSN_F_FRAMENO_MASK;
+}
+
static void mark_jmp_point(struct bpf_verifier_env *env, int idx)
{
env->insn_aux_data[idx].jmp_point = true;
@@ -3429,28 +3462,51 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx)
}
/* for any branch, call, exit record the history of jmps in the given state */
-static int push_jmp_history(struct bpf_verifier_env *env,
- struct bpf_verifier_state *cur)
+static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_state *cur,
+ int insn_flags)
{
u32 cnt = cur->jmp_history_cnt;
- struct bpf_idx_pair *p;
+ struct bpf_jmp_history_entry *p;
size_t alloc_size;
- if (!is_jmp_point(env, env->insn_idx))
+ /* combine instruction flags if we already recorded this instruction */
+ if (env->cur_hist_ent) {
+ /* atomic instructions push insn_flags twice, for READ and
+ * WRITE sides, but they should agree on stack slot
+ */
+ WARN_ONCE((env->cur_hist_ent->flags & insn_flags) &&
+ (env->cur_hist_ent->flags & insn_flags) != insn_flags,
+ "verifier insn history bug: insn_idx %d cur flags %x new flags %x\n",
+ env->insn_idx, env->cur_hist_ent->flags, insn_flags);
+ env->cur_hist_ent->flags |= insn_flags;
return 0;
+ }
cnt++;
alloc_size = kmalloc_size_roundup(size_mul(cnt, sizeof(*p)));
p = krealloc(cur->jmp_history, alloc_size, GFP_USER);
if (!p)
return -ENOMEM;
- p[cnt - 1].idx = env->insn_idx;
- p[cnt - 1].prev_idx = env->prev_insn_idx;
cur->jmp_history = p;
+
+ p = &cur->jmp_history[cnt - 1];
+ p->idx = env->insn_idx;
+ p->prev_idx = env->prev_insn_idx;
+ p->flags = insn_flags;
cur->jmp_history_cnt = cnt;
+ env->cur_hist_ent = p;
+
return 0;
}
+static struct bpf_jmp_history_entry *get_jmp_hist_entry(struct bpf_verifier_state *st,
+ u32 hist_end, int insn_idx)
+{
+ if (hist_end > 0 && st->jmp_history[hist_end - 1].idx == insn_idx)
+ return &st->jmp_history[hist_end - 1];
+ return NULL;
+}
+
/* Backtrack one insn at a time. If idx is not at the top of recorded
* history then previous instruction came from straight line execution.
* Return -ENOENT if we exhausted all instructions within given state.
@@ -3612,9 +3668,14 @@ static inline bool bt_is_reg_set(struct backtrack_state *bt, u32 reg)
return bt->reg_masks[bt->frame] & (1 << reg);
}
+static inline bool bt_is_frame_slot_set(struct backtrack_state *bt, u32 frame, u32 slot)
+{
+ return bt->stack_masks[frame] & (1ull << slot);
+}
+
static inline bool bt_is_slot_set(struct backtrack_state *bt, u32 slot)
{
- return bt->stack_masks[bt->frame] & (1ull << slot);
+ return bt_is_frame_slot_set(bt, bt->frame, slot);
}
/* format registers bitmask, e.g., "r0,r2,r4" for 0x15 mask */
@@ -3668,7 +3729,7 @@ static bool calls_callback(struct bpf_verifier_env *env, int insn_idx);
* - *was* processed previously during backtracking.
*/
static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
- struct backtrack_state *bt)
+ struct bpf_jmp_history_entry *hist, struct backtrack_state *bt)
{
const struct bpf_insn_cbs cbs = {
.cb_call = disasm_kfunc_name,
@@ -3681,7 +3742,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
u8 mode = BPF_MODE(insn->code);
u32 dreg = insn->dst_reg;
u32 sreg = insn->src_reg;
- u32 spi, i;
+ u32 spi, i, fr;
if (insn->code == 0)
return 0;
@@ -3744,20 +3805,15 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
* by 'precise' mark in corresponding register of this state.
* No further tracking necessary.
*/
- if (insn->src_reg != BPF_REG_FP)
+ if (!hist || !(hist->flags & INSN_F_STACK_ACCESS))
return 0;
-
/* dreg = *(u64 *)[fp - off] was a fill from the stack.
* that [fp - off] slot contains scalar that needs to be
* tracked with precision
*/
- spi = (-insn->off - 1) / BPF_REG_SIZE;
- if (spi >= 64) {
- verbose(env, "BUG spi %d\n", spi);
- WARN_ONCE(1, "verifier backtracking bug");
- return -EFAULT;
- }
- bt_set_slot(bt, spi);
+ spi = insn_stack_access_spi(hist->flags);
+ fr = insn_stack_access_frameno(hist->flags);
+ bt_set_frame_slot(bt, fr, spi);
} else if (class == BPF_STX || class == BPF_ST) {
if (bt_is_reg_set(bt, dreg))
/* stx & st shouldn't be using _scalar_ dst_reg
@@ -3766,17 +3822,13 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
*/
return -ENOTSUPP;
/* scalars can only be spilled into stack */
- if (insn->dst_reg != BPF_REG_FP)
+ if (!hist || !(hist->flags & INSN_F_STACK_ACCESS))
return 0;
- spi = (-insn->off - 1) / BPF_REG_SIZE;
- if (spi >= 64) {
- verbose(env, "BUG spi %d\n", spi);
- WARN_ONCE(1, "verifier backtracking bug");
- return -EFAULT;
- }
- if (!bt_is_slot_set(bt, spi))
+ spi = insn_stack_access_spi(hist->flags);
+ fr = insn_stack_access_frameno(hist->flags);
+ if (!bt_is_frame_slot_set(bt, fr, spi))
return 0;
- bt_clear_slot(bt, spi);
+ bt_clear_frame_slot(bt, fr, spi);
if (class == BPF_STX)
bt_set_reg(bt, sreg);
} else if (class == BPF_JMP || class == BPF_JMP32) {
@@ -3820,10 +3872,14 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
WARN_ONCE(1, "verifier backtracking bug");
return -EFAULT;
}
- /* we don't track register spills perfectly,
- * so fallback to force-precise instead of failing */
- if (bt_stack_mask(bt) != 0)
- return -ENOTSUPP;
+ /* we are now tracking register spills correctly,
+ * so any instance of leftover slots is a bug
+ */
+ if (bt_stack_mask(bt) != 0) {
+ verbose(env, "BUG stack slots %llx\n", bt_stack_mask(bt));
+ WARN_ONCE(1, "verifier backtracking bug (subprog leftover stack slots)");
+ return -EFAULT;
+ }
/* propagate r1-r5 to the caller */
for (i = BPF_REG_1; i <= BPF_REG_5; i++) {
if (bt_is_reg_set(bt, i)) {
@@ -3848,8 +3904,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
WARN_ONCE(1, "verifier backtracking bug");
return -EFAULT;
}
- if (bt_stack_mask(bt) != 0)
- return -ENOTSUPP;
+ if (bt_stack_mask(bt) != 0) {
+ verbose(env, "BUG stack slots %llx\n", bt_stack_mask(bt));
+ WARN_ONCE(1, "verifier backtracking bug (callback leftover stack slots)");
+ return -EFAULT;
+ }
/* clear r1-r5 in callback subprog's mask */
for (i = BPF_REG_1; i <= BPF_REG_5; i++)
bt_clear_reg(bt, i);
@@ -4286,6 +4345,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
for (;;) {
DECLARE_BITMAP(mask, 64);
u32 history = st->jmp_history_cnt;
+ struct bpf_jmp_history_entry *hist;
if (env->log.level & BPF_LOG_LEVEL2) {
verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d subseq_idx %d \n",
@@ -4349,7 +4409,8 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
err = 0;
skip_first = false;
} else {
- err = backtrack_insn(env, i, subseq_idx, bt);
+ hist = get_jmp_hist_entry(st, history, i);
+ err = backtrack_insn(env, i, subseq_idx, hist, bt);
}
if (err == -ENOTSUPP) {
mark_all_scalars_precise(env, env->cur_state);
@@ -4402,22 +4463,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr));
for_each_set_bit(i, mask, 64) {
if (i >= func->allocated_stack / BPF_REG_SIZE) {
- /* the sequence of instructions:
- * 2: (bf) r3 = r10
- * 3: (7b) *(u64 *)(r3 -8) = r0
- * 4: (79) r4 = *(u64 *)(r10 -8)
- * doesn't contain jmps. It's backtracked
- * as a single block.
- * During backtracking insn 3 is not recognized as
- * stack access, so at the end of backtracking
- * stack slot fp-8 is still marked in stack_mask.
- * However the parent state may not have accessed
- * fp-8 and it's "unallocated" stack space.
- * In such case fallback to conservative.
- */
- mark_all_scalars_precise(env, env->cur_state);
- bt_reset(bt);
- return 0;
+ verbose(env, "BUG backtracking (stack slot %d, total slots %d)\n",
+ i, func->allocated_stack / BPF_REG_SIZE);
+ WARN_ONCE(1, "verifier backtracking bug (stack slot out of bounds)");
+ return -EFAULT;
}
if (!is_spilled_scalar_reg(&func->stack[i])) {
@@ -4546,7 +4595,8 @@ static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_
dst->live = live;
}
-static void save_register_state(struct bpf_func_state *state,
+static void save_register_state(struct bpf_verifier_env *env,
+ struct bpf_func_state *state,
int spi, struct bpf_reg_state *reg,
int size)
{
@@ -4561,7 +4611,7 @@ static void save_register_state(struct bpf_func_state *state,
/* size < 8 bytes spill */
for (; i; i--)
- scrub_spilled_slot(&state->stack[spi].slot_type[i - 1]);
+ mark_stack_slot_misc(env, &state->stack[spi].slot_type[i - 1]);
}
static bool is_bpf_st_mem(struct bpf_insn *insn)
@@ -4582,7 +4632,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err;
struct bpf_insn *insn = &env->prog->insnsi[insn_idx];
struct bpf_reg_state *reg = NULL;
- u32 dst_reg = insn->dst_reg;
+ int insn_flags = insn_stack_access_flags(state->frameno, spi);
/* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0,
* so it's aligned access and [off, off + size) are within stack limits
@@ -4619,20 +4669,8 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
return err;
mark_stack_slot_scratched(env, spi);
- if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) &&
- !register_is_null(reg) && env->bpf_capable) {
- if (dst_reg != BPF_REG_FP) {
- /* The backtracking logic can only recognize explicit
- * stack slot address like [fp - 8]. Other spill of
- * scalar via different register has to be conservative.
- * Backtrack from here and mark all registers as precise
- * that contributed into 'reg' being a constant.
- */
- err = mark_chain_precision(env, value_regno);
- if (err)
- return err;
- }
- save_register_state(state, spi, reg, size);
+ if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && env->bpf_capable) {
+ save_register_state(env, state, spi, reg, size);
/* Break the relation on a narrowing spill. */
if (fls64(reg->umax_value) > BITS_PER_BYTE * size)
state->stack[spi].spilled_ptr.id = 0;
@@ -4642,7 +4680,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
__mark_reg_known(&fake_reg, insn->imm);
fake_reg.type = SCALAR_VALUE;
- save_register_state(state, spi, &fake_reg, size);
+ save_register_state(env, state, spi, &fake_reg, size);
} else if (reg && is_spillable_regtype(reg->type)) {
/* register containing pointer is being spilled into stack */
if (size != BPF_REG_SIZE) {
@@ -4654,7 +4692,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
verbose(env, "cannot spill pointers to stack into stack frame of the caller\n");
return -EINVAL;
}
- save_register_state(state, spi, reg, size);
+ save_register_state(env, state, spi, reg, size);
} else {
u8 type = STACK_MISC;
@@ -4679,7 +4717,12 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
/* when we zero initialize stack slots mark them as such */
if ((reg && register_is_null(reg)) ||
(!reg && is_bpf_st_mem(insn) && insn->imm == 0)) {
- /* backtracking doesn't work for STACK_ZERO yet. */
+ /* STACK_ZERO case happened because register spill
+ * wasn't properly aligned at the stack slot boundary,
+ * so it's not a register spill anymore; force
+ * originating register to be precise to make
+ * STACK_ZERO correct for subsequent states
+ */
err = mark_chain_precision(env, value_regno);
if (err)
return err;
@@ -4688,9 +4731,12 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
/* Mark slots affected by this stack write. */
for (i = 0; i < size; i++)
- state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] =
- type;
+ state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] = type;
+ insn_flags = 0; /* not a register spill */
}
+
+ if (insn_flags)
+ return push_jmp_history(env, env->cur_state, insn_flags);
return 0;
}
@@ -4879,6 +4925,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
int i, slot = -off - 1, spi = slot / BPF_REG_SIZE;
struct bpf_reg_state *reg;
u8 *stype, type;
+ int insn_flags = insn_stack_access_flags(reg_state->frameno, spi);
stype = reg_state->stack[spi].slot_type;
reg = ®_state->stack[spi].spilled_ptr;
@@ -4911,25 +4958,42 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
copy_register_state(&state->regs[dst_regno], reg);
state->regs[dst_regno].subreg_def = subreg_def;
} else {
+ int spill_cnt = 0, zero_cnt = 0;
+
for (i = 0; i < size; i++) {
type = stype[(slot - i) % BPF_REG_SIZE];
- if (type == STACK_SPILL)
+ if (type == STACK_SPILL) {
+ spill_cnt++;
continue;
+ }
if (type == STACK_MISC)
continue;
+ if (type == STACK_ZERO) {
+ zero_cnt++;
+ continue;
+ }
if (type == STACK_INVALID && env->allow_uninit_stack)
continue;
verbose(env, "invalid read from stack off %d+%d size %d\n",
off, i, size);
return -EACCES;
}
- mark_reg_unknown(env, state->regs, dst_regno);
+
+ if (spill_cnt == size &&
+ tnum_is_const(reg->var_off) && reg->var_off.value == 0) {
+ __mark_reg_const_zero(&state->regs[dst_regno]);
+ /* this IS register fill, so keep insn_flags */
+ } else if (zero_cnt == size) {
+ /* similarly to mark_reg_stack_read(), preserve zeroes */
+ __mark_reg_const_zero(&state->regs[dst_regno]);
+ insn_flags = 0; /* not restoring original register state */
+ } else {
+ mark_reg_unknown(env, state->regs, dst_regno);
+ insn_flags = 0; /* not restoring original register state */
+ }
}
state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
- return 0;
- }
-
- if (dst_regno >= 0) {
+ } else if (dst_regno >= 0) {
/* restore register state from stack */
copy_register_state(&state->regs[dst_regno], reg);
/* mark reg as written since spilled pointer state likely
@@ -4965,7 +5029,10 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
if (dst_regno >= 0)
mark_reg_stack_read(env, reg_state, off, off + size, dst_regno);
+ insn_flags = 0; /* we are not restoring spilled register */
}
+ if (insn_flags)
+ return push_jmp_history(env, env->cur_state, insn_flags);
return 0;
}
@@ -7050,7 +7117,6 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
BPF_SIZE(insn->code), BPF_WRITE, -1, true, false);
if (err)
return err;
-
return 0;
}
@@ -16845,7 +16911,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
* the precision needs to be propagated back in
* the current state.
*/
- err = err ? : push_jmp_history(env, cur);
+ if (is_jmp_point(env, env->insn_idx))
+ err = err ? : push_jmp_history(env, cur, 0);
err = err ? : propagate_precision(env, &sl->state);
if (err)
return err;
@@ -17069,6 +17136,9 @@ static int do_check(struct bpf_verifier_env *env)
u8 class;
int err;
+ /* reset current history entry on each new instruction */
+ env->cur_hist_ent = NULL;
+
env->prev_insn_idx = prev_insn_idx;
if (env->insn_idx >= insn_cnt) {
verbose(env, "invalid insn idx %d insn_cnt %d\n",
@@ -17108,7 +17178,7 @@ static int do_check(struct bpf_verifier_env *env)
}
if (is_jmp_point(env, env->insn_idx)) {
- err = push_jmp_history(env, state);
+ err = push_jmp_history(env, state, 0);
if (err)
return err;
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 686bbe72bb41..5ebe01e8f37e 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -430,7 +430,7 @@ static void coredump_task_exit(struct task_struct *tsk)
complete(&core_state->startup);
for (;;) {
- set_current_state(TASK_UNINTERRUPTIBLE|TASK_FREEZABLE);
+ set_current_state(TASK_IDLE|TASK_FREEZABLE);
if (!self.task) /* see coredump_finish() */
break;
schedule();
@@ -981,6 +981,7 @@ void __noreturn make_task_dead(int signr)
futex_exit_recursive(tsk);
tsk->exit_state = EXIT_DEAD;
refcount_inc(&tsk->rcu_users);
+ preempt_disable();
do_task_dead();
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 5b60692b1a4e..c65a70581af7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -93,6 +93,7 @@
#include <linux/thread_info.h>
#include <linux/stackleak.h>
#include <linux/kasan.h>
+#include <linux/randomize_kstack.h>
#include <linux/scs.h>
#include <linux/io_uring.h>
#include <linux/bpf.h>
@@ -2517,6 +2518,7 @@ __latent_entropy struct task_struct *copy_process(
if (retval)
goto bad_fork_cleanup_io;
+ random_kstack_task_init(p);
stackleak_task_init(p);
if (pid != &init_struct_pid) {
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index bf3a28ee7d8f..def1f8fbc85c 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -1511,20 +1511,23 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
*
* Must be called with lock->wait_lock held and interrupts disabled. It must
* have just failed to try_to_take_rt_mutex().
+ *
+ * When invoked from rt_mutex_start_proxy_lock() waiter::task != current !
*/
static void __sched remove_waiter(struct rt_mutex_base *lock,
struct rt_mutex_waiter *waiter)
{
bool is_top_waiter = (waiter == rt_mutex_top_waiter(lock));
struct task_struct *owner = rt_mutex_owner(lock);
+ struct task_struct *waiter_task = waiter->task;
struct rt_mutex_base *next_lock;
lockdep_assert_held(&lock->wait_lock);
- raw_spin_lock(¤t->pi_lock);
- rt_mutex_dequeue(lock, waiter);
- current->pi_blocked_on = NULL;
- raw_spin_unlock(¤t->pi_lock);
+ scoped_guard(raw_spinlock, &waiter_task->pi_lock) {
+ rt_mutex_dequeue(lock, waiter);
+ waiter_task->pi_blocked_on = NULL;
+ }
/*
* Only update priority if the waiter was the highest priority
@@ -1560,7 +1563,7 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
raw_spin_unlock_irq(&lock->wait_lock);
rt_mutex_adjust_prio_chain(owner, RT_MUTEX_MIN_CHAINWALK, lock,
- next_lock, NULL, current);
+ next_lock, NULL, waiter_task);
raw_spin_lock_irq(&lock->wait_lock);
}
diff --git a/kernel/padata.c b/kernel/padata.c
index 9260ab0b39eb..44ea75bfd868 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -261,20 +261,17 @@ EXPORT_SYMBOL(padata_do_parallel);
* be parallel processed by another cpu and is not yet present in
* the cpu's reorder queue.
*/
-static struct padata_priv *padata_find_next(struct parallel_data *pd,
- bool remove_object)
+static struct padata_priv *padata_find_next(struct parallel_data *pd, int cpu,
+ unsigned int processed)
{
struct padata_priv *padata;
struct padata_list *reorder;
- int cpu = pd->cpu;
reorder = per_cpu_ptr(pd->reorder_list, cpu);
spin_lock(&reorder->lock);
- if (list_empty(&reorder->list)) {
- spin_unlock(&reorder->lock);
- return NULL;
- }
+ if (list_empty(&reorder->list))
+ goto notfound;
padata = list_entry(reorder->list.next, struct padata_priv, list);
@@ -282,101 +279,52 @@ static struct padata_priv *padata_find_next(struct parallel_data *pd,
* Checks the rare case where two or more parallel jobs have hashed to
* the same CPU and one of the later ones finishes first.
*/
- if (padata->seq_nr != pd->processed) {
- spin_unlock(&reorder->lock);
- return NULL;
- }
-
- if (remove_object) {
- list_del_init(&padata->list);
- ++pd->processed;
- /* When sequence wraps around, reset to the first CPU. */
- if (unlikely(pd->processed == 0))
- pd->cpu = cpumask_first(pd->cpumask.pcpu);
- else
- pd->cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1, false);
- }
+ if (padata->seq_nr != processed)
+ goto notfound;
+ list_del_init(&padata->list);
spin_unlock(&reorder->lock);
return padata;
+
+notfound:
+ pd->processed = processed;
+ pd->cpu = cpu;
+ spin_unlock(&reorder->lock);
+ return NULL;
}
-static void padata_reorder(struct parallel_data *pd)
+static void padata_reorder(struct padata_priv *padata)
{
+ struct parallel_data *pd = padata->pd;
struct padata_instance *pinst = pd->ps->pinst;
- int cb_cpu;
- struct padata_priv *padata;
- struct padata_serial_queue *squeue;
- struct padata_list *reorder;
+ unsigned int processed;
+ int cpu;
- /*
- * We need to ensure that only one cpu can work on dequeueing of
- * the reorder queue the time. Calculating in which percpu reorder
- * queue the next object will arrive takes some time. A spinlock
- * would be highly contended. Also it is not clear in which order
- * the objects arrive to the reorder queues. So a cpu could wait to
- * get the lock just to notice that there is nothing to do at the
- * moment. Therefore we use a trylock and let the holder of the lock
- * care for all the objects enqueued during the holdtime of the lock.
- */
- if (!spin_trylock_bh(&pd->lock))
- return;
+ processed = pd->processed;
+ cpu = pd->cpu;
- while (1) {
- padata = padata_find_next(pd, true);
+ do {
+ struct padata_serial_queue *squeue;
+ int cb_cpu;
- /*
- * If the next object that needs serialization is parallel
- * processed by another cpu and is still on it's way to the
- * cpu's reorder queue, nothing to do for now.
- */
- if (!padata)
- break;
+ cpu = cpumask_next_wrap(cpu, pd->cpumask.pcpu, -1, false);
+ processed++;
cb_cpu = padata->cb_cpu;
squeue = per_cpu_ptr(pd->squeue, cb_cpu);
spin_lock(&squeue->serial.lock);
list_add_tail(&padata->list, &squeue->serial.list);
- spin_unlock(&squeue->serial.lock);
-
queue_work_on(cb_cpu, pinst->serial_wq, &squeue->work);
- }
- spin_unlock_bh(&pd->lock);
-
- /*
- * The next object that needs serialization might have arrived to
- * the reorder queues in the meantime.
- *
- * Ensure reorder queue is read after pd->lock is dropped so we see
- * new objects from another task in padata_do_serial. Pairs with
- * smp_mb in padata_do_serial.
- */
- smp_mb();
-
- reorder = per_cpu_ptr(pd->reorder_list, pd->cpu);
- if (!list_empty(&reorder->list) && padata_find_next(pd, false)) {
/*
- * Other context(eg. the padata_serial_worker) can finish the request.
- * To avoid UAF issue, add pd ref here, and put pd ref after reorder_work finish.
+ * If the next object that needs serialization is parallel
+ * processed by another cpu and is still on it's way to the
+ * cpu's reorder queue, end the loop.
*/
- padata_get_pd(pd);
- if (!queue_work(pinst->serial_wq, &pd->reorder_work))
- padata_put_pd(pd);
- }
-}
-
-static void invoke_padata_reorder(struct work_struct *work)
-{
- struct parallel_data *pd;
-
- local_bh_disable();
- pd = container_of(work, struct parallel_data, reorder_work);
- padata_reorder(pd);
- local_bh_enable();
- /* Pairs with putting the reorder_work in the serial_wq */
- padata_put_pd(pd);
+ padata = padata_find_next(pd, cpu, processed);
+ spin_unlock(&squeue->serial.lock);
+ } while (padata);
}
static void padata_serial_worker(struct work_struct *serial_work)
@@ -427,6 +375,7 @@ void padata_do_serial(struct padata_priv *padata)
struct padata_list *reorder = per_cpu_ptr(pd->reorder_list, hashed_cpu);
struct padata_priv *cur;
struct list_head *pos;
+ bool gotit = true;
spin_lock(&reorder->lock);
/* Sort in ascending order of sequence number. */
@@ -436,17 +385,14 @@ void padata_do_serial(struct padata_priv *padata)
if ((signed int)(cur->seq_nr - padata->seq_nr) < 0)
break;
}
- list_add(&padata->list, pos);
+ if (padata->seq_nr != pd->processed) {
+ gotit = false;
+ list_add(&padata->list, pos);
+ }
spin_unlock(&reorder->lock);
- /*
- * Ensure the addition to the reorder list is ordered correctly
- * with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
- * in padata_reorder.
- */
- smp_mb();
-
- padata_reorder(pd);
+ if (gotit)
+ padata_reorder(padata);
}
EXPORT_SYMBOL(padata_do_serial);
@@ -633,9 +579,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps)
padata_init_squeues(pd);
pd->seq_nr = -1;
refcount_set(&pd->refcnt, 1);
- spin_lock_init(&pd->lock);
pd->cpu = cpumask_first(pd->cpumask.pcpu);
- INIT_WORK(&pd->reorder_work, invoke_padata_reorder);
return pd;
@@ -1145,12 +1089,6 @@ void padata_free_shell(struct padata_shell *ps)
if (!ps)
return;
- /*
- * Wait for all _do_serial calls to finish to avoid touching
- * freed pd's and ps's.
- */
- synchronize_rcu();
-
mutex_lock(&ps->pinst->lock);
list_del(&ps->list);
pd = rcu_dereference_protected(ps->pd, 1);
diff --git a/kernel/regset.c b/kernel/regset.c
index 586823786f39..b2871fa68b2a 100644
--- a/kernel/regset.c
+++ b/kernel/regset.c
@@ -16,14 +16,14 @@ static int __regset_get(struct task_struct *target,
if (size > regset->n * regset->size)
size = regset->n * regset->size;
if (!p) {
- to_free = p = kzalloc(size, GFP_KERNEL);
+ to_free = p = kvzalloc(size, GFP_KERNEL);
if (!p)
return -ENOMEM;
}
res = regset->regset_get(target, regset,
(struct membuf){.p = p, .left = size});
if (res < 0) {
- kfree(to_free);
+ kvfree(to_free);
return res;
}
*data = p;
@@ -71,6 +71,6 @@ int copy_regset_to_user(struct task_struct *target,
ret = regset_get_alloc(target, regset, size, &buf);
if (ret > 0)
ret = copy_to_user(data, buf, ret) ? -EFAULT : 0;
- kfree(buf);
+ kvfree(buf);
return ret;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index c4a9797e9eff..d558e43aedcf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4823,7 +4823,7 @@ void sched_post_fork(struct task_struct *p)
uclamp_post_fork(p);
}
-unsigned long to_ratio(u64 period, u64 runtime)
+u64 to_ratio(u64 period, u64 runtime)
{
if (runtime == RUNTIME_INF)
return BW_UNIT;
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 0b420a65b31d..46d2250b7235 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2776,7 +2776,7 @@ static int tg_rt_schedulable(struct task_group *tg, void *data)
{
struct rt_schedulable_data *d = data;
struct task_group *child;
- unsigned long total, sum = 0;
+ u64 total, sum = 0;
u64 period, runtime;
period = ktime_to_ns(tg->rt_bandwidth.rt_period);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index e1913e253221..65ff0254659a 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2463,7 +2463,7 @@ extern void init_dl_entity(struct sched_dl_entity *dl_se);
#define RATIO_SHIFT 8
#define MAX_BW_BITS (64 - BW_SHIFT)
#define MAX_BW ((1ULL << MAX_BW_BITS) - 1)
-unsigned long to_ratio(u64 period, u64 runtime);
+u64 to_ratio(u64 period, u64 runtime);
extern void init_entity_runnable_average(struct sched_entity *se);
extern void post_init_entity_util_avg(struct task_struct *p);
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 8ce3fa0c19e2..a16392b1bdc1 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -656,6 +656,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
goto err;
memcpy(stats, tsk->signal->stats, sizeof(*stats));
+ stats->version = TASKSTATS_VERSION;
send:
send_cpu_listeners(rep_skb, listeners);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index d46a1033ba5b..dee9494ed189 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -1366,6 +1366,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
parg->offset = *size;
*size += parg->type->size * (parg->count ?: 1);
+ if (*size > MAX_PROBE_EVENT_SIZE) {
+ ret = -E2BIG;
+ trace_probe_log_err(ctx->offset, EVENT_TOO_BIG);
+ goto fail;
+ }
+
if (parg->count) {
len = strlen(parg->type->fmttype) + 6;
parg->fmt = kmalloc(len, GFP_KERNEL);
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index c71fa9c2f381..ce5a0935cd45 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -35,6 +35,7 @@
#define MAX_ARG_NAME_LEN 32
#define MAX_BTF_ARGS_LEN 128
#define MAX_STRING_SIZE PATH_MAX
+#define MAX_PROBE_EVENT_SIZE 3072
/* Reserved field names */
#define FIELD_STRING_IP "__probe_ip"
@@ -546,7 +547,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(NO_BTF_FIELD, "This field is not found."), \
C(BAD_BTF_TID, "Failed to get BTF type info."),\
C(BAD_TYPE4STR, "This type does not fit for string."),\
- C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),
+ C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\
+ C(EVENT_TOO_BIG, "Event too big (too many fields?)"),
#undef C
#define C(a, b) TP_ERR_##a
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 8d1507dd0724..f7a4210d5d5e 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -337,6 +337,8 @@ static int tracepoint_add_func(struct tracepoint *tp,
lockdep_is_held(&tracepoints_mutex));
old = func_add(&tp_funcs, func, prio);
if (IS_ERR(old)) {
+ if (tp->unregfunc && !static_key_enabled(&tp->key))
+ tp->unregfunc();
WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM);
return PTR_ERR(old);
}
diff --git a/lib/crypto/mpi/mpicoder.c b/lib/crypto/mpi/mpicoder.c
index 3cb6bd148fa9..b6efe618e614 100644
--- a/lib/crypto/mpi/mpicoder.c
+++ b/lib/crypto/mpi/mpicoder.c
@@ -453,7 +453,7 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
lzeros = 0;
len = 0;
while (nbytes > 0) {
- while (len && !*buff) {
+ while (len && !*buff && lzeros < nbytes) {
lzeros++;
len--;
buff++;
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 7bc2220fea80..398014d6626c 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -1117,8 +1117,7 @@ static ssize_t extract_user_to_sg(struct iov_iter *iter,
size_t len, off;
/* We decant the page list into the tail of the scatterlist */
- pages = (void *)sgtable->sgl +
- array_size(sg_max, sizeof(struct scatterlist));
+ pages = (void *)sg + array_size(sg_max, sizeof(struct scatterlist));
pages -= sg_max;
do {
@@ -1241,7 +1240,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *iter,
else
page = virt_to_page((void *)kaddr);
- sg_set_page(sg, page, len, off);
+ sg_set_page(sg, page, seg, off);
sgtable->nents++;
sg++;
sg_max--;
@@ -1250,6 +1249,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *iter,
kaddr += PAGE_SIZE;
off = 0;
} while (len > 0 && sg_max > 0);
+ ret -= len;
if (maxsize <= 0 || sg_max == 0)
break;
@@ -1342,7 +1342,7 @@ ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t maxsize,
struct sg_table *sgtable, unsigned int sg_max,
iov_iter_extraction_t extraction_flags)
{
- if (maxsize == 0)
+ if (maxsize == 0 || sg_max == 0)
return 0;
switch (iov_iter_type(iter)) {
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index b823ba7cb6a1..cb50065e37a3 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -183,11 +183,60 @@ static int dmirror_fops_open(struct inode *inode, struct file *filp)
return 0;
}
+static void dmirror_device_evict_chunk(struct dmirror_chunk *chunk)
+{
+ unsigned long start_pfn = chunk->pagemap.range.start >> PAGE_SHIFT;
+ unsigned long end_pfn = chunk->pagemap.range.end >> PAGE_SHIFT;
+ unsigned long npages = end_pfn - start_pfn + 1;
+ unsigned long i;
+ unsigned long *src_pfns;
+ unsigned long *dst_pfns;
+
+ src_pfns = kvcalloc(npages, sizeof(*src_pfns), GFP_KERNEL | __GFP_NOFAIL);
+ dst_pfns = kvcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL | __GFP_NOFAIL);
+
+ migrate_device_range(src_pfns, start_pfn, npages);
+ for (i = 0; i < npages; i++) {
+ struct page *dpage, *spage;
+
+ spage = migrate_pfn_to_page(src_pfns[i]);
+ if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE))
+ continue;
+
+ if (WARN_ON(!is_device_private_page(spage) &&
+ !is_device_coherent_page(spage)))
+ continue;
+ spage = BACKING_PAGE(spage);
+ dpage = alloc_page(GFP_HIGHUSER_MOVABLE | __GFP_NOFAIL);
+ lock_page(dpage);
+ copy_highpage(dpage, spage);
+ dst_pfns[i] = migrate_pfn(page_to_pfn(dpage));
+ if (src_pfns[i] & MIGRATE_PFN_WRITE)
+ dst_pfns[i] |= MIGRATE_PFN_WRITE;
+ }
+ migrate_device_pages(src_pfns, dst_pfns, npages);
+ migrate_device_finalize(src_pfns, dst_pfns, npages);
+ kvfree(src_pfns);
+ kvfree(dst_pfns);
+}
+
static int dmirror_fops_release(struct inode *inode, struct file *filp)
{
struct dmirror *dmirror = filp->private_data;
+ struct dmirror_device *mdevice = dmirror->mdevice;
+ int i;
mmu_interval_notifier_remove(&dmirror->notifier);
+
+ if (mdevice->devmem_chunks) {
+ for (i = 0; i < mdevice->devmem_count; i++) {
+ struct dmirror_chunk *devmem =
+ mdevice->devmem_chunks[i];
+
+ dmirror_device_evict_chunk(devmem);
+ }
+ }
+
xa_destroy(&dmirror->pt);
kfree(dmirror);
return 0;
@@ -1217,43 +1266,6 @@ static int dmirror_snapshot(struct dmirror *dmirror,
return ret;
}
-static void dmirror_device_evict_chunk(struct dmirror_chunk *chunk)
-{
- unsigned long start_pfn = chunk->pagemap.range.start >> PAGE_SHIFT;
- unsigned long end_pfn = chunk->pagemap.range.end >> PAGE_SHIFT;
- unsigned long npages = end_pfn - start_pfn + 1;
- unsigned long i;
- unsigned long *src_pfns;
- unsigned long *dst_pfns;
-
- src_pfns = kvcalloc(npages, sizeof(*src_pfns), GFP_KERNEL | __GFP_NOFAIL);
- dst_pfns = kvcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL | __GFP_NOFAIL);
-
- migrate_device_range(src_pfns, start_pfn, npages);
- for (i = 0; i < npages; i++) {
- struct page *dpage, *spage;
-
- spage = migrate_pfn_to_page(src_pfns[i]);
- if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE))
- continue;
-
- if (WARN_ON(!is_device_private_page(spage) &&
- !is_device_coherent_page(spage)))
- continue;
- spage = BACKING_PAGE(spage);
- dpage = alloc_page(GFP_HIGHUSER_MOVABLE | __GFP_NOFAIL);
- lock_page(dpage);
- copy_highpage(dpage, spage);
- dst_pfns[i] = migrate_pfn(page_to_pfn(dpage));
- if (src_pfns[i] & MIGRATE_PFN_WRITE)
- dst_pfns[i] |= MIGRATE_PFN_WRITE;
- }
- migrate_device_pages(src_pfns, dst_pfns, npages);
- migrate_device_finalize(src_pfns, dst_pfns, npages);
- kvfree(src_pfns);
- kvfree(dst_pfns);
-}
-
/* Removes free pages from the free list so they can't be re-allocated */
static void dmirror_remove_free_pages(struct dmirror_chunk *devmem)
{
diff --git a/lib/ts_kmp.c b/lib/ts_kmp.c
index c77a3d537f24..ed13eb0fcd72 100644
--- a/lib/ts_kmp.c
+++ b/lib/ts_kmp.c
@@ -94,8 +94,22 @@ static struct ts_config *kmp_init(const void *pattern, unsigned int len,
struct ts_config *conf;
struct ts_kmp *kmp;
int i;
- unsigned int prefix_tbl_len = len * sizeof(unsigned int);
- size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len;
+ unsigned int prefix_tbl_len;
+ size_t priv_size;
+
+ /* Zero-length patterns would make kmp_find() read beyond kmp->pattern. */
+ if (unlikely(!len))
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * kmp->pattern is stored immediately after the prefix_tbl[] table.
+ * Reject lengths that would wrap while sizing either region.
+ */
+ if (unlikely(check_mul_overflow(len, sizeof(*kmp->prefix_tbl),
+ &prefix_tbl_len) ||
+ check_add_overflow(sizeof(*kmp), (size_t)len, &priv_size) ||
+ check_add_overflow(priv_size, prefix_tbl_len, &priv_size)))
+ return ERR_PTR(-EINVAL);
conf = alloc_ts_config(priv_size, gfp_mask);
if (IS_ERR(conf))
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 48747236c21c..8e5e3bb835d1 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -762,6 +762,39 @@ int damon_stop(struct damon_ctx **ctxs, int nr_ctxs)
return err;
}
+/**
+ * damon_is_running() - Returns if a given DAMON context is running.
+ * @ctx: The DAMON context to see if running.
+ *
+ * Return: true if @ctx is running, false otherwise.
+ */
+bool damon_is_running(struct damon_ctx *ctx)
+{
+ bool running;
+
+ mutex_lock(&ctx->kdamond_lock);
+ running = ctx->kdamond != NULL;
+ mutex_unlock(&ctx->kdamond_lock);
+ return running;
+}
+
+/**
+ * damon_kdamond_pid() - Return pid of a given DAMON context's worker thread.
+ * @ctx: The DAMON context of the question.
+ *
+ * Return: pid if @ctx is running, negative error code otherwise.
+ */
+int damon_kdamond_pid(struct damon_ctx *ctx)
+{
+ int pid = -EINVAL;
+
+ mutex_lock(&ctx->kdamond_lock);
+ if (ctx->kdamond)
+ pid = ctx->kdamond->pid;
+ mutex_unlock(&ctx->kdamond_lock);
+ return pid;
+}
+
/*
* Reset the aggregated monitoring results ('nr_accesses' of each region).
*/
@@ -1026,6 +1059,7 @@ static void damos_set_effective_quota(struct damos_quota *quota)
else
throughput = PAGE_SIZE * 1024;
esz = throughput * quota->ms;
+ esz = max(DAMON_MIN_REGION, esz);
if (quota->sz && quota->sz < esz)
esz = quota->sz;
@@ -1048,7 +1082,8 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
quota->charged_from = jiffies;
/* New charge window starts */
- if (time_after_eq(jiffies, quota->charged_from +
+ if (!time_in_range_open(jiffies, quota->charged_from,
+ quota->charged_from +
msecs_to_jiffies(quota->reset_interval))) {
if (quota->esz && quota->charged_sz >= quota->esz)
s->stat.qt_exceeds++;
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index b4032538b22c..6797bb24a307 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -111,15 +111,6 @@ module_param(monitor_region_start, ulong, 0600);
static unsigned long monitor_region_end __read_mostly;
module_param(monitor_region_end, ulong, 0600);
-/*
- * PID of the DAMON thread
- *
- * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
- * Else, -1.
- */
-static int kdamond_pid __read_mostly = -1;
-module_param(kdamond_pid, int, 0400);
-
static struct damos_stat damon_lru_sort_hot_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat,
lru_sort_tried_hot_regions, lru_sorted_hot_regions,
@@ -249,60 +240,93 @@ static int damon_lru_sort_turn(bool on)
{
int err;
- if (!on) {
- err = damon_stop(&ctx, 1);
- if (!err)
- kdamond_pid = -1;
- return err;
- }
+ if (!on)
+ return damon_stop(&ctx, 1);
err = damon_lru_sort_apply_parameters();
if (err)
return err;
- err = damon_start(&ctx, 1, true);
- if (err)
- return err;
- kdamond_pid = ctx->kdamond->pid;
- return 0;
+ return damon_start(&ctx, 1, true);
+}
+
+static bool damon_lru_sort_enabled(void)
+{
+ if (!ctx)
+ return false;
+ return damon_is_running(ctx);
}
static int damon_lru_sort_enabled_store(const char *val,
const struct kernel_param *kp)
{
- bool is_enabled = enabled;
- bool enable;
int err;
- err = kstrtobool(val, &enable);
+ err = kstrtobool(val, &enabled);
if (err)
return err;
- if (is_enabled == enable)
+ if (damon_lru_sort_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!ctx)
- goto set_param_out;
+ return 0;
- err = damon_lru_sort_turn(enable);
- if (err)
- return err;
+ return damon_lru_sort_turn(enabled);
+}
-set_param_out:
- enabled = enable;
- return err;
+static int damon_lru_sort_enabled_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_lru_sort_enabled_store,
- .get = param_get_bool,
+ .get = damon_lru_sort_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_LRU_SORT (default: disabled)");
+static int damon_lru_sort_kdamond_pid_store(const char *val,
+ const struct kernel_param *kp)
+{
+ /*
+ * kdamond_pid is read-only, but kernel command line could write it.
+ * Do nothing here.
+ */
+ return 0;
+}
+
+static int damon_lru_sort_kdamond_pid_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ int kdamond_pid = -1;
+
+ if (ctx) {
+ kdamond_pid = damon_kdamond_pid(ctx);
+ if (kdamond_pid < 0)
+ kdamond_pid = -1;
+ }
+ return sprintf(buffer, "%d\n", kdamond_pid);
+}
+
+static const struct kernel_param_ops kdamond_pid_param_ops = {
+ .set = damon_lru_sort_kdamond_pid_store,
+ .get = damon_lru_sort_kdamond_pid_load,
+};
+
+/*
+ * PID of the DAMON thread
+ *
+ * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
+ * Else, -1.
+ */
+module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
+
static int damon_lru_sort_handle_commit_inputs(void)
{
int err;
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index 586daa2cefe4..e264f202714e 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -107,15 +107,6 @@ module_param(monitor_region_end, ulong, 0600);
static bool skip_anon __read_mostly;
module_param(skip_anon, bool, 0600);
-/*
- * PID of the DAMON thread
- *
- * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
- * Else, -1.
- */
-static int kdamond_pid __read_mostly = -1;
-module_param(kdamond_pid, int, 0400);
-
static struct damos_stat damon_reclaim_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
reclaim_tried_regions, reclaimed_regions, quota_exceeds);
@@ -203,60 +194,93 @@ static int damon_reclaim_turn(bool on)
{
int err;
- if (!on) {
- err = damon_stop(&ctx, 1);
- if (!err)
- kdamond_pid = -1;
- return err;
- }
+ if (!on)
+ return damon_stop(&ctx, 1);
err = damon_reclaim_apply_parameters();
if (err)
return err;
- err = damon_start(&ctx, 1, true);
- if (err)
- return err;
- kdamond_pid = ctx->kdamond->pid;
- return 0;
+ return damon_start(&ctx, 1, true);
+}
+
+static bool damon_reclaim_enabled(void)
+{
+ if (!ctx)
+ return false;
+ return damon_is_running(ctx);
}
static int damon_reclaim_enabled_store(const char *val,
const struct kernel_param *kp)
{
- bool is_enabled = enabled;
- bool enable;
int err;
- err = kstrtobool(val, &enable);
+ err = kstrtobool(val, &enabled);
if (err)
return err;
- if (is_enabled == enable)
+ if (damon_reclaim_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!ctx)
- goto set_param_out;
+ return 0;
- err = damon_reclaim_turn(enable);
- if (err)
- return err;
+ return damon_reclaim_turn(enabled);
+}
-set_param_out:
- enabled = enable;
- return err;
+static int damon_reclaim_enabled_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_reclaim_enabled_store,
- .get = param_get_bool,
+ .get = damon_reclaim_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_RECLAIM (default: disabled)");
+static int damon_reclaim_kdamond_pid_store(const char *val,
+ const struct kernel_param *kp)
+{
+ /*
+ * kdamond_pid is read-only, but kernel command line could write it.
+ * Do nothing here.
+ */
+ return 0;
+}
+
+static int damon_reclaim_kdamond_pid_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ int kdamond_pid = -1;
+
+ if (ctx) {
+ kdamond_pid = damon_kdamond_pid(ctx);
+ if (kdamond_pid < 0)
+ kdamond_pid = -1;
+ }
+ return sprintf(buffer, "%d\n", kdamond_pid);
+}
+
+static const struct kernel_param_ops kdamond_pid_param_ops = {
+ .set = damon_reclaim_kdamond_pid_store,
+ .get = damon_reclaim_kdamond_pid_load,
+};
+
+/*
+ * PID of the DAMON thread
+ *
+ * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
+ * Else, -1.
+ */
+module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
+
static int damon_reclaim_handle_commit_inputs(void)
{
int err;
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index c774f1e5c0a5..dd04bd38567a 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -360,9 +360,14 @@ static ssize_t memcg_path_show(struct kobject *kobj,
{
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
+ int len;
- return sysfs_emit(buf, "%s\n",
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ len = sysfs_emit(buf, "%s\n",
filter->memcg_path ? filter->memcg_path : "");
+ mutex_unlock(&damon_sysfs_lock);
+ return len;
}
static ssize_t memcg_path_store(struct kobject *kobj,
@@ -376,8 +381,13 @@ static ssize_t memcg_path_store(struct kobject *kobj,
return -ENOMEM;
strscpy(path, buf, count + 1);
+ if (!mutex_trylock(&damon_sysfs_lock)) {
+ kfree(path);
+ return -EBUSY;
+ }
kfree(filter->memcg_path);
filter->memcg_path = path;
+ mutex_unlock(&damon_sysfs_lock);
return count;
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index aa0ef3bc4dd6..6a1e0eefd254 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -7493,6 +7493,7 @@ void __init hugetlb_cma_reserve(int order)
* let's allocate 1 GB on first three nodes and ignore the last one.
*/
per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes);
+ per_node = round_up(per_node, PAGE_SIZE << order);
pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
}
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index c31edbd7c2ab..748188d3b878 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -172,19 +172,12 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
static struct batadv_neigh_node *
batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr,
- struct batadv_orig_node *orig_node,
- struct batadv_orig_node *orig_neigh)
+ struct batadv_orig_node *orig_node)
{
struct batadv_neigh_node *neigh_node;
neigh_node = batadv_neigh_node_get_or_create(orig_node,
hard_iface, neigh_addr);
- if (!neigh_node)
- goto out;
-
- neigh_node->orig_node = orig_neigh;
-
-out:
return neigh_node;
}
@@ -334,7 +327,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
const char *fwd_str;
u8 packet_num;
- s16 buff_pos;
+ int buff_pos;
struct batadv_ogm_packet *batadv_ogm_packet;
struct sk_buff *skb;
u8 *packet_pos;
@@ -900,6 +893,31 @@ static u8 batadv_iv_orig_ifinfo_sum(struct batadv_orig_node *orig_node,
return sum;
}
+/**
+ * batadv_iv_ogm_neigh_ifinfo_sum() - Get bcast_own sum for a last-hop neighbor
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @neigh_node: last-hop neighbor of an originator
+ *
+ * Return: Number of replied (rebroadcasted) OGMs for the originator currently
+ * announced by the neighbor. Returns 0 if the neighbor's originator entry is
+ * not available anymore.
+ */
+static u8 batadv_iv_ogm_neigh_ifinfo_sum(struct batadv_priv *bat_priv,
+ const struct batadv_neigh_node *neigh_node)
+{
+ struct batadv_orig_node *orig_neigh;
+ u8 sum;
+
+ orig_neigh = batadv_orig_hash_find(bat_priv, neigh_node->addr);
+ if (!orig_neigh)
+ return 0;
+
+ sum = batadv_iv_orig_ifinfo_sum(orig_neigh, neigh_node->if_incoming);
+ batadv_orig_node_put(orig_neigh);
+
+ return sum;
+}
+
/**
* batadv_iv_ogm_orig_update() - use OGM to update corresponding data in an
* originator
@@ -969,17 +987,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
}
if (!neigh_node) {
- struct batadv_orig_node *orig_tmp;
-
- orig_tmp = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source);
- if (!orig_tmp)
- goto unlock;
-
neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
ethhdr->h_source,
- orig_node, orig_tmp);
-
- batadv_orig_node_put(orig_tmp);
+ orig_node);
if (!neigh_node)
goto unlock;
} else {
@@ -1031,10 +1041,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
*/
if (router_ifinfo &&
neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) {
- sum_orig = batadv_iv_orig_ifinfo_sum(router->orig_node,
- router->if_incoming);
- sum_neigh = batadv_iv_orig_ifinfo_sum(neigh_node->orig_node,
- neigh_node->if_incoming);
+ sum_orig = batadv_iv_ogm_neigh_ifinfo_sum(bat_priv, router);
+ sum_neigh = batadv_iv_ogm_neigh_ifinfo_sum(bat_priv,
+ neigh_node);
if (sum_orig >= sum_neigh)
goto out;
}
@@ -1100,7 +1109,6 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
if (!neigh_node)
neigh_node = batadv_iv_ogm_neigh_new(if_incoming,
orig_neigh_node->orig,
- orig_neigh_node,
orig_neigh_node);
if (!neigh_node)
@@ -1296,6 +1304,32 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
return ret;
}
+/**
+ * batadv_orig_to_direct_router() - get direct next hop neighbor to an orig address
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @orig_addr: the originator MAC address to search the best next hop router for
+ * @if_outgoing: the interface where the OGM should be sent to
+ *
+ * Return: A neighbor node which is the best router towards the given originator
+ * address. Bonding candidates are ignored.
+ */
+static struct batadv_neigh_node *
+batadv_orig_to_direct_router(struct batadv_priv *bat_priv, u8 *orig_addr,
+ struct batadv_hard_iface *if_outgoing)
+{
+ struct batadv_neigh_node *neigh_node;
+ struct batadv_orig_node *orig_node;
+
+ orig_node = batadv_orig_hash_find(bat_priv, orig_addr);
+ if (!orig_node)
+ return NULL;
+
+ neigh_node = batadv_orig_router_get(orig_node, if_outgoing);
+ batadv_orig_node_put(orig_node);
+
+ return neigh_node;
+}
+
/**
* batadv_iv_ogm_process_per_outif() - process a batman iv OGM for an outgoing
* interface
@@ -1366,8 +1400,9 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
router = batadv_orig_router_get(orig_node, if_outgoing);
if (router) {
- router_router = batadv_orig_router_get(router->orig_node,
- if_outgoing);
+ router_router = batadv_orig_to_direct_router(bat_priv,
+ router->addr,
+ if_outgoing);
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
}
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 96b3c1c972cd..30deb7d73b2b 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -318,8 +318,8 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
if (claim->backbone_gw != backbone_gw)
continue;
- batadv_claim_put(claim);
hlist_del_rcu(&claim->hash_entry);
+ batadv_claim_put(claim);
}
spin_unlock_bh(list_lock);
}
@@ -723,6 +723,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
if (unlikely(hash_added != 0)) {
/* only local changes happened. */
+ batadv_backbone_gw_put(backbone_gw);
kfree(claim);
return;
}
@@ -1288,6 +1289,13 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(claim, head, hash_entry) {
+ /* only purge claims not currently in the process of being released.
+ * Such claims could otherwise have a NULL-ptr backbone_gw set because
+ * they already went through batadv_claim_release()
+ */
+ if (!kref_get_unless_zero(&claim->refcount))
+ continue;
+
backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
if (now)
goto purge_now;
@@ -1313,6 +1321,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
claim->addr, claim->vid);
skip:
batadv_backbone_gw_put(backbone_gw);
+ batadv_claim_put(claim);
}
rcu_read_unlock();
}
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index e8a449915566..18b32c39ed4b 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -262,6 +262,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
batadv_purge_outstanding_packets(bat_priv, NULL);
+ batadv_tp_stop_all(bat_priv);
batadv_gw_node_free(bat_priv);
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 7f3dd3c393e0..87797969c220 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -12,6 +12,7 @@
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/etherdevice.h>
@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
}
/**
- * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
- * @bat_priv: the bat priv with all the soft interface information
- * @tp_vars: the private data of the current TP meter session to cleanup
+ * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv,
- struct batadv_tp_vars *tp_vars)
+static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
{
- cancel_delayed_work(&tp_vars->finish_work);
+ bool detached = false;
spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
+ if (!hlist_unhashed(&tp_vars->list)) {
+ hlist_del_init_rcu(&tp_vars->list);
+ detached = true;
+ }
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
+ if (!detached)
+ return;
+
+ atomic_dec(&tp_vars->bat_priv->tp_num);
+
/* drop list reference */
batadv_tp_vars_put(tp_vars);
+}
- atomic_dec(&tp_vars->bat_priv->tp_num);
+/**
+ * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
+ * @tp_vars: the private data of the current TP meter session to cleanup
+ */
+static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+{
+ cancel_delayed_work_sync(&tp_vars->finish_work);
+
+ batadv_tp_list_detach(tp_vars);
/* kill the timer and remove its reference */
del_timer_sync(&tp_vars->timer);
@@ -886,7 +902,8 @@ static int batadv_tp_send(void *arg)
batadv_orig_node_put(orig_node);
batadv_tp_sender_end(bat_priv, tp_vars);
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
batadv_tp_vars_put(tp_vars);
@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
batadv_tp_vars_put(tp_vars);
/* cleanup of failed tp meter variables */
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
return;
}
@@ -947,6 +965,13 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
/* look for an already existing test towards this node */
spin_lock_bh(&bat_priv->tp_list_lock);
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) {
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+ batadv_tp_batctl_error_notify(BATADV_TP_REASON_DST_UNREACHABLE,
+ dst, bat_priv, session_cookie);
+ return;
+ }
+
tp_vars = batadv_tp_list_find(bat_priv, dst);
if (tp_vars) {
spin_unlock_bh(&bat_priv->tp_list_lock);
@@ -969,6 +994,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC);
if (!tp_vars) {
+ atomic_dec(&bat_priv->tp_num);
spin_unlock_bh(&bat_priv->tp_list_lock);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: %s cannot allocate list elements\n",
@@ -1017,6 +1043,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars->start_time = jiffies;
init_waitqueue_head(&tp_vars->more_bytes);
+ init_completion(&tp_vars->finished);
spin_lock_init(&tp_vars->unacked_lock);
INIT_LIST_HEAD(&tp_vars->unacked_list);
@@ -1119,14 +1146,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
"Shutting down for inactivity (more than %dms) from %pM\n",
BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
- spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
- spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
-
- /* drop list reference */
- batadv_tp_vars_put(tp_vars);
-
- atomic_dec(&bat_priv->tp_num);
+ batadv_tp_list_detach(tp_vars);
spin_lock_bh(&tp_vars->unacked_lock);
list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
@@ -1329,9 +1349,12 @@ static struct batadv_tp_vars *
batadv_tp_init_recv(struct batadv_priv *bat_priv,
const struct batadv_icmp_tp_packet *icmp)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_vars *tp_vars = NULL;
spin_lock_bh(&bat_priv->tp_list_lock);
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+ goto out_unlock;
+
tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
icmp->session);
if (tp_vars)
@@ -1344,8 +1367,10 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,
}
tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC);
- if (!tp_vars)
+ if (!tp_vars) {
+ atomic_dec(&bat_priv->tp_num);
goto out_unlock;
+ }
ether_addr_copy(tp_vars->other_end, icmp->orig);
tp_vars->role = BATADV_TP_RECEIVER;
@@ -1464,6 +1489,9 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
{
struct batadv_icmp_tp_packet *icmp;
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+ goto out;
+
icmp = (struct batadv_icmp_tp_packet *)skb->data;
switch (icmp->subtype) {
@@ -1478,9 +1506,57 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
"Received unknown TP Metric packet type %u\n",
icmp->subtype);
}
+
+out:
consume_skb(skb);
}
+/**
+ * batadv_tp_stop_all() - stop all currently running tp meter sessions
+ * @bat_priv: the bat priv with all the mesh interface information
+ */
+void batadv_tp_stop_all(struct batadv_priv *bat_priv)
+{
+ struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
+ struct batadv_tp_vars *tp_var;
+ size_t count = 0;
+ size_t i;
+
+ spin_lock_bh(&bat_priv->tp_list_lock);
+ hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
+ if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+ break;
+
+ if (!kref_get_unless_zero(&tp_var->refcount))
+ continue;
+
+ tp_vars[count++] = tp_var;
+ }
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+
+ for (i = 0; i < count; i++) {
+ tp_var = tp_vars[i];
+
+ switch (tp_var->role) {
+ case BATADV_TP_SENDER:
+ batadv_tp_sender_shutdown(tp_var,
+ BATADV_TP_REASON_CANCEL);
+ wake_up(&tp_var->more_bytes);
+ wait_for_completion(&tp_var->finished);
+ break;
+ case BATADV_TP_RECEIVER:
+ batadv_tp_list_detach(tp_var);
+ if (timer_shutdown_sync(&tp_var->timer))
+ batadv_tp_vars_put(tp_var);
+ break;
+ }
+
+ batadv_tp_vars_put(tp_var);
+ }
+
+ synchronize_net();
+}
+
/**
* batadv_tp_meter_init() - initialize global tp_meter structures
*/
diff --git a/net/batman-adv/tp_meter.h b/net/batman-adv/tp_meter.h
index f0046d366eac..4e97cd10cd02 100644
--- a/net/batman-adv/tp_meter.h
+++ b/net/batman-adv/tp_meter.h
@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie);
void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
u8 return_value);
+void batadv_tp_stop_all(struct batadv_priv *bat_priv);
void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
#endif /* _NET_BATMAN_ADV_TP_METER_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index d6854c109cd2..788507b29f9a 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -14,6 +14,7 @@
#include <linux/average.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/kref.h>
@@ -1396,6 +1397,9 @@ struct batadv_tp_vars {
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
+ /** @finished: completion signaled when a sender thread exits */
+ struct completion finished;
+
/** @test_length: test length in milliseconds */
u32 test_length;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 97e48c1f69af..f51c530a3c45 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -2014,6 +2014,9 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
u32 flags = 0;
int err;
+ if (!hci_conn_valid(hdev, conn))
+ return -ECANCELED;
+
if (qos->bcast.out.phy == 0x02)
flags |= MGMT_ADV_FLAG_SEC_2M;
@@ -2125,11 +2128,24 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "conn %p", conn);
+ if (err == -ECANCELED)
+ goto done;
+
+ hci_dev_lock(hdev);
+
+ if (!hci_conn_valid(hdev, conn))
+ goto unlock;
+
if (err) {
bt_dev_err(hdev, "Unable to create BIG: %d", err);
hci_connect_cfm(conn, err);
hci_conn_del(conn);
}
+
+unlock:
+ hci_dev_unlock(hdev);
+done:
+ hci_conn_put(conn);
}
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
@@ -2230,10 +2246,11 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
BT_BOUND, &data);
/* Queue start periodic advertising and create BIG */
- err = hci_cmd_sync_queue(hdev, create_big_sync, conn,
+ err = hci_cmd_sync_queue(hdev, create_big_sync, hci_conn_get(conn),
create_big_complete);
if (err < 0) {
hci_conn_drop(conn);
+ hci_conn_put(conn);
return ERR_PTR(err);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8b184839b013..f6285c4325d6 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5409,9 +5409,11 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "");
+ hci_dev_lock(hdev);
+
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
- return;
+ goto unlock;
conn->passkey_notify = __le32_to_cpu(ev->passkey);
conn->passkey_entered = 0;
@@ -5420,6 +5422,9 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev, void *data,
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
@@ -5430,14 +5435,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "");
+ hci_dev_lock(hdev);
+
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
- return;
+ goto unlock;
switch (ev->type) {
case HCI_KEYPRESS_STARTED:
conn->passkey_entered = 0;
- return;
+ goto unlock;
case HCI_KEYPRESS_ENTERED:
conn->passkey_entered++;
@@ -5452,13 +5459,16 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, void *data,
break;
case HCI_KEYPRESS_COMPLETED:
- return;
+ goto unlock;
}
if (hci_dev_test_flag(hdev, HCI_MGMT))
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data,
@@ -6864,9 +6874,29 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
continue;
}
+ if (ev->num_bis <= i) {
+ bt_dev_err(hdev,
+ "Not enough BIS handles for BIG 0x%2.2x",
+ ev->handle);
+ ev->status = HCI_ERROR_UNSPECIFIED;
+ hci_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
+ continue;
+ }
+
if (hci_conn_set_handle(conn,
- __le16_to_cpu(ev->bis_handle[i++])))
+ __le16_to_cpu(ev->bis_handle[i++]))) {
+ bt_dev_err(hdev,
+ "Failed to set BIS handle for BIG 0x%2.2x",
+ ev->handle);
+ /* Force error so BIG gets terminated as not all BIS
+ * could be connected.
+ */
+ ev->status = HCI_ERROR_UNSPECIFIED;
+ hci_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
continue;
+ }
conn->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
@@ -6875,7 +6905,10 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
hci_iso_setup_path(conn);
}
- if (!ev->status && !i)
+ /* If there is an unexpected error or if no BISes have been connected
+ * for the BIG, terminate it.
+ */
+ if (ev->status == HCI_ERROR_UNSPECIFIED || (!ev->status && !i))
/* If no BISes have been connected for the BIG,
* terminate. This is in case all bound connections
* have been closed before the BIG creation
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 1960d35b3be0..fd727a2961fa 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1464,6 +1464,9 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
{
struct sock *sk, *parent = chan->data;
+ if (!parent)
+ return NULL;
+
lock_sock(parent);
/* Check for backlog size */
@@ -1624,6 +1627,9 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
{
struct sock *sk = chan->data;
+ if (!sk)
+ return;
+
sk->sk_state = state;
if (err)
@@ -1725,6 +1731,9 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
{
struct sock *sk = chan->data;
+ if (!sk)
+ return 0;
+
return sk->sk_sndtimeo;
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 51a6ad6a36c8..1874d50e96aa 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1319,8 +1319,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
struct mgmt_mode *cp;
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
cp = cmd->param;
@@ -1347,23 +1346,29 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
mgmt_status(err));
}
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_powered_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp;
+ struct mgmt_mode cp;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
/* Make sure cmd still outstanding. */
- if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
+ }
- cp = cmd->param;
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
BT_DBG("%s", hdev->name);
- return hci_set_powered_sync(hdev, cp->val);
+ return hci_set_powered_sync(hdev, cp.val);
}
static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -1504,8 +1509,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
hci_dev_lock(hdev);
@@ -1527,12 +1531,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk);
done:
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
}
static int set_discoverable_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
BT_DBG("%s", hdev->name);
return hci_update_discoverable_sync(hdev);
@@ -1679,8 +1686,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
hci_dev_lock(hdev);
@@ -1696,7 +1702,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
done:
if (cmd)
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
}
@@ -1732,6 +1738,9 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
static int set_connectable_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
BT_DBG("%s", hdev->name);
return hci_update_connectable_sync(hdev);
@@ -1908,14 +1917,17 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
{
struct cmd_lookup match = { NULL, hdev };
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 enable = cp->val;
+ struct mgmt_mode *cp;
+ u8 enable;
bool changed;
/* Make sure cmd still outstanding. */
- if (err == -ECANCELED || cmd != pending_find(MGMT_OP_SET_SSP, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
+ cp = cmd->param;
+ enable = cp->val;
+
if (err) {
u8 mgmt_err = mgmt_status(err);
@@ -1924,8 +1936,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
new_settings(hdev, NULL);
}
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true,
- cmd_status_rsp, &mgmt_err);
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
+ mgmt_pending_free(cmd);
return;
}
@@ -1935,7 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
}
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match);
+ settings_rsp(cmd, &match);
if (changed)
new_settings(hdev, match.sk);
@@ -1944,19 +1956,31 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
sock_put(match.sk);
hci_update_eir_sync(hdev);
+ mgmt_pending_free(cmd);
}
static int set_ssp_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
+ struct mgmt_mode cp;
bool changed = false;
int err;
- if (cp->val)
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ if (cp.val)
changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
- err = hci_write_ssp_mode_sync(hdev, cp->val);
+ err = hci_write_ssp_mode_sync(hdev, cp.val);
if (!err && changed)
hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
@@ -2049,32 +2073,50 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
static void set_le_complete(struct hci_dev *hdev, void *data, int err)
{
+ struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev };
u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err);
- if (status) {
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp,
- &status);
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
return;
+
+ if (status) {
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
+ goto done;
}
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match);
+ settings_rsp(cmd, &match);
new_settings(hdev, match.sk);
if (match.sk)
sock_put(match.sk);
+
+done:
+ mgmt_pending_free(cmd);
}
static int set_le_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 val = !!cp->val;
+ struct mgmt_mode cp;
+ u8 val;
int err;
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+ val = !!cp.val;
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
if (!val) {
hci_clear_adv_instance_sync(hdev, NULL, 0x00, true);
@@ -2116,7 +2158,12 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
u8 status = mgmt_status(err);
- struct sock *sk = cmd->sk;
+ struct sock *sk;
+
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
+ return;
+
+ sk = cmd->sk;
if (status) {
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
@@ -2131,24 +2178,37 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
static int set_mesh_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_set_mesh *cp = cmd->param;
- size_t len = cmd->param_len;
+ struct mgmt_cp_set_mesh cp;
+ size_t len;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ len = cmd->param_len;
memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
- if (cp->enable)
+ if (cp.enable)
hci_dev_set_flag(hdev, HCI_MESH);
else
hci_dev_clear_flag(hdev, HCI_MESH);
- hdev->le_scan_interval = __le16_to_cpu(cp->period);
- hdev->le_scan_window = __le16_to_cpu(cp->window);
+ hdev->le_scan_interval = __le16_to_cpu(cp.period);
+ hdev->le_scan_window = __le16_to_cpu(cp.window);
- len -= sizeof(*cp);
+ len -= sizeof(cp);
/* If filters don't fit, forward all adv pkts */
if (len <= sizeof(hdev->mesh_ad_types))
- memcpy(hdev->mesh_ad_types, cp->ad_types, len);
+ memcpy(hdev->mesh_ad_types, cp.ad_types, len);
hci_update_passive_scan_sync(hdev);
return 0;
@@ -3802,15 +3862,16 @@ static int name_changed_sync(struct hci_dev *hdev, void *data)
static void set_name_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_set_local_name *cp = cmd->param;
+ struct mgmt_cp_set_local_name *cp;
u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err);
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
+ cp = cmd->param;
+
if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
status);
@@ -3822,16 +3883,27 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
}
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_name_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_cp_set_local_name *cp = cmd->param;
+ struct mgmt_cp_set_local_name cp;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
if (lmp_bredr_capable(hdev)) {
- hci_update_name_sync(hdev, cp->name);
+ hci_update_name_sync(hdev, cp.name);
hci_update_eir_sync(hdev);
}
@@ -3983,12 +4055,10 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- struct sk_buff *skb = cmd->skb;
+ struct sk_buff *skb;
u8 status = mgmt_status(err);
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
- return;
+ skb = cmd->skb;
if (!status) {
if (!skb)
@@ -4015,7 +4085,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
if (skb && !IS_ERR(skb))
kfree_skb(skb);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int set_default_phy_sync(struct hci_dev *hdev, void *data)
@@ -4023,7 +4093,9 @@ static int set_default_phy_sync(struct hci_dev *hdev, void *data)
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_phy_configuration *cp = cmd->param;
struct hci_cp_le_set_default_phy cp_phy;
- u32 selected_phys = __le32_to_cpu(cp->selected_phys);
+ u32 selected_phys;
+
+ selected_phys = __le32_to_cpu(cp->selected_phys);
memset(&cp_phy, 0, sizeof(cp_phy));
@@ -4163,7 +4235,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
+ cmd = mgmt_pending_new(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
len);
if (!cmd)
err = -ENOMEM;
@@ -5253,7 +5325,17 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
{
struct mgmt_rp_add_adv_patterns_monitor rp;
struct mgmt_pending_cmd *cmd = data;
- struct adv_monitor *monitor = cmd->user_data;
+ struct adv_monitor *monitor;
+
+ /* This is likely the result of hdev being closed and mgmt_index_removed
+ * is attempting to clean up any pending command so
+ * hci_adv_monitors_clear is about to be called which will take care of
+ * freeing the adv_monitor instances.
+ */
+ if (status == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
+ return;
+
+ monitor = cmd->user_data;
hci_dev_lock(hdev);
@@ -5279,9 +5361,20 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct adv_monitor *monitor = cmd->user_data;
+ struct adv_monitor *mon;
- return hci_add_adv_monitor(hdev, monitor);
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ mon = cmd->user_data;
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ return hci_add_adv_monitor(hdev, mon);
}
static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
@@ -5548,7 +5641,8 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
status);
}
-static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)
+static void read_local_oob_data_complete(struct hci_dev *hdev, void *data,
+ int err)
{
struct mgmt_rp_read_local_oob_data mgmt_rp;
size_t rp_size = sizeof(mgmt_rp);
@@ -5568,7 +5662,8 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int e
bt_dev_dbg(hdev, "status %d", status);
if (status) {
- mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);
+ mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+ status);
goto remove;
}
@@ -5873,17 +5968,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
- if (err == -ECANCELED)
- return;
-
- if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) &&
- cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) &&
- cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
DISCOVERY_FINDING);
@@ -5891,6 +5981,9 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int start_discovery_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
return hci_start_discovery_sync(hdev);
}
@@ -6113,15 +6206,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd = data;
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@@ -6129,6 +6221,9 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int stop_discovery_sync(struct hci_dev *hdev, void *data)
{
+ if (!mgmt_pending_listed(hdev, data))
+ return -ECANCELED;
+
return hci_stop_discovery_sync(hdev);
}
@@ -6338,14 +6433,18 @@ static void enable_advertising_instance(struct hci_dev *hdev, int err)
static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
{
+ struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev };
u8 instance;
struct adv_info *adv_instance;
u8 status = mgmt_status(err);
+ if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
+ return;
+
if (status) {
- mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true,
- cmd_status_rsp, &status);
+ mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
+ mgmt_pending_free(cmd);
return;
}
@@ -6354,8 +6453,8 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
- mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp,
- &match);
+ settings_rsp(cmd, &match);
+ mgmt_pending_free(cmd);
new_settings(hdev, match.sk);
@@ -6387,10 +6486,23 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
static int set_adv_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
- struct mgmt_mode *cp = cmd->param;
- u8 val = !!cp->val;
+ struct mgmt_mode cp;
+ u8 val;
- if (cp->val == 0x02)
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ if (!__mgmt_pending_listed(hdev, cmd)) {
+ mutex_unlock(&hdev->mgmt_pending_lock);
+ return -ECANCELED;
+ }
+
+ memcpy(&cp, cmd->param, sizeof(cp));
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ val = !!cp.val;
+
+ if (cp.val == 0x02)
hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
@@ -8100,10 +8212,6 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
u8 status = mgmt_status(err);
u16 eir_len;
- if (err == -ECANCELED ||
- cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
- return;
-
if (!status) {
if (!skb)
status = MGMT_STATUS_FAILED;
@@ -8210,7 +8318,7 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
kfree_skb(skb);
kfree(mgmt_rp);
- mgmt_pending_remove(cmd);
+ mgmt_pending_free(cmd);
}
static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
@@ -8219,7 +8327,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
struct mgmt_pending_cmd *cmd;
int err;
- cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
+ cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
cp, sizeof(*cp));
if (!cmd)
return -ENOMEM;
diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
index 4ba500c377a4..e612121b96d0 100644
--- a/net/bluetooth/mgmt_util.c
+++ b/net/bluetooth/mgmt_util.c
@@ -320,6 +320,52 @@ void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
mgmt_pending_free(cmd);
}
+bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
+{
+ struct mgmt_pending_cmd *tmp;
+
+ lockdep_assert_held(&hdev->mgmt_pending_lock);
+
+ if (!cmd)
+ return false;
+
+ list_for_each_entry(tmp, &hdev->mgmt_pending, list) {
+ if (cmd == tmp)
+ return true;
+ }
+
+ return false;
+}
+
+bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
+{
+ bool listed;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+ listed = __mgmt_pending_listed(hdev, cmd);
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ return listed;
+}
+
+bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
+{
+ bool listed;
+
+ if (!cmd)
+ return false;
+
+ mutex_lock(&hdev->mgmt_pending_lock);
+
+ listed = __mgmt_pending_listed(hdev, cmd);
+ if (listed)
+ list_del(&cmd->list);
+
+ mutex_unlock(&hdev->mgmt_pending_lock);
+
+ return listed;
+}
+
void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk)
diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h
index 024e51dd6937..bcba8c9d8952 100644
--- a/net/bluetooth/mgmt_util.h
+++ b/net/bluetooth/mgmt_util.h
@@ -65,6 +65,9 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
void *data, u16 len);
void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
+bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
+bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
+bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk);
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index f033a5167560..985aaf7ff156 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -199,11 +199,12 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
+ const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if ((p && (p->flags & BR_PROXYARP)) ||
- (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) ||
- br_is_neigh_suppress_enabled(f->dst, vid)) {
+ (dst && (dst->flags & BR_PROXYARP_WIFI)) ||
+ br_is_neigh_suppress_enabled(dst, vid)) {
if (!vid)
br_arp_send(br, p, skb->dev, sip, tip,
sha, n->ha, sha, 0, 0);
@@ -463,9 +464,10 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
f = br_fdb_find_rcu(br, n->ha, vid);
if (f) {
+ const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
- if (br_is_neigh_suppress_enabled(f->dst, vid)) {
+ if (br_is_neigh_suppress_enabled(dst, vid)) {
if (vid != 0)
br_nd_send(br, p, skb, n,
skb->vlan_proto,
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index fa2970db2130..0a51f648c57e 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -246,6 +246,7 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
const unsigned char *addr,
__u16 vid)
{
+ const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct net_device *dev = NULL;
struct net_bridge *br;
@@ -258,8 +259,11 @@ struct net_device *br_fdb_find_port(const struct net_device *br_dev,
br = netdev_priv(br_dev);
rcu_read_lock();
f = br_fdb_find_rcu(br, addr, vid);
- if (f && f->dst)
- dev = f->dst->dev;
+ if (f) {
+ dst = READ_ONCE(f->dst);
+ if (dst)
+ dev = dst->dev;
+ }
rcu_read_unlock();
return dev;
@@ -349,7 +353,7 @@ static void fdb_delete_local(struct net_bridge *br,
vg = nbp_vlan_group(op);
if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
(!vid || br_vlan_find(vg, vid))) {
- f->dst = op;
+ WRITE_ONCE(f->dst, op);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@@ -360,7 +364,7 @@ static void fdb_delete_local(struct net_bridge *br,
/* Maybe bridge device has same hw addr? */
if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
(!vid || (v && br_vlan_should_use(v)))) {
- f->dst = NULL;
+ WRITE_ONCE(f->dst, NULL);
clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
return;
}
@@ -790,6 +794,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long maxnum, unsigned long skip)
{
+ const struct net_bridge_port *dst;
struct net_bridge_fdb_entry *f;
struct __fdb_entry *fe = buf;
unsigned long delta;
@@ -806,7 +811,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
continue;
/* ignore pseudo entry for local MAC address */
- if (!f->dst)
+ dst = READ_ONCE(f->dst);
+ if (!dst)
continue;
if (skip) {
@@ -818,8 +824,8 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
/* due to ABI compat need to split into hi/lo */
- fe->port_no = f->dst->port_no;
- fe->port_hi = f->dst->port_no >> 8;
+ fe->port_no = dst->port_no;
+ fe->port_hi = dst->port_no >> 8;
fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
if (!test_bit(BR_FDB_STATIC, &f->flags)) {
@@ -940,9 +946,11 @@ int br_fdb_dump(struct sk_buff *skb,
rcu_read_lock();
hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
+ const struct net_bridge_port *dst = READ_ONCE(f->dst);
+
if (*idx < cb->args[2])
goto skip;
- if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
+ if (filter_dev && (!dst || dst->dev != filter_dev)) {
if (filter_dev != dev)
goto skip;
/* !f->dst is a special case for bridge
@@ -950,10 +958,10 @@ int br_fdb_dump(struct sk_buff *skb,
* Therefore need a little more filtering
* we only want to dump the !f->dst case
*/
- if (f->dst)
+ if (dst)
goto skip;
}
- if (!filter_dev && f->dst)
+ if (!filter_dev && dst)
goto skip;
err = fdb_fill_info(skb, br, f,
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 9cef9496a707..9a474d99bae8 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -197,10 +197,20 @@ bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
void caif_free_client(struct cflayer *adap_layer)
{
+ struct cflayer *serv_layer;
struct cfsrvl *servl;
- if (adap_layer == NULL || adap_layer->dn == NULL)
+
+ if (!adap_layer)
+ return;
+
+ serv_layer = adap_layer->dn;
+ if (!serv_layer)
return;
- servl = container_obj(adap_layer->dn);
+
+ layer_set_dn(adap_layer, NULL);
+ layer_set_up(serv_layer, NULL);
+
+ servl = container_obj(serv_layer);
servl->release(&servl->layer);
}
EXPORT_SYMBOL(caif_free_client);
diff --git a/net/ceph/auth.c b/net/ceph/auth.c
index 0d75679c6a7e..06d0d73309c2 100644
--- a/net/ceph/auth.c
+++ b/net/ceph/auth.c
@@ -245,7 +245,7 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
ac->protocol = 0;
ac->ops = NULL;
}
- if (ac->protocol != protocol) {
+ if (!ac->protocol) {
ret = init_protocol(ac, protocol);
if (ret) {
pr_err("auth protocol '%s' init failed: %d\n",
@@ -257,7 +257,7 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
ac->negotiating = false;
}
- if (result) {
+ if (result < 0) {
pr_err("auth protocol '%s' mauth authentication failed: %d\n",
ceph_auth_proto_name(ac->protocol), result);
ret = result;
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index 290fd7ab125f..9608072863dc 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -174,6 +174,8 @@ int ceph_monmap_contains(struct ceph_monmap *m, struct ceph_entity_addr *addr)
*/
static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
{
+ BUG_ON(len > monc->m_auth->front_alloc_len);
+
monc->pending_auth = 1;
monc->m_auth->front.iov_len = len;
monc->m_auth->hdr.front_len = cpu_to_le32(len);
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index aafa754b6cba..9432e5362b44 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -1350,16 +1350,13 @@ bool __skb_flow_dissect(const struct net *net,
break;
}
- /* least significant bit of the most significant octet
- * indicates if protocol field was compressed
+ /* PFC (compressed 1-byte protocol) frames are not processed.
+ * A compressed protocol field has the least significant bit of
+ * the most significant octet set, which will fail the following
+ * ppp_proto_is_valid(), returning FLOW_DISSECT_RET_OUT_BAD.
*/
ppp_proto = ntohs(hdr->proto);
- if (ppp_proto & 0x0100) {
- ppp_proto = ppp_proto >> 8;
- nhoff += PPPOE_SES_HLEN - 1;
- } else {
- nhoff += PPPOE_SES_HLEN;
- }
+ nhoff += PPPOE_SES_HLEN;
if (ppp_proto == PPP_IP) {
proto = htons(ETH_P_IP);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index acb3a8e19743..350705730f76 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1362,6 +1362,7 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
port_guid.vf = ivi.vf;
memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
+ memset(&vf_broadcast, 0, sizeof(vf_broadcast));
memcpy(vf_broadcast.broadcast, dev->broadcast, dev->addr_len);
vf_vlan.vlan = ivi.vlan;
vf_vlan.qos = ivi.qos;
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 015c0f4ec5ba..9f00d251770d 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -27,9 +27,7 @@ static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
{
unsigned int len;
- len = size + crypto_ahash_digestsize(ahash) +
- (crypto_ahash_alignmask(ahash) &
- ~(crypto_tfm_ctx_alignment() - 1));
+ len = size + crypto_ahash_digestsize(ahash);
len = ALIGN(len, crypto_tfm_ctx_alignment());
@@ -46,10 +44,9 @@ static inline u8 *ah_tmp_auth(void *tmp, unsigned int offset)
return tmp + offset;
}
-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
- unsigned int offset)
+static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset)
{
- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+ return tmp + offset;
}
static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
@@ -127,9 +124,14 @@ static void ah_output_done(void *data, int err)
struct iphdr *top_iph = ip_hdr(skb);
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
int ihl = ip_hdrlen(skb);
+ int seqhi_len = 0;
+ __be32 *seqhi;
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
iph = AH_SKB_CB(skb)->tmp;
- icv = ah_tmp_icv(ahp->ahash, iph, ihl);
+ seqhi = (__be32 *)((char *)iph + ihl);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
top_iph->tos = iph->tos;
@@ -182,7 +184,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
if (!iph)
goto out;
seqhi = (__be32 *)((char *)iph + ihl);
- icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
req = ah_tmp_req(ahash, icv);
sg = ah_req_sg(ahash, req);
seqhisg = sg + nfrags;
@@ -273,13 +275,18 @@ static void ah_input_done(void *data, int err)
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
int ihl = ip_hdrlen(skb);
int ah_hlen = (ah->hdrlen + 2) << 2;
+ int seqhi_len = 0;
+ __be32 *seqhi;
if (err)
goto out;
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
work_iph = AH_SKB_CB(skb)->tmp;
- auth_data = ah_tmp_auth(work_iph, ihl);
- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+ seqhi = (__be32 *)((char *)work_iph + ihl);
+ auth_data = ah_tmp_auth(seqhi, seqhi_len);
+ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
if (err)
@@ -374,7 +381,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
seqhi = (__be32 *)((char *)work_iph + ihl);
auth_data = ah_tmp_auth(seqhi, seqhi_len);
- icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
req = ah_tmp_req(ahash, icv);
sg = ah_req_sg(ahash, req);
seqhisg = sg + nfrags;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 3171392c8c06..3fcf11f83d87 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -64,6 +64,7 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
+#include <linux/nospec.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
@@ -359,7 +360,9 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
to, len);
skb->csum = csum_block_add(skb->csum, csum, odd);
- if (icmp_pointers[icmp_param->data.icmph.type].error)
+ if (icmp_param->data.icmph.type <= NR_ICMP_TYPES &&
+ icmp_pointers[array_index_nospec(icmp_param->data.icmph.type,
+ NR_ICMP_TYPES + 1)].error)
nf_ct_attach(skb, icmp_param->skb);
return 0;
}
@@ -515,6 +518,9 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
if (!IS_ERR(rt)) {
if (rt != rt2)
return rt;
+ if (inet_addr_type_dev_table(net, route_lookup_dev,
+ fl4->daddr) == RTN_LOCAL)
+ return rt;
} else if (PTR_ERR(rt) == -EPERM) {
rt = NULL;
} else
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 7ac315b93bc6..a6f9192b4e53 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -1429,16 +1429,19 @@ void inet_csk_listen_stop(struct sock *sk)
if (nreq) {
refcount_set(&nreq->rsk_refcnt, 1);
+ rcu_read_lock();
if (inet_csk_reqsk_queue_add(nsk, nreq, child)) {
__NET_INC_STATS(sock_net(nsk),
LINUX_MIB_TCPMIGRATEREQSUCCESS);
reqsk_migrate_reset(req);
+ READ_ONCE(nsk->sk_data_ready)(nsk);
} else {
__NET_INC_STATS(sock_net(nsk),
LINUX_MIB_TCPMIGRATEREQFAILURE);
reqsk_migrate_reset(nreq);
__reqsk_free(nreq);
}
+ rcu_read_unlock();
/* inet_csk_reqsk_queue_add() has already
* called inet_child_forget() on failure case.
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 5361e2107458..c6f1ad058dd2 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -79,9 +79,7 @@ static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
{
unsigned int len;
- len = size + crypto_ahash_digestsize(ahash) +
- (crypto_ahash_alignmask(ahash) &
- ~(crypto_tfm_ctx_alignment() - 1));
+ len = size + crypto_ahash_digestsize(ahash);
len = ALIGN(len, crypto_tfm_ctx_alignment());
@@ -103,10 +101,9 @@ static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset)
return tmp + offset;
}
-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
- unsigned int offset)
+static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset)
{
- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+ return tmp + offset;
}
static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
@@ -320,14 +317,19 @@ static void ah6_output_done(void *data, int err)
struct ipv6hdr *top_iph = ipv6_hdr(skb);
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
struct tmp_ext *iph_ext;
+ int seqhi_len = 0;
+ __be32 *seqhi;
extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
if (extlen)
extlen += sizeof(*iph_ext);
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
iph_base = AH_SKB_CB(skb)->tmp;
iph_ext = ah_tmp_ext(iph_base);
- icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
+ seqhi = (__be32 *)((char *)iph_ext + extlen);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
@@ -384,7 +386,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
iph_ext = ah_tmp_ext(iph_base);
seqhi = (__be32 *)((char *)iph_ext + extlen);
- icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
req = ah_tmp_req(ahash, icv);
sg = ah_req_sg(ahash, req);
seqhisg = sg + nfrags;
@@ -474,13 +476,18 @@ static void ah6_input_done(void *data, int err)
struct ip_auth_hdr *ah = ip_auth_hdr(skb);
int hdr_len = skb_network_header_len(skb);
int ah_hlen = ipv6_authlen(ah);
+ int seqhi_len = 0;
+ __be32 *seqhi;
if (err)
goto out;
+ if (x->props.flags & XFRM_STATE_ESN)
+ seqhi_len = sizeof(*seqhi);
work_iph = AH_SKB_CB(skb)->tmp;
auth_data = ah_tmp_auth(work_iph, hdr_len);
- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+ seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
if (err)
@@ -588,7 +595,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
- icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
+ icv = ah_tmp_icv(seqhi, seqhi_len);
req = ah_tmp_req(ahash, icv);
sg = ah_req_sg(ahash, req);
seqhisg = sg + nfrags;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index a8790163e8b6..54e71623aac9 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -491,6 +491,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
struct net *net = dev_net(skb->dev);
struct inet6_dev *idev;
struct ipv6hdr *oldhdr;
+ unsigned int chdr_len;
unsigned char *buf;
int accept_rpl_seg;
int i, err;
@@ -594,8 +595,10 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
skb_pull(skb, ((hdr->hdrlen + 1) << 3));
skb_postpull_rcsum(skb, oldhdr,
sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
- if (unlikely(!hdr->segments_left)) {
- if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
+ chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3);
+ if (unlikely(!hdr->segments_left ||
+ skb_headroom(skb) < chdr_len + skb->mac_len)) {
+ if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0,
GFP_ATOMIC)) {
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
@@ -605,7 +608,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
oldhdr = ipv6_hdr(skb);
}
- skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
+ skb_push(skb, chdr_len);
skb_reset_network_header(skb);
skb_mac_header_rebuild(skb);
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 63ac4a8e095b..b10d2e59d8c4 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -2299,10 +2299,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
- struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
+ struct ip6_tnl *t = netdev_priv(dev);
struct __ip6_tnl_parm p;
- struct ip6_tnl *t;
+ struct ip6gre_net *ign;
+ ign = net_generic(t->net, ip6gre_net_id);
t = ip6gre_changelink_common(dev, tb, data, &p, extack);
if (IS_ERR(t))
return PTR_ERR(t);
diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c
index 523aa8c9b382..702509dffd7c 100644
--- a/net/ipv6/rpl_iptunnel.c
+++ b/net/ipv6/rpl_iptunnel.c
@@ -282,7 +282,16 @@ static int rpl_input(struct sk_buff *skb)
if (!dst) {
ip6_route_input(skb);
+
+ /* ip6_route_input() sets a NOREF dst; force a refcount on it
+ * before caching or further use.
+ */
+ skb_dst_force(skb);
dst = skb_dst(skb);
+ if (unlikely(!dst)) {
+ err = -ENETUNREACH;
+ goto drop;
+ }
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 50bc05b85329..6fb1f99c5412 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -496,7 +496,16 @@ static int seg6_input_core(struct net *net, struct sock *sk,
if (!dst) {
ip6_route_input(skb);
+
+ /* ip6_route_input() sets a NOREF dst; force a refcount on it
+ * before caching or further use.
+ */
+ skb_dst_force(skb);
dst = skb_dst(skb);
+ if (unlikely(!dst)) {
+ err = -ENETUNREACH;
+ goto drop;
+ }
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
@@ -711,7 +720,8 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
newts->type = LWTUNNEL_ENCAP_SEG6;
newts->flags |= LWTUNNEL_STATE_INPUT_REDIRECT;
- if (tuninfo->mode != SEG6_IPTUN_MODE_L2ENCAP)
+ if (tuninfo->mode != SEG6_IPTUN_MODE_L2ENCAP &&
+ tuninfo->mode != SEG6_IPTUN_MODE_L2ENCAP_RED)
newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT;
newts->headroom = seg6_lwt_headroom(tuninfo);
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c
index ea2f805d3b01..9b586fcec485 100644
--- a/net/ipv6/xfrm6_protocol.c
+++ b/net/ipv6/xfrm6_protocol.c
@@ -88,8 +88,10 @@ int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
dst = ip6_route_input_lookup(dev_net(skb->dev), skb->dev, &fl6,
skb, flags);
- if (dst->error)
+ if (dst->error) {
+ dst_release(dst);
goto drop;
+ }
skb_dst_set(skb, dst);
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 77da0bd5891e..496f2b36a0be 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6940,7 +6940,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss = (void *)cbss->priv;
struct sta_info *new_sta = NULL;
struct ieee80211_link_data *link;
- bool have_sta = false;
+ struct sta_info *have_sta = NULL;
bool mlo;
int err;
@@ -6978,11 +6978,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
goto out_err;
}
- if (assoc) {
- rcu_read_lock();
+ if (assoc)
have_sta = sta_info_get(sdata, ap_mld_addr);
- rcu_read_unlock();
- }
if (!have_sta) {
if (mlo)
@@ -7106,6 +7103,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
out_release_chan:
ieee80211_link_release_channel(link);
out_err:
+ if (mlo && have_sta)
+ WARN_ON(__sta_info_destroy(have_sta));
ieee80211_vif_set_links(sdata, 0, 0);
return err;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6bfd262dce26..a716a055bff9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4820,7 +4820,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
struct sk_buff *skb = rx->skb;
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- static ieee80211_rx_result res;
+ ieee80211_rx_result res;
int orig_len = skb->len;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
int snap_offs = hdrlen;
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 59fbc54d8e66..a565cf2bc733 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -335,6 +335,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
unsigned long f;
u8 tag, flags;
int rc;
+ u8 ver;
msk = NULL;
rc = -EINVAL;
@@ -357,7 +358,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
mh = mctp_hdr(skb);
skb_pull(skb, sizeof(struct mctp_hdr));
- if (mh->ver != 1)
+ ver = mh->ver & MCTP_HDR_VER_MASK;
+ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
goto out;
flags = mh->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
@@ -1124,6 +1126,7 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
struct mctp_skb_cb *cb;
struct mctp_route *rt;
struct mctp_hdr *mh;
+ u8 ver;
rcu_read_lock();
mdev = __mctp_dev_get(dev);
@@ -1141,7 +1144,8 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
/* We have enough for a header; decode and route */
mh = mctp_hdr(skb);
- if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
+ ver = mh->ver & MCTP_HDR_VER_MASK;
+ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
goto err_drop;
/* source must be valid unicast or null; drop reserved ranges and
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 6bf6bd741cba..71995d00696e 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3177,7 +3177,8 @@ bool __mptcp_close(struct sock *sk, long timeout)
goto cleanup;
}
- if (mptcp_data_avail(msk) || timeout < 0) {
+ if (mptcp_data_avail(msk) || timeout < 0 ||
+ (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
/* If the msk has read data, or the caller explicitly ask it,
* do the MPTCP equivalent of TCP reset, aka MPTCP fastclose
*/
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index b31ba9f905e3..b5bf47218a18 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -159,10 +159,10 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct mptcp_sock *msk, int optnam
lock_sock(sk);
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
- bool slow = lock_sock_fast(ssk);
- sock_set_timestamp(sk, optname, !!val);
- unlock_sock_fast(ssk, slow);
+ lock_sock(ssk);
+ sock_set_timestamp(ssk, optname, !!val);
+ release_sock(ssk);
}
release_sock(sk);
@@ -235,10 +235,10 @@ static int mptcp_setsockopt_sol_socket_timestamping(struct mptcp_sock *msk,
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
- bool slow = lock_sock_fast(ssk);
- sock_set_timestamping(sk, optname, timestamping);
- unlock_sock_fast(ssk, slow);
+ lock_sock(ssk);
+ sock_set_timestamping(ssk, optname, timestamping);
+ release_sock(ssk);
}
release_sock(sk);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 36c6d76f18df..49be98ffd1de 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -558,7 +558,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
subflow->backup);
if (!subflow_thmac_valid(subflow)) {
- MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC);
+ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKMAC);
subflow->reset_reason = MPTCP_RST_EMPTCP;
goto do_reset;
}
@@ -885,7 +885,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
if (!subflow_hmac_valid(req, &mp_opt)) {
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
- subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT);
+ subflow_add_reset_reason(skb, MPTCP_RST_EMPTCP);
goto dispose_child;
}
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 7de95674fd8c..2cfb0104680c 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -149,7 +149,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
if (err < 0)
return err;
- if (priv->data.data[0] >= BITS_PER_TYPE(u32)) {
+ if (!priv->data.data[0] ||
+ priv->data.data[0] >= BITS_PER_TYPE(u32)) {
nft_data_release(&priv->data, desc.type);
return -EINVAL;
}
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index 68d38c12427c..ca9cee48d152 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -189,9 +189,13 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
*/
if (vport->dev->reg_state == NETREG_REGISTERED)
rtnl_delete_link(vport->dev, 0, NULL);
- rtnl_unlock();
+ /* We can't put the device reference yet, since it can still be in
+ * use, but rtnl_unlock()->netdev_run_todo() will block until all
+ * the references are released, so the RCU call must be before it.
+ */
call_rcu(&vport->rcu, vport_netdev_free);
+ rtnl_unlock();
}
EXPORT_SYMBOL_GPL(ovs_netdev_tunnel_destroy);
diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
index 654a3cc0d347..ecf49172307f 100644
--- a/net/qrtr/ns.c
+++ b/net/qrtr/ns.c
@@ -22,8 +22,10 @@ static struct {
struct socket *sock;
struct sockaddr_qrtr bcast_sq;
struct list_head lookups;
+ u32 lookup_count;
struct workqueue_struct *workqueue;
struct work_struct work;
+ void (*saved_data_ready)(struct sock *sk);
int local_node;
} qrtr_ns;
@@ -67,8 +69,26 @@ struct qrtr_server {
struct qrtr_node {
unsigned int id;
struct xarray servers;
+ u32 server_count;
};
+/* Max server limit is chosen based on the current platform requirements. If the
+ * requirement changes in the future, this value can be increased.
+ */
+#define QRTR_NS_MAX_SERVERS 256
+
+/* Max lookup limit is chosen based on the current platform requirements. If the
+ * requirement changes in the future, this value can be increased.
+ */
+#define QRTR_NS_MAX_LOOKUPS 64
+
+/* Max nodes limit is chosen based on the current platform requirements.
+ * If the requirement changes in the future, this value can be increased.
+ */
+#define QRTR_NS_MAX_NODES 64
+
+static u8 node_count;
+
static struct qrtr_node *node_get(unsigned int node_id)
{
struct qrtr_node *node;
@@ -77,6 +97,11 @@ static struct qrtr_node *node_get(unsigned int node_id)
if (node)
return node;
+ if (node_count >= QRTR_NS_MAX_NODES) {
+ pr_err_ratelimited("QRTR clients exceed max node limit!\n");
+ return NULL;
+ }
+
/* If node didn't exist, allocate and insert it to the tree */
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
@@ -90,6 +115,8 @@ static struct qrtr_node *node_get(unsigned int node_id)
return NULL;
}
+ node_count++;
+
return node;
}
@@ -226,6 +253,17 @@ static struct qrtr_server *server_add(unsigned int service,
if (!service || !port)
return NULL;
+ node = node_get(node_id);
+ if (!node)
+ return NULL;
+
+ /* Make sure the new servers per port are capped at the maximum value */
+ old = xa_load(&node->servers, port);
+ if (!old && node->server_count >= QRTR_NS_MAX_SERVERS) {
+ pr_err_ratelimited("QRTR client node %u exceeds max server limit!\n", node_id);
+ return NULL;
+ }
+
srv = kzalloc(sizeof(*srv), GFP_KERNEL);
if (!srv)
return NULL;
@@ -235,10 +273,6 @@ static struct qrtr_server *server_add(unsigned int service,
srv->node = node_id;
srv->port = port;
- node = node_get(node_id);
- if (!node)
- goto err;
-
/* Delete the old server on the same port */
old = xa_store(&node->servers, port, srv, GFP_KERNEL);
if (old) {
@@ -249,6 +283,8 @@ static struct qrtr_server *server_add(unsigned int service,
} else {
kfree(old);
}
+ } else {
+ node->server_count++;
}
trace_qrtr_ns_server_add(srv->service, srv->instance,
@@ -289,6 +325,7 @@ static int server_del(struct qrtr_node *node, unsigned int port, bool bcast)
}
kfree(srv);
+ node->server_count--;
return 0;
}
@@ -338,7 +375,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
struct qrtr_node *node;
unsigned long index;
struct kvec iv;
- int ret;
+ int ret = 0;
iv.iov_base = &pkt;
iv.iov_len = sizeof(pkt);
@@ -353,8 +390,10 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
/* Advertise the removal of this client to all local servers */
local_node = node_get(qrtr_ns.local_node);
- if (!local_node)
- return 0;
+ if (!local_node) {
+ ret = 0;
+ goto delete_node;
+ }
memset(&pkt, 0, sizeof(pkt));
pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
@@ -371,10 +410,19 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
if (ret < 0) {
pr_err("failed to send bye cmd\n");
- return ret;
+ goto delete_node;
}
}
- return 0;
+
+ /* Ignore -ENODEV */
+ ret = 0;
+
+delete_node:
+ xa_erase(&nodes, from->sq_node);
+ kfree(node);
+ node_count--;
+
+ return ret;
}
static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
@@ -414,6 +462,7 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
list_del(&lookup->li);
kfree(lookup);
+ qrtr_ns.lookup_count--;
}
/* Remove the server belonging to this port but don't broadcast
@@ -531,6 +580,11 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
if (from->sq_node != qrtr_ns.local_node)
return -EINVAL;
+ if (qrtr_ns.lookup_count >= QRTR_NS_MAX_LOOKUPS) {
+ pr_err_ratelimited("QRTR client node exceeds max lookup limit!\n");
+ return -ENOSPC;
+ }
+
lookup = kzalloc(sizeof(*lookup), GFP_KERNEL);
if (!lookup)
return -ENOMEM;
@@ -539,6 +593,7 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
lookup->service = service;
lookup->instance = instance;
list_add_tail(&lookup->li, &qrtr_ns.lookups);
+ qrtr_ns.lookup_count++;
memset(&filter, 0, sizeof(filter));
filter.service = service;
@@ -579,6 +634,7 @@ static void ctrl_cmd_del_lookup(struct sockaddr_qrtr *from,
list_del(&lookup->li);
kfree(lookup);
+ qrtr_ns.lookup_count--;
}
}
@@ -667,7 +723,7 @@ static void qrtr_ns_worker(struct work_struct *work)
}
if (ret < 0)
- pr_err("failed while handling packet from %d:%d",
+ pr_err_ratelimited("failed while handling packet from %d:%d",
sq.sq_node, sq.sq_port);
}
@@ -706,6 +762,7 @@ int qrtr_ns_init(void)
goto err_sock;
}
+ qrtr_ns.saved_data_ready = qrtr_ns.sock->sk->sk_data_ready;
qrtr_ns.sock->sk->sk_data_ready = qrtr_ns_data_ready;
sq.sq_port = QRTR_PORT_CTRL;
@@ -746,6 +803,10 @@ int qrtr_ns_init(void)
return 0;
err_wq:
+ write_lock_bh(&qrtr_ns.sock->sk->sk_callback_lock);
+ qrtr_ns.sock->sk->sk_data_ready = qrtr_ns.saved_data_ready;
+ write_unlock_bh(&qrtr_ns.sock->sk->sk_callback_lock);
+
destroy_workqueue(qrtr_ns.workqueue);
err_sock:
sock_release(qrtr_ns.sock);
@@ -755,7 +816,12 @@ EXPORT_SYMBOL_GPL(qrtr_ns_init);
void qrtr_ns_remove(void)
{
+ write_lock_bh(&qrtr_ns.sock->sk->sk_callback_lock);
+ qrtr_ns.sock->sk->sk_data_ready = qrtr_ns.saved_data_ready;
+ write_unlock_bh(&qrtr_ns.sock->sk->sk_callback_lock);
+
cancel_work_sync(&qrtr_ns.work);
+ synchronize_net();
destroy_workqueue(qrtr_ns.workqueue);
/* sock_release() expects the two references that were put during
diff --git a/net/rds/message.c b/net/rds/message.c
index 7af59d2443e5..921d89973b93 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -129,24 +129,34 @@ static void rds_rm_zerocopy_callback(struct rds_sock *rs,
*/
static void rds_message_purge(struct rds_message *rm)
{
+ struct rds_znotifier *znotifier;
unsigned long i, flags;
- bool zcopy = false;
+ bool zcopy;
if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
return;
spin_lock_irqsave(&rm->m_rs_lock, flags);
+ znotifier = rm->data.op_mmp_znotifier;
+ rm->data.op_mmp_znotifier = NULL;
+ zcopy = !!znotifier;
+
if (rm->m_rs) {
struct rds_sock *rs = rm->m_rs;
- if (rm->data.op_mmp_znotifier) {
- zcopy = true;
- rds_rm_zerocopy_callback(rs, rm->data.op_mmp_znotifier);
+ if (znotifier) {
+ rds_rm_zerocopy_callback(rs, znotifier);
rds_wake_sk_sleep(rs);
- rm->data.op_mmp_znotifier = NULL;
}
sock_put(rds_rs_to_sk(rs));
rm->m_rs = NULL;
+ } else if (znotifier) {
+ /*
+ * Zerocopy can fail before the message is queued on the
+ * socket, so there is no rs to carry the notification.
+ */
+ mm_unaccount_pinned_pages(&znotifier->z_mmp);
+ kfree(rds_info_from_znotifier(znotifier));
}
spin_unlock_irqrestore(&rm->m_rs_lock, flags);
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index 00dbcd4d28e6..34d9333e4229 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -326,10 +326,6 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
if (args->cookie_addr &&
put_user(cookie, (u64 __user *)(unsigned long)args->cookie_addr)) {
- if (!need_odp) {
- unpin_user_pages(pages, nr_pages);
- kfree(sg);
- }
ret = -EFAULT;
goto out;
}
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index f4512761f572..1db479f3d6d3 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -1269,7 +1269,6 @@ int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);
void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
-void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_purge_queue(struct sk_buff_head *);
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
index 0f78544d043b..07b2d81145d6 100644
--- a/net/rxrpc/call_event.c
+++ b/net/rxrpc/call_event.c
@@ -456,8 +456,31 @@ bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
resend = true;
}
- if (skb)
- rxrpc_input_call_packet(call, skb);
+ if (skb) {
+ struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+ if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
+ sp->hdr.securityIndex != 0 &&
+ (skb_cloned(skb) ||
+ skb_has_frag_list(skb) ||
+ skb_has_shared_frag(skb))) {
+ /* Unshare the packet so that it can be modified by
+ * in-place decryption.
+ */
+ struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
+
+ if (nskb) {
+ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
+ rxrpc_input_call_packet(call, nskb);
+ rxrpc_free_skb(nskb, rxrpc_skb_put_input);
+ } else {
+ /* OOM - Drop the packet. */
+ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
+ }
+ } else {
+ rxrpc_input_call_packet(call, skb);
+ }
+ }
rxrpc_transmit_some_data(call);
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 6ef2dc1aa8cc..3a58fb921038 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -226,6 +226,34 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
rxrpc_notify_socket(call);
}
+static int rxrpc_verify_response(struct rxrpc_connection *conn,
+ struct sk_buff *skb)
+{
+ int ret;
+
+ if (skb_cloned(skb) || skb_has_frag_list(skb) ||
+ skb_has_shared_frag(skb)) {
+ /* Copy the packet if shared so that we can do in-place
+ * decryption.
+ */
+ struct sk_buff *nskb = skb_copy(skb, GFP_NOFS);
+
+ if (nskb) {
+ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared);
+ ret = conn->security->verify_response(conn, nskb);
+ rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy);
+ } else {
+ /* OOM - Drop the packet. */
+ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem);
+ ret = -ENOMEM;
+ }
+ } else {
+ ret = conn->security->verify_response(conn, skb);
+ }
+
+ return ret;
+}
+
/*
* connection-level Rx packet processor
*/
@@ -253,7 +281,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
}
spin_unlock(&conn->state_lock);
- ret = conn->security->verify_response(conn, skb);
+ ret = rxrpc_verify_response(conn, skb);
if (ret < 0)
return ret;
@@ -344,7 +372,6 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
{
struct sk_buff *skb;
- int ret;
if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
rxrpc_secure_connection(conn);
@@ -353,17 +380,8 @@ static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
* connection that each one has when we've finished with it */
while ((skb = skb_dequeue(&conn->rx_queue))) {
rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
- ret = rxrpc_process_event(conn, skb);
- switch (ret) {
- case -ENOMEM:
- case -EAGAIN:
- skb_queue_head(&conn->rx_queue, skb);
- rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
- break;
- default:
- rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
- break;
- }
+ rxrpc_process_event(conn, skb);
+ rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
}
}
diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
index 0491f2bbf61e..f542eda13ff0 100644
--- a/net/rxrpc/io_thread.c
+++ b/net/rxrpc/io_thread.c
@@ -167,13 +167,12 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)
/*
* Process packets received on the local endpoint
*/
-static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
+static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb)
{
struct rxrpc_connection *conn;
struct sockaddr_rxrpc peer_srx;
struct rxrpc_skb_priv *sp;
struct rxrpc_peer *peer = NULL;
- struct sk_buff *skb = *_skb;
bool ret = false;
skb_pull(skb, sizeof(struct udphdr));
@@ -219,25 +218,6 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
if (sp->hdr.seq == 0)
return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq);
-
- /* Unshare the packet so that it can be modified for in-place
- * decryption.
- */
- if (sp->hdr.securityIndex != 0) {
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (!skb) {
- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
- *_skb = NULL;
- return just_discard;
- }
-
- if (skb != *_skb) {
- rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare);
- *_skb = skb;
- rxrpc_new_skb(skb, rxrpc_skb_new_unshared);
- sp = rxrpc_skb(skb);
- }
- }
break;
case RXRPC_PACKET_TYPE_CHALLENGE:
@@ -479,7 +459,7 @@ int rxrpc_io_thread(void *data)
switch (skb->mark) {
case RXRPC_SKB_MARK_PACKET:
skb->priority = 0;
- if (!rxrpc_input_packet(local, &skb))
+ if (!rxrpc_input_packet(local, skb))
rxrpc_reject_packet(local, skb);
trace_rxrpc_rx_done(skb->mark, skb->priority);
rxrpc_free_skb(skb, rxrpc_skb_put_input);
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 149939d19b00..e2119af55250 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -492,6 +492,9 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
rxkad_abort_2_short_header);
+ /* Don't let the crypto algo see a misaligned length. */
+ sp->len = round_down(sp->len, 8);
+
/* Decrypt the skbuff in-place. TODO: We really want to decrypt
* directly into the target buffer.
*/
@@ -525,8 +528,10 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
if (sg != _sg)
kfree(sg);
if (ret < 0) {
- WARN_ON_ONCE(ret != -ENOMEM);
- return ret;
+ if (ret == -ENOMEM)
+ return ret;
+ return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+ rxkad_abort_2_crypto_unaligned);
}
/* Extract the decrypted packet length */
@@ -1047,7 +1052,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
struct rxrpc_crypt session_key;
struct key *server_key;
time64_t expiry;
- void *ticket;
+ void *ticket = NULL;
u32 version, kvno, ticket_len, level;
__be32 csum;
int ret, i;
@@ -1073,13 +1078,13 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
ret = -ENOMEM;
response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
if (!response)
- goto temporary_error;
+ goto error;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
response, sizeof(*response)) < 0) {
- rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
- rxkad_abort_resp_short);
- goto protocol_error;
+ ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
+ rxkad_abort_resp_short);
+ goto error;
}
version = ntohl(response->version);
@@ -1089,62 +1094,62 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
trace_rxrpc_rx_response(conn, sp->hdr.serial, version, kvno, ticket_len);
if (version != RXKAD_VERSION) {
- rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
- rxkad_abort_resp_version);
- goto protocol_error;
+ ret = rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
+ rxkad_abort_resp_version);
+ goto error;
}
if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN) {
- rxrpc_abort_conn(conn, skb, RXKADTICKETLEN, -EPROTO,
- rxkad_abort_resp_tkt_len);
- goto protocol_error;
+ ret = rxrpc_abort_conn(conn, skb, RXKADTICKETLEN, -EPROTO,
+ rxkad_abort_resp_tkt_len);
+ goto error;
}
if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5) {
- rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, -EPROTO,
- rxkad_abort_resp_unknown_tkt);
- goto protocol_error;
+ ret = rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, -EPROTO,
+ rxkad_abort_resp_unknown_tkt);
+ goto error;
}
/* extract the kerberos ticket and decrypt and decode it */
ret = -ENOMEM;
ticket = kmalloc(ticket_len, GFP_NOFS);
if (!ticket)
- goto temporary_error_free_resp;
+ goto error;
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response),
ticket, ticket_len) < 0) {
- rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
- rxkad_abort_resp_short_tkt);
- goto protocol_error;
+ ret = rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
+ rxkad_abort_resp_short_tkt);
+ goto error;
}
ret = rxkad_decrypt_ticket(conn, server_key, skb, ticket, ticket_len,
&session_key, &expiry);
if (ret < 0)
- goto temporary_error_free_ticket;
+ goto error;
/* use the session key from inside the ticket to decrypt the
* response */
ret = rxkad_decrypt_response(conn, response, &session_key);
if (ret < 0)
- goto temporary_error_free_ticket;
+ goto error;
if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
ntohl(response->encrypted.cid) != conn->proto.cid ||
ntohl(response->encrypted.securityIndex) != conn->security_ix) {
- rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
- rxkad_abort_resp_bad_param);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+ rxkad_abort_resp_bad_param);
+ goto error;
}
csum = response->encrypted.checksum;
response->encrypted.checksum = 0;
rxkad_calc_response_checksum(response);
if (response->encrypted.checksum != csum) {
- rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
- rxkad_abort_resp_bad_checksum);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+ rxkad_abort_resp_bad_checksum);
+ goto error;
}
for (i = 0; i < RXRPC_MAXCALLS; i++) {
@@ -1152,38 +1157,38 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
u32 counter = READ_ONCE(conn->channels[i].call_counter);
if (call_id > INT_MAX) {
- rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
- rxkad_abort_resp_bad_callid);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+ rxkad_abort_resp_bad_callid);
+ goto error;
}
if (call_id < counter) {
- rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
- rxkad_abort_resp_call_ctr);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+ rxkad_abort_resp_call_ctr);
+ goto error;
}
if (call_id > counter) {
if (conn->channels[i].call) {
- rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+ ret = rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
rxkad_abort_resp_call_state);
- goto protocol_error_free;
+ goto error;
}
conn->channels[i].call_counter = call_id;
}
}
if (ntohl(response->encrypted.inc_nonce) != conn->rxkad.nonce + 1) {
- rxrpc_abort_conn(conn, skb, RXKADOUTOFSEQUENCE, -EPROTO,
- rxkad_abort_resp_ooseq);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADOUTOFSEQUENCE, -EPROTO,
+ rxkad_abort_resp_ooseq);
+ goto error;
}
level = ntohl(response->encrypted.level);
if (level > RXRPC_SECURITY_ENCRYPT) {
- rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EPROTO,
- rxkad_abort_resp_level);
- goto protocol_error_free;
+ ret = rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EPROTO,
+ rxkad_abort_resp_level);
+ goto error;
}
conn->security_level = level;
@@ -1191,31 +1196,12 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
* this the connection security can be handled in exactly the same way
* as for a client connection */
ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
- if (ret < 0)
- goto temporary_error_free_ticket;
-
- kfree(ticket);
- kfree(response);
- _leave(" = 0");
- return 0;
-protocol_error_free:
- kfree(ticket);
-protocol_error:
- kfree(response);
- key_put(server_key);
- return -EPROTO;
-
-temporary_error_free_ticket:
+error:
kfree(ticket);
-temporary_error_free_resp:
kfree(response);
-temporary_error:
- /* Ignore the response packet if we got a temporary error such as
- * ENOMEM. We just want to send the challenge again. Note that we
- * also come out this way if the ticket decryption fails.
- */
key_put(server_key);
+ _leave(" = %d", ret);
return ret;
}
diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c
index 3bcd6ee80396..e2169d1a14b5 100644
--- a/net/rxrpc/skbuff.c
+++ b/net/rxrpc/skbuff.c
@@ -46,15 +46,6 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)
skb_get(skb);
}
-/*
- * Note the dropping of a ref on a socket buffer by the core.
- */
-void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace why)
-{
- int n = atomic_inc_return(&rxrpc_n_rx_skbs);
- trace_rxrpc_skb(skb, 0, n, why);
-}
-
/*
* Note the destruction of a socket buffer.
*/
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 3c6b4460cf2c..ea3580d1d19e 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -153,7 +153,7 @@ static struct sk_buff *red_dequeue(struct Qdisc *sch)
struct red_sched_data *q = qdisc_priv(sch);
struct Qdisc *child = q->qdisc;
- skb = child->dequeue(child);
+ skb = qdisc_dequeue_peeked(child);
if (skb) {
qdisc_bstats_update(sch, skb);
qdisc_qstats_backlog_dec(sch, skb);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 852c4f66eab5..b3c19210667f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1985,6 +1985,15 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
goto out_unlock;
iov_iter_revert(&msg->msg_iter, err);
+
+ /* sctp_sendmsg_to_asoc() may have released the socket
+ * lock (sctp_wait_for_sndbuf), during which other
+ * associations on ep->asocs could have been peeled
+ * off or freed. @asoc itself is revalidated by the
+ * base.dead and base.sk checks in sctp_wait_for_sndbuf,
+ * so re-derive the cached cursor from it.
+ */
+ tmp = list_next_entry(asoc, asocs);
}
goto out_unlock;
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index 2f748226f143..1bf6cd010f04 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -784,8 +784,8 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
dclc = (struct smc_clc_msg_decline *)clcm;
reason_code = SMC_CLC_DECL_PEERDECL;
smc->peer_diagnosis = ntohl(dclc->peer_diagnosis);
- if (((struct smc_clc_msg_decline *)buf)->hdr.typev2 &
- SMC_FIRST_CONTACT_MASK) {
+ if ((dclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK) &&
+ smc->conn.lgr) {
smc->conn.lgr->sync_err = 1;
smc_lgr_terminate_sched(smc->conn.lgr);
}
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
index b61384b08e7c..2a805c964210 100644
--- a/net/strparser/strparser.c
+++ b/net/strparser/strparser.c
@@ -45,6 +45,14 @@ static void strp_abort_strp(struct strparser *strp, int err)
strp->stopped = 1;
+ if (strp->skb_head) {
+ kfree_skb(strp->skb_head);
+ strp->skb_head = NULL;
+ }
+
+ strp->skb_nextp = NULL;
+ strp->need_bytes = 0;
+
if (strp->sk) {
struct sock *sk = strp->sk;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6bc7aef06a5b..651c7debe799 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2807,6 +2807,9 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
goto out;
}
+ if (sk->sk_type != SOCK_STREAM)
+ return -EOPNOTSUPP;
+
mutex_lock(&u->iolock);
goto redo;
unlock:
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index ca1289e64bcc..187cc259f820 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -1728,12 +1728,12 @@ static void vsock_update_buffer_size(struct vsock_sock *vsk,
const struct vsock_transport *transport,
u64 val)
{
- if (val > vsk->buffer_max_size)
- val = vsk->buffer_max_size;
-
if (val < vsk->buffer_min_size)
val = vsk->buffer_min_size;
+ if (val > vsk->buffer_max_size)
+ val = vsk->buffer_max_size;
+
if (val != vsk->buffer_size &&
transport && transport->notify_buffer_size)
transport->notify_buffer_size(vsk, &val);
diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index 56c232cf5b0f..34871ed1a099 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -375,10 +375,10 @@ static void hvs_open_connection(struct vmbus_channel *chan)
} else {
sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE);
sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE);
- sndbuf = ALIGN(sndbuf, HV_HYP_PAGE_SIZE);
+ sndbuf = VMBUS_RING_SIZE(sndbuf);
rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE);
rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE);
- rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE);
+ rcvbuf = VMBUS_RING_SIZE(rcvbuf);
}
chan->max_pkt_size = HVS_MAX_PKT_SIZE;
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 4c374c36c29d..f5eb68145ca1 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -122,12 +122,12 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
size_t payload_len;
void *payload_buf;
- /* A packet could be split to fit the RX buffer, so we can retrieve
- * the payload length from the header and the buffer pointer taking
- * care of the offset in the original packet.
+ /* A packet could be split to fit the RX buffer, so we use
+ * the payload length from the header, which has been updated
+ * by the sender to reflect the fragment size.
*/
pkt_hdr = virtio_vsock_hdr(pkt);
- payload_len = pkt->len;
+ payload_len = le32_to_cpu(pkt_hdr->len);
payload_buf = pkt->data;
skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len,
@@ -1353,8 +1353,6 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
return -ENOMEM;
}
- sk_acceptq_added(sk);
-
lock_sock_nested(child, SINGLE_DEPTH_NESTING);
child->sk_state = TCP_ESTABLISHED;
@@ -1376,6 +1374,7 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
return ret;
}
+ sk_acceptq_added(sk);
if (virtio_transport_space_update(child, skb))
child->sk_write_space(child);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index ca42c9b8cecc..8ba31cf9b319 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -752,12 +752,12 @@ int __xfrm_state_delete(struct xfrm_state *x)
x->km.state = XFRM_STATE_DEAD;
spin_lock(&net->xfrm.xfrm_state_lock);
list_del(&x->km.all);
- hlist_del_rcu(&x->bydst);
- hlist_del_rcu(&x->bysrc);
- if (x->km.seq)
- hlist_del_rcu(&x->byseq);
- if (x->id.spi)
- hlist_del_rcu(&x->byspi);
+ hlist_del_init_rcu(&x->bydst);
+ hlist_del_init_rcu(&x->bysrc);
+ if (!hlist_unhashed(&x->byseq))
+ hlist_del_init_rcu(&x->byseq);
+ if (!hlist_unhashed(&x->byspi))
+ hlist_del_init_rcu(&x->byspi);
net->xfrm.state_num--;
spin_unlock(&net->xfrm.xfrm_state_lock);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index fd6330984f88..9074434196f4 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -3015,6 +3015,7 @@ const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
[XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
+ [XFRM_MSG_MAPPING - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping),
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
};
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d4a99d98ec77..60092d0b013c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2903,7 +2903,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
{
const struct task_security_struct *tsec = selinux_cred(current_cred());
struct superblock_security_struct *sbsec;
- struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+ struct xattr *xattr;
u32 newsid, clen;
int rc;
char *context;
@@ -2930,6 +2930,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
+ xattr = lsm_get_xattr_slot(xattrs, xattr_count);
if (xattr) {
rc = security_sid_to_context_force(newsid,
&context, &clen);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 54bc18e8164b..3e28fa2444fb 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -272,35 +272,13 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char *page;
- ssize_t length;
- int new_value;
-
- if (count >= PAGE_SIZE)
- return -ENOMEM;
-
- /* No partial writes. */
- if (*ppos != 0)
- return -EINVAL;
-
- page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- if (sscanf(page, "%d", &new_value) != 1) {
- length = -EINVAL;
- goto out;
- }
- length = count;
-
- if (new_value) {
- pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n");
- pr_err("SELinux: Runtime disable is not supported, use selinux=0 on the kernel cmdline.\n");
- }
-
-out:
- kfree(page);
- return length;
+ /*
+ * Setting disable is no longer supported, see
+ * https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable
+ */
+ pr_err_once("SELinux: %s (%d) wrote to disable. This is no longer supported.\n",
+ current->comm, current->pid);
+ return count;
}
static const struct file_operations sel_disable_ops = {
@@ -594,34 +572,31 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (!count)
return -EINVAL;
- mutex_lock(&selinux_state.policy_mutex);
-
length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
if (length)
- goto out;
+ return length;
data = vmalloc(count);
- if (!data) {
- length = -ENOMEM;
- goto out;
- }
+ if (!data)
+ return -ENOMEM;
if (copy_from_user(data, buf, count) != 0) {
length = -EFAULT;
goto out;
}
+ mutex_lock(&selinux_state.policy_mutex);
length = security_load_policy(data, count, &load_state);
if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n");
- goto out;
+ goto out_unlock;
}
fsi = file_inode(file)->i_sb->s_fs_info;
length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) {
pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
selinux_policy_cancel(&load_state);
- goto out;
+ goto out_unlock;
}
selinux_policy_commit(&load_state);
@@ -631,8 +606,9 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
-out:
+out_unlock:
mutex_unlock(&selinux_state.policy_mutex);
+out:
vfree(data);
return length;
}
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index a8a59d71dcec..a714a3f3f6a5 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -121,10 +121,9 @@ static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 l, r;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
@@ -145,15 +144,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
- r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
- mutex_unlock(&onyx->mutex);
+ r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1])
return 0;
- }
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
ucontrol->value.integer.value[0]
@@ -161,7 +158,6 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
ucontrol->value.integer.value[1]
- VOLUME_RANGE_SHIFT);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -197,9 +193,8 @@ static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 ig;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] =
(ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
@@ -216,14 +211,13 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
n = v;
n &= ~ONYX_ADC_PGA_GAIN_MASK;
n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
& ONYX_ADC_PGA_GAIN_MASK;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
- mutex_unlock(&onyx->mutex);
return n != v;
}
@@ -251,9 +245,8 @@ static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
- mutex_unlock(&onyx->mutex);
ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
@@ -264,13 +257,12 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic)
{
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
v &= ~ONYX_ADC_INPUT_MIC;
if (mic)
v |= ONYX_ADC_INPUT_MIC;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
- mutex_unlock(&onyx->mutex);
}
static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
@@ -311,9 +303,8 @@ static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 c;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
@@ -328,9 +319,9 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
u8 v = 0, c = 0;
int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx->analog_locked)
- goto out_unlock;
+ return -EBUSY;
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
c = v;
@@ -341,9 +332,6 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
c |= ONYX_MUTE_RIGHT;
err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -372,9 +360,8 @@ static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, address, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
@@ -393,11 +380,10 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (spdiflock && onyx->spdif_locked) {
/* even if alsamixer doesn't care.. */
- err = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
onyx_read_register(onyx, address, &v);
c = v;
@@ -406,9 +392,6 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
c |= mask;
err = onyx_write_register(onyx, address, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -489,7 +472,7 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
ucontrol->value.iec958.status[0] = v & 0x3e;
@@ -501,7 +484,6 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
ucontrol->value.iec958.status[4] = v & 0x0f;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -512,7 +494,7 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
@@ -527,7 +509,6 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -672,14 +653,13 @@ static int onyx_usable(struct codec_info_item *cii,
struct onyx *onyx = cii->codec_data;
int spdif_enabled, analog_enabled;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
analog_enabled =
(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
!= (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
- mutex_unlock(&onyx->mutex);
switch (ti->tag) {
case 0: return 1;
@@ -695,9 +675,8 @@ static int onyx_prepare(struct codec_info_item *cii,
{
u8 v;
struct onyx *onyx = cii->codec_data;
- int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
@@ -706,10 +685,9 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DAC_CONTROL,
v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
- goto out_unlock;
+ return -EBUSY;
onyx->analog_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
#endif
switch (substream->runtime->rate) {
@@ -719,8 +697,7 @@ static int onyx_prepare(struct codec_info_item *cii,
/* these rates are ok for all outputs */
/* FIXME: program spdif channel control bits here so that
* userspace doesn't have to if it only plays pcm! */
- err = 0;
- goto out_unlock;
+ return 0;
default:
/* got some rate that the digital output can't do,
* so disable and lock it */
@@ -728,16 +705,12 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DIG_INFO4,
v & ~ONYX_SPDIF_ENABLE))
- goto out_unlock;
+ return -EBUSY;
onyx->spdif_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return -EBUSY;
}
static int onyx_open(struct codec_info_item *cii,
@@ -745,9 +718,8 @@ static int onyx_open(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count++;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -757,11 +729,10 @@ static int onyx_close(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count--;
if (!onyx->open_count)
onyx->spdif_locked = onyx->analog_locked = 0;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -771,7 +742,7 @@ static int onyx_switch_clock(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* this *MUST* be more elaborate later... */
switch (what) {
case CLOCK_SWITCH_PREPARE_SLAVE:
@@ -783,7 +754,6 @@ static int onyx_switch_clock(struct codec_info_item *cii,
default: /* silence warning */
break;
}
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -794,27 +764,21 @@ static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
/* Apple does a sleep here but the datasheet says to do it on resume */
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
static int onyx_resume(struct codec_info_item *cii)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* reset codec */
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
@@ -826,17 +790,13 @@ static int onyx_resume(struct codec_info_item *cii)
/* take codec out of suspend (if it still is after reset) */
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
/* FIXME: should divide by sample rate, but 8k is the lowest we go */
msleep(2205000/8000);
/* reset all values */
onyx_register_init(onyx);
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
#endif /* CONFIG_PM */
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index ab1472390061..4446307c095c 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -235,10 +235,9 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->cached_volume_l;
ucontrol->value.integer.value[1] = tas->cached_volume_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -254,18 +253,15 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > 177)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->cached_volume_l == ucontrol->value.integer.value[0]
- && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->cached_volume_r == ucontrol->value.integer.value[1])
return 0;
- }
tas->cached_volume_l = ucontrol->value.integer.value[0];
tas->cached_volume_r = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -285,10 +281,9 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = !tas->mute_l;
ucontrol->value.integer.value[1] = !tas->mute_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -297,18 +292,15 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mute_l == !ucontrol->value.integer.value[0]
- && tas->mute_r == !ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mute_r == !ucontrol->value.integer.value[1])
return 0;
- }
tas->mute_l = !ucontrol->value.integer.value[0];
tas->mute_r = !ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -337,10 +329,9 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->mixer_l[idx];
ucontrol->value.integer.value[1] = tas->mixer_r[idx];
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -351,19 +342,16 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
- && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
return 0;
- }
tas->mixer_l[idx] = ucontrol->value.integer.value[0];
tas->mixer_r[idx] = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_mixer(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -396,9 +384,8 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_range;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -411,16 +398,13 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->drc_range == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_range == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_range = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -440,9 +424,8 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_enabled;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -451,16 +434,13 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
- if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_enabled == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_enabled = !!ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -486,9 +466,8 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -500,7 +479,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] > 1)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
oldacr = tas->acr;
/*
@@ -512,13 +491,10 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0])
tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
TAS_ACR_B_MON_SEL_RIGHT;
- if (oldacr == tas->acr) {
- mutex_unlock(&tas->mtx);
+ if (oldacr == tas->acr)
return 0;
- }
if (tas->hw_enabled)
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -557,9 +533,8 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->treble;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -571,16 +546,13 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->treble == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->treble == ucontrol->value.integer.value[0])
return 0;
- }
tas->treble = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_treble(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -608,9 +580,8 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->bass;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -622,16 +593,13 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->bass == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->bass == ucontrol->value.integer.value[0])
return 0;
- }
tas->bass = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_bass(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -722,13 +690,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
break;
case CLOCK_SWITCH_SLAVE:
/* Clocks are back, re-init the codec */
- mutex_lock(&tas->mtx);
- tas_reset_init(tas);
- tas_set_volume(tas);
- tas_set_mixer(tas);
- tas->hw_enabled = 1;
- tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
- mutex_unlock(&tas->mtx);
+ scoped_guard(mutex, &tas->mtx) {
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
+ tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+ }
break;
default:
/* doesn't happen as of now */
@@ -743,23 +711,21 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
* our i2c device is suspended, and then take note of that! */
static int tas_suspend(struct tas *tas)
{
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas->hw_enabled = 0;
tas->acr |= TAS_ACR_ANALOG_PDOWN;
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 0;
}
static int tas_resume(struct tas *tas)
{
/* reset codec */
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas_reset_init(tas);
tas_set_volume(tas);
tas_set_mixer(tas);
tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -802,14 +768,13 @@ static int tas_init_codec(struct aoa_codec *codec)
return -EINVAL;
}
- mutex_lock(&tas->mtx);
- if (tas_reset_init(tas)) {
- printk(KERN_ERR PFX "tas failed to initialise\n");
- mutex_unlock(&tas->mtx);
- return -ENXIO;
+ scoped_guard(mutex, &tas->mtx) {
+ if (tas_reset_init(tas)) {
+ printk(KERN_ERR PFX "tas failed to initialise\n");
+ return -ENXIO;
+ }
+ tas->hw_enabled = 1;
}
- tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
aoa_get_card(),
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index 39bb409b27f6..19ed0e6907da 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -212,10 +212,9 @@ static void ftr_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(¬if->mutex);
}
static void gpio_enable_dual_edge(int gpio)
@@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!irq)
return -ENODEV;
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify)
@@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
if (err)
- goto out_unlock;
+ return err;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(¬if->mutex);
- return err;
+ return 0;
}
static int ftr_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
index 37866039d1ea..e76bde25e41a 100644
--- a/sound/aoa/core/gpio-pmf.c
+++ b/sound/aoa/core/gpio-pmf.c
@@ -74,10 +74,9 @@ static void pmf_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(¬if->mutex);
}
static void pmf_gpio_init(struct gpio_runtime *rt)
@@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_runtime *rt,
return -EINVAL;
}
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify) {
@@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
irq_client = kzalloc(sizeof(struct pmf_irq_client),
GFP_KERNEL);
- if (!irq_client) {
- err = -ENOMEM;
- goto out_unlock;
- }
+ if (!irq_client)
+ return -ENOMEM;
irq_client->data = notif;
irq_client->handler = pmf_handle_notify_irq;
irq_client->owner = THIS_MODULE;
@@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_runtime *rt,
printk(KERN_ERR "snd-aoa: gpio layer failed to"
" register %s irq (%d)\n", name, err);
kfree(irq_client);
- goto out_unlock;
+ return err;
}
notif->gpio_private = irq_client;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(¬if->mutex);
- return err;
+ return 0;
}
static int pmf_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 51ed2f34b276..14631e65aa70 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -83,6 +83,7 @@ static void i2sbus_release_dev(struct device *dev)
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
free_irq(i2sdev->interrupts[i], i2sdev);
i2sbus_control_remove_dev(i2sdev->control, i2sdev);
+ of_node_put(i2sdev->sound.ofdev.dev.of_node);
mutex_destroy(&i2sdev->lock);
kfree(i2sdev);
}
@@ -148,7 +149,6 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
}
/* Returns 1 if added, 0 for otherwise; don't return a negative value! */
-/* FIXME: look at device node refcounting */
static int i2sbus_add_dev(struct macio_dev *macio,
struct i2sbus_control *control,
struct device_node *np)
@@ -179,8 +179,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
i = 0;
for_each_child_of_node(np, child) {
if (of_node_name_eq(child, "sound")) {
+ of_node_put(sound);
i++;
- sound = child;
+ sound = of_node_get(child);
}
}
if (i == 1) {
@@ -206,6 +207,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
}
+ of_node_put(sound);
/* for the time being, until we can handle non-layout-id
* things in some fabric, refuse to attach if there is no
* layout-id property or we haven't been forced to attach.
@@ -220,7 +222,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
mutex_init(&dev->lock);
spin_lock_init(&dev->low_lock);
dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask;
- dev->sound.ofdev.dev.of_node = np;
+ dev->sound.ofdev.dev.of_node = of_node_get(np);
dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask;
dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
dev->sound.ofdev.dev.release = i2sbus_release_dev;
@@ -328,6 +330,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
for (i=0;i<3;i++)
release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
+ of_node_put(dev->sound.ofdev.dev.of_node);
kfree(dev);
return 0;
}
@@ -408,6 +411,9 @@ static int i2sbus_resume(struct macio_dev* dev)
int err, ret = 0;
list_for_each_entry(i2sdev, &control->list, item) {
+ if (list_empty(&i2sdev->sound.codec_list))
+ continue;
+
/* reset i2s bus format etc. */
i2sbus_pcm_prepare_both(i2sdev);
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 07df5cc0f2d7..8184152797ca 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
u64 formats = 0;
unsigned int rates = 0;
struct transfer_info v;
- int result = 0;
int bus_factor = 0, sysclock_factor = 0;
int found_this;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
@@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (pi->active) {
/* alsa messed up */
- result = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
/* we now need to assign the hw */
@@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
ti++;
}
}
- if (!masks_inited || !bus_factor || !sysclock_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ if (!masks_inited || !bus_factor || !sysclock_factor)
+ return -ENODEV;
/* bus dependent stuff */
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
@@ -169,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
* currently in use (if any). */
hw->rate_min = 5512;
hw->rate_max = 192000;
- /* if the other stream is active, then we can only
- * support what it is currently using.
- * FIXME: I lied. This comment is wrong. We can support
- * anything that works with the same serial format, ie.
- * when recording 24 bit sound we can well play 16 bit
- * sound at the same time iff using the same transfer mode.
+ /* If the other stream is already prepared, keep this stream
+ * on the same duplex format and rate.
+ *
+ * i2sbus_pcm_prepare() still programs one shared transport
+ * configuration for both directions, so mixed duplex formats
+ * are not supported here.
*/
if (other->active) {
- /* FIXME: is this guaranteed by the alsa api? */
hw->formats &= pcm_format_to_bits(i2sdev->format);
- /* see above, restrict rates to the one we already have */
+ /* Restrict rates to the one already in use. */
hw->rate_min = i2sdev->rate;
hw->rate_max = i2sdev->rate;
}
@@ -194,15 +189,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
hw->periods_max = MAX_DBDMA_COMMANDS;
err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- result = err;
- goto out_unlock;
- }
+ if (err < 0)
+ return err;
list_for_each_entry(cii, &sdev->codec_list, list) {
if (cii->codec->open) {
err = cii->codec->open(cii, pi->substream);
if (err) {
- result = err;
/* unwind */
found_this = 0;
list_for_each_entry_reverse(rev,
@@ -214,14 +206,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (rev == cii)
found_this = 1;
}
- goto out_unlock;
+ return err;
}
}
}
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ return 0;
}
#undef CHECK_RATE
@@ -232,7 +222,7 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
struct pcm_info *pi;
int err = 0, tmp;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, NULL);
@@ -246,7 +236,6 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
pi->substream = NULL;
pi->active = 0;
- mutex_unlock(&i2sdev->lock);
return err;
}
@@ -293,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
}
#endif
+static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+
+ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ pi->active = 0;
+}
+
+static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, int in)
+{
+ i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
+ return 0;
+}
+
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
@@ -301,14 +307,27 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
+ i2sbus_pcm_clear_active(i2sdev, in);
return 0;
}
+static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 0);
+}
+
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 0);
}
+static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 1);
+}
+
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 1);
@@ -330,33 +349,25 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int input_16bit;
struct pcm_info *pi, *other;
int cnt;
- int result = 0;
unsigned int cmd, stopaddr;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
- if (pi->dbdma_ring.running) {
- result = -EBUSY;
- goto out_unlock;
- }
+ if (pi->dbdma_ring.running)
+ return -EBUSY;
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
- if (!pi->substream || !pi->substream->runtime) {
- result = -EINVAL;
- goto out_unlock;
- }
+ if (!pi->substream || !pi->substream->runtime)
+ return -EINVAL;
runtime = pi->substream->runtime;
- pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
- || (i2sdev->rate != runtime->rate))) {
- result = -EINVAL;
- goto out_unlock;
- }
+ || (i2sdev->rate != runtime->rate)))
+ return -EINVAL;
i2sdev->format = runtime->format;
i2sdev->rate = runtime->rate;
@@ -400,6 +411,9 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* set stop command */
command->command = cpu_to_le16(DBDMA_STOP);
+ cii = list_first_entry(&i2sdev->sound.codec_list,
+ struct codec_info_item, list);
+
/* ok, let's set the serial format and stuff */
switch (runtime->format) {
/* 16 bit formats */
@@ -407,15 +421,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
case SNDRV_PCM_FORMAT_U16_BE:
/* FIXME: if we add different bus factors we need to
* do more here!! */
- bi.bus_factor = 0;
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- bi.bus_factor = cii->codec->bus_factor;
- break;
- }
- if (!bi.bus_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ bi.bus_factor = cii->codec->bus_factor;
input_16bit = 1;
break;
case SNDRV_PCM_FORMAT_S32_BE:
@@ -426,22 +432,16 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
input_16bit = 0;
break;
default:
- result = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
/* we assume all sysclocks are the same! */
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- bi.sysclock_factor = cii->codec->sysclock_factor;
- break;
- }
+ bi.sysclock_factor = cii->codec->sysclock_factor;
if (clock_and_divisors(bi.sysclock_factor,
bi.bus_factor,
runtime->rate,
- &sfr) < 0) {
- result = -EINVAL;
- goto out_unlock;
- }
+ &sfr) < 0)
+ return -EINVAL;
switch (bi.bus_factor) {
case 32:
sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
@@ -457,10 +457,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int err = 0;
if (cii->codec->prepare)
err = cii->codec->prepare(cii, &bi, pi->substream);
- if (err) {
- result = err;
- goto out_unlock;
- }
+ if (err)
+ return err;
}
/* codecs are fine with it, so set our clocks */
if (input_16bit)
@@ -474,9 +472,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* early exit if already programmed correctly */
/* not locking these is fine since we touch them only in this function */
- if (in_le32(&i2sdev->intfregs->serial_format) == sfr
- && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
- goto out_unlock;
+ if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
+ in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
+ pi->active = 1;
+ return 0;
+ }
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -514,9 +514,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ pi->active = 1;
+ return 0;
}
#ifdef CONFIG_PM
@@ -772,6 +771,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_playback_ops = {
.open = i2sbus_playback_open,
.close = i2sbus_playback_close,
+ .hw_params = i2sbus_playback_hw_params,
.hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
@@ -840,6 +840,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_record_ops = {
.open = i2sbus_record_open,
.close = i2sbus_record_close,
+ .hw_params = i2sbus_record_hw_params,
.hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
diff --git a/sound/core/control.c b/sound/core/control.c
index dd4bdb39782c..3b464260795e 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1672,6 +1672,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue)
/* check that there are enough valid names */
p = names;
for (i = 0; i < ue->info.value.enumerated.items; ++i) {
+ if (buf_len == 0) {
+ kvfree(names);
+ return -EINVAL;
+ }
name_len = strnlen(p, buf_len);
if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
kvfree(names);
diff --git a/sound/core/misc.c b/sound/core/misc.c
index d32a19976a2b..fd891a3ceb96 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -171,14 +171,18 @@ static LIST_HEAD(snd_fasync_list);
static void snd_fasync_work_fn(struct work_struct *work)
{
struct snd_fasync *fasync;
+ int signal, poll;
spin_lock_irq(&snd_fasync_lock);
while (!list_empty(&snd_fasync_list)) {
fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
list_del_init(&fasync->list);
+ if (!fasync->on)
+ continue;
+ signal = fasync->signal;
+ poll = fasync->poll;
spin_unlock_irq(&snd_fasync_lock);
- if (fasync->on)
- kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
+ kill_fasync(&fasync->fasync, signal, poll);
spin_lock_irq(&snd_fasync_lock);
}
spin_unlock_irq(&snd_fasync_lock);
@@ -198,35 +202,32 @@ int snd_fasync_helper(int fd, struct file *file, int on,
INIT_LIST_HEAD(&fasync->list);
}
- spin_lock_irq(&snd_fasync_lock);
- if (*fasyncp) {
- kfree(fasync);
- fasync = *fasyncp;
- } else {
- if (!fasync) {
- spin_unlock_irq(&snd_fasync_lock);
- return 0;
+ scoped_guard(spinlock_irq, &snd_fasync_lock) {
+ if (*fasyncp) {
+ kfree(fasync);
+ fasync = *fasyncp;
+ } else {
+ if (!fasync)
+ return 0;
+ *fasyncp = fasync;
}
- *fasyncp = fasync;
+ fasync->on = on;
}
- fasync->on = on;
- spin_unlock_irq(&snd_fasync_lock);
return fasync_helper(fd, file, on, &fasync->fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_helper);
void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
{
- unsigned long flags;
-
- if (!fasync || !fasync->on)
+ if (!fasync)
+ return;
+ guard(spinlock_irqsave)(&snd_fasync_lock);
+ if (!fasync->on)
return;
- spin_lock_irqsave(&snd_fasync_lock, flags);
fasync->signal = signal;
fasync->poll = poll;
list_move(&fasync->list, &snd_fasync_list);
schedule_work(&snd_fasync_work);
- spin_unlock_irqrestore(&snd_fasync_lock, flags);
}
EXPORT_SYMBOL_GPL(snd_kill_fasync);
@@ -234,7 +235,12 @@ void snd_fasync_free(struct snd_fasync *fasync)
{
if (!fasync)
return;
- fasync->on = 0;
+
+ scoped_guard(spinlock_irq, &snd_fasync_lock) {
+ fasync->on = 0;
+ list_del_init(&fasync->list);
+ }
+
flush_work(&snd_fasync_work);
kfree(fasync);
}
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 8a142fd54a19..307ef98c44c7 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -101,9 +101,9 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count,
break;
}
fmt = (*(unsigned short *)rec.c) & 0xffff;
- /* FIXME the return value isn't correct */
- return snd_seq_oss_synth_load_patch(dp, rec.s.dev,
- fmt, buf, 0, count);
+ err = snd_seq_oss_synth_load_patch(dp, rec.s.dev,
+ fmt, buf, 0, count);
+ return err < 0 ? err : count;
}
if (ev_is_long(&rec)) {
/* extended code */
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 31428cdc0f63..9d71decaddd6 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1333,7 +1333,11 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3))
client->midi_version = client_info->midi_version;
memcpy(client->event_filter, client_info->event_filter, 32);
- client->group_filter = client_info->group_filter;
+ client->group_filter = client_info->group_filter & SND_SEQ_GROUP_FILTER_MASK;
+
+ /* notify the change */
+ snd_seq_system_client_ev_client_change(client->number);
+
return 0;
}
@@ -1457,6 +1461,9 @@ static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg)
if (port) {
snd_seq_set_port_info(port, info);
snd_seq_port_unlock(port);
+ /* notify the change */
+ snd_seq_system_client_ev_port_change(info->addr.client,
+ info->addr.port);
}
return 0;
}
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index 915b1017286e..05c8758f50ad 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -14,6 +14,9 @@
/* client manager */
+#define SND_SEQ_GROUP_FILTER_MASK GENMASK(SNDRV_UMP_MAX_GROUPS, 0)
+#define SND_SEQ_GROUP_FILTER_GROUPS GENMASK(SNDRV_UMP_MAX_GROUPS, 1)
+
struct snd_seq_user_client {
struct file *file; /* file struct of client */
/* ... */
@@ -40,7 +43,7 @@ struct snd_seq_client {
int number; /* client number */
unsigned int filter; /* filter flags */
DECLARE_BITMAP(event_filter, 256);
- unsigned short group_filter;
+ unsigned int group_filter;
snd_use_lock_t use_lock;
int event_lost;
/* ports */
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index 1c6c49560ae1..55923ee6c97a 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -273,8 +273,6 @@ static void update_port_infos(struct seq_ump_client *client)
new);
if (err < 0)
continue;
- /* notify to system port */
- snd_seq_system_client_ev_port_change(client->seq_client, i);
}
}
@@ -372,7 +370,7 @@ static void setup_client_group_filter(struct seq_ump_client *client)
cptr = snd_seq_kernel_client_get(client->seq_client);
if (!cptr)
return;
- filter = ~(1U << 0); /* always allow groupless messages */
+ filter = SND_SEQ_GROUP_FILTER_GROUPS; /* always allow groupless messages */
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
if (client->ump->groups[p].active)
filter &= ~(1U << (p + 1));
diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c
index b8bff5522bce..4eb59e9d2322 100644
--- a/sound/drivers/pcmtest.c
+++ b/sound/drivers/pcmtest.c
@@ -753,13 +753,24 @@ static int __init mod_init(void)
err = init_debug_files(buf_allocated);
if (err)
- return err;
+ goto err_free_patterns;
err = platform_device_register(&pcmtst_pdev);
- if (err)
- return err;
+ if (err) {
+ platform_device_put(&pcmtst_pdev);
+ goto err_clear_debug;
+ }
err = platform_driver_register(&pcmtst_pdrv);
- if (err)
+ if (err) {
platform_device_unregister(&pcmtst_pdev);
+ goto err_clear_debug;
+ }
+
+ return 0;
+
+err_clear_debug:
+ clear_debug_files();
+err_free_patterns:
+ free_pattern_buffers();
return err;
}
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 74eed9505665..9c3f68d8daef 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -73,6 +73,7 @@ static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
length = rounddown(remained, sizeof(*entries));
if (length == 0)
break;
+ tail_pos = head_pos + length / sizeof(*entries);
spin_unlock_irq(&tscm->lock);
if (copy_to_user(pos, &entries[head_pos], length))
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index fbdb8a3d5b8e..939539af68f6 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -791,7 +791,8 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
struct src *src;
int err;
int n_amixer = apcm->substream->runtime->channels, i;
- unsigned int pitch, rsr = atc->pll_rate;
+ unsigned int pitch;
+ unsigned int rsr = atc->pll_rate ? atc->pll_rate : atc->rsr;
/* first release old resources */
atc_pcm_release_resources(atc, apcm);
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
index 8d86a13b8a96..bae7b1d592c6 100644
--- a/sound/pci/hda/cs35l56_hda.c
+++ b/sound/pci/hda/cs35l56_hda.c
@@ -176,9 +176,13 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
{
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int reg_val;
- int i;
+ int i, ret;
+
+ ret = regmap_read(cs35l56->base.regmap, kcontrol->private_value,
+ ®_val);
+ if (ret)
+ return ret;
- regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val);
reg_val &= CS35L56_ASP_TXn_SRC_MASK;
for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
@@ -197,13 +201,18 @@ static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
unsigned int item = ucontrol->value.enumerated.item[0];
bool changed;
+ int ret;
if (item >= CS35L56_NUM_INPUT_SRC)
return -EINVAL;
- regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
- CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
- &changed);
+ ret = regmap_update_bits_check(cs35l56->base.regmap,
+ kcontrol->private_value,
+ CS35L56_INPUT_MASK,
+ cs35l56_tx_input_values[item],
+ &changed);
+ if (ret)
+ return ret;
return changed;
}
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index aaa0f44ef9e0..8281cdae9fd0 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -52,6 +52,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15-fc0xxx"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Gaming Laptop 16-ap0xxx"),
+ }
+ },
{
.driver_data = &acp6x_card,
.matches = {
@@ -647,6 +654,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8EE4"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8E35"),
+ }
+ },
{
.driver_data = &acp6x_card,
.matches = {
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 13396a167b8a..c78abf7698e0 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1286,7 +1286,7 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
/*
* Release the context
*
- * This funciton is mainly doing the revert thing in request context
+ * This function is mainly doing the revert thing in request context
*/
static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
{
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 5c9e06ed1a53..de95a79d083e 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -111,6 +111,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
if (ret) {
dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
+ clk_disable_unprepare(priv->mclk);
return ret;
}
} else {
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index 1c2900cccba6..80df74985919 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -321,6 +321,7 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_STOP:
/* TODO support be handled via SoftPause Module */
prtd->state = Q6APM_STREAM_STOPPED;
+ prtd->queue_ptr = 0;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 9fcf8f59ea28..8f8fb537876f 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -175,7 +175,7 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
* It is recommend to load DSP with source graph first and then sink
* graph, so sequence for playback and capture will be different
*/
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai_data->graph[dai->id] == NULL) {
graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id);
if (IS_ERR(graph)) {
dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id);
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index b2ea760ff16e..7b447cb50d50 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -225,6 +225,8 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a
mutex_lock(&graph->lock);
+ data->dsp_buf = 0;
+
if (data->buf) {
mutex_unlock(&graph->lock);
return 0;
@@ -779,6 +781,7 @@ static int apm_probe(gpr_device_t *gdev)
static void apm_remove(gpr_device_t *gdev)
{
+ of_platform_depopulate(&gdev->dev);
snd_soc_unregister_component(&gdev->dev);
}
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
index d7b044f33d79..c469bb706e4a 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -371,6 +371,9 @@ static int sof_compr_pointer(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ if (!sstream->channels || !sstream->sample_container_bytes)
+ return -EBUSY;
+
tstamp->sampling_rate = sstream->sampling_rate;
tstamp->copied_total = sstream->copied_total;
tstamp->pcm_io_frames = div_u64(spcm->stream[cstream->direction].posn.dai_posn,
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index 9bd8dcbb68e4..7c2274120c76 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -290,15 +290,17 @@ static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int vol0 = ucontrol->value.integer.value[0] - 15;
+ int vol1 = ucontrol->value.integer.value[1] - 15;
int changed = 0;
- if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
- rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
+ if (rt->input_vol[0] != vol0) {
+ rt->input_vol[0] = vol0;
rt->ivol_updated &= ~(1 << 0);
changed = 1;
}
- if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
- rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
+ if (rt->input_vol[1] != vol1) {
+ rt->input_vol[1] = vol1;
rt->ivol_updated &= ~(1 << 1);
changed = 1;
}
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index af459c49baf4..4598fb7e8be0 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -87,6 +87,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
int v = ucontrol->value.integer.value[0];
+ int ret;
unsigned char cmd;
switch (cdev->chip.usb_id) {
@@ -103,6 +104,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
if (pos & CNT_INTVAL) {
int i = pos & ~CNT_INTVAL;
+ unsigned char old = cdev->control_state[i];
+
+ if (old == v)
+ return 0;
cdev->control_state[i] = v;
@@ -113,10 +118,11 @@ static int control_put(struct snd_kcontrol *kcontrol,
cdev->ep8_out_buf[0] = i;
cdev->ep8_out_buf[1] = v;
- usb_bulk_msg(cdev->chip.dev,
- usb_sndbulkpipe(cdev->chip.dev, 8),
- cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
- &actual_len, 200);
+ ret = usb_bulk_msg(cdev->chip.dev,
+ usb_sndbulkpipe(cdev->chip.dev, 8),
+ cdev->ep8_out_buf,
+ sizeof(cdev->ep8_out_buf),
+ &actual_len, 200);
} else if (cdev->chip.usb_id ==
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) {
@@ -128,21 +134,36 @@ static int control_put(struct snd_kcontrol *kcontrol,
offset = MASCHINE_BANK_SIZE;
}
- snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
- cdev->control_state + offset,
- MASCHINE_BANK_SIZE);
+ ret = snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
+ cdev->control_state + offset,
+ MASCHINE_BANK_SIZE);
} else {
- snd_usb_caiaq_send_command(cdev, cmd,
- cdev->control_state, sizeof(cdev->control_state));
+ ret = snd_usb_caiaq_send_command(cdev, cmd,
+ cdev->control_state,
+ sizeof(cdev->control_state));
+ }
+
+ if (ret < 0) {
+ cdev->control_state[i] = old;
+ return ret;
}
} else {
- if (v)
- cdev->control_state[pos / 8] |= 1 << (pos % 8);
- else
- cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
+ int idx = pos / 8;
+ unsigned char mask = 1 << (pos % 8);
+ unsigned char old = cdev->control_state[idx];
+ unsigned char val = v ? (old | mask) : (old & ~mask);
- snd_usb_caiaq_send_command(cdev, cmd,
- cdev->control_state, sizeof(cdev->control_state));
+ if (old == val)
+ return 0;
+
+ cdev->control_state[idx] = val;
+ ret = snd_usb_caiaq_send_command(cdev, cmd,
+ cdev->control_state,
+ sizeof(cdev->control_state));
+ if (ret < 0) {
+ cdev->control_state[idx] = old;
+ return ret;
+ }
}
return 1;
@@ -640,4 +661,3 @@ int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
return ret;
}
-
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 51177ebfb8c6..b20aae0caf60 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -290,7 +290,7 @@ int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,
tmp, sizeof(tmp));
}
-static void setup_card(struct snd_usb_caiaqdev *cdev)
+static int setup_card(struct snd_usb_caiaqdev *cdev)
{
int ret;
char val[4];
@@ -325,8 +325,10 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0);
if (!wait_event_timeout(cdev->ep1_wait_queue,
- cdev->control_state[0] != 0xff, HZ))
- return;
+ cdev->control_state[0] != 0xff, HZ)) {
+ dev_err(dev, "Read timeout for control state\n");
+ return -EINVAL;
+ }
/* fix up some defaults */
if ((cdev->control_state[1] != 2) ||
@@ -347,33 +349,43 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
cdev->spec.num_digital_audio_out +
cdev->spec.num_digital_audio_in > 0) {
ret = snd_usb_caiaq_audio_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);
+ return ret;
+ }
}
if (cdev->spec.num_midi_in +
cdev->spec.num_midi_out > 0) {
ret = snd_usb_caiaq_midi_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);
+ return ret;
+ }
}
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
ret = snd_usb_caiaq_input_init(cdev);
- if (ret < 0)
+ if (ret < 0 && ret != -ENODEV) {
dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);
+ return ret;
+ }
#endif
/* finally, register the card and all its sub-instances */
ret = snd_card_register(cdev->chip.card);
if (ret < 0) {
dev_err(dev, "snd_card_register() returned %d\n", ret);
- snd_card_free(cdev->chip.card);
+ return ret;
}
ret = snd_usb_caiaq_control_init(cdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
}
static void card_free(struct snd_card *card)
@@ -411,6 +423,7 @@ static int create_card(struct usb_device *usb_dev,
cdev = caiaqdev(card);
cdev->chip.dev = usb_get_dev(usb_dev);
+ card->private_free = card_free;
cdev->chip.card = card;
cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct));
@@ -499,8 +512,10 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
scnprintf(card->longname, sizeof(card->longname), "%s %s (%s)",
cdev->vendor_name, cdev->product_name, usbpath);
- setup_card(cdev);
- card->private_free = card_free;
+ err = setup_card(cdev);
+ if (err < 0)
+ goto err_kill_urb;
+
return 0;
err_kill_urb:
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index a9130891bb69..5c70fdf61cc1 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -804,7 +804,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
default:
/* no input methods supported on this device */
- ret = -EINVAL;
+ ret = -ENODEV;
goto exit_free_idev;
}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index f6cef6aaca77..b399a7065cf3 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1397,9 +1397,6 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
goto unlock;
}
- ep->packsize[0] = min(ep->packsize[0], ep->maxframesize);
- ep->packsize[1] = min(ep->packsize[1], ep->maxframesize);
-
/* calculate the frequency in 16.16 format */
ep->freqm = ep->freqn;
ep->freqshift = INT_MIN;
@@ -1426,6 +1423,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes;
ep->curframesize = ep->curpacksize / ep->cur_frame_bytes;
+ ep->packsize[0] = min(ep->packsize[0], ep->maxframesize);
+ ep->packsize[1] = min(ep->packsize[1], ep->maxframesize);
+
err = update_clock_ref_rate(chip, ep);
if (err >= 0) {
ep->need_setup = false;
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 682adbdf7ee7..aec676a889ac 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -461,7 +461,7 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
nr_rates++;
if (nr_rates >= MAX_NR_RATES) {
usb_audio_err(chip, "invalid uac2 rates\n");
- break;
+ return nr_rates;
}
skip_rate:
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index 8c668502e1a5..9e183d9d1b09 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -234,7 +234,7 @@ static void kill_midi_urbs(struct snd_usb_midi2_endpoint *ep, bool suspending)
if (!ep)
return;
if (suspending)
- ep->suspended = ep->running;
+ atomic_set(&ep->suspended, atomic_read(&ep->running));
atomic_set(&ep->running, 0);
for (i = 0; i < ep->num_urbs; i++) {
if (!ep->urbs[i].urb)
@@ -1193,10 +1193,11 @@ void snd_usb_midi_v2_suspend_all(struct snd_usb_audio *chip)
static void resume_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
{
- ep->running = ep->suspended;
- if (ep->direction == STR_IN)
+ atomic_set(&ep->running, atomic_read(&ep->suspended));
+ atomic_set(&ep->suspended, 0);
+
+ if (ep->direction == STR_IN || atomic_read(&ep->running))
submit_io_urbs(ep);
- /* FIXME: does it all? */
}
void snd_usb_midi_v2_resume_all(struct snd_usb_audio *chip)
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 4f6b20ed29dd..303c7a00489e 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -994,6 +994,13 @@ static int detect_usb_format(struct ua101 *ua)
ua->capture.channels = fmt_capture->bNrChannels;
ua->playback.channels = fmt_playback->bNrChannels;
+ if (!ua->capture.channels || !ua->playback.channels) {
+ dev_err(&ua->dev->dev,
+ "invalid channel count: capture %u, playback %u\n",
+ ua->capture.channels, ua->playback.channels);
+ return -EINVAL;
+ }
+
ua->capture.frame_bytes =
fmt_capture->bSubframeSize * ua->capture.channels;
ua->playback.frame_bytes =
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 223deaef64f4..8c4fb5be3dba 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1814,10 +1814,11 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
range = (cval->max - cval->min) / cval->res;
/*
- * There are definitely devices with a range of ~20,000, so let's be
- * conservative and allow for a bit more.
+ * Are there devices with volume range more than 255? I use a bit more
+ * to be sure. 384 is a resolution magic number found on Logitech
+ * devices. It will definitively catch all buggy Logitech devices.
*/
- if (range > 65535) {
+ if (range > 384) {
usb_audio_warn(mixer->chip,
"Warning! Unlikely big volume range (=%u), cval->res is probably wrong.",
range);
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 270a0be672b7..b85896a821b2 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1561,15 +1561,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
{
struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *cval;
+ int err;
int unitid = 12; /* SampleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
if (mixer->id_elems[unitid]) {
cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
- snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
- cval->control << 8,
- samplerate_id);
- snd_usb_mixer_notify_id(mixer, unitid);
+ err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
+ cval->control << 8,
+ samplerate_id);
+ if (!err)
+ snd_usb_mixer_notify_id(mixer, unitid);
break;
}
}
@@ -2064,7 +2066,7 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
int err;
reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
- if (reg != list->kctl->private_value)
+ if (reg == list->kctl->private_value)
return 0;
kcontrol->private_value = reg;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 12a5e053ec54..920a718f91e6 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -352,6 +352,8 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
if (len < sizeof(*cs_desc))
break;
cs_len = le16_to_cpu(cs_desc->wLength);
+ if (cs_len < sizeof(*cs_desc))
+ break;
if (len < cs_len)
break;
cs_type = cs_desc->bSegmentType;
@@ -991,7 +993,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
* and request Cluster Descriptor
*/
wLength = le16_to_cpu(hc_header.wLength);
- if (wLength < sizeof(cluster))
+ if (wLength < sizeof(*cluster))
return NULL;
cluster = kzalloc(wLength, GFP_KERNEL);
if (!cluster)
diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c
index 1334214546d7..3fa750535567 100644
--- a/tools/accounting/getdelays.c
+++ b/tools/accounting/getdelays.c
@@ -59,7 +59,7 @@ int print_task_context_switch_counts;
}
/* Maximum size of response requested or message sent */
-#define MAX_MSG_SIZE 1024
+#define MAX_MSG_SIZE 2048
/* Maximum number of cpus expected to be specified in a cpumask */
#define MAX_CPUS 32
@@ -114,6 +114,32 @@ static int create_nl_socket(int protocol)
return -1;
}
+static int recv_taskstats_msg(int sd, struct msgtemplate *msg)
+{
+ struct sockaddr_nl nladdr;
+ struct iovec iov = {
+ .iov_base = msg,
+ .iov_len = sizeof(*msg),
+ };
+ struct msghdr hdr = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ int ret;
+
+ ret = recvmsg(sd, &hdr, 0);
+ if (ret < 0)
+ return -1;
+ if (hdr.msg_flags & MSG_TRUNC) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ return ret;
+}
+
static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
__u8 genl_cmd, __u16 nla_type,
@@ -465,12 +491,16 @@ int main(int argc, char *argv[])
}
do {
- rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
+ rep_len = recv_taskstats_msg(nl_sd, &msg);
PRINTF("received %d bytes\n", rep_len);
if (rep_len < 0) {
- fprintf(stderr, "nonfatal reply error: errno %d\n",
- errno);
+ if (errno == EMSGSIZE)
+ fprintf(stderr,
+ "dropped truncated taskstats netlink message, please increase MAX_MSG_SIZE\n");
+ else
+ fprintf(stderr, "nonfatal reply error: errno %d\n",
+ errno);
continue;
}
if (msg.n.nlmsg_type == NLMSG_ERROR ||
@@ -512,6 +542,9 @@ int main(int argc, char *argv[])
printf("TGID\t%d\n", rtid);
break;
case TASKSTATS_TYPE_STATS:
+ PRINTF("version %u\n",
+ ((struct taskstats *)
+ NLA_DATA(na))->version);
if (print_delays)
print_delayacct((struct taskstats *) NLA_DATA(na));
if (print_io_accounting)
diff --git a/tools/accounting/procacct.c b/tools/accounting/procacct.c
index 90c4a37f53d9..298fb3f6d80b 100644
--- a/tools/accounting/procacct.c
+++ b/tools/accounting/procacct.c
@@ -71,7 +71,7 @@ int print_task_context_switch_counts;
}
/* Maximum size of response requested or message sent */
-#define MAX_MSG_SIZE 1024
+#define MAX_MSG_SIZE 2048
/* Maximum number of cpus expected to be specified in a cpumask */
#define MAX_CPUS 32
@@ -121,6 +121,32 @@ static int create_nl_socket(int protocol)
return -1;
}
+static int recv_taskstats_msg(int sd, struct msgtemplate *msg)
+{
+ struct sockaddr_nl nladdr;
+ struct iovec iov = {
+ .iov_base = msg,
+ .iov_len = sizeof(*msg),
+ };
+ struct msghdr hdr = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ int ret;
+
+ ret = recvmsg(sd, &hdr, 0);
+ if (ret < 0)
+ return -1;
+ if (hdr.msg_flags & MSG_TRUNC) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ return ret;
+}
+
static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
__u8 genl_cmd, __u16 nla_type,
@@ -239,6 +265,8 @@ void handle_aggr(int mother, struct nlattr *na, int fd)
PRINTF("TGID\t%d\n", rtid);
break;
case TASKSTATS_TYPE_STATS:
+ PRINTF("version %u\n",
+ ((struct taskstats *)NLA_DATA(na))->version);
if (mother == TASKSTATS_TYPE_AGGR_PID)
print_procacct((struct taskstats *) NLA_DATA(na));
if (fd) {
@@ -348,12 +376,16 @@ int main(int argc, char *argv[])
}
do {
- rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
+ rep_len = recv_taskstats_msg(nl_sd, &msg);
PRINTF("received %d bytes\n", rep_len);
if (rep_len < 0) {
- fprintf(stderr, "nonfatal reply error: errno %d\n",
- errno);
+ if (errno == EMSGSIZE)
+ fprintf(stderr,
+ "dropped truncated taskstats netlink message, please increase MAX_MSG_SIZE\n");
+ else
+ fprintf(stderr, "nonfatal reply error: errno %d\n",
+ errno);
continue;
}
if (msg.n.nlmsg_type == NLMSG_ERROR ||
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index a8979280b505..e93ac83270da 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -1777,7 +1777,7 @@ sub save_logs {
my ($result, $basedir) = @_;
my @t = localtime;
my $date = sprintf "%04d%02d%02d%02d%02d%02d",
- 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
+ 1900+$t[5],$t[4]+1,$t[3],$t[2],$t[1],$t[0];
my $type = $build_type;
if ($type =~ /useconfig/) {
diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 6115520154e3..1f71f596d33f 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -4,6 +4,7 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
+#include <../../../tools/include/linux/filter.h>
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
@@ -450,4 +451,284 @@ l0_%=: r1 >>= 16; \
: __clobber_all);
}
+SEC("raw_tp")
+__log_level(2)
+__success
+__msg("fp-8=0m??mmmm")
+__msg("fp-16=00mm??mm")
+__msg("fp-24=00mm???m")
+__naked void spill_subregs_preserve_stack_zero(void)
+{
+ asm volatile (
+ "call %[bpf_get_prandom_u32];"
+
+ /* 32-bit subreg spill with ZERO, MISC, and INVALID */
+ ".8byte %[fp1_u8_st_zero];" /* ZERO, LLVM-18+: *(u8 *)(r10 -1) = 0; */
+ "*(u8 *)(r10 -2) = r0;" /* MISC */
+ /* fp-3 and fp-4 stay INVALID */
+ "*(u32 *)(r10 -8) = r0;"
+
+ /* 16-bit subreg spill with ZERO, MISC, and INVALID */
+ ".8byte %[fp10_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r10 -10) = 0; */
+ "*(u16 *)(r10 -12) = r0;" /* MISC */
+ /* fp-13 and fp-14 stay INVALID */
+ "*(u16 *)(r10 -16) = r0;"
+
+ /* 8-bit subreg spill with ZERO, MISC, and INVALID */
+ ".8byte %[fp18_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r18 -10) = 0; */
+ "*(u16 *)(r10 -20) = r0;" /* MISC */
+ /* fp-21, fp-22, and fp-23 stay INVALID */
+ "*(u8 *)(r10 -24) = r0;"
+
+ "r0 = 0;"
+ "exit;"
+ :
+ : __imm(bpf_get_prandom_u32),
+ __imm_insn(fp1_u8_st_zero, BPF_ST_MEM(BPF_B, BPF_REG_FP, -1, 0)),
+ __imm_insn(fp10_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -10, 0)),
+ __imm_insn(fp18_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -18, 0))
+ : __clobber_all);
+}
+
+char single_byte_buf[1] SEC(".data.single_byte_buf");
+
+SEC("raw_tp")
+__log_level(2)
+__success
+/* make sure fp-8 is all STACK_ZERO */
+__msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=00000000")
+/* but fp-16 is spilled IMPRECISE zero const reg */
+__msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=0 R10=fp0 fp-16_w=0")
+/* and now check that precision propagation works even for such tricky case */
+__msg("10: (71) r2 = *(u8 *)(r10 -9) ; R2_w=P0 R10=fp0 fp-16_w=0")
+__msg("11: (0f) r1 += r2")
+__msg("mark_precise: frame0: last_idx 11 first_idx 0 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r2 stack= before 10: (71) r2 = *(u8 *)(r10 -9)")
+__msg("mark_precise: frame0: regs= stack=-16 before 9: (bf) r1 = r6")
+__msg("mark_precise: frame0: regs= stack=-16 before 8: (73) *(u8 *)(r1 +0) = r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 7: (0f) r1 += r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 6: (71) r2 = *(u8 *)(r10 -1)")
+__msg("mark_precise: frame0: regs= stack=-16 before 5: (bf) r1 = r6")
+__msg("mark_precise: frame0: regs= stack=-16 before 4: (7b) *(u64 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 3: (b7) r0 = 0")
+__naked void partial_stack_load_preserves_zeros(void)
+{
+ asm volatile (
+ /* fp-8 is all STACK_ZERO */
+ ".8byte %[fp8_st_zero];" /* LLVM-18+: *(u64 *)(r10 -8) = 0; */
+
+ /* fp-16 is const zero register */
+ "r0 = 0;"
+ "*(u64 *)(r10 -16) = r0;"
+
+ /* load single U8 from non-aligned STACK_ZERO slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u8 *)(r10 -1);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U8 from non-aligned ZERO REG slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u8 *)(r10 -9);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U16 from non-aligned STACK_ZERO slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u16 *)(r10 -2);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U16 from non-aligned ZERO REG slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u16 *)(r10 -10);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U32 from non-aligned STACK_ZERO slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u32 *)(r10 -4);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U32 from non-aligned ZERO REG slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u32 *)(r10 -12);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* for completeness, load U64 from STACK_ZERO slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u64 *)(r10 -8);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* for completeness, load U64 from ZERO REG slot */
+ "r1 = %[single_byte_buf];"
+ "r2 = *(u64 *)(r10 -16);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ "r0 = 0;"
+ "exit;"
+ :
+ : __imm_ptr(single_byte_buf),
+ __imm_insn(fp8_st_zero, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0))
+ : __clobber_common);
+}
+
+char two_byte_buf[2] SEC(".data.two_byte_buf");
+
+SEC("raw_tp")
+__log_level(2) __flag(BPF_F_TEST_STATE_FREQ)
+__success
+/* make sure fp-8 is IMPRECISE fake register spill */
+__msg("3: (7a) *(u64 *)(r10 -8) = 1 ; R10=fp0 fp-8_w=1")
+/* and fp-16 is spilled IMPRECISE const reg */
+__msg("5: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16_w=1")
+/* validate load from fp-8, which was initialized using BPF_ST_MEM */
+__msg("8: (79) r2 = *(u64 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=1")
+__msg("9: (0f) r1 += r2")
+__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r2 stack= before 8: (79) r2 = *(u64 *)(r10 -8)")
+__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6")
+/* note, fp-8 is precise, fp-16 is not yet precise, we'll get there */
+__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx(off=0,imm=0) R6_r=map_value(off=0,ks=4,vs=2,imm=0) R10=fp0 fp-8_rw=P1 fp-16_w=1")
+__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7")
+__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0")
+__msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1")
+__msg("mark_precise: frame0: regs= stack=-8 before 3: (7a) *(u64 *)(r10 -8) = 1")
+__msg("10: R1_w=map_value(off=1,ks=4,vs=2,imm=0) R2_w=1")
+/* validate load from fp-16, which was initialized using BPF_STX_MEM */
+__msg("12: (79) r2 = *(u64 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=1")
+__msg("13: (0f) r1 += r2")
+__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r2 stack= before 12: (79) r2 = *(u64 *)(r10 -16)")
+__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6")
+__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 8: (79) r2 = *(u64 *)(r10 -8)")
+__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6")
+/* now both fp-8 and fp-16 are precise, very good */
+__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx(off=0,imm=0) R6_r=map_value(off=0,ks=4,vs=2,imm=0) R10=fp0 fp-8_rw=P1 fp-16_rw=P1")
+__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7")
+__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0")
+__msg("mark_precise: frame0: regs= stack=-16 before 5: (7b) *(u64 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1")
+__msg("14: R1_w=map_value(off=1,ks=4,vs=2,imm=0) R2_w=1")
+__naked void stack_load_preserves_const_precision(void)
+{
+ asm volatile (
+ /* establish checkpoint with state that has no stack slots;
+ * if we bubble up to this state without finding desired stack
+ * slot, then it's a bug and should be caught
+ */
+ "goto +0;"
+
+ /* fp-8 is const 1 *fake* register */
+ ".8byte %[fp8_st_one];" /* LLVM-18+: *(u64 *)(r10 -8) = 1; */
+
+ /* fp-16 is const 1 register */
+ "r0 = 1;"
+ "*(u64 *)(r10 -16) = r0;"
+
+ /* force checkpoint to check precision marks preserved in parent states */
+ "goto +0;"
+
+ /* load single U64 from aligned FAKE_REG=1 slot */
+ "r1 = %[two_byte_buf];"
+ "r2 = *(u64 *)(r10 -8);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U64 from aligned REG=1 slot */
+ "r1 = %[two_byte_buf];"
+ "r2 = *(u64 *)(r10 -16);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ "r0 = 0;"
+ "exit;"
+ :
+ : __imm_ptr(two_byte_buf),
+ __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 1))
+ : __clobber_common);
+}
+
+SEC("raw_tp")
+__log_level(2) __flag(BPF_F_TEST_STATE_FREQ)
+__success
+/* make sure fp-8 is 32-bit FAKE subregister spill */
+__msg("3: (62) *(u32 *)(r10 -8) = 1 ; R10=fp0 fp-8=1")
+/* but fp-16 is spilled IMPRECISE zero const reg */
+__msg("5: (63) *(u32 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16=1")
+/* validate load from fp-8, which was initialized using BPF_ST_MEM */
+__msg("8: (61) r2 = *(u32 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=1")
+__msg("9: (0f) r1 += r2")
+__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r2 stack= before 8: (61) r2 = *(u32 *)(r10 -8)")
+__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6")
+__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx(off=0,imm=0) R6_r=map_value(off=0,ks=4,vs=2,imm=0) R10=fp0 fp-8_r=P1 fp-16=1")
+__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7")
+__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0")
+__msg("mark_precise: frame0: regs= stack=-8 before 5: (63) *(u32 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1")
+__msg("mark_precise: frame0: regs= stack=-8 before 3: (62) *(u32 *)(r10 -8) = 1")
+__msg("10: R1_w=map_value(off=1,ks=4,vs=2,imm=0) R2_w=1")
+/* validate load from fp-16, which was initialized using BPF_STX_MEM */
+__msg("12: (61) r2 = *(u32 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=1")
+__msg("13: (0f) r1 += r2")
+__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r2 stack= before 12: (61) r2 = *(u32 *)(r10 -16)")
+__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6")
+__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2")
+__msg("mark_precise: frame0: regs= stack=-16 before 8: (61) r2 = *(u32 *)(r10 -8)")
+__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6")
+__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx(off=0,imm=0) R6_r=map_value(off=0,ks=4,vs=2,imm=0) R10=fp0 fp-8_r=P1 fp-16_r=P1")
+__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7")
+__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0")
+__msg("mark_precise: frame0: regs= stack=-16 before 5: (63) *(u32 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1")
+__msg("14: R1_w=map_value(off=1,ks=4,vs=2,imm=0) R2_w=1")
+__naked void stack_load_preserves_const_precision_subreg(void)
+{
+ asm volatile (
+ /* establish checkpoint with state that has no stack slots;
+ * if we bubble up to this state without finding desired stack
+ * slot, then it's a bug and should be caught
+ */
+ "goto +0;"
+
+ /* fp-8 is const 1 *fake* SUB-register */
+ ".8byte %[fp8_st_one];" /* LLVM-18+: *(u32 *)(r10 -8) = 1; */
+
+ /* fp-16 is const 1 SUB-register */
+ "r0 = 1;"
+ "*(u32 *)(r10 -16) = r0;"
+
+ /* force checkpoint to check precision marks preserved in parent states */
+ "goto +0;"
+
+ /* load single U32 from aligned FAKE_REG=1 slot */
+ "r1 = %[two_byte_buf];"
+ "r2 = *(u32 *)(r10 -8);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ /* load single U32 from aligned REG=1 slot */
+ "r1 = %[two_byte_buf];"
+ "r2 = *(u32 *)(r10 -16);"
+ "r1 += r2;"
+ "*(u8 *)(r1 + 0) = r2;" /* this should be fine */
+
+ "r0 = 0;"
+ "exit;"
+ :
+ : __imm_ptr(two_byte_buf),
+ __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_W, BPF_REG_FP, -8, 1)) /* 32-bit spill */
+ : __clobber_common);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
index f61d623b1ce8..4b8b0f45d17d 100644
--- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
+++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
@@ -541,11 +541,24 @@ static __u64 subprog_spill_reg_precise(void)
SEC("?raw_tp")
__success __log_level(2)
-/* precision backtracking can't currently handle stack access not through r10,
- * so we won't be able to mark stack slot fp-8 as precise, and so will
- * fallback to forcing all as precise
- */
-__msg("mark_precise: frame0: falling back to forcing all scalars precise")
+__msg("10: (0f) r1 += r7")
+__msg("mark_precise: frame0: last_idx 10 first_idx 7 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r7 stack= before 9: (bf) r1 = r8")
+__msg("mark_precise: frame0: regs=r7 stack= before 8: (27) r7 *= 4")
+__msg("mark_precise: frame0: regs=r7 stack= before 7: (79) r7 = *(u64 *)(r10 -8)")
+__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=2 R6_w=1 R8_rw=map_value(off=0,ks=4,vs=16,imm=0) R10=fp0 fp-8_rw=P1")
+__msg("mark_precise: frame0: last_idx 18 first_idx 0 subseq_idx 7")
+__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit")
+__msg("mark_precise: frame1: regs= stack= before 17: (0f) r0 += r2")
+__msg("mark_precise: frame1: regs= stack= before 16: (79) r2 = *(u64 *)(r1 +0)")
+__msg("mark_precise: frame1: regs= stack= before 15: (79) r0 = *(u64 *)(r10 -16)")
+__msg("mark_precise: frame1: regs= stack= before 14: (7b) *(u64 *)(r10 -16) = r2")
+__msg("mark_precise: frame1: regs= stack= before 13: (7b) *(u64 *)(r1 +0) = r2")
+__msg("mark_precise: frame1: regs=r2 stack= before 6: (85) call pc+6")
+__msg("mark_precise: frame0: regs=r2 stack= before 5: (bf) r2 = r6")
+__msg("mark_precise: frame0: regs=r6 stack= before 4: (07) r1 += -8")
+__msg("mark_precise: frame0: regs=r6 stack= before 3: (bf) r1 = r10")
+__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1")
__naked int subprog_spill_into_parent_stack_slot_precise(void)
{
asm volatile (
@@ -580,14 +593,68 @@ __naked int subprog_spill_into_parent_stack_slot_precise(void)
);
}
-__naked __noinline __used
-static __u64 subprog_with_checkpoint(void)
+SEC("?raw_tp")
+__success __log_level(2)
+__msg("17: (0f) r1 += r0")
+__msg("mark_precise: frame0: last_idx 17 first_idx 0 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r0 stack= before 16: (bf) r1 = r7")
+__msg("mark_precise: frame0: regs=r0 stack= before 15: (27) r0 *= 4")
+__msg("mark_precise: frame0: regs=r0 stack= before 14: (79) r0 = *(u64 *)(r10 -16)")
+__msg("mark_precise: frame0: regs= stack=-16 before 13: (7b) *(u64 *)(r7 -8) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 12: (79) r0 = *(u64 *)(r8 +16)")
+__msg("mark_precise: frame0: regs= stack=-16 before 11: (7b) *(u64 *)(r8 +16) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 10: (79) r0 = *(u64 *)(r7 -8)")
+__msg("mark_precise: frame0: regs= stack=-16 before 9: (7b) *(u64 *)(r10 -16) = r0")
+__msg("mark_precise: frame0: regs=r0 stack= before 8: (07) r8 += -32")
+__msg("mark_precise: frame0: regs=r0 stack= before 7: (bf) r8 = r10")
+__msg("mark_precise: frame0: regs=r0 stack= before 6: (07) r7 += -8")
+__msg("mark_precise: frame0: regs=r0 stack= before 5: (bf) r7 = r10")
+__msg("mark_precise: frame0: regs=r0 stack= before 21: (95) exit")
+__msg("mark_precise: frame1: regs=r0 stack= before 20: (bf) r0 = r1")
+__msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+15")
+__msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6")
+__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1")
+__naked int stack_slot_aliases_precision(void)
{
asm volatile (
- "r0 = 0;"
- /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */
- "goto +0;"
+ "r6 = 1;"
+ /* pass r6 through r1 into subprog to get it back as r0;
+ * this whole chain will have to be marked as precise later
+ */
+ "r1 = r6;"
+ "call identity_subprog;"
+ /* let's setup two registers that are aliased to r10 */
+ "r7 = r10;"
+ "r7 += -8;" /* r7 = r10 - 8 */
+ "r8 = r10;"
+ "r8 += -32;" /* r8 = r10 - 32 */
+ /* now spill subprog's return value (a r6 -> r1 -> r0 chain)
+ * a few times through different stack pointer regs, making
+ * sure to use r10, r7, and r8 both in LDX and STX insns, and
+ * *importantly* also using a combination of const var_off and
+ * insn->off to validate that we record final stack slot
+ * correctly, instead of relying on just insn->off derivation,
+ * which is only valid for r10-based stack offset
+ */
+ "*(u64 *)(r10 - 16) = r0;"
+ "r0 = *(u64 *)(r7 - 8);" /* r7 - 8 == r10 - 16 */
+ "*(u64 *)(r8 + 16) = r0;" /* r8 + 16 = r10 - 16 */
+ "r0 = *(u64 *)(r8 + 16);"
+ "*(u64 *)(r7 - 8) = r0;"
+ "r0 = *(u64 *)(r10 - 16);"
+ /* get ready to use r0 as an index into array to force precision */
+ "r0 *= 4;"
+ "r1 = %[vals];"
+ /* here r0->r1->r6 chain is forced to be precise and has to be
+ * propagated back to the beginning, including through the
+ * subprog call and all the stack spills and loads
+ */
+ "r1 += r0;"
+ "r0 = *(u32 *)(r1 + 0);"
"exit;"
+ :
+ : __imm_ptr(vals)
+ : __clobber_common, "r6"
);
}
diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c
index 0d84dd1f38b6..8a2ff81d8350 100644
--- a/tools/testing/selftests/bpf/verifier/precise.c
+++ b/tools/testing/selftests/bpf/verifier/precise.c
@@ -140,10 +140,11 @@
.result = REJECT,
},
{
- "precise: ST insn causing spi > allocated_stack",
+ "precise: ST zero to stack insn is supported",
.insns = {
BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0),
+ /* not a register spill, so we stop precision propagation for R4 here */
BPF_ST_MEM(BPF_DW, BPF_REG_3, -8, 0),
BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8),
BPF_MOV64_IMM(BPF_REG_0, -1),
@@ -157,11 +158,11 @@
mark_precise: frame0: last_idx 4 first_idx 2\
mark_precise: frame0: regs=r4 stack= before 4\
mark_precise: frame0: regs=r4 stack= before 3\
- mark_precise: frame0: regs= stack=-8 before 2\
- mark_precise: frame0: falling back to forcing all scalars precise\
- force_precise: frame0: forcing r0 to be precise\
mark_precise: frame0: last_idx 5 first_idx 5\
- mark_precise: frame0: parent state regs= stack=:",
+ mark_precise: frame0: parent state regs=r0 stack=:\
+ mark_precise: frame0: last_idx 4 first_idx 2\
+ mark_precise: frame0: regs=r0 stack= before 4\
+ 5: R0=-1 R4=0",
.result = VERBOSE_ACCEPT,
.retval = -1,
},
@@ -169,6 +170,8 @@
"precise: STX insn causing spi > allocated_stack",
.insns = {
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
+ /* make later reg spill more interesting by having somewhat known scalar */
+ BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xff),
BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0),
BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, -8),
@@ -179,18 +182,21 @@
},
.prog_type = BPF_PROG_TYPE_XDP,
.flags = BPF_F_TEST_STATE_FREQ,
- .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\
+ .errstr = "mark_precise: frame0: last_idx 7 first_idx 7\
mark_precise: frame0: parent state regs=r4 stack=:\
- mark_precise: frame0: last_idx 5 first_idx 3\
- mark_precise: frame0: regs=r4 stack= before 5\
- mark_precise: frame0: regs=r4 stack= before 4\
- mark_precise: frame0: regs= stack=-8 before 3\
- mark_precise: frame0: falling back to forcing all scalars precise\
- force_precise: frame0: forcing r0 to be precise\
- force_precise: frame0: forcing r0 to be precise\
- force_precise: frame0: forcing r0 to be precise\
- force_precise: frame0: forcing r0 to be precise\
- mark_precise: frame0: last_idx 6 first_idx 6\
+ mark_precise: frame0: last_idx 6 first_idx 4\
+ mark_precise: frame0: regs=r4 stack= before 6: (b7) r0 = -1\
+ mark_precise: frame0: regs=r4 stack= before 5: (79) r4 = *(u64 *)(r10 -8)\
+ mark_precise: frame0: regs= stack=-8 before 4: (7b) *(u64 *)(r3 -8) = r0\
+ mark_precise: frame0: parent state regs=r0 stack=:\
+ mark_precise: frame0: last_idx 3 first_idx 3\
+ mark_precise: frame0: regs=r0 stack= before 3: (55) if r3 != 0x7b goto pc+0\
+ mark_precise: frame0: regs=r0 stack= before 2: (bf) r3 = r10\
+ mark_precise: frame0: regs=r0 stack= before 1: (57) r0 &= 255\
+ mark_precise: frame0: parent state regs=r0 stack=:\
+ mark_precise: frame0: last_idx 0 first_idx 0\
+ mark_precise: frame0: regs=r0 stack= before 0: (85) call bpf_get_prandom_u32#7\
+ mark_precise: frame0: last_idx 7 first_idx 7\
mark_precise: frame0: parent state regs= stack=:",
.result = VERBOSE_ACCEPT,
.retval = -1,
diff --git a/tools/testing/selftests/mqueue/setting b/tools/testing/selftests/mqueue/setting
deleted file mode 100644
index a953c96aa16e..000000000000
--- a/tools/testing/selftests/mqueue/setting
+++ /dev/null
@@ -1 +0,0 @@
-timeout=180
diff --git a/tools/testing/selftests/mqueue/settings b/tools/testing/selftests/mqueue/settings
new file mode 100644
index 000000000000..a953c96aa16e
--- /dev/null
+++ b/tools/testing/selftests/mqueue/settings
@@ -0,0 +1 @@
+timeout=180
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-17 15:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-17 15:39 Linux 6.6.140 Greg Kroah-Hartman
2026-05-17 15:39 ` Greg Kroah-Hartman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox