From 1f7d764785e331a2e49cd6d5cad8fd0c778e3f19 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 13 May 2022 17:47:36 +0200 Subject: [PATCH] ANDROID: reset android13-5.10-lts branch back to android13-5.10 state The android13-5.10-lts branch was allowed to get out of sync with regards to the ABI state while some LTS releases were merged into it. In order to sort this out, and ensure that the ABI is stable, reset it back to the current state of the android13-5.10 branch as of commit 46fc349c5456 ("ANDROID: Update the ABI representation") Bug: 161946584 Signed-off-by: Greg Kroah-Hartman Change-Id: Ia1c4798fb0b80e61de81b3f0ae89c89f8c6b1c55 --- Documentation/ABI/testing/sysfs-fs-erofs | 7 + Documentation/ABI/testing/sysfs-fs-f2fs | 54 +- Documentation/admin-guide/mm/index.rst | 1 + Documentation/admin-guide/mm/multigen_lru.rst | 152 + Documentation/admin-guide/sysctl/kernel.rst | 1 - Documentation/core-api/dma-attributes.rst | 8 - .../bindings/mtd/nand-controller.yaml | 4 +- .../devicetree/bindings/spi/spi-mxic.txt | 4 +- Documentation/filesystems/erofs.rst | 8 + Documentation/filesystems/fscrypt.rst | 25 +- Documentation/process/stable-kernel-rules.rst | 11 +- Documentation/sound/hd-audio/models.rst | 4 - Documentation/vm/index.rst | 1 + Documentation/vm/multigen_lru.rst | 160 + Makefile | 2 +- android/abi_gki_aarch64.xml | 12167 ++++++++-------- android/abi_gki_aarch64_generic | 83 +- android/abi_gki_aarch64_hikey960 | 1 - android/abi_gki_aarch64_virtual_device | 132 +- arch/Kconfig | 9 + arch/arc/kernel/process.c | 2 +- arch/arm/boot/dts/bcm2711.dtsi | 50 - arch/arm/boot/dts/bcm2837.dtsi | 49 - arch/arm/boot/dts/dra7-l4.dtsi | 5 +- arch/arm/boot/dts/dra7.dtsi | 8 +- arch/arm/boot/dts/exynos5250-pinctrl.dtsi | 2 +- arch/arm/boot/dts/exynos5250-smdk5250.dts | 3 - arch/arm/boot/dts/exynos5420-smdk5420.dts | 3 - arch/arm/boot/dts/imx53-m53menlo.dts | 29 +- arch/arm/boot/dts/imx7-colibri.dtsi | 4 +- arch/arm/boot/dts/imx7-mba7.dtsi | 2 +- arch/arm/boot/dts/imx7d-nitrogen7.dts | 2 +- arch/arm/boot/dts/imx7d-pico-hobbit.dts | 4 +- arch/arm/boot/dts/imx7d-pico-pi.dts | 4 +- arch/arm/boot/dts/imx7d-sdb.dts | 4 +- arch/arm/boot/dts/imx7s-warp.dts | 4 +- arch/arm/boot/dts/qcom-ipq4019.dtsi | 3 +- arch/arm/boot/dts/qcom-msm8960.dtsi | 8 +- arch/arm/boot/dts/sama5d2.dtsi | 2 +- arch/arm/boot/dts/spear1340.dtsi | 6 +- arch/arm/boot/dts/spear13xx.dtsi | 6 +- arch/arm/boot/dts/sun8i-v3s.dtsi | 22 +- arch/arm/boot/dts/tegra20-tamonten.dtsi | 6 +- arch/arm/configs/multi_v5_defconfig | 1 - arch/arm/crypto/Kconfig | 2 - arch/arm/kernel/entry-ftrace.S | 51 +- arch/arm/kernel/swp_emulate.c | 2 +- arch/arm/kernel/traps.c | 2 +- .../mach-iop32x/include/mach/entry-macro.S | 2 +- arch/arm/mach-iop32x/include/mach/irqs.h | 2 +- arch/arm/mach-iop32x/irq.c | 6 +- arch/arm/mach-iop32x/irqs.h | 60 +- arch/arm/mach-mmp/sram.c | 22 +- arch/arm/mach-mstar/Kconfig | 1 - arch/arm/mach-s3c/mach-jive.c | 6 +- .../boot/dts/broadcom/northstar2/ns2-svk.dts | 8 +- .../boot/dts/broadcom/northstar2/ns2.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 +- arch/arm64/boot/dts/qcom/sm8150.dtsi | 6 +- .../boot/dts/rockchip/rk3399-firefly.dts | 4 +- arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 5 +- arch/arm64/boot/dts/ti/k3-am65.dtsi | 1 - arch/arm64/boot/dts/ti/k3-j7200-main.dtsi | 5 +- arch/arm64/boot/dts/ti/k3-j7200.dtsi | 1 - arch/arm64/boot/dts/ti/k3-j721e-main.dtsi | 5 +- arch/arm64/boot/dts/ti/k3-j721e.dtsi | 1 - arch/arm64/configs/db845c_gki.fragment | 1 - arch/arm64/configs/defconfig | 2 +- arch/arm64/configs/gki_defconfig | 8 +- arch/arm64/include/asm/el2_setup.h | 15 + arch/arm64/include/asm/kvm_asm.h | 5 +- arch/arm64/include/asm/kvm_emulate.h | 5 + arch/arm64/include/asm/kvm_host.h | 9 +- arch/arm64/include/asm/kvm_mmu.h | 4 + arch/arm64/include/asm/kvm_s2mpu.h | 56 +- arch/arm64/include/asm/pgtable.h | 14 +- arch/arm64/include/asm/sysreg.h | 7 + arch/arm64/include/asm/vectors.h | 4 +- arch/arm64/include/asm/virt.h | 12 +- arch/arm64/kernel/image-vars.h | 11 +- arch/arm64/kernel/paravirt.c | 24 +- arch/arm64/kernel/signal.c | 10 +- arch/arm64/kvm/arm.c | 33 +- arch/arm64/kvm/handle_exit.c | 1 + arch/arm64/kvm/hyp/exception.c | 89 +- arch/arm64/kvm/hyp/include/nvhe/iommu.h | 21 +- arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 3 + arch/arm64/kvm/hyp/nvhe/ffa.c | 39 +- arch/arm64/kvm/hyp/nvhe/host.S | 18 +- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 186 +- arch/arm64/kvm/hyp/nvhe/hyp-smp.c | 2 + arch/arm64/kvm/hyp/nvhe/iommu.c | 227 +- arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c | 92 +- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 63 +- arch/arm64/kvm/hyp/nvhe/mm.c | 10 +- arch/arm64/kvm/hyp/nvhe/pkvm.c | 74 + arch/arm64/kvm/hyp/nvhe/psci-relay.c | 45 + arch/arm64/kvm/hyp/nvhe/setup.c | 12 +- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 42 +- arch/arm64/kvm/hypercalls.c | 26 - arch/arm64/kvm/iommu.c | 13 +- arch/arm64/kvm/iommu/s2mpu.c | 36 +- arch/arm64/kvm/mmu.c | 31 +- arch/arm64/kvm/pmu.c | 16 +- arch/arm64/kvm/va_layout.c | 12 + arch/arm64/mm/fault.c | 22 + arch/arm64/mm/init.c | 36 +- arch/arm64/mm/mmu.c | 41 +- arch/arm64/net/bpf_jit_comp.c | 18 +- arch/csky/kernel/perf_callchain.c | 2 +- arch/csky/kernel/signal.c | 2 +- arch/m68k/coldfire/device.c | 6 +- arch/microblaze/include/asm/uaccess.h | 18 +- arch/mips/dec/int-handler.S | 6 +- arch/mips/dec/prom/Makefile | 2 +- arch/mips/dec/setup.c | 3 +- arch/mips/include/asm/dec/prom.h | 15 +- arch/mips/include/asm/pgalloc.h | 6 - arch/mips/rb532/devices.c | 6 +- arch/nds32/include/asm/uaccess.h | 22 +- arch/nios2/include/asm/uaccess.h | 26 +- arch/nios2/kernel/signal.c | 20 +- arch/parisc/include/asm/traps.h | 1 - arch/parisc/kernel/traps.c | 2 - arch/parisc/mm/fault.c | 89 - arch/powerpc/Makefile | 2 +- arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts | 30 - arch/powerpc/boot/dts/fsl/t1040rdb.dts | 8 +- arch/powerpc/include/asm/io.h | 40 +- arch/powerpc/include/asm/uaccess.h | 3 - arch/powerpc/kernel/kvm.c | 2 +- arch/powerpc/kvm/book3s_hv.c | 5 +- arch/powerpc/kvm/powerpc.c | 4 +- arch/powerpc/lib/sstep.c | 12 +- arch/powerpc/mm/kasan/kasan_init_32.c | 3 +- arch/powerpc/mm/numa.c | 4 +- arch/powerpc/perf/imc-pmu.c | 6 +- arch/powerpc/platforms/8xx/pic.c | 1 - arch/powerpc/platforms/powernv/rng.c | 6 +- arch/powerpc/sysdev/fsl_gtm.c | 4 +- arch/riscv/include/asm/module.lds.h | 6 +- arch/riscv/include/asm/thread_info.h | 10 +- arch/riscv/kernel/perf_callchain.c | 6 +- arch/sparc/kernel/signal_32.c | 2 +- arch/um/drivers/mconsole_kern.c | 3 +- arch/x86/Kconfig | 1 + arch/x86/configs/gki_defconfig | 7 +- arch/x86/events/intel/pt.c | 2 +- arch/x86/include/asm/kfence.h | 7 +- arch/x86/include/asm/pgtable.h | 9 +- arch/x86/kernel/acpi/boot.c | 24 - arch/x86/kernel/kvm.c | 2 +- arch/x86/kvm/emulate.c | 14 +- arch/x86/kvm/hyperv.c | 9 +- arch/x86/kvm/lapic.c | 5 +- arch/x86/kvm/mmu/paging_tmpl.h | 77 +- arch/x86/kvm/mmu/tdp_mmu.c | 3 - arch/x86/kvm/svm/avic.c | 10 +- arch/x86/mm/pgtable.c | 5 +- arch/x86/xen/pmu.c | 10 +- arch/x86/xen/pmu.h | 3 +- arch/x86/xen/smp_pv.c | 2 +- arch/xtensa/include/asm/processor.h | 4 +- arch/xtensa/kernel/jump_label.c | 2 +- block/bfq-cgroup.c | 6 - block/bfq-iosched.c | 31 +- block/blk-merge.c | 11 - block/blk-mq-sched.c | 9 +- block/blk-sysfs.c | 8 +- block/mq-deadline.c | 4 +- build.config.common | 3 +- build.config.constants | 2 +- build.config.gki.aarch64 | 2 + build.config.gki.x86_64 | 2 + crypto/authenc.c | 2 +- crypto/rsa-pkcs1pad.c | 11 +- drivers/acpi/acpica/nswalk.c | 3 - drivers/acpi/apei/bert.c | 10 +- drivers/acpi/apei/erst.c | 2 +- drivers/acpi/apei/hest.c | 2 +- drivers/acpi/battery.c | 12 - drivers/acpi/cppc_acpi.c | 5 - drivers/acpi/property.c | 2 +- drivers/acpi/video_detect.c | 75 - drivers/android/binder.c | 17 +- drivers/android/vendor_hooks.c | 15 + drivers/atm/eni.c | 2 - drivers/base/dd.c | 2 +- drivers/base/power/main.c | 6 +- drivers/block/drbd/drbd_req.c | 3 +- drivers/block/loop.c | 10 +- drivers/block/virtio_blk.c | 4 +- drivers/bluetooth/btmtksdio.c | 4 +- drivers/bluetooth/hci_serdev.c | 3 +- drivers/bus/mips_cdmm.c | 1 - drivers/char/hw_random/Kconfig | 2 +- drivers/char/hw_random/atmel-rng.c | 1 - drivers/char/hw_random/cavium-rng-vf.c | 194 +- drivers/char/hw_random/cavium-rng.c | 11 +- drivers/char/hw_random/nomadik-rng.c | 4 +- drivers/char/tpm/tpm-chip.c | 46 +- drivers/char/tpm/tpm-dev-common.c | 8 +- drivers/char/tpm/tpm.h | 2 - drivers/char/tpm/tpm2-space.c | 73 +- drivers/char/virtio_console.c | 7 - drivers/clk/actions/owl-s700.c | 1 - drivers/clk/actions/owl-s900.c | 2 +- drivers/clk/at91/sama7g5.c | 8 +- drivers/clk/clk-clps711x.c | 2 - drivers/clk/clk.c | 13 - drivers/clk/imx/clk-imx7d.c | 1 + drivers/clk/loongson1/clk-loongson1c.c | 1 - drivers/clk/qcom/clk-rcg2.c | 14 +- drivers/clk/qcom/gcc-ipq8074.c | 21 +- drivers/clk/qcom/gcc-msm8994.c | 1 - drivers/clk/tegra/clk-tegra124-emc.c | 1 - .../clk/uniphier/clk-uniphier-fixed-rate.c | 1 - drivers/clocksource/acpi_pm.c | 6 +- drivers/clocksource/exynos_mct.c | 60 +- drivers/clocksource/timer-microchip-pit64b.c | 2 +- drivers/clocksource/timer-of.c | 6 +- drivers/clocksource/timer-ti-dm-systimer.c | 4 +- drivers/cpufreq/qcom-cpufreq-nvmem.c | 2 +- .../allwinner/sun8i-ce/sun8i-ce-cipher.c | 3 - .../crypto/allwinner/sun8i-ce/sun8i-ce-hash.c | 3 - .../allwinner/sun8i-ss/sun8i-ss-cipher.c | 3 - .../crypto/allwinner/sun8i-ss/sun8i-ss-core.c | 2 - .../crypto/allwinner/sun8i-ss/sun8i-ss-hash.c | 3 - drivers/crypto/amlogic/amlogic-gxl-cipher.c | 2 - drivers/crypto/ccp/ccp-dmaengine.c | 16 - drivers/crypto/ccree/cc_buffer_mgr.c | 7 - drivers/crypto/ccree/cc_cipher.c | 2 +- drivers/crypto/mxs-dcp.c | 2 +- drivers/crypto/qat/qat_common/qat_crypto.c | 8 - drivers/crypto/qcom-rng.c | 17 +- .../crypto/rockchip/rk3288_crypto_skcipher.c | 1 + drivers/crypto/vmx/Kconfig | 4 - drivers/dax/super.c | 1 - drivers/dma-buf/dma-buf.c | 8 +- drivers/dma-buf/udmabuf.c | 4 - drivers/dma/hisi_dma.c | 2 +- drivers/firmware/efi/apple-properties.c | 2 +- drivers/firmware/efi/efi-pstore.c | 2 +- drivers/firmware/efi/efi.c | 2 +- drivers/firmware/google/Kconfig | 2 +- drivers/firmware/qcom_scm.c | 6 + drivers/firmware/stratix10-svc.c | 2 +- drivers/fsi/fsi-master-aspeed.c | 21 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +- .../display/dc/irq/dcn21/irq_service_dcn21.c | 14 + drivers/gpu/drm/amd/pm/amdgpu_pm.c | 4 +- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 +- drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 - drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 29 +- drivers/gpu/drm/bridge/cdns-dsi.c | 1 - drivers/gpu/drm/bridge/nwl-dsi.c | 1 - drivers/gpu/drm/bridge/sil-sii8620.c | 2 +- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 1 - drivers/gpu/drm/drm_edid.c | 11 +- drivers/gpu/drm/i915/display/intel_opregion.c | 15 - drivers/gpu/drm/i915/gem/i915_gem_mman.c | 2 +- drivers/gpu/drm/imx/parallel-display.c | 8 + drivers/gpu/drm/meson/meson_drv.c | 6 +- drivers/gpu/drm/meson/meson_osd_afbcd.c | 41 +- drivers/gpu/drm/meson/meson_osd_afbcd.h | 1 - drivers/gpu/drm/mgag200/mgag200_mode.c | 5 +- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 8 - drivers/gpu/drm/msm/dp/dp_display.c | 5 - .../gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c | 9 +- drivers/gpu/drm/panel/panel-simple.c | 2 +- drivers/gpu/drm/panfrost/panfrost_gpu.c | 5 +- drivers/gpu/drm/tegra/dsi.c | 4 +- drivers/gpu/host1x/dev.c | 1 - drivers/greybus/svc.c | 8 +- drivers/hid/hid-logitech-dj.c | 1 - drivers/hid/i2c-hid/i2c-hid-core.c | 32 +- drivers/hid/intel-ish-hid/ishtp-fw-loader.c | 29 +- drivers/hv/Kconfig | 1 - drivers/hv/hv_balloon.c | 2 +- drivers/hwmon/pmbus/pmbus.h | 1 - drivers/hwmon/pmbus/pmbus_core.c | 18 +- drivers/hwmon/sch56xx-common.c | 2 +- .../coresight/coresight-etm4x-core.c | 6 +- .../coresight/coresight-etm4x-sysfs.c | 8 +- drivers/i2c/busses/i2c-meson.c | 12 +- drivers/i2c/busses/i2c-xiic.c | 3 +- drivers/i2c/muxes/i2c-demux-pinctrl.c | 5 +- drivers/iio/accel/mma8452.c | 29 +- drivers/iio/adc/twl6030-gpadc.c | 2 - drivers/iio/afe/iio-rescale.c | 8 +- drivers/iio/inkern.c | 40 +- drivers/infiniband/core/cma.c | 2 +- drivers/infiniband/core/verbs.c | 1 - drivers/infiniband/hw/hfi1/verbs.c | 3 +- drivers/infiniband/hw/mlx5/devx.c | 4 +- drivers/infiniband/hw/mlx5/mr.c | 2 - drivers/input/input.c | 6 + drivers/input/tablet/aiptek.c | 10 +- drivers/input/touchscreen/zinitix.c | 44 +- drivers/iommu/ipmmu-vmsa.c | 4 +- drivers/irqchip/irq-nvic.c | 2 - drivers/irqchip/qcom-pdc.c | 5 +- drivers/mailbox/imx-mailbox.c | 9 - drivers/mailbox/tegra-hsp.c | 5 - drivers/md/bcache/btree.c | 6 +- drivers/md/bcache/writeback.c | 6 +- drivers/md/dm-bow.c | 2 - drivers/md/dm-crypt.c | 2 +- drivers/md/dm-integrity.c | 6 +- drivers/md/dm.c | 17 +- drivers/media/i2c/adv7511-v4l2.c | 2 +- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/adv7842.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 4 +- drivers/media/pci/cx88/cx88-mpeg.c | 3 - drivers/media/pci/ivtv/ivtv-driver.h | 1 + drivers/media/pci/ivtv/ivtv-ioctl.c | 10 +- drivers/media/pci/ivtv/ivtv-streams.c | 11 +- drivers/media/pci/saa7134/saa7134-alsa.c | 8 +- drivers/media/platform/aspeed-video.c | 9 +- drivers/media/platform/coda/coda-common.c | 1 - drivers/media/platform/davinci/vpif.c | 12 +- .../platform/mtk-vcodec/mtk_vcodec_fw_vpu.c | 2 - drivers/media/rc/gpio-ir-tx.c | 28 +- drivers/media/rc/ir_toy.c | 2 +- .../media/test-drivers/vidtv/vidtv_s302m.c | 17 +- drivers/media/usb/em28xx/em28xx-cards.c | 13 +- drivers/media/usb/go7007/s2250-board.c | 10 +- drivers/media/usb/hdpvr/hdpvr-video.c | 4 +- drivers/media/usb/stk1160/stk1160-core.c | 2 +- drivers/media/usb/stk1160/stk1160-v4l.c | 10 +- drivers/media/usb/stk1160/stk1160.h | 2 +- drivers/memory/emif.c | 8 +- drivers/mfd/asic3.c | 10 +- drivers/mfd/mc13xxx-core.c | 4 +- drivers/misc/cardreader/alcor_pci.c | 9 +- drivers/misc/habanalabs/common/debugfs.c | 2 - drivers/misc/kgdbts.c | 4 +- drivers/misc/mei/hw-me-regs.h | 1 - drivers/misc/mei/interrupt.c | 35 +- drivers/misc/mei/pci-me.c | 1 - drivers/mmc/core/host.c | 15 +- drivers/mmc/host/davinci_mmc.c | 6 +- drivers/mtd/nand/onenand/generic.c | 7 +- drivers/mtd/nand/raw/atmel/nand-controller.c | 14 +- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 3 - drivers/mtd/nand/raw/nand_base.c | 44 +- drivers/mtd/nand/raw/nandsim.c | 1 + drivers/mtd/ubi/build.c | 10 +- drivers/mtd/ubi/fastmap.c | 28 +- drivers/mtd/ubi/vmt.c | 8 +- drivers/net/bareudp.c | 25 +- drivers/net/can/m_can/m_can.c | 5 +- .../net/can/spi/mcp251xfd/mcp251xfd-core.c | 2 +- drivers/net/can/usb/ems_usb.c | 1 + drivers/net/can/usb/mcba_usb.c | 27 +- drivers/net/can/usb/usb_8dev.c | 30 +- drivers/net/can/vxcan.c | 2 +- drivers/net/dsa/bcm_sf2_cfp.c | 6 +- drivers/net/dsa/microchip/ksz8795_spi.c | 11 - drivers/net/dsa/microchip/ksz9477_spi.c | 12 - drivers/net/dsa/mv88e6xxx/chip.c | 1 - drivers/net/ethernet/8390/mcf8390.c | 10 +- .../net/ethernet/apm/xgene/xgene_enet_main.c | 12 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 + .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 28 +- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 15 +- .../net/ethernet/broadcom/genet/bcmgenet.c | 10 +- .../ethernet/freescale/enetc/enetc_ethtool.c | 5 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 11 +- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 16 +- drivers/net/ethernet/mscc/ocelot_flower.c | 16 +- .../net/ethernet/pensando/ionic/ionic_main.c | 6 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 29 +- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 1 - .../net/ethernet/qlogic/qlcnic/qlcnic_dcb.h | 10 +- drivers/net/ethernet/sun/sunhme.c | 6 +- .../net/ethernet/xilinx/xilinx_axienet_main.c | 72 +- drivers/net/hamradio/6pack.c | 4 +- drivers/net/hyperv/netvsc_drv.c | 3 - drivers/net/phy/broadcom.c | 21 - drivers/net/phy/marvell.c | 8 +- drivers/net/phy/mscc/mscc_main.c | 3 - drivers/net/usb/smsc95xx.c | 86 +- drivers/net/wireguard/queueing.c | 3 +- drivers/net/wireguard/socket.c | 5 +- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- drivers/net/wireless/ath/ath10k/wow.c | 7 +- drivers/net/wireless/ath/ath9k/htc_hst.c | 5 - drivers/net/wireless/ath/carl9170/main.c | 2 +- drivers/net/wireless/ath/regd.c | 10 +- drivers/net/wireless/ath/wcn36xx/main.c | 3 - drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 - .../broadcom/brcm80211/brcmfmac/firmware.c | 2 - .../broadcom/brcm80211/brcmfmac/pcie.c | 66 +- .../net/wireless/intel/iwlwifi/dvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 +- .../net/wireless/mediatek/mt76/mt7603/main.c | 3 - .../net/wireless/mediatek/mt76/mt7615/main.c | 3 - .../net/wireless/mediatek/mt76/mt7915/mcu.c | 9 +- drivers/net/wireless/ray_cs.c | 6 - drivers/nfc/st21nfca/se.c | 10 - drivers/nvdimm/region_devs.c | 3 - drivers/nvme/host/core.c | 9 +- drivers/nvme/host/tcp.c | 40 - drivers/nvme/target/core.c | 1 + drivers/pci/access.c | 9 +- drivers/pci/controller/pci-aardvark.c | 4 +- drivers/pci/controller/pci-xgene.c | 35 +- drivers/pci/hotplug/pciehp_hpc.c | 2 - drivers/pci/pci.c | 8 +- drivers/pci/quirks.c | 12 - drivers/phy/phy-core-mipi-dphy.c | 4 +- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 2 - drivers/pinctrl/mediatek/pinctrl-paris.c | 30 +- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 4 +- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 185 +- drivers/pinctrl/pinconf-generic.c | 6 +- drivers/pinctrl/pinctrl-rockchip.c | 2 - drivers/pinctrl/renesas/core.c | 5 +- drivers/pinctrl/renesas/pfc-r8a77470.c | 4 +- drivers/pinctrl/samsung/pinctrl-samsung.c | 30 +- drivers/platform/chrome/Makefile | 3 +- .../platform/chrome/cros_ec_sensorhub_ring.c | 3 +- .../platform/chrome/cros_ec_sensorhub_trace.h | 123 - drivers/platform/chrome/cros_ec_trace.h | 95 + drivers/platform/chrome/cros_ec_typec.c | 6 - drivers/platform/x86/huawei-wmi.c | 13 +- drivers/power/reset/gemini-poweroff.c | 4 +- drivers/power/supply/ab8500_fg.c | 4 +- drivers/power/supply/bq24190_charger.c | 7 +- drivers/power/supply/wm8350_power.c | 97 +- drivers/pwm/pwm-lpc18xx-sct.c | 20 +- drivers/regulator/qcom_smd-regulator.c | 4 +- .../regulator/rpi-panel-attiny-regulator.c | 56 +- drivers/remoteproc/qcom_q6v5_adsp.c | 1 - drivers/remoteproc/qcom_q6v5_mss.c | 11 +- drivers/remoteproc/qcom_wcnss.c | 1 - drivers/remoteproc/remoteproc_debugfs.c | 2 +- drivers/rtc/interface.c | 7 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- drivers/scsi/libsas/sas_ata.c | 2 +- drivers/scsi/mpt3sas/mpt3sas_base.c | 5 +- drivers/scsi/pm8001/pm8001_hwi.c | 23 +- drivers/scsi/pm8001/pm80xx_hwi.c | 209 +- drivers/scsi/qla2xxx/qla_attr.c | 7 +- drivers/scsi/qla2xxx/qla_def.h | 10 +- drivers/scsi/qla2xxx/qla_gs.c | 5 +- drivers/scsi/qla2xxx/qla_init.c | 73 +- drivers/scsi/qla2xxx/qla_iocb.c | 8 +- drivers/scsi/qla2xxx/qla_isr.c | 1 - drivers/scsi/qla2xxx/qla_mbx.c | 14 +- drivers/scsi/qla2xxx/qla_nvme.c | 22 - drivers/scsi/qla2xxx/qla_os.c | 8 +- drivers/scsi/qla2xxx/qla_sup.c | 4 +- drivers/scsi/qla2xxx/qla_target.c | 4 +- drivers/scsi/scsi_error.c | 9 +- drivers/scsi/sd.c | 6 +- drivers/scsi/ufs/ufs-mediatek.c | 3 +- drivers/scsi/ufs/ufs.h | 6 + drivers/scsi/ufs/ufshcd-pci.c | 18 + drivers/scsi/ufs/ufshcd.c | 148 +- drivers/scsi/ufs/ufshcd.h | 9 +- drivers/scsi/ufs/ufshpb.c | 2 +- drivers/soc/qcom/ocmem.c | 1 - drivers/soc/qcom/qcom_aoss.c | 2 +- drivers/soc/qcom/rpmpd.c | 3 - drivers/soc/ti/wkup_m3_ipc.c | 4 +- drivers/soundwire/intel.c | 4 +- drivers/spi/spi-mxic.c | 28 +- drivers/spi/spi-pxa2xx-pci.c | 17 +- drivers/spi/spi-tegra114.c | 4 - drivers/spi/spi-tegra20-slink.c | 8 +- drivers/spi/spi-zynqmp-gqspi.c | 5 +- drivers/spi/spi.c | 4 +- drivers/staging/android/ion/ion_buffer.c | 3 + drivers/staging/fbtft/fb_st7789v.c | 2 - drivers/staging/iio/adc/ad7280a.c | 4 +- .../staging/media/atomisp/pci/atomisp_acc.c | 28 +- .../media/atomisp/pci/atomisp_gmin_platform.c | 18 - drivers/staging/media/atomisp/pci/hmm/hmm.c | 7 +- .../staging/media/hantro/hantro_h1_jpeg_enc.c | 2 +- drivers/staging/media/hantro/hantro_h1_regs.h | 2 +- drivers/staging/media/meson/vdec/esparser.c | 7 +- .../staging/media/meson/vdec/vdec_helpers.c | 8 +- .../staging/media/meson/vdec/vdec_helpers.h | 4 +- .../staging/media/sunxi/cedrus/cedrus_h264.c | 2 +- .../staging/media/sunxi/cedrus/cedrus_h265.c | 2 +- drivers/staging/media/zoran/zoran.h | 2 +- drivers/staging/media/zoran/zoran_card.c | 86 +- drivers/staging/media/zoran/zoran_device.c | 7 +- drivers/staging/media/zoran/zoran_driver.c | 18 +- drivers/staging/mt7621-dts/gbpc1.dts | 40 +- drivers/staging/mt7621-dts/gbpc2.dts | 116 +- drivers/staging/mt7621-dts/mt7621.dtsi | 26 +- drivers/target/target_core_configfs.c | 1 + drivers/target/target_core_file.c | 1 + .../intel/int340x_thermal/int3400_thermal.c | 7 +- drivers/tty/hvc/hvc_iucv.c | 4 +- drivers/tty/mxser.c | 15 +- drivers/tty/serial/8250/8250_dma.c | 11 +- drivers/tty/serial/8250/8250_lpss.c | 28 +- drivers/tty/serial/8250/8250_mid.c | 19 +- drivers/tty/serial/8250/8250_port.c | 16 +- drivers/tty/serial/kgdboc.c | 6 +- drivers/tty/serial/serial_core.c | 14 - drivers/usb/class/usbtmc.c | 13 +- drivers/usb/dwc3/core.c | 12 +- drivers/usb/gadget/function/f_accessory.c | 1 + drivers/usb/gadget/function/f_mass_storage.c | 1 + drivers/usb/gadget/function/f_uac1_legacy.c | 1 + drivers/usb/gadget/function/rndis.c | 1 - drivers/usb/gadget/function/storage_common.c | 1 + drivers/usb/gadget/udc/core.c | 3 + drivers/usb/host/xhci-hub.c | 5 +- drivers/usb/host/xhci-mem.c | 2 +- drivers/usb/host/xhci.c | 20 +- drivers/usb/host/xhci.h | 14 +- drivers/usb/serial/Kconfig | 1 - drivers/usb/serial/pl2303.c | 1 - drivers/usb/serial/pl2303.h | 3 - drivers/usb/serial/usb-serial-simple.c | 7 - drivers/usb/storage/ene_ub6250.c | 155 +- drivers/usb/storage/realtek_cr.c | 2 +- drivers/vdpa/mlx5/net/mlx5_vnet.c | 18 +- drivers/vfio/platform/vfio_amba.c | 10 +- drivers/vhost/vsock.c | 3 +- drivers/video/fbdev/atafb.c | 12 +- drivers/video/fbdev/atmel_lcdfb.c | 11 +- drivers/video/fbdev/cirrusfb.c | 16 +- drivers/video/fbdev/controlfb.c | 6 +- drivers/video/fbdev/core/fbcvt.c | 53 +- drivers/video/fbdev/matrox/matroxfb_base.c | 2 +- drivers/video/fbdev/nvidia/nv_i2c.c | 2 +- .../omap2/omapfb/displays/connector-dvi.c | 1 - .../omap2/omapfb/displays/panel-dsi-cm.c | 8 +- .../omapfb/displays/panel-sony-acx565akm.c | 2 +- .../omapfb/displays/panel-tpo-td043mtea1.c | 4 +- drivers/video/fbdev/sm712fb.c | 46 +- drivers/video/fbdev/smscufx.c | 3 +- drivers/video/fbdev/udlfb.c | 8 +- drivers/video/fbdev/w100fb.c | 15 +- drivers/virtio/virtio_pci_common.c | 48 +- drivers/virtio/virtio_pci_common.h | 7 +- drivers/virtio/virtio_pci_legacy.c | 5 +- drivers/virtio/virtio_pci_modern.c | 40 +- drivers/watchdog/rti_wdt.c | 1 - fs/9p/v9fs.c | 1 + fs/Makefile | 2 + fs/adfs/super.c | 1 + fs/affs/super.c | 1 + fs/afs/main.c | 1 + fs/attr.c | 6 +- fs/autofs/init.c | 1 + fs/bad_inode.c | 4 +- fs/befs/linuxvfs.c | 1 + fs/bfs/inode.c | 1 + fs/binfmt_elf.c | 90 +- fs/binfmt_elf_fdpic.c | 18 +- fs/binfmt_misc.c | 1 + fs/block_dev.c | 4 +- fs/btrfs/reflink.c | 7 +- fs/btrfs/super.c | 1 + fs/buffer.c | 34 +- fs/cachefiles/main.c | 1 + fs/ceph/super.c | 1 + fs/cifs/cifsfs.c | 1 + fs/cifs/smb2ops.c | 130 +- fs/coda/psdev.c | 1 + fs/configfs/mount.c | 1 + fs/coredump.c | 88 +- fs/cramfs/inode.c | 1 + fs/crypto/Makefile | 2 + fs/crypto/inline_crypt.c | 42 +- fs/dcache.c | 6 +- fs/direct-io.c | 2 +- fs/ecryptfs/main.c | 1 + fs/efivarfs/super.c | 1 + fs/efs/inode.c | 1 + fs/erofs/Makefile | 2 +- fs/erofs/internal.h | 12 + fs/erofs/super.c | 13 + fs/erofs/sysfs.c | 239 + fs/exec.c | 30 +- fs/exfat/super.c | 3 +- fs/ext2/super.c | 7 +- fs/ext4/inline.c | 9 +- fs/ext4/inode.c | 3 +- fs/ext4/mballoc.c | 126 +- fs/ext4/namei.c | 10 +- fs/ext4/super.c | 1 + fs/f2fs/Kconfig | 7 + fs/f2fs/checkpoint.c | 16 +- fs/f2fs/data.c | 20 +- fs/f2fs/debug.c | 25 +- fs/f2fs/f2fs.h | 48 +- fs/f2fs/file.c | 35 +- fs/f2fs/gc.c | 3 + fs/f2fs/inode.c | 9 +- fs/f2fs/namei.c | 3 +- fs/f2fs/node.c | 2 + fs/f2fs/node.h | 3 + fs/f2fs/recovery.c | 31 +- fs/f2fs/segment.c | 22 +- fs/f2fs/segment.h | 5 +- fs/f2fs/super.c | 28 +- fs/f2fs/sysfs.c | 34 +- fs/fat/inode.c | 1 + fs/fat/namei_msdos.c | 1 + fs/fat/namei_vfat.c | 1 + fs/file.c | 33 +- fs/freevxfs/vxfs_super.c | 1 + fs/fs-writeback.c | 8 +- fs/fs_types.c | 2 +- fs/fscache/Makefile | 2 + fs/fuse/backing.c | 528 +- fs/fuse/control.c | 2 +- fs/fuse/dev.c | 30 +- fs/fuse/file.c | 2 +- fs/fuse/fuse_i.h | 277 +- fs/fuse/inode.c | 14 + fs/fuse/readdir.c | 12 +- fs/fuse/virtio_fs.c | 8 +- fs/gfs2/main.c | 1 + fs/gfs2/rgrp.c | 3 +- fs/hfs/super.c | 1 + fs/hfsplus/super.c | 1 + fs/hpfs/super.c | 1 + fs/incfs/data_mgmt.h | 6 + fs/incfs/main.c | 1 + fs/incfs/vfs.c | 79 +- fs/inode.c | 36 +- fs/io_uring.c | 7 +- fs/ioctl.c | 4 +- fs/isofs/inode.c | 1 + fs/jbd2/Makefile | 2 + fs/jbd2/journal.c | 1 + fs/jffs2/build.c | 4 +- fs/jffs2/fs.c | 2 +- fs/jffs2/scan.c | 6 +- fs/jffs2/super.c | 1 + fs/jfs/jfs_dmap.c | 7 - fs/jfs/super.c | 1 + fs/libfs.c | 2 +- fs/minix/inode.c | 1 + fs/mpage.c | 4 +- fs/namei.c | 14 +- fs/namespace.c | 4 +- fs/nfs/callback_proc.c | 27 +- fs/nfs/callback_xdr.c | 4 + fs/nfs/inode.c | 1 + fs/nfs/nfs2xdr.c | 2 +- fs/nfs/nfs3xdr.c | 21 +- fs/nfs/nfs4proc.c | 1 - fs/nfs/nfs4super.c | 1 + fs/nfs/pnfs.c | 11 - fs/nfs/pnfs.h | 2 - fs/nfs/write.c | 5 +- fs/nfsd/filecache.c | 6 +- fs/nfsd/nfs4state.c | 12 +- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfsproc.c | 2 +- fs/nfsd/xdr.h | 2 +- fs/nilfs2/super.c | 1 + fs/nls/nls_base.c | 6 +- fs/nls/nls_euc-jp.c | 1 + fs/nls/nls_koi8-ru.c | 1 + fs/ntfs/inode.c | 4 - fs/ntfs/super.c | 1 + fs/ocfs2/dlmfs/dlmfs.c | 1 + fs/ocfs2/super.c | 23 +- fs/omfs/inode.c | 1 + fs/open.c | 4 +- fs/orangefs/orangefs-mod.c | 1 + fs/overlayfs/super.c | 1 + fs/proc/bootconfig.c | 2 - fs/proc/task_mmu.c | 6 +- fs/pstore/platform.c | 38 +- fs/qnx4/inode.c | 1 + fs/qnx6/inode.c | 1 + fs/read_write.c | 4 +- fs/reiserfs/super.c | 1 + fs/romfs/super.c | 1 + fs/splice.c | 4 +- fs/squashfs/super.c | 1 + fs/stat.c | 2 +- fs/super.c | 4 +- fs/sync.c | 2 +- fs/sysv/super.c | 1 + fs/ubifs/dir.c | 32 +- fs/ubifs/file.c | 14 +- fs/ubifs/io.c | 34 +- fs/ubifs/ioctl.c | 2 +- fs/ubifs/super.c | 1 + fs/udf/super.c | 1 + fs/ufs/super.c | 1 + fs/userfaultfd.c | 6 +- fs/vboxsf/super.c | 1 + fs/verity/Makefile | 2 + fs/xattr.c | 6 +- fs/xfs/xfs_super.c | 1 + fs/zonefs/super.c | 1 + include/linux/binfmts.h | 3 - include/linux/blk-cgroup.h | 17 - include/linux/bpf_types.h | 2 +- include/linux/cgroup.h | 15 +- include/linux/coredump.h | 5 +- include/linux/damon.h | 511 + include/linux/delay.h | 8 + include/linux/dma-mapping.h | 12 +- include/linux/export.h | 6 +- include/linux/gfp.h | 8 +- include/linux/if_arp.h | 1 - include/linux/kasan.h | 13 +- include/linux/memcontrol.h | 34 + include/linux/mm.h | 12 +- include/linux/mm_inline.h | 400 +- include/linux/mm_types.h | 85 +- include/linux/mmzone.h | 217 + include/linux/module.h | 3 +- include/linux/mtd/rawnand.h | 2 - include/linux/netdevice.h | 6 +- include/linux/nodemask.h | 1 + include/linux/page-flags-layout.h | 65 +- include/linux/page-flags.h | 8 +- include/linux/page_ext.h | 4 +- include/linux/page_idle.h | 6 +- include/linux/page_pinner.h | 52 +- include/linux/pci.h | 1 - include/linux/pgtable.h | 17 +- include/linux/pstore.h | 6 +- include/linux/sched.h | 4 + include/linux/serial_core.h | 2 - include/linux/soc/ti/ti_sci_protocol.h | 2 +- include/linux/sunrpc/xdr.h | 2 - include/linux/swap.h | 6 + include/linux/swap_slots.h | 1 + include/linux/wait.h | 1 + include/net/af_vsock.h | 3 +- include/net/esp.h | 2 - include/net/sock.h | 1 - include/net/udp.h | 1 - include/net/udp_tunnel.h | 3 +- include/scsi/scsi_device.h | 1 + include/sound/pcm.h | 2 - include/trace/events/damon.h | 46 + include/trace/events/ext4.h | 78 +- include/trace/events/mmflags.h | 2 +- include/trace/events/pagemap.h | 11 +- include/trace/events/rxrpc.h | 8 +- include/trace/hooks/avc.h | 1 - include/trace/hooks/binder.h | 1 - include/trace/hooks/block.h | 1 - include/trace/hooks/bug.h | 1 - include/trace/hooks/cgroup.h | 1 - include/trace/hooks/cpu.h | 1 - include/trace/hooks/cpufreq.h | 1 - include/trace/hooks/cpuidle.h | 1 - include/trace/hooks/cpuidle_psci.h | 1 - include/trace/hooks/creds.h | 1 - include/trace/hooks/debug.h | 1 - include/trace/hooks/dtask.h | 1 - include/trace/hooks/epoch.h | 1 - include/trace/hooks/fault.h | 1 - include/trace/hooks/fips140.h | 1 - include/trace/hooks/fpsimd.h | 1 - include/trace/hooks/fs.h | 1 - include/trace/hooks/ftrace_dump.h | 1 - include/trace/hooks/futex.h | 1 - include/trace/hooks/gic.h | 1 - include/trace/hooks/gic_v3.h | 1 - include/trace/hooks/gpiolib.h | 1 - include/trace/hooks/gup.h | 33 + include/trace/hooks/hung_task.h | 1 - include/trace/hooks/i2c.h | 1 - include/trace/hooks/iommu.h | 1 - include/trace/hooks/ipv6.h | 1 - include/trace/hooks/logbuf.h | 1 - include/trace/hooks/memory.h | 1 - include/trace/hooks/mm.h | 1 - include/trace/hooks/mmc_core.h | 1 - include/trace/hooks/module.h | 1 - include/trace/hooks/mpam.h | 1 - include/trace/hooks/net.h | 1 - include/trace/hooks/pci.h | 21 + include/trace/hooks/pm_domain.h | 1 - include/trace/hooks/power.h | 1 - include/trace/hooks/preemptirq.h | 1 - include/trace/hooks/printk.h | 1 - include/trace/hooks/psi.h | 1 - include/trace/hooks/remoteproc.h | 1 - include/trace/hooks/rwsem.h | 1 - include/trace/hooks/sched.h | 25 +- include/trace/hooks/scmi.h | 1 - include/trace/hooks/selinux.h | 1 - include/trace/hooks/shmem_fs.h | 1 - include/trace/hooks/signal.h | 1 - include/trace/hooks/snd_compr.h | 1 - include/trace/hooks/softlockup.h | 1 - include/trace/hooks/sound.h | 1 - include/trace/hooks/sys.h | 1 - include/trace/hooks/syscall_check.h | 1 - include/trace/hooks/sysrqcrash.h | 1 - include/trace/hooks/thermal.h | 1 - include/trace/hooks/timer.h | 1 - include/trace/hooks/topology.h | 1 - include/trace/hooks/traps.h | 1 - include/trace/hooks/typec.h | 1 - include/trace/hooks/ufshcd.h | 1 - include/trace/hooks/usb.h | 1 - include/trace/hooks/user.h | 1 - include/trace/hooks/v4l2core.h | 1 - include/trace/hooks/v4l2mc.h | 1 - include/trace/hooks/vendor_hooks.h | 2 + include/trace/hooks/vmscan.h | 1 - include/trace/hooks/workqueue.h | 1 - include/trace/hooks/wqlockup.h | 1 - include/uapi/linux/bpf.h | 12 +- include/uapi/linux/fuse.h | 50 +- include/uapi/linux/kvm.h | 2 - include/uapi/linux/psci.h | 2 + include/uapi/linux/rseq.h | 20 +- kernel/audit.h | 4 - kernel/auditsc.c | 87 +- kernel/bounds.c | 7 + kernel/bpf/bpf_fuse.c | 6 +- kernel/bpf/stackmap.c | 56 +- kernel/cgroup/cgroup-internal.h | 20 - kernel/cgroup/cgroup-v1.c | 32 +- kernel/cgroup/cgroup.c | 84 +- kernel/debug/kdb/kdb_support.c | 2 +- kernel/dma/debug.c | 4 +- kernel/dma/swiotlb.c | 3 +- kernel/events/core.c | 3 - kernel/exit.c | 1 + kernel/fork.c | 13 +- kernel/futex.c | 8 +- kernel/livepatch/core.c | 4 +- kernel/locking/lockdep.c | 38 +- kernel/locking/lockdep_internals.h | 6 +- kernel/locking/lockdep_proc.c | 51 +- kernel/power/hibernate.c | 2 +- kernel/power/suspend_test.c | 8 +- kernel/printk/printk.c | 6 +- kernel/ptrace.c | 47 +- kernel/rcu/Kconfig | 14 + kernel/rcu/rcu.h | 5 + kernel/rcu/tree.c | 51 +- kernel/rcu/tree.h | 5 + kernel/rcu/tree_exp.h | 147 +- kernel/rcu/tree_plugin.h | 1 - kernel/rseq.c | 13 +- kernel/sched/core.c | 2 +- kernel/sched/debug.c | 10 + kernel/sched/fair.c | 10 + kernel/sched/pelt.c | 11 +- kernel/sched/rt.c | 3 + kernel/scs.c | 12 +- kernel/sys.c | 19 +- kernel/time/timer.c | 30 +- kernel/watch_queue.c | 4 +- lib/kunit/try-catch.c | 2 +- lib/raid6/test/Makefile | 4 +- lib/raid6/test/test.c | 1 + lib/test_kasan.c | 56 +- lib/test_kmod.c | 1 - lib/test_lockup.c | 12 +- lib/test_xarray.c | 22 - lib/xarray.c | 4 - mm/Kconfig | 38 +- mm/Makefile | 1 + mm/compaction.c | 2 +- mm/damon/Kconfig | 88 + mm/damon/Makefile | 7 + mm/damon/core-test.h | 253 + mm/damon/core.c | 1075 ++ mm/damon/dbgfs-test.h | 180 + mm/damon/dbgfs.c | 990 ++ mm/damon/paddr.c | 275 + mm/damon/prmtv-common.c | 133 + mm/damon/prmtv-common.h | 16 + mm/damon/reclaim.c | 425 + mm/damon/vaddr-test.h | 324 + mm/damon/vaddr.c | 761 + mm/debug.c | 1 - mm/gup.c | 72 +- mm/huge_memory.c | 3 +- mm/kasan/hw_tags.c | 23 +- mm/kasan/kasan.h | 20 +- mm/kasan/report.c | 17 +- mm/kasan/shadow.c | 5 +- mm/kmemleak.c | 9 +- mm/ksm.c | 18 +- mm/madvise.c | 92 +- mm/memcontrol.c | 29 +- mm/memory.c | 68 +- mm/mempolicy.c | 10 +- mm/migrate.c | 2 +- mm/mlock.c | 12 +- mm/mm_init.c | 10 +- mm/mmap.c | 14 +- mm/mmzone.c | 2 + mm/mprotect.c | 2 +- mm/page_alloc.c | 429 +- mm/page_ext.c | 12 +- mm/page_idle.c | 10 - mm/page_io.c | 54 - mm/page_pinner.c | 363 +- mm/rmap.c | 7 + mm/swap.c | 117 +- mm/swap_state.c | 3 +- mm/usercopy.c | 5 +- mm/vmscan.c | 3129 +++- mm/workingset.c | 119 +- net/9p/mod.c | 1 + net/batman-adv/bridge_loop_avoidance.c | 6 - net/batman-adv/distributed-arp-table.c | 3 - net/batman-adv/gateway_client.c | 12 +- net/batman-adv/gateway_client.h | 16 +- net/batman-adv/hard-interface.h | 3 - net/batman-adv/network-coding.c | 6 - net/batman-adv/originator.c | 72 +- net/batman-adv/originator.h | 96 +- net/batman-adv/soft-interface.c | 15 +- net/batman-adv/soft-interface.h | 16 +- net/batman-adv/tp_meter.c | 3 - net/batman-adv/translation-table.c | 22 +- net/batman-adv/translation-table.h | 18 +- net/batman-adv/tvlv.c | 6 - net/bluetooth/hci_conn.c | 2 - net/bpfilter/bpfilter_kern.c | 1 + net/can/isotp.c | 69 +- net/core/skbuff.c | 4 +- net/core/skmsg.c | 17 +- net/dsa/dsa2.c | 1 - net/ipv4/esp4.c | 5 - net/ipv4/route.c | 18 +- net/ipv4/tcp_bpf.c | 14 +- net/ipv4/tcp_output.c | 5 +- net/ipv4/udp.c | 6 - net/ipv6/esp6.c | 8 +- net/ipv6/ip6_output.c | 4 +- net/ipv6/udp.c | 4 +- net/key/af_key.c | 2 +- net/llc/af_llc.c | 49 +- net/mac80211/cfg.c | 3 + net/netfilter/nf_conntrack_proto_tcp.c | 17 +- net/netfilter/nf_tables_core.c | 2 +- net/netlink/af_netlink.c | 2 - net/openvswitch/conntrack.c | 118 +- net/openvswitch/flow_netlink.c | 4 +- net/rxrpc/ar-internal.h | 15 +- net/rxrpc/call_event.c | 2 +- net/rxrpc/call_object.c | 40 +- net/sunrpc/sunrpc_syms.c | 1 + net/sunrpc/xprt.c | 7 - net/tipc/socket.c | 3 +- net/unix/af_unix.c | 1 + net/vmw_vsock/af_vsock.c | 9 +- net/vmw_vsock/virtio_transport.c | 7 +- net/vmw_vsock/vmci_transport.c | 5 +- net/wireless/nl80211.c | 3 +- net/x25/af_x25.c | 11 +- samples/bpf/xdpsock_user.c | 5 +- scripts/dtc/Makefile | 2 +- scripts/gcc-plugins/stackleak_plugin.c | 25 +- security/integrity/evm/evm_main.c | 2 +- security/keys/keyctl_pkey.c | 14 +- security/security.c | 17 +- security/selinux/hooks.c | 11 +- security/selinux/include/policycap.h | 1 - security/selinux/include/policycap_names.h | 3 +- security/selinux/include/security.h | 7 - security/selinux/selinuxfs.c | 2 - security/selinux/xfrm.c | 2 +- security/smack/smack_lsm.c | 2 +- security/tomoyo/load_policy.c | 4 +- sound/core/oss/pcm_oss.c | 12 +- sound/core/oss/pcm_plugin.c | 5 +- sound/core/pcm.c | 3 - sound/core/pcm_lib.c | 5 - sound/core/pcm_memory.c | 11 +- sound/core/pcm_native.c | 120 +- sound/firewire/fcp.c | 4 +- sound/isa/cs423x/cs4236.c | 8 +- sound/pci/ac97/ac97_codec.c | 4 +- sound/pci/cmipci.c | 3 +- sound/pci/hda/patch_hdmi.c | 8 +- sound/pci/hda/patch_realtek.c | 19 +- sound/soc/atmel/atmel_ssc_dai.c | 5 +- sound/soc/atmel/sam9g20_wm8731.c | 1 - sound/soc/atmel/sam9x5_wm8731.c | 16 +- sound/soc/codecs/Kconfig | 5 - sound/soc/codecs/msm8916-wcd-analog.c | 22 +- sound/soc/codecs/msm8916-wcd-digital.c | 5 +- sound/soc/codecs/mt6358.c | 4 - sound/soc/codecs/rt5663.c | 2 - sound/soc/codecs/wcd934x.c | 6 +- sound/soc/codecs/wm8350.c | 28 +- sound/soc/dwc/dwc-i2s.c | 17 +- sound/soc/fsl/fsl_spdif.c | 2 - sound/soc/fsl/imx-es8328.c | 1 - sound/soc/generic/simple-card-utils.c | 2 +- sound/soc/mxs/mxs-saif.c | 5 +- sound/soc/mxs/mxs-sgtl5000.c | 3 - sound/soc/rockchip/rockchip_i2s.c | 18 +- sound/soc/sh/fsi.c | 19 +- sound/soc/soc-compress.c | 5 - sound/soc/soc-core.c | 2 +- sound/soc/soc-generic-dmaengine-pcm.c | 6 +- sound/soc/soc-topology.c | 3 +- sound/soc/sof/imx/imx8m.c | 1 - sound/soc/sof/intel/hda-loader.c | 11 +- sound/soc/sti/uniperif_player.c | 6 +- sound/soc/sti/uniperif_reader.c | 2 +- sound/soc/ti/davinci-i2s.c | 5 +- sound/soc/xilinx/xlnx_formatter_pcm.c | 25 - sound/spi/at73c213.c | 27 +- sound/usb/mixer_maps.c | 10 - sound/usb/mixer_quirks.c | 7 +- tools/include/uapi/linux/bpf.h | 4 +- tools/lib/bpf/btf_dump.c | 5 - tools/lib/bpf/libbpf.c | 3 - tools/lib/bpf/xsk.c | 11 - tools/perf/util/symbol.c | 2 +- .../selftests/bpf/prog_tests/timer_crash.c | 32 + .../selftests/bpf/progs/test_sock_fields.c | 2 +- .../testing/selftests/bpf/progs/timer_crash.c | 54 + .../testing/selftests/bpf/test_lirc_mode2.sh | 5 +- .../selftests/bpf/test_lwt_ip_encap.sh | 10 +- tools/testing/selftests/damon/Makefile | 7 + .../selftests/damon/_chk_dependency.sh | 28 + .../testing/selftests/damon/debugfs_attrs.sh | 88 + .../selftests/filesystems/fuse/fd_bpf.c | 2 +- .../selftests/filesystems/fuse/fuse_test.c | 2 +- .../selftests/filesystems/fuse/test_bpf.c | 12 +- .../selftests/filesystems/incfs/Makefile | 4 +- .../selftests/filesystems/incfs/incfs_test.c | 33 +- .../selftests/filesystems/incfs/utils.c | 15 +- .../selftests/filesystems/incfs/utils.h | 2 + .../selftests/net/test_vxlan_under_vrf.sh | 8 +- tools/testing/selftests/vm/Makefile | 6 +- tools/testing/selftests/x86/Makefile | 6 +- tools/testing/selftests/x86/check_cc.sh | 2 +- tools/virtio/virtio_test.c | 1 - virt/kvm/kvm_main.c | 13 - 1048 files changed, 22576 insertions(+), 14080 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-fs-erofs create mode 100644 Documentation/admin-guide/mm/multigen_lru.rst create mode 100644 Documentation/vm/multigen_lru.rst delete mode 100644 arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts delete mode 100644 drivers/platform/chrome/cros_ec_sensorhub_trace.h create mode 100644 fs/erofs/sysfs.c create mode 100644 include/linux/damon.h create mode 100644 include/trace/events/damon.h create mode 100644 include/trace/hooks/gup.h create mode 100644 include/trace/hooks/pci.h create mode 100644 mm/damon/Kconfig create mode 100644 mm/damon/Makefile create mode 100644 mm/damon/core-test.h create mode 100644 mm/damon/core.c create mode 100644 mm/damon/dbgfs-test.h create mode 100644 mm/damon/dbgfs.c create mode 100644 mm/damon/paddr.c create mode 100644 mm/damon/prmtv-common.c create mode 100644 mm/damon/prmtv-common.h create mode 100644 mm/damon/reclaim.c create mode 100644 mm/damon/vaddr-test.h create mode 100644 mm/damon/vaddr.c create mode 100644 tools/testing/selftests/bpf/prog_tests/timer_crash.c create mode 100644 tools/testing/selftests/bpf/progs/timer_crash.c create mode 100644 tools/testing/selftests/damon/Makefile create mode 100644 tools/testing/selftests/damon/_chk_dependency.sh create mode 100644 tools/testing/selftests/damon/debugfs_attrs.sh diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs new file mode 100644 index 0000000000000..a9512594dc4ca --- /dev/null +++ b/Documentation/ABI/testing/sysfs-fs-erofs @@ -0,0 +1,7 @@ +What: /sys/fs/erofs/features/ +Date: November 2021 +Contact: "Huang Jianan" +Description: Shows all enabled kernel features. + Supported features: + zero_padding, compr_cfgs, big_pcluster, chunked_file, + device_table, compr_head2, sb_chksum. diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 9beb2b650f167..9b583dd0298b7 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -55,8 +55,9 @@ Description: Controls the in-place-update policy. 0x04 F2FS_IPU_UTIL 0x08 F2FS_IPU_SSR_UTIL 0x10 F2FS_IPU_FSYNC - 0x20 F2FS_IPU_ASYNC, + 0x20 F2FS_IPU_ASYNC 0x40 F2FS_IPU_NOCACHE + 0x80 F2FS_IPU_HONOR_OPU_WRITE ==== ================= Refer segment.h for details. @@ -98,6 +99,33 @@ Description: Controls the issue rate of discard commands that consist of small checkpoint is triggered, and issued during the checkpoint. By default, it is disabled with 0. +What: /sys/fs/f2fs//max_discard_request +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the number of discards a thread will issue at a time. + Higher number will allow the discard thread to finish its work + faster, at the cost of higher latency for incomming I/O. + +What: /sys/fs/f2fs//min_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait between + issuing discard requests when there are discards to be issued and + no I/O aware interruptions occur. + +What: /sys/fs/f2fs//mid_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait between + issuing discard requests when there are discards to be issued and + an I/O aware interruption occurs. + +What: /sys/fs/f2fs//max_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait when there are + no discard operations to be issued. + What: /sys/fs/f2fs//discard_granularity Date: July 2017 Contact: "Chao Yu" @@ -269,11 +297,16 @@ Description: Shows current reserved blocks in system, it may be temporarily What: /sys/fs/f2fs//gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" -Description: Do background GC agressively when set. When gc_urgent = 1, - background thread starts to do GC by given gc_urgent_sleep_time - interval. When gc_urgent = 2, F2FS will lower the bar of - checking idle in order to process outstanding discard commands - and GC a little bit aggressively. It is set to 0 by default. +Description: Do background GC aggressively when set. Set to 0 by default. + gc urgent high(1): does GC forcibly in a period of given + gc_urgent_sleep_time and ignores I/O idling check. uses greedy + GC approach and turns SSR mode on. + gc urgent low(2): lowers the bar of checking I/O idling in + order to process outstanding discard commands and GC a + little bit aggressively. uses cost benefit GC approach. + gc urgent mid(3): does GC forcibly in a period of given + gc_urgent_sleep_time and executes a mid level of I/O idling check. + uses cost benefit GC approach. What: /sys/fs/f2fs//gc_urgent_sleep_time Date: August 2017 @@ -430,6 +463,7 @@ Description: Show status of f2fs superblock in real time. 0x800 SBI_QUOTA_SKIP_FLUSH skip flushing quota in current CP 0x1000 SBI_QUOTA_NEED_REPAIR quota file may be corrupted 0x2000 SBI_IS_RESIZEFS resizefs is in process + 0x4000 SBI_IS_FREEZING freefs is in process ====== ===================== ================================= What: /sys/fs/f2fs//ckpt_thread_ioprio @@ -503,7 +537,7 @@ Date: July 2021 Contact: "Daeho Jeong" Description: Show how many segments have been reclaimed by GC during a specific GC mode (0: GC normal, 1: GC idle CB, 2: GC idle greedy, - 3: GC idle AT, 4: GC urgent high, 5: GC urgent low) + 3: GC idle AT, 4: GC urgent high, 5: GC urgent low 6: GC urgent mid) You can re-initialize this value to "0". What: /sys/fs/f2fs//gc_segment_mode @@ -540,3 +574,9 @@ Contact: "Daeho Jeong" Description: You can set the trial count limit for GC urgent high mode with this value. If GC thread gets to the limit, the mode will turn back to GC normal mode. By default, the value is zero, which means there is no limit like before. + +What: /sys/fs/f2fs//max_roll_forward_node_blocks +Date: January 2022 +Contact: "Jaegeuk Kim" +Description: Controls max # of node block writes to be used for roll forward + recovery. This can limit the roll forward recovery time. diff --git a/Documentation/admin-guide/mm/index.rst b/Documentation/admin-guide/mm/index.rst index cd727cfc1b040..2a2b5bd8299a8 100644 --- a/Documentation/admin-guide/mm/index.rst +++ b/Documentation/admin-guide/mm/index.rst @@ -31,6 +31,7 @@ the Linux memory management. idle_page_tracking ksm memory-hotplug + multigen_lru nommu-mmap numa_memory_policy numaperf diff --git a/Documentation/admin-guide/mm/multigen_lru.rst b/Documentation/admin-guide/mm/multigen_lru.rst new file mode 100644 index 0000000000000..3d9a6ef842298 --- /dev/null +++ b/Documentation/admin-guide/mm/multigen_lru.rst @@ -0,0 +1,152 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +Multi-Gen LRU +============= +The multi-gen LRU is an alternative LRU implementation that optimizes +page reclaim and improves performance under memory pressure. Page +reclaim decides the kernel's caching policy and ability to overcommit +memory. It directly impacts the kswapd CPU usage and RAM efficiency. + +Quick start +=========== +Build the kernel with the following configurations. + +* ``CONFIG_LRU_GEN=y`` +* ``CONFIG_LRU_GEN_ENABLED=y`` + +All set! + +Runtime options +=============== +``/sys/kernel/mm/lru_gen/`` contains stable ABIs described in the +following subsections. + +Kill switch +----------- +``enable`` accepts different values to enable or disable the following +components. Its default value depends on ``CONFIG_LRU_GEN_ENABLED``. +All the components should be enabled unless some of them have +unforeseen side effects. Writing to ``enable`` has no effect when a +component is not supported by the hardware, and valid values will be +accepted even when the main switch is off. + +====== =============================================================== +Values Components +====== =============================================================== +0x0001 The main switch for the multi-gen LRU. +0x0002 Clearing the accessed bit in leaf page table entries in large + batches, when MMU sets it (e.g., on x86). This behavior can + theoretically worsen lock contention (mmap_lock). If it is + disabled, the multi-gen LRU will suffer a minor performance + degradation. +0x0004 Clearing the accessed bit in non-leaf page table entries as + well, when MMU sets it (e.g., on x86). This behavior was not + verified on x86 varieties other than Intel and AMD. If it is + disabled, the multi-gen LRU will suffer a negligible + performance degradation. +[yYnN] Apply to all the components above. +====== =============================================================== + +E.g., +:: + + echo y >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0007 + echo 5 >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0005 + +Thrashing prevention +-------------------- +Personal computers are more sensitive to thrashing because it can +cause janks (lags when rendering UI) and negatively impact user +experience. The multi-gen LRU offers thrashing prevention to the +majority of laptop and desktop users who do not have ``oomd``. + +Users can write ``N`` to ``min_ttl_ms`` to prevent the working set of +``N`` milliseconds from getting evicted. The OOM killer is triggered +if this working set cannot be kept in memory. In other words, this +option works as an adjustable pressure relief valve, and when open, it +terminates applications that are hopefully not being used. + +Based on the average human detectable lag (~100ms), ``N=1000`` usually +eliminates intolerable janks due to thrashing. Larger values like +``N=3000`` make janks less noticeable at the risk of premature OOM +kills. + +The default value ``0`` means disabled. + +Experimental features +===================== +``/sys/kernel/debug/lru_gen`` accepts commands described in the +following subsections. Multiple command lines are supported, so does +concatenation with delimiters ``,`` and ``;``. + +``/sys/kernel/debug/lru_gen_full`` provides additional stats for +debugging. ``CONFIG_LRU_GEN_STATS=y`` keeps historical stats from +evicted generations in this file. + +Working set estimation +---------------------- +Working set estimation measures how much memory an application +requires in a given time interval, and it is usually done with little +impact on the performance of the application. E.g., data centers want +to optimize job scheduling (bin packing) to improve memory +utilizations. When a new job comes in, the job scheduler needs to find +out whether each server it manages can allocate a certain amount of +memory for this new job before it can pick a candidate. To do so, this +job scheduler needs to estimate the working sets of the existing jobs. + +When it is read, ``lru_gen`` returns a histogram of numbers of pages +accessed over different time intervals for each memcg and node. +``MAX_NR_GENS`` decides the number of bins for each histogram. +:: + + memcg memcg_id memcg_path + node node_id + min_gen_nr age_in_ms nr_anon_pages nr_file_pages + ... + max_gen_nr age_in_ms nr_anon_pages nr_file_pages + +Each generation contains an estimated number of pages that have been +accessed within ``age_in_ms`` non-cumulatively. E.g., ``min_gen_nr`` +contains the coldest pages and ``max_gen_nr`` contains the hottest +pages, since ``age_in_ms`` of the former is the largest and that of +the latter is the smallest. + +Users can write ``+ memcg_id node_id max_gen_nr +[can_swap[full_scan]]`` to ``lru_gen`` to create a new generation +``max_gen_nr+1``. ``can_swap`` defaults to the swap setting and, if it +is set to ``1``, it forces the scan of anon pages when swap is off. +``full_scan`` defaults to ``1`` and, if it is set to ``0``, it reduces +the overhead as well as the coverage when scanning page tables. + +A typical use case is that a job scheduler writes to ``lru_gen`` at a +certain time interval to create new generations, and it ranks the +servers it manages based on the sizes of their cold memory defined by +this time interval. + +Proactive reclaim +----------------- +Proactive reclaim induces memory reclaim when there is no memory +pressure and usually targets cold memory only. E.g., when a new job +comes in, the job scheduler wants to proactively reclaim memory on the +server it has selected to improve the chance of successfully landing +this new job. + +Users can write ``- memcg_id node_id min_gen_nr [swappiness +[nr_to_reclaim]]`` to ``lru_gen`` to evict generations less than or +equal to ``min_gen_nr``. Note that ``min_gen_nr`` should be less than +``max_gen_nr-1`` as ``max_gen_nr`` and ``max_gen_nr-1`` are not fully +aged and therefore cannot be evicted. ``swappiness`` overrides the +default value in ``/proc/sys/vm/swappiness``. ``nr_to_reclaim`` limits +the number of pages to evict. + +A typical use case is that a job scheduler writes to ``lru_gen`` +before it tries to land a new job on a server, and if it fails to +materialize the cold memory without impacting the existing jobs on +this server, it retries on the next server according to the ranking +result obtained from the working set estimation step described +earlier. diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index e338306f45873..7d5e8a67c775f 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -787,7 +787,6 @@ bit 1 print system memory info bit 2 print timer info bit 3 print locks info if ``CONFIG_LOCKDEP`` is on bit 4 print ftrace buffer -bit 5 print all printk messages in buffer ===== ============================================ So for example to print tasks and memory info on panic, user can:: diff --git a/Documentation/core-api/dma-attributes.rst b/Documentation/core-api/dma-attributes.rst index 17706dc91ec9f..1887d92e8e926 100644 --- a/Documentation/core-api/dma-attributes.rst +++ b/Documentation/core-api/dma-attributes.rst @@ -130,11 +130,3 @@ accesses to DMA buffers in both privileged "supervisor" and unprivileged subsystem that the buffer is fully accessible at the elevated privilege level (and ideally inaccessible or at least read-only at the lesser-privileged levels). - -DMA_ATTR_OVERWRITE ------------------- - -This is a hint to the DMA-mapping subsystem that the device is expected to -overwrite the entire mapped size, thus the caller does not require any of the -previous buffer contents to be preserved. This allows bounce-buffering -implementations to optimise DMA_FROM_DEVICE transfers. diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index 6fe2a3d8ee6b8..b29050fd7470a 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -44,7 +44,7 @@ patternProperties: properties: reg: description: - Contains the chip-select IDs. + Contains the native Ready/Busy IDs. nand-ecc-mode: description: @@ -174,6 +174,6 @@ examples: nand-ecc-mode = "soft"; nand-ecc-algo = "bch"; - /* NAND chip specific properties */ + /* controller specific properties */ }; }; diff --git a/Documentation/devicetree/bindings/spi/spi-mxic.txt b/Documentation/devicetree/bindings/spi/spi-mxic.txt index 7bcbb229b78bb..529f2dab2648a 100644 --- a/Documentation/devicetree/bindings/spi/spi-mxic.txt +++ b/Documentation/devicetree/bindings/spi/spi-mxic.txt @@ -8,13 +8,11 @@ Required properties: - reg: should contain 2 entries, one for the registers and one for the direct mapping area - reg-names: should contain "regs" and "dirmap" +- interrupts: interrupt line connected to the SPI controller - clock-names: should contain "ps_clk", "send_clk" and "send_dly_clk" - clocks: should contain 3 entries for the "ps_clk", "send_clk" and "send_dly_clk" clocks -Optional properties: -- interrupts: interrupt line connected to the SPI controller - Example: spi@43c30000 { diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst index 01df283c7d04f..7119aa213be71 100644 --- a/Documentation/filesystems/erofs.rst +++ b/Documentation/filesystems/erofs.rst @@ -93,6 +93,14 @@ dax A legacy option which is an alias for ``dax=always``. device=%s Specify a path to an extra device to be used together. =================== ========================================================= +Sysfs Entries +============= + +Information about mounted erofs file systems can be found in /sys/fs/erofs. +Each mounted filesystem will have a directory in /sys/fs/erofs based on its +device name (i.e., /sys/fs/erofs/sda). +(see also Documentation/ABI/testing/sysfs-fs-erofs) + On-disk details =============== diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 4d5d50dca65c6..6ccd5efb25b77 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -1047,8 +1047,8 @@ astute users may notice some differences in behavior: may be used to overwrite the source files but isn't guaranteed to be effective on all filesystems and storage devices. -- Direct I/O is not supported on encrypted files. Attempts to use - direct I/O on such files will fall back to buffered I/O. +- Direct I/O is supported on encrypted files only under some + circumstances. For details, see `Direct I/O support`_. - The fallocate operations FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE are not supported on encrypted files and will @@ -1179,6 +1179,27 @@ Inline encryption doesn't affect the ciphertext or other aspects of the on-disk format, so users may freely switch back and forth between using "inlinecrypt" and not using "inlinecrypt". +Direct I/O support +================== + +For direct I/O on an encrypted file to work, the following conditions +must be met (in addition to the conditions for direct I/O on an +unencrypted file): + +* The file must be using inline encryption. Usually this means that + the filesystem must be mounted with ``-o inlinecrypt`` and inline + encryption hardware must be present. However, a software fallback + is also available. For details, see `Inline encryption support`_. + +* The I/O request must be fully aligned to the filesystem block size. + This means that the file position the I/O is targeting, the lengths + of all I/O segments, and the memory addresses of all I/O buffers + must be multiples of this value. Note that the filesystem block + size may be greater than the logical block size of the block device. + +If either of the above conditions is not met, then direct I/O on the +encrypted file will fall back to buffered I/O. + Implementation details ====================== diff --git a/Documentation/process/stable-kernel-rules.rst b/Documentation/process/stable-kernel-rules.rst index fbcb48bc2a903..003c865e9c212 100644 --- a/Documentation/process/stable-kernel-rules.rst +++ b/Documentation/process/stable-kernel-rules.rst @@ -168,16 +168,7 @@ Trees - The finalized and tagged releases of all stable kernels can be found in separate branches per version at: - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git - - - The release candidate of all stable kernel versions can be found at: - - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/ - - .. warning:: - The -stable-rc tree is a snapshot in time of the stable-queue tree and - will change frequently, hence will be rebased often. It should only be - used for testing purposes (e.g. to be consumed by CI systems). + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git Review committee diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 9b52f50a68542..d25335993e553 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -261,10 +261,6 @@ alc-sense-combo huawei-mbx-stereo Enable initialization verbs for Huawei MBX stereo speakers; might be risky, try this at your own risk -alc298-samsung-headphone - Samsung laptops with ALC298 -alc256-samsung-headphone - Samsung laptops with ALC256 ALC66x/67x/892 ============== diff --git a/Documentation/vm/index.rst b/Documentation/vm/index.rst index eff5fbd492d08..9f80cc8a1cd9e 100644 --- a/Documentation/vm/index.rst +++ b/Documentation/vm/index.rst @@ -41,6 +41,7 @@ descriptions of data structures and algorithms. ksm memory-model mmu_notifier + multigen_lru numa overcommit-accounting page_migration diff --git a/Documentation/vm/multigen_lru.rst b/Documentation/vm/multigen_lru.rst new file mode 100644 index 0000000000000..8f6498002576c --- /dev/null +++ b/Documentation/vm/multigen_lru.rst @@ -0,0 +1,160 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +Multi-Gen LRU +============= +The multi-gen LRU is an alternative LRU implementation that optimizes +page reclaim and improves performance under memory pressure. Page +reclaim decides the kernel's caching policy and ability to overcommit +memory. It directly impacts the kswapd CPU usage and RAM efficiency. + +Design overview +=============== +Objectives +---------- +The design objectives are: + +* Good representation of access recency +* Try to profit from spatial locality +* Fast paths to make obvious choices +* Simple self-correcting heuristics + +The representation of access recency is at the core of all LRU +implementations. In the multi-gen LRU, each generation represents a +group of pages with similar access recency. Generations establish a +common frame of reference and therefore help make better choices, +e.g., between different memcgs on a computer or different computers in +a data center (for job scheduling). + +Exploiting spatial locality improves efficiency when gathering the +accessed bit. A rmap walk targets a single page and does not try to +profit from discovering a young PTE. A page table walk can sweep all +the young PTEs in an address space, but the address space can be too +large to make a profit. The key is to optimize both methods and use +them in combination. + +Fast paths reduce code complexity and runtime overhead. Unmapped pages +do not require TLB flushes; clean pages do not require writeback. +These facts are only helpful when other conditions, e.g., access +recency, are similar. With generations as a common frame of reference, +additional factors stand out. But obvious choices might not be good +choices; thus self-correction is required. + +The benefits of simple self-correcting heuristics are self-evident. +Again, with generations as a common frame of reference, this becomes +attainable. Specifically, pages in the same generation can be +categorized based on additional factors, and a feedback loop can +statistically compare the refault percentages across those categories +and infer which of them are better choices. + +Assumptions +----------- +The protection of hot pages and the selection of cold pages are based +on page access channels and patterns. There are two access channels: + +* Accesses through page tables +* Accesses through file descriptors + +The protection of the former channel is by design stronger because: + +1. The uncertainty in determining the access patterns of the former + channel is higher due to the approximation of the accessed bit. +2. The cost of evicting the former channel is higher due to the TLB + flushes required and the likelihood of encountering the dirty bit. +3. The penalty of underprotecting the former channel is higher because + applications usually do not prepare themselves for major page + faults like they do for blocked I/O. E.g., GUI applications + commonly use dedicated I/O threads to avoid blocking the rendering + threads. + +There are also two access patterns: + +* Accesses exhibiting temporal locality +* Accesses not exhibiting temporal locality + +For the reasons listed above, the former channel is assumed to follow +the former pattern unless ``VM_SEQ_READ`` or ``VM_RAND_READ`` is +present, and the latter channel is assumed to follow the latter +pattern unless outlying refaults have been observed. + +Workflow overview +================= +Evictable pages are divided into multiple generations for each +``lruvec``. The youngest generation number is stored in +``lrugen->max_seq`` for both anon and file types as they are aged on +an equal footing. The oldest generation numbers are stored in +``lrugen->min_seq[]`` separately for anon and file types as clean file +pages can be evicted regardless of swap constraints. These three +variables are monotonically increasing. + +Generation numbers are truncated into ``order_base_2(MAX_NR_GENS+1)`` +bits in order to fit into the gen counter in ``page->flags``. Each +truncated generation number is an index to ``lrugen->lists[]``. The +sliding window technique is used to track at least ``MIN_NR_GENS`` and +at most ``MAX_NR_GENS`` generations. The gen counter stores a value +within ``[1, MAX_NR_GENS]`` while a page is on one of +``lrugen->lists[]``; otherwise it stores zero. + +Each generation is divided into multiple tiers. Tiers represent +different ranges of numbers of accesses through file descriptors. A +page accessed ``N`` times through file descriptors is in tier +``order_base_2(N)``. In contrast to moving across generations, which +requires the LRU lock, moving across tiers only requires operations on +``page->flags`` and therefore has a negligible cost. A feedback loop +modeled after the PID controller monitors refaults over all the tiers +from anon and file types and decides which tiers from which types to +evict or protect. + +There are two conceptually independent procedures: the aging and the +eviction. They form a closed-loop system, i.e., the page reclaim. + +Aging +----- +The aging produces young generations. Given an ``lruvec``, it +increments ``max_seq`` when ``max_seq-min_seq+1`` approaches +``MIN_NR_GENS``. The aging promotes hot pages to the youngest +generation when it finds them accessed through page tables; the +demotion of cold pages happens consequently when it increments +``max_seq``. The aging uses page table walks and rmap walks to find +young PTEs. For the former, it iterates ``lruvec_memcg()->mm_list`` +and calls ``walk_page_range()`` with each ``mm_struct`` on this list +to scan PTEs. On finding a young PTE, it clears the accessed bit and +updates the gen counter of the page mapped by this PTE to +``(max_seq%MAX_NR_GENS)+1``. After each iteration of this list, it +increments ``max_seq``. For the latter, when the eviction walks the +rmap and finds a young PTE, the aging scans the adjacent PTEs and +follows the same steps just described. + +Eviction +-------- +The eviction consumes old generations. Given an ``lruvec``, it +increments ``min_seq`` when ``lrugen->lists[]`` indexed by +``min_seq%MAX_NR_GENS`` becomes empty. To select a type and a tier to +evict from, it first compares ``min_seq[]`` to select the older type. +If both types are equally old, it selects the one whose first tier has +a lower refault percentage. The first tier contains single-use +unmapped clean pages, which are the best bet. The eviction sorts a +page according to the gen counter if the aging has found this page +accessed through page tables and updated the gen counter. It also +moves a page to the next generation, i.e., ``min_seq+1``, if this page +was accessed multiple times through file descriptors and the feedback +loop has detected outlying refaults from the tier this page is in. To +do this, the feedback loop uses the first tier as the baseline, for +the reason stated earlier. + +Summary +------- +The multi-gen LRU can be disassembled into the following parts: + +* Generations +* Page table walks +* Rmap walks +* Bloom filters +* The PID controller + +The aging and the eviction is a producer-consumer model; specifically, +the latter drives the former by the sliding window over generations. +Within the aging, rmap walks drive page table walks by inserting hot +densely populated page tables to the Bloom filters. Within the +eviction, the PID controller uses refaults as the feedback to select +types to evict and tiers to protect. diff --git a/Makefile b/Makefile index 3944630648626..e4517d58b89f0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 10 -SUBLEVEL = 110 +SUBLEVEL = 107 EXTRAVERSION = NAME = Dare mighty things diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml index 9f3e735ec93d1..61944e90b46a5 100644 --- a/android/abi_gki_aarch64.xml +++ b/android/abi_gki_aarch64.xml @@ -1,15 +1,17 @@ - - - + + + - - + + + + - + @@ -21,78 +23,79 @@ - - - - - + + + + + - - - - + + + + - - + + - - + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + - + - + - + - - - - - - - - - + + + + + + + + + @@ -101,7 +104,7 @@ - + @@ -113,83 +116,83 @@ - + - + - - - - + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + @@ -197,67 +200,82 @@ - + + + - - - + + + - - + + + - - - + + + + - - - - + + + + + + - + - + + + + + - + - + + + - + - - - - + + + + + + - + + @@ -271,56 +289,56 @@ - - + + - - + + - - - - - + + + + + - + - - - + + + - - + + - + - - + + - + - - - - - - - - - - + + + + + + + + + + @@ -346,43 +364,42 @@ - + - + - - + + - + - - - - - + + + + + - - - + + + - + - - - - + + + + - - + @@ -393,28 +410,28 @@ - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + @@ -422,184 +439,184 @@ - - + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -608,72 +625,71 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + - + - + - - - - - - + + + + + + - - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + @@ -681,34 +697,36 @@ - - - - - - - + + + + + + + - - - + + + - + - - + + - - + + - - - + + + + + @@ -716,373 +734,372 @@ - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1095,53 +1112,53 @@ - - - - - - - - + + + + + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - + + + + + + @@ -1152,132 +1169,132 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + @@ -1286,261 +1303,262 @@ - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + + - - + + - + - + - + - + - - + + - - - - - - - + + + + + + + @@ -1553,101 +1571,112 @@ - - - + + + - - - - - - - + + + + + + + - - - + + + - + + - - - + + + - - - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - + + + + + - + - - - - - - - + + + + + + + @@ -1656,71 +1685,71 @@ - - - - - + + + + + - - + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1733,12 +1762,11 @@ - - - + + - - + + @@ -1749,185 +1777,190 @@ - - - + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + - - + + - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + - + - - + + - + @@ -1935,49 +1968,49 @@ - - - - - + + + + + - + - - + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + - + @@ -1994,23 +2027,23 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + @@ -2026,28 +2059,25 @@ - - - - - - + + - + - - - - - - - + + + + + + + + @@ -2068,89 +2098,89 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -2159,50 +2189,50 @@ - - - - - - + + + + + + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - + @@ -2211,310 +2241,315 @@ - - - - + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - + + - + @@ -2524,42 +2559,42 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + @@ -2582,112 +2617,112 @@ - - + + - - - - - + + + + + - + - + - + - - + + - - + + - + - - + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - - + + + + - - + + @@ -2698,404 +2733,394 @@ - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - - - - - - - + + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -3115,7 +3140,7 @@ - + @@ -3136,45 +3161,46 @@ - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - + - - - + + + - + @@ -3185,160 +3211,161 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - + + + + + - + - + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - + + - - + + - - + + - - - - - - + + + + + + - - - - + + + + + - + - - - + + + - - - + + + - + @@ -3348,238 +3375,243 @@ - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + - - - - - + + + + + - - + + - + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + - + - - - + + + - - + + - - + + - - - + + + @@ -3592,30 +3624,30 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + @@ -3625,32 +3657,32 @@ - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -3661,6 +3693,7 @@ + @@ -3668,6 +3701,7 @@ + @@ -3678,60 +3712,72 @@ + + + + + + - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -3756,101 +3802,102 @@ - + - + - - + + + - + - + - - - + + + - + - - + - - + - - - - - - - + + + + + + + - + - + - - + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + - - + + - - + + @@ -3861,14 +3908,14 @@ - - + + - - - + + + @@ -4122,7 +4169,7 @@ - + @@ -4314,12 +4361,12 @@ - + - + - + @@ -4731,7 +4778,7 @@ - + @@ -5019,6 +5066,7 @@ + @@ -5600,41 +5648,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6308,12 +6321,12 @@ - + - + - + @@ -7021,24 +7034,24 @@ - + - + - + - + - + - + - + @@ -7379,7 +7392,6 @@ - @@ -7497,7 +7509,7 @@ - + @@ -8014,7 +8026,7 @@ - + @@ -8025,15 +8037,15 @@ - + - + - + - + @@ -8606,7 +8618,7 @@ - + @@ -9347,10 +9359,13 @@ - + - - + + + + + @@ -9409,12 +9424,12 @@ - + - + - + @@ -9579,6 +9594,7 @@ + @@ -10646,66 +10662,66 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -11394,7 +11410,7 @@ - + @@ -11414,6 +11430,7 @@ + @@ -11971,18 +11988,18 @@ - + - + - + - + - + @@ -12632,33 +12649,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -13246,7 +13263,6 @@ - @@ -13462,7 +13478,6 @@ - @@ -13550,6 +13565,7 @@ + @@ -14272,7 +14288,7 @@ - + @@ -14613,12 +14629,12 @@ - + - + - + @@ -14692,42 +14708,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -15343,12 +15359,12 @@ - + - + - + @@ -15988,21 +16004,15 @@ - - - - - - - + - + - + - + @@ -16989,21 +16999,21 @@ - + - + - + - + - + - + @@ -17704,6 +17714,7 @@ + @@ -17992,222 +18003,222 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -18859,21 +18870,21 @@ - + - + - + - + - + - + @@ -18894,7 +18905,7 @@ - + @@ -19854,7 +19865,6 @@ - @@ -20121,38 +20131,38 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -20475,7 +20485,6 @@ - @@ -20586,7 +20595,6 @@ - @@ -20736,12 +20744,12 @@ - + - + - - + + @@ -20760,57 +20768,57 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -20869,7 +20877,6 @@ - @@ -21207,6 +21214,10 @@ + + + + @@ -21433,7 +21444,7 @@ - + @@ -21448,7 +21459,7 @@ - + @@ -21470,15 +21481,6 @@ - - - - - - - - - @@ -21515,8 +21517,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -21735,12 +21766,12 @@ - + - + - + @@ -22165,10 +22196,6 @@ - - - - @@ -22196,18 +22223,18 @@ - + - + - + - + - + @@ -22235,15 +22262,15 @@ - + - + - + - + @@ -22282,87 +22309,87 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -22468,33 +22495,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -22754,6 +22781,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23034,7 +23108,7 @@ - + @@ -24191,7 +24265,7 @@ - + @@ -24475,14 +24549,6 @@ - - - - - - - - @@ -24996,7 +25062,7 @@ - + @@ -25065,12 +25131,12 @@ - + - + - + @@ -25142,21 +25208,21 @@ - + - + - + - + - + - + @@ -27361,15 +27427,15 @@ - + - + - + - + @@ -27466,7 +27532,7 @@ - + @@ -27761,9 +27827,9 @@ - + - + @@ -27776,7 +27842,6 @@ - @@ -27842,7 +27907,7 @@ - + @@ -27852,30 +27917,30 @@ - + - + - + - + - + - + - + - + - + @@ -28431,24 +28496,24 @@ - + - + - + - + - + - + - + @@ -29199,12 +29264,6 @@ - - - - - - @@ -29842,7 +29901,7 @@ - + @@ -29988,12 +30047,6 @@ - - - - - - @@ -32449,7 +32502,7 @@ - + @@ -32696,96 +32749,99 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - - + + - - + + - - + + - - + + @@ -33556,12 +33612,12 @@ - + - + - + @@ -33720,6 +33776,10 @@ + + + + @@ -33843,7 +33903,7 @@ - + @@ -33858,30 +33918,30 @@ - + - + - + - + - + - + - + - + - + @@ -34014,7 +34074,6 @@ - @@ -35175,7 +35234,7 @@ - + @@ -35532,36 +35591,39 @@ - + - + + + + - + - + - + - + - + - + - + - + @@ -35678,6 +35740,11 @@ + + + + + @@ -35828,7 +35895,6 @@ - @@ -36491,30 +36557,30 @@ - + - + - + - + - + - + - + - + - + @@ -36905,18 +36971,18 @@ - + - + - + - + - + @@ -37499,7 +37565,7 @@ - + @@ -38405,6 +38471,12 @@ + + + + + + @@ -38733,78 +38805,78 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -39228,9 +39300,9 @@ - + - + @@ -39365,24 +39437,24 @@ - + - + - + - + - + - + - + @@ -39392,21 +39464,21 @@ - + - + - + - + - + - + @@ -39610,15 +39682,15 @@ - + - + - + - + @@ -39629,6 +39701,14 @@ + + + + + + + + @@ -39707,7 +39787,6 @@ - @@ -39782,7 +39861,6 @@ - @@ -40695,7 +40773,7 @@ - + @@ -41024,7 +41102,7 @@ - + @@ -41501,24 +41579,24 @@ - + - + - + - + - + - + - + @@ -41952,18 +42030,18 @@ - + - + - + - + - + @@ -42187,6 +42265,11 @@ + + + + + @@ -42812,20 +42895,6 @@ - - - - - - - - - - - - - - @@ -42893,12 +42962,12 @@ - + - + - + @@ -43947,27 +44016,27 @@ - + - + - + - + - + - + - + - + @@ -44163,6 +44232,7 @@ + @@ -44803,54 +44873,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -45402,18 +45472,18 @@ - + - + - + - + - + @@ -45733,7 +45803,7 @@ - + @@ -45967,16 +46037,12 @@ - - - - - + @@ -46020,42 +46086,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -46078,13 +46144,13 @@ - + - + - + @@ -46093,7 +46159,7 @@ - + @@ -46218,54 +46284,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -46418,6 +46484,11 @@ + + + + + @@ -46667,12 +46738,12 @@ - + - + - + @@ -47450,11 +47521,21 @@ + + + + + + + + + + + + + + - - - - @@ -47616,12 +47697,6 @@ - - - - - - @@ -47934,7 +48009,7 @@ - + @@ -48089,15 +48164,18 @@ - + - + - + + + + @@ -48827,6 +48905,11 @@ + + + + + @@ -48984,20 +49067,17 @@ - - - - + - + - + - + @@ -49118,21 +49198,21 @@ - + - + - + - + - + - + @@ -49636,7 +49716,6 @@ - @@ -50025,15 +50104,15 @@ - + - + - + - + @@ -50974,36 +51053,36 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -51998,26 +52077,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -53473,24 +53532,24 @@ - + - + - + - + - + - + - + @@ -53675,12 +53734,6 @@ - - - - - - @@ -55382,11 +55435,6 @@ - - - - - @@ -55636,12 +55684,12 @@ - + - + - + @@ -55832,61 +55880,61 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -57454,9 +57502,6 @@ - - - @@ -57610,7 +57655,7 @@ - + @@ -58133,6 +58178,7 @@ + @@ -58198,7 +58244,6 @@ - @@ -58274,63 +58319,63 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -58775,6 +58820,7 @@ + @@ -58896,6 +58942,10 @@ + + + + @@ -58938,7 +58988,6 @@ - @@ -59284,7 +59333,7 @@ - + @@ -59355,7 +59404,6 @@ - @@ -59367,7 +59415,7 @@ - + @@ -59726,17 +59774,6 @@ - - - - - - - - - - - @@ -60607,15 +60644,15 @@ - + - + - + - + @@ -60886,7 +60923,7 @@ - + @@ -61115,6 +61152,7 @@ + @@ -61853,37 +61891,47 @@ - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + @@ -62504,7 +62552,6 @@ - @@ -62675,6 +62722,7 @@ + @@ -62689,6 +62737,11 @@ + + + + + @@ -62848,7 +62901,7 @@ - + @@ -62981,39 +63034,39 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -63100,7 +63153,7 @@ - + @@ -63381,21 +63434,21 @@ - + - + - + - + - + - + @@ -63426,50 +63479,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -63840,7 +63849,7 @@ - + @@ -64526,6 +64535,7 @@ + @@ -64691,25 +64701,25 @@ - + - + - + - + - + - + - + @@ -67163,7 +67173,7 @@ - + @@ -67171,7 +67181,7 @@ - + @@ -67203,7 +67213,7 @@ - + @@ -67230,7 +67240,7 @@ - + @@ -67241,7 +67251,7 @@ - + @@ -67270,7 +67280,7 @@ - + @@ -67278,7 +67288,7 @@ - + @@ -67286,10 +67296,10 @@ - + - + @@ -67316,10 +67326,10 @@ - + - + @@ -67360,7 +67370,7 @@ - + @@ -67368,7 +67378,7 @@ - + @@ -67384,10 +67394,10 @@ - + - + @@ -67499,16 +67509,16 @@ - + - + - + - + @@ -67578,7 +67588,7 @@ - + @@ -67589,10 +67599,10 @@ - + - + @@ -67717,18 +67727,18 @@ - + - + - + - + @@ -67805,7 +67815,7 @@ - + @@ -67854,7 +67864,7 @@ - + @@ -67870,7 +67880,7 @@ - + @@ -67987,15 +67997,15 @@ - + - + - + - + @@ -68037,15 +68047,15 @@ - + - + - + - + @@ -68245,87 +68255,87 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -68368,7 +68378,7 @@ - + @@ -68393,15 +68403,15 @@ - + - + - + @@ -68409,7 +68419,7 @@ - + @@ -68468,7 +68478,7 @@ - + @@ -68487,7 +68497,7 @@ - + @@ -68495,21 +68505,21 @@ - + - + - + - + - + @@ -68520,12 +68530,12 @@ - + - + - + @@ -68546,10 +68556,10 @@ - + - + @@ -68565,7 +68575,7 @@ - + @@ -68601,7 +68611,7 @@ - + @@ -68614,7 +68624,7 @@ - + @@ -68660,7 +68670,7 @@ - + @@ -68693,13 +68703,13 @@ - + - + - + @@ -68730,7 +68740,7 @@ - + @@ -68741,13 +68751,13 @@ - + - + @@ -68788,7 +68798,7 @@ - + @@ -68921,10 +68931,10 @@ - + - + @@ -68932,27 +68942,27 @@ - + - + - + - + - + - + - + @@ -68960,22 +68970,22 @@ - + - + - + - + - + - + @@ -69034,36 +69044,36 @@ - + - + - + - + - + - + - + - + - + - + @@ -69074,7 +69084,7 @@ - + @@ -69090,96 +69100,96 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -69192,13 +69202,13 @@ - + - + - + @@ -69332,7 +69342,7 @@ - + @@ -69373,11 +69383,6 @@ - - - - - @@ -69665,6 +69670,7 @@ + @@ -70504,14 +70510,8 @@ - - - - - - @@ -71089,6 +71089,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -72360,7 +72395,6 @@ - @@ -73069,7 +73103,7 @@ - + @@ -73092,6 +73126,7 @@ + @@ -73728,7 +73763,7 @@ - + @@ -74140,228 +74175,228 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -74375,15 +74410,15 @@ - + - + - + - + @@ -74396,7 +74431,6 @@ - @@ -74590,10 +74624,13 @@ - + + + + @@ -74653,10 +74690,6 @@ - - - - @@ -74968,12 +75001,12 @@ - + - + - + @@ -75749,409 +75782,412 @@ - + - + - + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -76504,7 +76540,7 @@ - + @@ -76638,52 +76674,46 @@ - - - - + - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -77276,12 +77306,12 @@ - + - + - + @@ -77487,117 +77517,117 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -77672,12 +77702,12 @@ - + - + - + @@ -77974,15 +78004,15 @@ - + - + - + - + @@ -78129,6 +78159,7 @@ + @@ -78927,21 +78958,21 @@ - + - + - + - + - + - + @@ -79379,6 +79410,7 @@ + @@ -79425,15 +79457,19 @@ - + + + + + - + - + - + @@ -80991,9 +81027,9 @@ - + - + @@ -81187,6 +81223,7 @@ + @@ -81267,21 +81304,21 @@ - + - + - + - + - + - + @@ -81617,18 +81654,18 @@ - + - + - + - + - + @@ -82146,12 +82183,12 @@ - + - + - + @@ -82257,7 +82294,7 @@ - + @@ -83034,7 +83071,7 @@ - + @@ -83447,15 +83484,15 @@ - + - + - + - + @@ -83658,7 +83695,7 @@ - + @@ -83738,22 +83775,22 @@ - + - + - + - + - + - + @@ -84597,7 +84634,12 @@ - + + + + + + @@ -84705,24 +84747,24 @@ - + - + - + - + - + - + - + @@ -85344,7 +85386,6 @@ - @@ -86124,15 +86165,15 @@ - + - + - + - + @@ -86445,27 +86486,27 @@ - + - + - + - + - + - + - + - + @@ -86892,12 +86933,12 @@ - + - + - + @@ -87211,21 +87252,21 @@ - + - + - + - + - + - + @@ -87278,36 +87319,36 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -87547,7 +87588,7 @@ - + @@ -88648,7 +88689,7 @@ - + @@ -89003,14 +89044,6 @@ - - - - - - - - @@ -89047,6 +89080,9 @@ + + + @@ -89330,7 +89366,7 @@ - + @@ -89949,63 +89985,63 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -90019,21 +90055,21 @@ - + - + - + - + - + - + @@ -90251,18 +90287,18 @@ - + - + - + - + - + @@ -90310,7 +90346,7 @@ - + @@ -90776,85 +90812,88 @@ - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -91417,12 +91456,12 @@ - + - + - + @@ -91436,7 +91475,7 @@ - + @@ -91792,51 +91831,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -92046,6 +92085,9 @@ + + + @@ -92466,21 +92508,21 @@ - + - + - + - + - + - + @@ -92909,15 +92951,15 @@ - + - + - + - + @@ -93085,7 +93127,6 @@ - @@ -93121,7 +93162,7 @@ - + @@ -93613,7 +93654,18 @@ - + + + + + + + + + + + + @@ -93621,7 +93673,7 @@ - + @@ -93629,7 +93681,7 @@ - + @@ -93637,7 +93689,7 @@ - + @@ -93645,7 +93697,7 @@ - + @@ -93653,7 +93705,7 @@ - + @@ -93661,7 +93713,7 @@ - + @@ -93708,7 +93760,7 @@ - + @@ -93719,7 +93771,7 @@ - + @@ -93739,7 +93791,7 @@ - + @@ -93762,7 +93814,7 @@ - + @@ -93782,26 +93834,26 @@ - + - + - + - + - + @@ -93815,7 +93867,7 @@ - + @@ -93823,7 +93875,7 @@ - + @@ -93843,7 +93895,7 @@ - + @@ -93866,7 +93918,7 @@ - + @@ -93874,7 +93926,7 @@ - + @@ -93882,7 +93934,7 @@ - + @@ -93890,7 +93942,7 @@ - + @@ -93898,7 +93950,7 @@ - + @@ -93924,17 +93976,17 @@ - + - + - + @@ -93942,17 +93994,17 @@ - + - + - + @@ -93972,7 +94024,7 @@ - + @@ -93980,7 +94032,7 @@ - + @@ -93988,7 +94040,7 @@ - + @@ -93996,12 +94048,12 @@ - + - + @@ -94009,7 +94061,7 @@ - + @@ -94017,7 +94069,7 @@ - + @@ -94031,7 +94083,7 @@ - + @@ -94072,7 +94124,7 @@ - + @@ -94089,17 +94141,6 @@ - - - - - - - - - - - @@ -94244,9 +94285,9 @@ - + - + @@ -94353,302 +94394,316 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - + + + + + + + + + + + + @@ -94659,7 +94714,7 @@ - + @@ -94667,7 +94722,7 @@ - + @@ -94675,7 +94730,7 @@ - + @@ -94689,7 +94744,7 @@ - + @@ -94697,7 +94752,7 @@ - + @@ -94705,7 +94760,7 @@ - + @@ -94713,7 +94768,7 @@ - + @@ -94721,7 +94776,7 @@ - + @@ -94732,7 +94787,7 @@ - + @@ -94740,7 +94795,7 @@ - + @@ -94751,7 +94806,7 @@ - + @@ -94759,7 +94814,7 @@ - + @@ -94767,7 +94822,7 @@ - + @@ -94775,7 +94830,7 @@ - + @@ -94795,7 +94850,7 @@ - + @@ -94809,7 +94864,7 @@ - + @@ -94826,7 +94881,7 @@ - + @@ -94840,7 +94895,7 @@ - + @@ -94854,7 +94909,7 @@ - + @@ -94862,7 +94917,7 @@ - + @@ -94876,7 +94931,7 @@ - + @@ -94887,7 +94942,7 @@ - + @@ -94904,7 +94959,7 @@ - + @@ -94912,7 +94967,7 @@ - + @@ -94920,7 +94975,7 @@ - + @@ -94931,7 +94986,7 @@ - + @@ -94942,7 +94997,7 @@ - + @@ -94950,7 +95005,7 @@ - + @@ -94967,7 +95022,7 @@ - + @@ -94990,7 +95045,7 @@ - + @@ -94998,7 +95053,7 @@ - + @@ -95009,7 +95064,7 @@ - + @@ -95023,18 +95078,18 @@ - + - + - + @@ -95060,7 +95115,7 @@ - + @@ -95068,7 +95123,7 @@ - + @@ -95076,7 +95131,7 @@ - + @@ -95087,7 +95142,7 @@ - + @@ -95095,7 +95150,7 @@ - + @@ -95106,7 +95161,7 @@ - + @@ -95117,12 +95172,12 @@ - + - + @@ -95130,7 +95185,7 @@ - + @@ -95138,7 +95193,7 @@ - + @@ -95146,7 +95201,7 @@ - + @@ -95154,7 +95209,7 @@ - + @@ -95162,7 +95217,7 @@ - + @@ -95203,7 +95258,7 @@ - + @@ -95217,7 +95272,7 @@ - + @@ -95243,7 +95298,7 @@ - + @@ -95308,7 +95363,7 @@ - + @@ -95319,7 +95374,7 @@ - + @@ -95336,7 +95391,7 @@ - + @@ -95380,7 +95435,7 @@ - + @@ -95391,7 +95446,7 @@ - + @@ -95402,7 +95457,7 @@ - + @@ -95422,7 +95477,7 @@ - + @@ -95430,7 +95485,7 @@ - + @@ -95447,7 +95502,7 @@ - + @@ -95476,7 +95531,7 @@ - + @@ -95493,7 +95548,7 @@ - + @@ -95507,17 +95562,17 @@ - + - + - + @@ -95525,7 +95580,7 @@ - + @@ -95536,7 +95591,7 @@ - + @@ -95544,7 +95599,7 @@ - + @@ -95558,7 +95613,7 @@ - + @@ -95578,7 +95633,7 @@ - + @@ -95586,7 +95641,7 @@ - + @@ -95594,7 +95649,7 @@ - + @@ -95602,12 +95657,12 @@ - + - + @@ -95615,7 +95670,7 @@ - + @@ -95626,7 +95681,7 @@ - + @@ -95634,18 +95689,18 @@ - + - + - - + + @@ -95659,12 +95714,12 @@ - + - + @@ -95672,12 +95727,12 @@ - + - + @@ -95685,12 +95740,12 @@ - + - + @@ -95698,7 +95753,7 @@ - + @@ -95715,7 +95770,7 @@ - + @@ -95723,7 +95778,7 @@ - + @@ -95731,12 +95786,12 @@ - + - + @@ -95744,7 +95799,7 @@ - + @@ -95752,7 +95807,7 @@ - + @@ -95769,12 +95824,12 @@ - + - + @@ -95800,7 +95855,7 @@ - + @@ -95811,7 +95866,7 @@ - + @@ -95831,7 +95886,7 @@ - + @@ -95854,7 +95909,7 @@ - + @@ -95889,7 +95944,7 @@ - + @@ -95900,7 +95955,7 @@ - + @@ -95914,12 +95969,12 @@ - + - + @@ -95930,7 +95985,7 @@ - + @@ -95944,7 +95999,7 @@ - + @@ -95955,7 +96010,7 @@ - + @@ -95969,7 +96024,7 @@ - + @@ -95983,12 +96038,12 @@ - + - + @@ -95996,7 +96051,7 @@ - + @@ -96010,7 +96065,7 @@ - + @@ -96018,7 +96073,7 @@ - + @@ -96029,7 +96084,7 @@ - + @@ -96046,7 +96101,7 @@ - + @@ -96066,7 +96121,7 @@ - + @@ -96083,7 +96138,7 @@ - + @@ -96094,7 +96149,7 @@ - + @@ -96102,7 +96157,7 @@ - + @@ -96110,7 +96165,7 @@ - + @@ -96118,7 +96173,7 @@ - + @@ -96132,7 +96187,7 @@ - + @@ -96140,7 +96195,7 @@ - + @@ -96151,7 +96206,7 @@ - + @@ -96168,7 +96223,7 @@ - + @@ -96194,7 +96249,7 @@ - + @@ -96205,7 +96260,7 @@ - + @@ -96216,7 +96271,7 @@ - + @@ -96477,27 +96532,27 @@ - + - + - + - + - + - + - + - + @@ -96604,7 +96659,7 @@ - + @@ -96772,7 +96827,7 @@ - + @@ -96943,7 +96998,7 @@ - + @@ -98025,6 +98080,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -98684,12 +98774,12 @@ - + - + - + @@ -98825,7 +98915,6 @@ - @@ -99046,11 +99135,6 @@ - - - - - @@ -99696,6 +99780,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -100406,7 +100513,6 @@ - @@ -100687,12 +100793,12 @@ - + - + - + @@ -100842,7 +100948,7 @@ - + @@ -101126,27 +101232,27 @@ - + - + - + - + - + - + - + - + @@ -102486,10 +102592,6 @@ - - - - @@ -103443,6 +103545,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103499,7 +103663,7 @@ - + @@ -103591,24 +103755,24 @@ - + - + - + - + - + - + - + @@ -104076,6 +104240,15 @@ + + + + + + + + + @@ -104104,9 +104277,9 @@ - + - + @@ -104386,7 +104559,6 @@ - @@ -104789,7 +104961,7 @@ - + @@ -105199,16 +105371,29 @@ + + + + + + + + + + + + + - - - - - + + + + + @@ -105271,34 +105456,34 @@ - - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - + + + @@ -105606,6 +105791,11 @@ + + + + + @@ -105644,24 +105834,24 @@ - - + + - - - + + + - - - + + + - - - - + + + + @@ -105969,11 +106159,11 @@ - - - - - + + + + + @@ -105986,13 +106176,13 @@ - - - - - - - + + + + + + + @@ -106005,13 +106195,13 @@ - - - + + + - - + + @@ -106070,8 +106260,8 @@ - - + + @@ -106083,8 +106273,8 @@ - - + + @@ -106225,8 +106415,8 @@ - - + + @@ -106323,502 +106513,595 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - - - - + + + + + - - - - - - - - - - - + + + + + - - - + + + + - - - - + + + + + + - - - - - + + + + + + - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + - - - - - - + + + + + - - - - - - + + + + + - - - - + + + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + - - - - + + + - - - - + + + + - - - + + + + - - - - + + + + - - - - + + + - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - - + + + - - - - + + + + - - - - - - + + + - - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - - + + + + + + - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + + + - - - - - + + + - - - - + + + + - - - + + + + - - - + + + + - - - + + + + + - - - - - + + + + - - - - + + + + - - - - - - - + + + + - - - - - - - - + + + - - - - - + + + - - - - - - + + + - - - - + + + + + - - - - - + + + + - - - + + + + + + + - - - - + + + + - - - - + + + + + + + + - - - - - + + + - - - - - + + + + + - - - - - + + + + + + - - - - + + + + - - - - - + + + + + - - - - + + + - - - - + + + + - - - - - - + + + + - - - - - - + + + + + + - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + + - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -106974,78 +107257,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -107094,9 +107391,9 @@ - - - + + + @@ -107142,12 +107439,12 @@ - - - - - - + + + + + + @@ -107318,7 +107615,7 @@ - + @@ -107352,9 +107649,9 @@ - - - + + + @@ -107450,17 +107747,17 @@ - - - + + + - - - - - - + + + + + + @@ -107505,13 +107802,6 @@ - - - - - - - @@ -108521,9 +108811,9 @@ - - - + + + @@ -108538,11 +108828,11 @@ - - - - - + + + + + @@ -108554,10 +108844,10 @@ - - - - + + + + @@ -108586,11 +108876,11 @@ - - - - - + + + + + @@ -108621,13 +108911,13 @@ - - - - - - - + + + + + + + @@ -108639,19 +108929,19 @@ - - - - - + + + + + - - - - - - + + + + + + @@ -108665,19 +108955,19 @@ - - - - - - + + + + + + - - - - - + + + + + @@ -108695,10 +108985,10 @@ - - - - + + + + @@ -108727,12 +109017,12 @@ - - - - - - + + + + + + @@ -108744,14 +109034,14 @@ - - - - + + + + - - + + @@ -108846,9 +109136,9 @@ - - - + + + @@ -108871,8 +109161,8 @@ - - + + @@ -108887,14 +109177,14 @@ - - - + + + - - - + + + @@ -108905,9 +109195,9 @@ - - - + + + @@ -108967,8 +109257,8 @@ - - + + @@ -109020,13 +109310,6 @@ - - - - - - - @@ -109041,9 +109324,9 @@ - - - + + + @@ -109123,11 +109406,12 @@ - - + + + - + @@ -109301,6 +109585,15 @@ + + + + + + + + + @@ -110485,11 +110778,6 @@ - - - - - @@ -110625,9 +110913,9 @@ - - - + + + @@ -110642,9 +110930,9 @@ - - - + + + @@ -110898,10 +111186,10 @@ - - - - + + + + @@ -111666,8 +111954,8 @@ - - + + @@ -111741,15 +112029,15 @@ - - - + + + - - - - + + + + @@ -112739,10 +113027,10 @@ - - - - + + + + @@ -113189,10 +113477,10 @@ - - - - + + + + @@ -113346,7 +113634,6 @@ - @@ -113483,7 +113770,7 @@ - + @@ -113491,13 +113778,13 @@ - - - + + + - - + + @@ -113543,6 +113830,11 @@ + + + + + @@ -113614,14 +113906,14 @@ - - - + + + - - - + + + @@ -113876,6 +114168,12 @@ + + + + + + @@ -113914,33 +114212,33 @@ - - + + - - - - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -113950,38 +114248,89 @@ - - + + - - - - - + + + - - - + + + - - + + - - - - + + + + - - + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -114209,7 +114558,6 @@ - @@ -114692,12 +115040,6 @@ - - - - - - @@ -114765,8 +115107,8 @@ - - + + @@ -115214,12 +115556,12 @@ - - + + - - + + @@ -115242,16 +115584,16 @@ - - + + - - + + - - + + @@ -115263,6 +115605,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -115602,6 +115966,11 @@ + + + + + @@ -116229,24 +116598,6 @@ - - - - - - - - - - - - - - - - - - @@ -116547,14 +116898,14 @@ - - - - + + + + - - + + @@ -116649,8 +117000,8 @@ - - + + @@ -116731,8 +117082,8 @@ - - + + @@ -117038,36 +117389,36 @@ - - - - - - + + + + + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + @@ -117174,11 +117525,22 @@ - - - + + + + + + + + + + + + + + @@ -117222,45 +117584,45 @@ - - - - + + + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -117268,14 +117630,14 @@ - - - + + + - - - + + + @@ -117799,14 +118161,14 @@ - - - - + + + + - - + + @@ -117884,8 +118246,8 @@ - - + + @@ -117896,12 +118258,12 @@ - - + + - - + + @@ -117916,12 +118278,12 @@ - - + + - - + + @@ -117937,10 +118299,10 @@ - - - - + + + + @@ -117948,20 +118310,20 @@ - - - + + + - - - + + + - - - - + + + + @@ -117985,9 +118347,9 @@ - - - + + + @@ -118003,9 +118365,9 @@ - - - + + + @@ -118018,14 +118380,14 @@ - - - + + + - - - + + + @@ -118033,36 +118395,44 @@ - - - - + + + + + + + + + + + + - - - - + + + + - - - - + + + + - - - + + + - - + + - - - + + + @@ -118075,21 +118445,21 @@ - - - - + + + + - - - + + + - - - - + + + + @@ -118100,26 +118470,26 @@ - - + + - - + + - - - + + + - - + + - - - + + + @@ -118127,8 +118497,8 @@ - - + + @@ -118139,27 +118509,27 @@ - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + @@ -118172,18 +118542,19 @@ - - - - + + + + - - - - + + + + + @@ -118203,12 +118574,12 @@ - - - - - - + + + + + + @@ -118249,20 +118620,20 @@ - - - - + + + + - - - - + + + + - - + + @@ -118282,8 +118653,8 @@ - - + + @@ -118327,29 +118698,29 @@ - - - - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -118441,8 +118812,11 @@ - - + + + + + @@ -118450,8 +118824,14 @@ - - + + + + + + + + @@ -118723,13 +119103,13 @@ - - + + - - + + @@ -118884,8 +119264,8 @@ - - + + @@ -119055,6 +119435,7 @@ + @@ -119112,8 +119493,8 @@ - - + + @@ -119176,8 +119557,8 @@ - - + + @@ -119482,12 +119863,12 @@ - - - - - - + + + + + + @@ -119800,7 +120181,7 @@ - + @@ -119849,41 +120230,41 @@ - - + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + @@ -120164,23 +120545,6 @@ - - - - - - - - - - - - - - - - - @@ -120254,40 +120618,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -120334,9 +120664,9 @@ - - - + + + @@ -120656,10 +120986,10 @@ - - - - + + + + @@ -120715,11 +121045,11 @@ - - - - - + + + + + @@ -120727,9 +121057,9 @@ - - - + + + @@ -120963,13 +121293,13 @@ - - - - - - - + + + + + + + @@ -121021,13 +121351,13 @@ - - - + + + - - + + @@ -121036,17 +121366,17 @@ - - - + + + - - - - - - + + + + + + @@ -121062,12 +121392,12 @@ - - - - - - + + + + + + @@ -121080,7 +121410,7 @@ - + @@ -121717,9 +122047,9 @@ - - - + + + @@ -121974,6 +122304,10 @@ + + + + @@ -122006,7 +122340,7 @@ - + @@ -122129,9 +122463,9 @@ - - - + + + @@ -122489,21 +122823,21 @@ - - - + + + - - - + + + - - - - - + + + + + @@ -122514,49 +122848,49 @@ - - - - - - + + + + + + - - + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + - - + + @@ -122569,52 +122903,52 @@ - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - + + + + + - - + + @@ -122623,9 +122957,9 @@ - - - + + + @@ -122641,74 +122975,74 @@ - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -122719,15 +123053,15 @@ - - - - - + + + + + - - + + @@ -122805,8 +123139,8 @@ - - + + @@ -122845,8 +123179,8 @@ - - + + @@ -122892,6 +123226,14 @@ + + + + + + + + @@ -123018,6 +123360,10 @@ + + + + @@ -123037,8 +123383,16 @@ - - + + + + + + + + + + @@ -123046,8 +123400,8 @@ - - + + @@ -123066,6 +123420,12 @@ + + + + + + @@ -123148,6 +123508,14 @@ + + + + + + + + @@ -123367,9 +123735,9 @@ - - - + + + @@ -124065,16 +124433,16 @@ - - - - + + + + - - - - + + + + @@ -124121,28 +124489,28 @@ - - - - + + + + - - - - + + + + - - - - - + + + + + - - - + + + @@ -124198,18 +124566,17 @@ - - - + + + - - + + - - + @@ -124269,8 +124636,8 @@ - - + + @@ -124380,57 +124747,57 @@ - - - - + + + + - - + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + @@ -124494,22 +124861,22 @@ - - - + + + - - + + - - + + - - - + + + @@ -124527,14 +124894,14 @@ - - - + + + - - - + + + @@ -124551,13 +124918,13 @@ - - + + - - - + + + @@ -124565,8 +124932,8 @@ - - + + diff --git a/android/abi_gki_aarch64_generic b/android/abi_gki_aarch64_generic index 14968c013c61a..d8bc7290f9bda 100644 --- a/android/abi_gki_aarch64_generic +++ b/android/abi_gki_aarch64_generic @@ -240,6 +240,7 @@ config_group_init_type_name config_item_init_type_name config_item_put + console_set_on_cmdline console_suspend_enabled console_trylock console_unlock @@ -285,6 +286,8 @@ cpuhp_tasks_frozen cpu_hwcap_keys cpu_hwcaps + cpuidle_driver_state_disabled + cpuidle_get_driver cpuidle_governor_latency_req cpuidle_pause_and_lock cpuidle_resume_and_unlock @@ -388,6 +391,7 @@ devfreq_update_interval dev_fwnode dev_get_by_name + dev_get_stats device_add device_add_disk device_add_groups @@ -567,6 +571,7 @@ dma_fence_remove_callback dma_fence_signal dma_fence_signal_locked + dma_fence_wait_timeout dma_free_attrs dma_free_noncoherent dma_get_sgtable_attrs @@ -769,6 +774,7 @@ drm_poll drm_prime_gem_destroy drm_printf + __drm_printfn_debug __drm_printfn_info __drm_printfn_seq_file drm_property_blob_get @@ -840,6 +846,7 @@ find_last_bit find_next_bit find_next_zero_bit + find_pid_ns find_task_by_vpid find_vma finish_wait @@ -896,6 +903,22 @@ get_device __get_free_pages get_governor_parent_kobj + gether_cleanup + gether_connect + gether_disconnect + gether_get_dev_addr + gether_get_host_addr + gether_get_host_addr_u8 + gether_get_ifname + gether_get_qmult + gether_register_netdev + gether_set_dev_addr + gether_set_gadget + gether_set_host_addr + gether_set_ifname + gether_set_qmult + gether_setup_name_default + get_pfnblock_flags_mask get_pid_task get_random_bytes get_random_bytes_arch @@ -990,6 +1013,7 @@ i2c_unregister_device i2c_verify_client ida_alloc_range + ida_destroy ida_free idr_alloc idr_alloc_cyclic @@ -1028,6 +1052,7 @@ input_mt_destroy_slots input_mt_init_slots input_mt_report_slot_state + input_mt_sync_frame input_open_device input_register_device input_register_handle @@ -1038,6 +1063,10 @@ input_unregister_device input_unregister_handle input_unregister_handler + interval_tree_insert + interval_tree_iter_first + interval_tree_iter_next + interval_tree_remove int_sqrt int_to_scsilun iomem_resource @@ -1088,7 +1117,9 @@ irq_create_mapping_affinity irq_create_of_mapping __irq_domain_add + irq_domain_get_irq_data irq_domain_remove + irq_domain_set_info irq_domain_xlate_twocell irq_find_mapping irq_get_irq_data @@ -1229,6 +1260,7 @@ mbox_free_channel mbox_request_channel mbox_send_message + memchr memcmp memcpy __memcpy_fromio @@ -1328,6 +1360,7 @@ nsec_to_clock_t ns_to_timespec64 __num_online_cpus + nvhe_hyp_panic_handler nvmem_device_put nvmem_device_read nvmem_device_write @@ -1422,7 +1455,7 @@ __page_frag_cache_drain page_frag_free page_mapping - __page_pinner_migration_failed + __page_pinner_put_page panic panic_notifier_list param_array_ops @@ -1456,6 +1489,8 @@ pci_irq_vector pci_load_and_free_saved_state pci_load_saved_state + pci_msi_mask_irq + pci_msi_unmask_irq pci_read_config_dword pci_read_config_word __pci_register_driver @@ -1474,6 +1509,7 @@ pci_write_config_dword pci_write_config_word PDE_DATA + pelt_load_avg_max __per_cpu_offset perf_aux_output_begin perf_aux_output_end @@ -1512,9 +1548,11 @@ pin_user_pages_fast pin_user_pages_remote pktgen_xfrm_outer_mode_output + pkvm_iommu_finalize pkvm_iommu_resume pkvm_iommu_s2mpu_register pkvm_iommu_suspend + pkvm_iommu_sysmmu_sync_register platform_bus_type platform_device_add platform_device_add_data @@ -1532,6 +1570,7 @@ platform_find_device_by_driver platform_get_irq platform_get_irq_byname + platform_get_irq_optional platform_get_resource platform_get_resource_byname platform_irq_count @@ -1653,6 +1692,7 @@ __rcu_read_unlock rdev_get_drvdata rdev_get_id + reboot_mode refcount_dec_not_one refcount_warn_saturate __refrigerator @@ -2044,6 +2084,7 @@ submit_bio submit_bio_wait subsys_system_register + suspend_set_ops __sw_hweight32 __sw_hweight64 sync_file_create @@ -2121,6 +2162,7 @@ _totalram_pages touch_softlockup_watchdog __trace_bprintk + __trace_bputs trace_event_buffer_commit trace_event_buffer_reserve trace_event_ignore_this_pid @@ -2128,6 +2170,7 @@ trace_event_reg trace_handle_return __traceiter_android_rvh_arm64_serror_panic + __traceiter_android_rvh_attach_entity_load_avg __traceiter_android_rvh_bad_mode __traceiter_android_rvh_cgroup_force_kthread_migration __traceiter_android_rvh_check_preempt_wakeup @@ -2135,6 +2178,7 @@ __traceiter_android_rvh_cpu_overutilized __traceiter_android_rvh_dequeue_task __traceiter_android_rvh_dequeue_task_fair + __traceiter_android_rvh_detach_entity_load_avg __traceiter_android_rvh_die_kernel_fault __traceiter_android_rvh_do_mem_abort __traceiter_android_rvh_do_sea @@ -2145,19 +2189,25 @@ __traceiter_android_rvh_find_energy_efficient_cpu __traceiter_android_rvh_irqs_disable __traceiter_android_rvh_irqs_enable + __traceiter_android_rvh_pci_d3_sleep __traceiter_android_rvh_post_init_entity_util_avg __traceiter_android_rvh_preempt_disable __traceiter_android_rvh_preempt_enable + __traceiter_android_rvh_remove_entity_load_avg __traceiter_android_rvh_sched_fork __traceiter_android_rvh_select_task_rq_fair __traceiter_android_rvh_select_task_rq_rt __traceiter_android_rvh_set_iowait + __traceiter_android_rvh_set_task_cpu __traceiter_android_rvh_typec_tcpci_chk_contaminant __traceiter_android_rvh_typec_tcpci_get_vbus __traceiter_android_rvh_uclamp_eff_get __traceiter_android_rvh_uclamp_rq_util_with __traceiter_android_rvh_ufs_complete_init __traceiter_android_rvh_ufs_reprogram_all_keys + __traceiter_android_rvh_update_blocked_fair + __traceiter_android_rvh_update_load_avg + __traceiter_android_rvh_update_rt_rq_load_avg __traceiter_android_rvh_util_est_update __traceiter_android_vh_arch_set_freq_scale __traceiter_android_vh_cma_alloc_finish @@ -2167,17 +2217,23 @@ __traceiter_android_vh_dup_task_struct __traceiter_android_vh_enable_thermal_genl_check __traceiter_android_vh_ep_create_wakeup_source + __traceiter_android_vh_get_user_pages + __traceiter_android_vh___get_user_pages_remote + __traceiter_android_vh_internal_get_user_pages_fast __traceiter_android_vh_ipi_stop __traceiter_android_vh_meminfo_proc_show __traceiter_android_vh_of_i2c_get_board_info __traceiter_android_vh_pagecache_get_page + __traceiter_android_vh_pin_user_pages __traceiter_android_vh_rmqueue + __traceiter_android_vh_scheduler_tick __traceiter_android_vh_setscheduler_uclamp __traceiter_android_vh_snd_compr_use_pause_in_drain __traceiter_android_vh_sound_usb_support_cpu_suspend __traceiter_android_vh_sysrq_crash __traceiter_android_vh_thermal_pm_notify_suspend __traceiter_android_vh_timerfd_create + __traceiter_android_vh_try_grab_compound_head __traceiter_android_vh_typec_store_partner_src_caps __traceiter_android_vh_typec_tcpci_override_toggling __traceiter_android_vh_typec_tcpm_get_timer @@ -2218,6 +2274,7 @@ __traceiter_suspend_resume trace_output_call __tracepoint_android_rvh_arm64_serror_panic + __tracepoint_android_rvh_attach_entity_load_avg __tracepoint_android_rvh_bad_mode __tracepoint_android_rvh_cgroup_force_kthread_migration __tracepoint_android_rvh_check_preempt_wakeup @@ -2225,6 +2282,7 @@ __tracepoint_android_rvh_cpu_overutilized __tracepoint_android_rvh_dequeue_task __tracepoint_android_rvh_dequeue_task_fair + __tracepoint_android_rvh_detach_entity_load_avg __tracepoint_android_rvh_die_kernel_fault __tracepoint_android_rvh_do_mem_abort __tracepoint_android_rvh_do_sea @@ -2235,19 +2293,25 @@ __tracepoint_android_rvh_find_energy_efficient_cpu __tracepoint_android_rvh_irqs_disable __tracepoint_android_rvh_irqs_enable + __tracepoint_android_rvh_pci_d3_sleep __tracepoint_android_rvh_post_init_entity_util_avg __tracepoint_android_rvh_preempt_disable __tracepoint_android_rvh_preempt_enable + __tracepoint_android_rvh_remove_entity_load_avg __tracepoint_android_rvh_sched_fork __tracepoint_android_rvh_select_task_rq_fair __tracepoint_android_rvh_select_task_rq_rt __tracepoint_android_rvh_set_iowait + __tracepoint_android_rvh_set_task_cpu __tracepoint_android_rvh_typec_tcpci_chk_contaminant __tracepoint_android_rvh_typec_tcpci_get_vbus __tracepoint_android_rvh_uclamp_eff_get __tracepoint_android_rvh_uclamp_rq_util_with __tracepoint_android_rvh_ufs_complete_init __tracepoint_android_rvh_ufs_reprogram_all_keys + __tracepoint_android_rvh_update_blocked_fair + __tracepoint_android_rvh_update_load_avg + __tracepoint_android_rvh_update_rt_rq_load_avg __tracepoint_android_rvh_util_est_update __tracepoint_android_vh_arch_set_freq_scale __tracepoint_android_vh_cma_alloc_finish @@ -2257,17 +2321,23 @@ __tracepoint_android_vh_dup_task_struct __tracepoint_android_vh_enable_thermal_genl_check __tracepoint_android_vh_ep_create_wakeup_source + __tracepoint_android_vh_get_user_pages + __tracepoint_android_vh___get_user_pages_remote + __tracepoint_android_vh_internal_get_user_pages_fast __tracepoint_android_vh_ipi_stop __tracepoint_android_vh_meminfo_proc_show __tracepoint_android_vh_of_i2c_get_board_info __tracepoint_android_vh_pagecache_get_page + __tracepoint_android_vh_pin_user_pages __tracepoint_android_vh_rmqueue + __tracepoint_android_vh_scheduler_tick __tracepoint_android_vh_setscheduler_uclamp __tracepoint_android_vh_snd_compr_use_pause_in_drain __tracepoint_android_vh_sound_usb_support_cpu_suspend __tracepoint_android_vh_sysrq_crash __tracepoint_android_vh_thermal_pm_notify_suspend __tracepoint_android_vh_timerfd_create + __tracepoint_android_vh_try_grab_compound_head __tracepoint_android_vh_typec_store_partner_src_caps __tracepoint_android_vh_typec_tcpci_override_toggling __tracepoint_android_vh_typec_tcpm_get_timer @@ -2377,26 +2447,37 @@ unregister_virtio_driver up update_devfreq + ___update_load_avg __update_load_avg_blocked_se + ___update_load_sum update_rq_clock up_read up_write usb_add_function usb_add_hcd + usb_assign_descriptors usb_copy_descriptors __usb_create_hcd usb_disabled usb_enable_autosuspend + usb_ep_alloc_request usb_ep_autoconfig usb_ep_disable usb_ep_enable + usb_ep_free_request + usb_ep_queue + usb_free_all_descriptors usb_function_register usb_function_unregister + usb_gadget_activate + usb_gadget_deactivate usb_gadget_set_state + usb_gstrings_attach usb_hcd_is_primary_hcd usb_hcd_platform_shutdown usb_hub_find_child usb_interface_id + usb_os_desc_prepare_interf_dir usb_otg_state_string usb_put_function_instance usb_put_hcd diff --git a/android/abi_gki_aarch64_hikey960 b/android/abi_gki_aarch64_hikey960 index 0609f21fcd3b7..eb9e5e3809909 100644 --- a/android/abi_gki_aarch64_hikey960 +++ b/android/abi_gki_aarch64_hikey960 @@ -791,7 +791,6 @@ of_get_next_available_child of_parse_phandle of_property_read_u64 - __page_pinner_migration_failed __put_page put_unused_fd rb_erase diff --git a/android/abi_gki_aarch64_virtual_device b/android/abi_gki_aarch64_virtual_device index 932cb8b3520d7..9968c643ed6bd 100644 --- a/android/abi_gki_aarch64_virtual_device +++ b/android/abi_gki_aarch64_virtual_device @@ -28,9 +28,6 @@ bt_warn cancel_delayed_work_sync cancel_work_sync - capable - cfg80211_inform_bss_data - cfg80211_put_bss __cfi_slowpath __check_object_size __class_create @@ -62,15 +59,12 @@ delayed_work_timer_fn del_gendisk del_timer - del_timer_sync destroy_workqueue dev_close _dev_err device_add_disk device_create - device_initialize device_init_wakeup - device_register device_release_driver device_unregister _dev_info @@ -82,7 +76,6 @@ devm_request_threaded_irq _dev_notice dev_queue_xmit - dev_set_name _dev_warn dma_alloc_attrs dma_buf_export @@ -96,7 +89,6 @@ dma_set_mask dma_sync_sg_for_device dma_unmap_sg_attrs - down_read down_write ether_setup ethtool_op_get_link @@ -123,14 +115,8 @@ hci_recv_frame hci_register_dev hci_unregister_dev - hwrng_register - hwrng_unregister ida_alloc_range ida_free - idr_alloc - idr_destroy - idr_remove - __init_rwsem __init_swait_queue_head init_timer_key init_wait_entry @@ -160,12 +146,10 @@ kmem_cache_free kmemdup kobject_uevent - krealloc kstrdup kstrndup kstrtoint kstrtouint - kstrtoull ktime_get ktime_get_mono_fast_ns ktime_get_raw_ts64 @@ -184,13 +168,10 @@ memcpy memmove memparse - memremap memset memstart_addr - memunmap misc_deregister misc_register - mod_timer module_layout module_put __msecs_to_jiffies @@ -216,15 +197,11 @@ nf_conntrack_destroy no_llseek nonseekable_open - noop_llseek nr_cpu_ids __num_online_cpus - of_find_property - of_get_property of_property_read_variable_u32_array - __page_pinner_migration_failed + __page_pinner_put_page param_ops_bool - param_ops_charp param_ops_int param_ops_uint passthru_features_check @@ -250,11 +227,8 @@ platform_get_irq platform_get_resource pm_runtime_allow - __pm_runtime_disable - pm_runtime_enable pm_runtime_force_resume pm_runtime_force_suspend - __pm_runtime_idle __pm_runtime_resume pm_runtime_set_autosuspend_delay __pm_runtime_suspend @@ -305,9 +279,7 @@ schedule schedule_timeout scnprintf - seq_lseek seq_printf - seq_read serio_close serio_interrupt serio_open @@ -330,7 +302,6 @@ snd_card_free snd_card_new snd_card_register - snd_ctl_enum_info snd_ctl_sync_vmaster snd_device_new snd_jack_new @@ -355,13 +326,11 @@ strncmp strncpy strscpy - strsep sync_file_create synchronize_rcu sysfs_create_group __sysfs_match_string sysfs_remove_group - sysfs_remove_link system_wq trace_event_buffer_commit trace_event_buffer_reserve @@ -385,7 +354,6 @@ unregister_netdevice_queue unregister_virtio_device unregister_virtio_driver - up_read up_write usb_alloc_urb usb_anchor_urb @@ -396,7 +364,6 @@ usb_register_driver usb_submit_urb usb_unanchor_urb - __usecs_to_jiffies usleep_range vabits_actual vfree @@ -457,10 +424,12 @@ mmc_remove_host mmc_request_done mmc_send_tuning + of_get_property pinctrl_lookup_state pinctrl_pm_select_sleep_state pinctrl_select_default_state pinctrl_select_state + __pm_runtime_idle regulator_disable regulator_enable reset_control_assert @@ -525,26 +494,9 @@ netdev_master_upper_dev_link rtnl_is_locked -# required by gnss-cmdline.ko - bus_find_device - device_find_child - device_match_name - platform_bus_type - strstr - -# required by gnss-serial.ko - gnss_allocate_device - gnss_deregister_device - gnss_insert_raw - gnss_put_device - gnss_register_device - serdev_device_close - serdev_device_open - serdev_device_set_baudrate - serdev_device_set_flow_control - serdev_device_wait_until_sent - serdev_device_write - serdev_device_write_wakeup +# required by goldfish_address_space.ko + memremap + memunmap # required by goldfish_battery.ko power_supply_changed @@ -584,12 +536,6 @@ skb_queue_head skb_queue_purge -# required by ledtrig-audio.ko - led_set_brightness_nosleep - led_trigger_event - led_trigger_register - led_trigger_unregister - # required by lzo-rle.ko lzorle1x_1_compress @@ -699,11 +645,15 @@ # required by open-dice.ko devm_memremap devm_memunmap + of_reserved_mem_lookup + __platform_driver_probe + simple_read_from_buffer vm_iomap_memory # required by psmouse.ko bus_register_notifier bus_unregister_notifier + del_timer_sync device_add_groups device_create_file device_remove_file @@ -724,6 +674,7 @@ input_set_capability kstrtobool kstrtou8 + mod_timer ps2_begin_command ps2_cmd_aborted ps2_command @@ -737,6 +688,7 @@ serio_rescan serio_unregister_child_port strcasecmp + strsep # required by pulse8-cec.ko cec_allocate_adapter @@ -759,6 +711,7 @@ rtc_update_irq # required by slcan.ko + capable hex_asc_upper hex_to_bin msleep_interruptible @@ -769,7 +722,6 @@ # required by snd-hda-codec-generic.ko _ctype - devm_led_classdev_register_ext snd_ctl_boolean_stereo_info strlcat __sw_hweight32 @@ -783,6 +735,8 @@ get_device_system_crosststamp kvasprintf ns_to_timespec64 + __pm_runtime_disable + pm_runtime_enable pm_runtime_forbid __printk_ratelimit regcache_mark_dirty @@ -794,6 +748,7 @@ snd_ctl_add_vmaster_hook snd_ctl_apply_vmaster_followers snd_ctl_boolean_mono_info + snd_ctl_enum_info snd_ctl_find_id snd_ctl_make_virtual_master snd_ctl_new1 @@ -817,11 +772,14 @@ bus_unregister device_add device_del + device_initialize + dev_set_name kasprintf kobject_add kobject_create_and_add kobject_init kobject_put + krealloc pm_runtime_get_if_active __pm_runtime_set_status prepare_to_wait @@ -840,6 +798,7 @@ param_array_ops param_get_int param_ops_bint + param_ops_charp param_set_int pci_dev_put pci_disable_msi @@ -873,35 +832,6 @@ vmap vunmap -# required by tpm.ko - alloc_chrdev_region - cdev_device_add - cdev_device_del - cdev_init - compat_only_sysfs_link_entry_to_kobj - devm_add_action - efi - efi_tpm_final_log_size - hash_digest_size - idr_get_next - idr_replace - jiffies_to_usecs - memchr_inv - of_property_match_string - pm_suspend_global_flags - securityfs_create_dir - securityfs_create_file - securityfs_remove - seq_open - seq_putc - seq_release - seq_write - unregister_chrdev_region - -# required by tpm_vtpm_proxy.ko - anon_inode_getfile - compat_ptr_ioctl - # required by usbip-core.ko iov_iter_kvec param_ops_ulong @@ -917,10 +847,12 @@ devres_free of_device_is_compatible of_find_compatible_node + of_find_property of_get_next_parent of_parse_phandle of_platform_populate of_root + __usecs_to_jiffies # required by vexpress-sysreg.ko bgpio_init @@ -937,6 +869,7 @@ platform_bus platform_device_add_data sockfd_lookup + sysfs_remove_link usb_add_hcd usb_create_hcd usb_create_shared_hcd @@ -958,6 +891,8 @@ # required by virt_wifi.ko cfg80211_connect_done cfg80211_disconnected + cfg80211_inform_bss_data + cfg80211_put_bss cfg80211_scan_done __dev_get_by_index dev_printk @@ -970,9 +905,6 @@ wiphy_register wiphy_unregister -# required by virt_wifi_sim.ko - ieee80211_get_channel_khz - # required by virtio-gpu.ko __devm_request_region dma_fence_match_context @@ -1090,6 +1022,7 @@ is_vmalloc_addr kmalloc_order_trace memdup_user + noop_llseek seq_puts sync_file_get_fence __traceiter_dma_fence_emit @@ -1102,6 +1035,8 @@ ww_mutex_unlock # required by virtio-rng.ko + hwrng_register + hwrng_unregister wait_for_completion_killable # required by virtio_blk.ko @@ -1151,6 +1086,8 @@ pipe_unlock __refrigerator __register_chrdev + seq_lseek + seq_read single_open single_release __splice_from_pipe @@ -1159,6 +1096,7 @@ # required by virtio_mmio.ko device_for_each_child + device_register devm_platform_ioremap_resource platform_device_register_full @@ -1307,16 +1245,23 @@ crypto_has_alg disk_end_io_acct disk_start_io_acct + down_read flush_dcache_page free_percpu fsync_bdev + idr_alloc + idr_destroy idr_find idr_for_each + idr_remove + __init_rwsem kstrtou16 + kstrtoull memset64 mutex_is_locked page_endio sysfs_streq + up_read vzalloc # required by zsmalloc.ko @@ -1339,3 +1284,4 @@ register_shrinker __SetPageMovable unregister_shrinker + diff --git a/arch/Kconfig b/arch/Kconfig index 9528d0bd544dd..d39f92e9cf51e 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1180,6 +1180,15 @@ config ARCH_SPLIT_ARG64 If a 32-bit architecture requires 64-bit arguments to be split into pairs of 32-bit arguments, select this option. +config ARCH_HAS_NONLEAF_PMD_YOUNG + bool + depends on PGTABLE_LEVELS > 2 + help + Architectures that select this option are capable of setting the + accessed bit in non-leaf PMD entries when using them as part of linear + address translations. Page table walkers that clear the accessed bit + may use this capability to reduce their search space. + source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index a85e9c625ab50..37f724ad5e399 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -43,7 +43,7 @@ SYSCALL_DEFINE0(arc_gettls) return task_thread_info(current)->thr_ptr; } -SYSCALL_DEFINE3(arc_usr_cmpxchg, int __user *, uaddr, int, expected, int, new) +SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) { struct pt_regs *regs = current_pt_regs(); u32 uval; diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index b50229c3102fa..e46a3f4ad350a 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -433,26 +433,12 @@ #size-cells = <0>; enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/100095/0003 - * /Level-1-Memory-System/About-the-L1-memory-system?lang=en - * Source for d/i-cache-size - * https://www.raspberrypi.com/documentation/computers - * /processors.html#bcm2711 - */ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000d8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu1: cpu@1 { @@ -461,13 +447,6 @@ reg = <1>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu2: cpu@2 { @@ -476,13 +455,6 @@ reg = <2>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu3: cpu@3 { @@ -491,28 +463,6 @@ reg = <3>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000f0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; - }; - - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/100095/0003 - * /Level-2-Memory-System/About-the-L2-memory-system?lang=en - * Source for d/i-cache-size - * https://www.raspberrypi.com/documentation/computers - * /processors.html#bcm2711 - */ - l2: l2-cache0 { - compatible = "cache"; - cache-size = <0x100000>; - cache-line-size = <64>; - cache-sets = <1024>; // 1MiB(size)/64(line-size)=16384ways/16-way set - cache-level = <2>; }; }; diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi index 5dbdebc462594..0199ec98cd616 100644 --- a/arch/arm/boot/dts/bcm2837.dtsi +++ b/arch/arm/boot/dts/bcm2837.dtsi @@ -40,26 +40,12 @@ #size-cells = <0>; enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/ddi0500/e/level-1-memory-system - * /about-the-l1-memory-system?lang=en - * - * Source for d/i-cache-size - * https://magpi.raspberrypi.com/articles/raspberry-pi-3-specs-benchmarks - */ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000d8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu1: cpu@1 { @@ -68,13 +54,6 @@ reg = <1>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu2: cpu@2 { @@ -83,13 +62,6 @@ reg = <2>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu3: cpu@3 { @@ -98,27 +70,6 @@ reg = <3>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000f0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; - }; - - /* Source for cache-line-size + cache-sets - * https://developer.arm.com/documentation/ddi0500 - * /e/level-2-memory-system/about-the-l2-memory-system?lang=en - * Source for cache-size - * https://datasheets.raspberrypi.com/cm/cm1-and-cm3-datasheet.pdf - */ - l2: l2-cache0 { - compatible = "cache"; - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; // 512KiB(size)/64(line-size)=8192ways/16-way set - cache-level = <2>; }; }; }; diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index f8c0eee7a62b9..30b72f4318501 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -3448,7 +3448,8 @@ ti,timer-pwm; }; }; - timer15_target: target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ + + target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x2c000 0x4>, <0x2c010 0x4>; @@ -3476,7 +3477,7 @@ }; }; - timer16_target: target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ + target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x2e000 0x4>, <0x2e010 0x4>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 9989321366560..7ecf8f86ac747 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1093,20 +1093,20 @@ }; /* Local timers, see ARM architected timer wrap erratum i940 */ -&timer15_target { +&timer3_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER15_CLKCTRL 24>; + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>; assigned-clock-parents = <&timer_sys_clk_div>; }; }; -&timer16_target { +&timer4_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER16_CLKCTRL 24>; + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>; assigned-clock-parents = <&timer_sys_clk_div>; }; }; diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index d7d756614edd1..d31a68672bfac 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -260,7 +260,7 @@ }; uart3_data: uart3-data { - samsung,pins = "gpa1-4", "gpa1-5"; + samsung,pins = "gpa1-4", "gpa1-4"; samsung,pin-function = ; samsung,pin-pud = ; samsung,pin-drv = ; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 572198b6834e6..d0e48c10aec2b 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -118,9 +118,6 @@ status = "okay"; ddc = <&i2c_2>; hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>; - vdd-supply = <&ldo8_reg>; - vdd_osc-supply = <&ldo10_reg>; - vdd_pll-supply = <&ldo8_reg>; }; &i2c_0 { diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 741294bd564e7..4e49d8095b292 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -124,9 +124,6 @@ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&hdmi_hpd_irq>; - vdd-supply = <&ldo6_reg>; - vdd_osc-supply = <&ldo7_reg>; - vdd_pll-supply = <&ldo6_reg>; }; &hsi2c_4 { diff --git a/arch/arm/boot/dts/imx53-m53menlo.dts b/arch/arm/boot/dts/imx53-m53menlo.dts index d5c68d1ea707c..4f88e96d81ddb 100644 --- a/arch/arm/boot/dts/imx53-m53menlo.dts +++ b/arch/arm/boot/dts/imx53-m53menlo.dts @@ -53,31 +53,6 @@ }; }; - lvds-decoder { - compatible = "ti,ds90cf364a", "lvds-decoder"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_decoder_in: endpoint { - remote-endpoint = <&lvds0_out>; - }; - }; - - port@1 { - reg = <1>; - - lvds_decoder_out: endpoint { - remote-endpoint = <&panel_in>; - }; - }; - }; - }; - panel { compatible = "edt,etm0700g0dh6"; pinctrl-0 = <&pinctrl_display_gpio>; @@ -86,7 +61,7 @@ port { panel_in: endpoint { - remote-endpoint = <&lvds_decoder_out>; + remote-endpoint = <&lvds0_out>; }; }; }; @@ -475,7 +450,7 @@ reg = <2>; lvds0_out: endpoint { - remote-endpoint = <&lvds_decoder_in>; + remote-endpoint = <&panel_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi index f1c60b0cb143e..62b771c1d5a9a 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -40,7 +40,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&codec>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -293,7 +293,7 @@ compatible = "fsl,sgtl5000"; #sound-dai-cells = <0>; reg = <0x0a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai1_mclk>; VDDA-supply = <®_module_3v3_avdd>; diff --git a/arch/arm/boot/dts/imx7-mba7.dtsi b/arch/arm/boot/dts/imx7-mba7.dtsi index 887497e3bb4b8..50abf18ad30b2 100644 --- a/arch/arm/boot/dts/imx7-mba7.dtsi +++ b/arch/arm/boot/dts/imx7-mba7.dtsi @@ -250,7 +250,7 @@ tlv320aic32x4: audio-codec@18 { compatible = "ti,tlv320aic32x4"; reg = <0x18>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; ldoin-supply = <®_audio_3v3>; iov-supply = <®_audio_3v3>; diff --git a/arch/arm/boot/dts/imx7d-nitrogen7.dts b/arch/arm/boot/dts/imx7d-nitrogen7.dts index a31de900139d6..e0751e6ba3c0f 100644 --- a/arch/arm/boot/dts/imx7d-nitrogen7.dts +++ b/arch/arm/boot/dts/imx7d-nitrogen7.dts @@ -288,7 +288,7 @@ codec: wm8960@1a { compatible = "wlf,wm8960"; reg = <0x1a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; wlf,shared-lrclk; }; diff --git a/arch/arm/boot/dts/imx7d-pico-hobbit.dts b/arch/arm/boot/dts/imx7d-pico-hobbit.dts index d917dc4f2f227..7b2198a9372c6 100644 --- a/arch/arm/boot/dts/imx7d-pico-hobbit.dts +++ b/arch/arm/boot/dts/imx7d-pico-hobbit.dts @@ -31,7 +31,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&sgtl5000>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -41,7 +41,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-pico-pi.dts b/arch/arm/boot/dts/imx7d-pico-pi.dts index f263e391e24cb..70bea95c06d83 100644 --- a/arch/arm/boot/dts/imx7d-pico-pi.dts +++ b/arch/arm/boot/dts/imx7d-pico-pi.dts @@ -31,7 +31,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&sgtl5000>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -41,7 +41,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 6823b9f1a2a32..ac0751bc1177e 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -378,14 +378,14 @@ codec: wm8960@1a { compatible = "wlf,wm8960"; reg = <0x1a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; wlf,shared-lrclk; wlf,hp-cfg = <2 2 3>; wlf,gpio-cfg = <1 3>; assigned-clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_SRC>, <&clks IMX7D_PLL_AUDIO_POST_DIV>, - <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; assigned-clock-rates = <0>, <884736000>, <12288000>; }; diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts index e035dd5bf4f62..d6b4888fa686b 100644 --- a/arch/arm/boot/dts/imx7s-warp.dts +++ b/arch/arm/boot/dts/imx7s-warp.dts @@ -75,7 +75,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&codec>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -232,7 +232,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai1_mclk>; VDDA-supply = <&vgen4_reg>; diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi index 3defd47fd8fab..74d8e2c8e4b34 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -142,8 +142,7 @@ clocks { sleep_clk: sleep_clk { compatible = "fixed-clock"; - clock-frequency = <32000>; - clock-output-names = "gcc_sleep_clk_src"; + clock-frequency = <32768>; #clock-cells = <0>; }; diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi index c197927e7435f..172ea3c70eac2 100644 --- a/arch/arm/boot/dts/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -146,9 +146,7 @@ reg = <0x108000 0x1000>; qcom,ipc = <&l2cc 0x8 2>; - interrupts = , - , - ; + interrupts = <0 19 0>, <0 21 0>, <0 22 0>; interrupt-names = "ack", "err", "wakeup"; regulators { @@ -194,7 +192,7 @@ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16440000 0x1000>, <0x16400000 0x1000>; - interrupts = ; + interrupts = <0 154 0x0>; clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; clock-names = "core", "iface"; status = "disabled"; @@ -320,7 +318,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x16080000 0x1000>; - interrupts = ; + interrupts = <0 147 0>; spi-max-frequency = <24000000>; cs-gpios = <&msmgpio 8 0>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 12f57278ba4a5..2c4952427296e 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -413,7 +413,7 @@ pmecc: ecc-engine@f8014070 { compatible = "atmel,sama5d2-pmecc"; reg = <0xf8014070 0x490>, - <0xf8014500 0x200>; + <0xf8014500 0x100>; }; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 66cd473ecb617..1a8f5e8b10e3a 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -136,9 +136,9 @@ reg = <0xb4100000 0x1000>; interrupts = <0 105 0x4>; status = "disabled"; - dmas = <&dwdma0 13 0 1>, - <&dwdma0 12 1 0>; - dma-names = "rx", "tx"; + dmas = <&dwdma0 12 0 1>, + <&dwdma0 13 1 0>; + dma-names = "tx", "rx"; }; thermal@e07008c4 { diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 9135533676879..c87b881b2c8bb 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -284,9 +284,9 @@ #size-cells = <0>; interrupts = <0 31 0x4>; status = "disabled"; - dmas = <&dwdma0 5 0 0>, - <&dwdma0 4 0 0>; - dma-names = "rx", "tx"; + dmas = <&dwdma0 4 0 0>, + <&dwdma0 5 0 0>; + dma-names = "tx", "rx"; }; rtc@e0580000 { diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index b21ecb820b133..89abd4cc7e23a 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -524,17 +524,6 @@ #size-cells = <0>; }; - gic: interrupt-controller@1c81000 { - compatible = "arm,gic-400"; - reg = <0x01c81000 0x1000>, - <0x01c82000 0x2000>, - <0x01c84000 0x2000>, - <0x01c86000 0x2000>; - interrupt-controller; - #interrupt-cells = <3>; - interrupts = ; - }; - csi1: camera@1cb4000 { compatible = "allwinner,sun8i-v3s-csi"; reg = <0x01cb4000 0x3000>; @@ -546,5 +535,16 @@ resets = <&ccu RST_BUS_CSI>; status = "disabled"; }; + + gic: interrupt-controller@1c81000 { + compatible = "arm,gic-400"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = ; + }; }; }; diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi index 7f14f0d005c3e..dd4d506683de7 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi @@ -183,8 +183,8 @@ }; conf_ata { nvidia,pins = "ata", "atb", "atc", "atd", "ate", - "cdev1", "cdev2", "dap1", "dtb", "dtf", - "gma", "gmb", "gmc", "gmd", "gme", "gpu7", + "cdev1", "cdev2", "dap1", "dtb", "gma", + "gmb", "gmc", "gmd", "gme", "gpu7", "gpv", "i2cp", "irrx", "irtx", "pta", "rm", "slxa", "slxk", "spia", "spib", "uac"; @@ -203,7 +203,7 @@ }; conf_crtp { nvidia,pins = "crtp", "dap2", "dap3", "dap4", - "dtc", "dte", "gpu", "sdio1", + "dtc", "dte", "dtf", "gpu", "sdio1", "slxc", "slxd", "spdi", "spdo", "spig", "uda"; nvidia,pull = ; diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 4393e689f2354..e00be9faa23bf 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -187,7 +187,6 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_PLATFORM_SUPPORT=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_ASPEED=m CONFIG_VIDEO_ATMEL_ISI=m diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index e4dba5461cb3e..2b575792363e5 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -102,8 +102,6 @@ config CRYPTO_AES_ARM_BS depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_LIB_AES - select CRYPTO_AES - select CRYPTO_CBC select CRYPTO_SIMD help Use a faster and more secure NEON based implementation of AES in CBC, diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index 5f1b1ce10473a..a74289ebc8036 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -22,7 +22,10 @@ * mcount can be thought of as a function called in the middle of a subroutine * call. As such, it needs to be transparent for both the caller and the * callee: the original lr needs to be restored when leaving mcount, and no - * registers should be clobbered. + * registers should be clobbered. (In the __gnu_mcount_nc implementation, we + * clobber the ip register. This is OK because the ARM calling convention + * allows it to be clobbered in subroutines and doesn't use it to hold + * parameters.) * * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). @@ -67,25 +70,26 @@ .macro __ftrace_regs_caller - str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0, + sub sp, sp, #8 @ space for PC and CPSR OLD_R0, @ OLD_R0 will overwrite previous LR - ldr lr, [sp, #8] @ get previous LR + add ip, sp, #12 @ move in IP the value of SP as it was + @ before the push {lr} of the mcount mechanism - str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR + str lr, [sp, #0] @ store LR instead of PC - str lr, [sp, #-4]! @ store previous LR as LR + ldr lr, [sp, #8] @ get previous LR - add lr, sp, #16 @ move in LR the value of SP as it was - @ before the push {lr} of the mcount mechanism + str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR - push {r0-r11, ip, lr} + stmdb sp!, {ip, lr} + stmdb sp!, {r0-r11, lr} @ stack content at this point: @ 0 4 48 52 56 60 64 68 72 - @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 | + @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | - mov r3, sp @ struct pt_regs* + mov r3, sp @ struct pt_regs* ldr r2, =function_trace_op ldr r2, [r2] @ pointer to the current @@ -108,9 +112,11 @@ ftrace_graph_regs_call: #endif @ pop saved regs - pop {r0-r11, ip, lr} @ restore r0 through r12 - ldr lr, [sp], #4 @ restore LR - ldr pc, [sp], #12 + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return .endm #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -126,9 +132,11 @@ ftrace_graph_regs_call: bl prepare_ftrace_return @ pop registers saved in ftrace_regs_caller - pop {r0-r11, ip, lr} @ restore r0 through r12 - ldr lr, [sp], #4 @ restore LR - ldr pc, [sp], #12 + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return .endm #endif @@ -194,17 +202,16 @@ ftrace_graph_call\suffix: .endm .macro mcount_exit - ldmia sp!, {r0-r3} - ldr lr, [sp, #4] - ldr pc, [sp], #8 + ldmia sp!, {r0-r3, ip, lr} + ret ip .endm ENTRY(__gnu_mcount_nc) UNWIND(.fnstart) #ifdef CONFIG_DYNAMIC_FTRACE - push {lr} - ldr lr, [sp, #4] - ldr pc, [sp], #8 + mov ip, lr + ldmia sp!, {lr} + ret ip #else __mcount #endif diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index b74bfcf94fb1a..6166ba38bf994 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -195,7 +195,7 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr) destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); /* Check access in reasonable access range for both SWP and SWPB */ - if (!access_ok((void __user *)(address & ~3), 4)) { + if (!access_ok((address & ~3), 4)) { pr_debug("SWP{B} emulation: access to %p not allowed!\n", (void *)address); res = -EFAULT; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index a531afad87fdb..2d9e72ad1b0f9 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -589,7 +589,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end < start || flags) return -EINVAL; - if (!access_ok((void __user *)start, end - start)) + if (!access_ok(start, end - start)) return -EFAULT; return __do_cache_op(start, end); diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mach-iop32x/include/mach/entry-macro.S index 341e5d9a6616d..8e6766d4621eb 100644 --- a/arch/arm/mach-iop32x/include/mach/entry-macro.S +++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S @@ -20,7 +20,7 @@ mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC cmp \irqstat, #0 clzne \irqnr, \irqstat - rsbne \irqnr, \irqnr, #32 + rsbne \irqnr, \irqnr, #31 .endm .macro arch_ret_to_user, tmp1, tmp2 diff --git a/arch/arm/mach-iop32x/include/mach/irqs.h b/arch/arm/mach-iop32x/include/mach/irqs.h index e09ae5f48aec5..c4e78df428e86 100644 --- a/arch/arm/mach-iop32x/include/mach/irqs.h +++ b/arch/arm/mach-iop32x/include/mach/irqs.h @@ -9,6 +9,6 @@ #ifndef __IRQS_H #define __IRQS_H -#define NR_IRQS 33 +#define NR_IRQS 32 #endif diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index d1e8824cbd824..2d48bf1398c10 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -32,14 +32,14 @@ static void intstr_write(u32 val) static void iop32x_irq_mask(struct irq_data *d) { - iop32x_mask &= ~(1 << (d->irq - 1)); + iop32x_mask &= ~(1 << d->irq); intctl_write(iop32x_mask); } static void iop32x_irq_unmask(struct irq_data *d) { - iop32x_mask |= 1 << (d->irq - 1); + iop32x_mask |= 1 << d->irq; intctl_write(iop32x_mask); } @@ -65,7 +65,7 @@ void __init iop32x_init_irq(void) machine_is_em7210()) *IOP3XX_PCIIRSR = 0x0f; - for (i = 1; i < NR_IRQS; i++) { + for (i = 0; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } diff --git a/arch/arm/mach-iop32x/irqs.h b/arch/arm/mach-iop32x/irqs.h index e1dfc8b4e7d7e..69858e4e905d1 100644 --- a/arch/arm/mach-iop32x/irqs.h +++ b/arch/arm/mach-iop32x/irqs.h @@ -7,40 +7,36 @@ #ifndef __IOP32X_IRQS_H #define __IOP32X_IRQS_H -/* Interrupts in Linux start at 1, hardware starts at 0 */ - -#define IOP_IRQ(x) ((x) + 1) - /* * IOP80321 chipset interrupts */ -#define IRQ_IOP32X_DMA0_EOT IOP_IRQ(0) -#define IRQ_IOP32X_DMA0_EOC IOP_IRQ(1) -#define IRQ_IOP32X_DMA1_EOT IOP_IRQ(2) -#define IRQ_IOP32X_DMA1_EOC IOP_IRQ(3) -#define IRQ_IOP32X_AA_EOT IOP_IRQ(6) -#define IRQ_IOP32X_AA_EOC IOP_IRQ(7) -#define IRQ_IOP32X_CORE_PMON IOP_IRQ(8) -#define IRQ_IOP32X_TIMER0 IOP_IRQ(9) -#define IRQ_IOP32X_TIMER1 IOP_IRQ(10) -#define IRQ_IOP32X_I2C_0 IOP_IRQ(11) -#define IRQ_IOP32X_I2C_1 IOP_IRQ(12) -#define IRQ_IOP32X_MESSAGING IOP_IRQ(13) -#define IRQ_IOP32X_ATU_BIST IOP_IRQ(14) -#define IRQ_IOP32X_PERFMON IOP_IRQ(15) -#define IRQ_IOP32X_CORE_PMU IOP_IRQ(16) -#define IRQ_IOP32X_BIU_ERR IOP_IRQ(17) -#define IRQ_IOP32X_ATU_ERR IOP_IRQ(18) -#define IRQ_IOP32X_MCU_ERR IOP_IRQ(19) -#define IRQ_IOP32X_DMA0_ERR IOP_IRQ(20) -#define IRQ_IOP32X_DMA1_ERR IOP_IRQ(21) -#define IRQ_IOP32X_AA_ERR IOP_IRQ(23) -#define IRQ_IOP32X_MSG_ERR IOP_IRQ(24) -#define IRQ_IOP32X_SSP IOP_IRQ(25) -#define IRQ_IOP32X_XINT0 IOP_IRQ(27) -#define IRQ_IOP32X_XINT1 IOP_IRQ(28) -#define IRQ_IOP32X_XINT2 IOP_IRQ(29) -#define IRQ_IOP32X_XINT3 IOP_IRQ(30) -#define IRQ_IOP32X_HPI IOP_IRQ(31) +#define IRQ_IOP32X_DMA0_EOT 0 +#define IRQ_IOP32X_DMA0_EOC 1 +#define IRQ_IOP32X_DMA1_EOT 2 +#define IRQ_IOP32X_DMA1_EOC 3 +#define IRQ_IOP32X_AA_EOT 6 +#define IRQ_IOP32X_AA_EOC 7 +#define IRQ_IOP32X_CORE_PMON 8 +#define IRQ_IOP32X_TIMER0 9 +#define IRQ_IOP32X_TIMER1 10 +#define IRQ_IOP32X_I2C_0 11 +#define IRQ_IOP32X_I2C_1 12 +#define IRQ_IOP32X_MESSAGING 13 +#define IRQ_IOP32X_ATU_BIST 14 +#define IRQ_IOP32X_PERFMON 15 +#define IRQ_IOP32X_CORE_PMU 16 +#define IRQ_IOP32X_BIU_ERR 17 +#define IRQ_IOP32X_ATU_ERR 18 +#define IRQ_IOP32X_MCU_ERR 19 +#define IRQ_IOP32X_DMA0_ERR 20 +#define IRQ_IOP32X_DMA1_ERR 21 +#define IRQ_IOP32X_AA_ERR 23 +#define IRQ_IOP32X_MSG_ERR 24 +#define IRQ_IOP32X_SSP 25 +#define IRQ_IOP32X_XINT0 27 +#define IRQ_IOP32X_XINT1 28 +#define IRQ_IOP32X_XINT2 29 +#define IRQ_IOP32X_XINT3 30 +#define IRQ_IOP32X_HPI 31 #endif diff --git a/arch/arm/mach-mmp/sram.c b/arch/arm/mach-mmp/sram.c index ecc46c31004f6..6794e2db1ad5f 100644 --- a/arch/arm/mach-mmp/sram.c +++ b/arch/arm/mach-mmp/sram.c @@ -72,8 +72,6 @@ static int sram_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - platform_set_drvdata(pdev, info); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "no memory resource defined\n"); @@ -109,6 +107,8 @@ static int sram_probe(struct platform_device *pdev) list_add(&info->node, &sram_bank_list); mutex_unlock(&sram_lock); + platform_set_drvdata(pdev, info); + dev_info(&pdev->dev, "initialized\n"); return 0; @@ -127,19 +127,17 @@ static int sram_remove(struct platform_device *pdev) struct sram_bank_info *info; info = platform_get_drvdata(pdev); + if (info == NULL) + return -ENODEV; - if (info->sram_size) { - mutex_lock(&sram_lock); - list_del(&info->node); - mutex_unlock(&sram_lock); - - gen_pool_destroy(info->gpool); - iounmap(info->sram_virt); - kfree(info->pool_name); - } + mutex_lock(&sram_lock); + list_del(&info->node); + mutex_unlock(&sram_lock); + gen_pool_destroy(info->gpool); + iounmap(info->sram_virt); + kfree(info->pool_name); kfree(info); - return 0; } diff --git a/arch/arm/mach-mstar/Kconfig b/arch/arm/mach-mstar/Kconfig index 30560fdf87ed2..576d1ab293c87 100644 --- a/arch/arm/mach-mstar/Kconfig +++ b/arch/arm/mach-mstar/Kconfig @@ -3,7 +3,6 @@ menuconfig ARCH_MSTARV7 depends on ARCH_MULTI_V7 select ARM_GIC select ARM_HEAVY_MB - select HAVE_ARM_ARCH_TIMER select MST_IRQ help Support for newer MStar/Sigmastar SoC families that are diff --git a/arch/arm/mach-s3c/mach-jive.c b/arch/arm/mach-s3c/mach-jive.c index ae6a1c9ebf78c..2a29c3eca559e 100644 --- a/arch/arm/mach-s3c/mach-jive.c +++ b/arch/arm/mach-s3c/mach-jive.c @@ -236,11 +236,11 @@ static int __init jive_mtdset(char *options) unsigned long set; if (options == NULL || options[0] == '\0') - return 1; + return 0; if (kstrtoul(options, 10, &set)) { printk(KERN_ERR "failed to parse mtdset=%s\n", options); - return 1; + return 0; } switch (set) { @@ -255,7 +255,7 @@ static int __init jive_mtdset(char *options) "using default.", set); } - return 1; + return 0; } /* parse the mtdset= option given to the kernel command line */ diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts index 12a4b1c03390c..ec19fbf928a14 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts @@ -111,8 +111,8 @@ compatible = "silabs,si3226x"; reg = <0>; spi-max-frequency = <5000000>; - spi-cpha; - spi-cpol; + spi-cpha = <1>; + spi-cpol = <1>; pl022,hierarchy = <0>; pl022,interface = <0>; pl022,slave-tx-disable = <0>; @@ -135,8 +135,8 @@ at25,byte-len = <0x8000>; at25,addr-mode = <2>; at25,page-size = <64>; - spi-cpha; - spi-cpol; + spi-cpha = <1>; + spi-cpol = <1>; pl022,hierarchy = <0>; pl022,interface = <0>; pl022,slave-tx-disable = <0>; diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi index 8c218689fef70..2cfeaf3b0a876 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi @@ -687,7 +687,7 @@ }; }; - sata: sata@663f2000 { + sata: ahci@663f2000 { compatible = "brcm,iproc-ahci", "generic-ahci"; reg = <0x663f2000 0x1000>; dma-coherent; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 9beb3c34fcdb5..ea6e3a11e641b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3406,10 +3406,10 @@ #clock-cells = <0>; clock-frequency = <9600000>; clock-output-names = "mclk"; - qcom,micbias1-microvolt = <1800000>; - qcom,micbias2-microvolt = <1800000>; - qcom,micbias3-microvolt = <1800000>; - qcom,micbias4-microvolt = <1800000>; + qcom,micbias1-millivolt = <1800>; + qcom,micbias2-millivolt = <1800>; + qcom,micbias3-millivolt = <1800>; + qcom,micbias4-millivolt = <1800>; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index a8a47378ba689..1aec54590a11a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1114,9 +1114,9 @@ qcom,tcs-offset = <0xd00>; qcom,drv-id = <2>; qcom,tcs-config = , - , - , - ; + , + , + ; rpmhcc: clock-controller { compatible = "qcom,sm8150-rpmh-clk"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index dc45ec372ada4..6db18808b9c54 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -665,8 +665,8 @@ sd-uhs-sdr104; /* Power supply */ - vqmmc-supply = <&vcc1v8_s3>; /* IO line */ - vmmc-supply = <&vcc_sdio>; /* card's power */ + vqmmc-supply = &vcc1v8_s3; /* IO line */ + vmmc-supply = &vcc_sdio; /* card's power */ #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index d04189771c773..b9662205be9bf 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -35,10 +35,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01880000 0x00 0x90000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01880000 0x00 0x90000>; /* GICR */ /* * vcpumntirq: * virtual CPU interface maintenance interrupt diff --git a/arch/arm64/boot/dts/ti/k3-am65.dtsi b/arch/arm64/boot/dts/ti/k3-am65.dtsi index c6a3fecc7518e..d84c0bc050233 100644 --- a/arch/arm64/boot/dts/ti/k3-am65.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65.dtsi @@ -84,7 +84,6 @@ <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, <0x00 0x50000000 0x00 0x50000000 0x00 0x8000000>, - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A53 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x200000>, <0x05 0x00000000 0x05 0x00000000 0x01 0x0000000>, <0x07 0x00000000 0x07 0x00000000 0x01 0x0000000>; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index bef47f96376d9..1ab9f9604af6c 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -47,10 +47,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts = ; diff --git a/arch/arm64/boot/dts/ti/k3-j7200.dtsi b/arch/arm64/boot/dts/ti/k3-j7200.dtsi index 59f5113e657dd..03a9623f0f956 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200.dtsi @@ -127,7 +127,6 @@ <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* timesync router */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */ <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 0350ddfe2c723..85526f72b4616 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -108,10 +108,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts = ; diff --git a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/k3-j721e.dtsi index ba4fe3f983158..a199227327ed2 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e.dtsi @@ -136,7 +136,6 @@ <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01800000>, /* PCIe Core*/ <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */ <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */ - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT */ <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT */ <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ diff --git a/arch/arm64/configs/db845c_gki.fragment b/arch/arm64/configs/db845c_gki.fragment index 5ba41f2d8ddcb..7260af26f4a36 100644 --- a/arch/arm64/configs/db845c_gki.fragment +++ b/arch/arm64/configs/db845c_gki.fragment @@ -1,7 +1,6 @@ CONFIG_QRTR=m CONFIG_QRTR_TUN=m CONFIG_SCSI_UFS_QCOM=m -CONFIG_USB_NET_AX88179_178A=m CONFIG_INPUT_PM8941_PWRKEY=m CONFIG_SERIAL_MSM=m CONFIG_SERIAL_QCOM_GENI=m diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 394c4411518a8..5fcd09e505b4c 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -840,7 +840,7 @@ CONFIG_DMADEVICES=y CONFIG_DMA_BCM2835=y CONFIG_DMA_SUN6I=m CONFIG_FSL_EDMA=y -CONFIG_IMX_SDMA=m +CONFIG_IMX_SDMA=y CONFIG_K3_DMA=y CONFIG_MV_XOR=y CONFIG_MV_XOR_V2=y diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig index 25698c34c673c..86f63c51de4d7 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -124,6 +124,10 @@ CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=16 CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_ANON_VMA_NAME=y +CONFIG_LRU_GEN=y +CONFIG_DAMON=y +CONFIG_DAMON_PADDR=y +CONFIG_DAMON_RECLAIM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -331,6 +335,7 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_WIREGUARD=y CONFIG_IFB=y +CONFIG_MACSEC=y CONFIG_TUN=y CONFIG_VETH=y CONFIG_PPP=y @@ -342,7 +347,6 @@ CONFIG_PPPOL2TP=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y -# CONFIG_USB_NET_AX88179_178A is not set CONFIG_USB_NET_CDC_EEM=y # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set @@ -394,6 +398,7 @@ CONFIG_HVC_DCC=y CONFIG_HVC_DCC_SERIALIZE_SMP=y CONFIG_SERIAL_DEV_BUS=y CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_CAVIUM is not set # CONFIG_DEVMEM is not set # CONFIG_DEVPORT is not set CONFIG_RANDOM_TRUST_CPU=y @@ -574,6 +579,7 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_F2FS_UNFAIR_RWSEM=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index bda918948471d..1bc198a5faade 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -149,6 +149,20 @@ msr spsr_el2, x0 .endm +.macro __init_el2_mpam + /* Memory Partioning And Monitoring: disable EL2 traps */ + mrs x1, id_aa64pfr0_el1 + ubfx x0, x1, #ID_AA64PFR0_MPAM_SHIFT, #4 + cbz x0, .Lskip_mpam_\@ // skip if no MPAM + msr_s SYS_MPAM0_EL1, xzr // use the default partition.. + msr_s SYS_MPAM2_EL2, xzr // ..and disable lower traps + msr_s SYS_MPAM1_EL1, xzr + mrs_s x0, SYS_MPAMIDR_EL1 + tbz x0, #17, .Lskip_mpam_\@ // skip if no MPAMHCR reg + msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2 +.Lskip_mpam_\@: +.endm + /** * Initialize EL2 registers to sane values. This should be called early on all * cores that were booted in EL2. Note that everything gets initialised as @@ -165,6 +179,7 @@ __init_el2_stage2 __init_el2_gicv3 __init_el2_hstr + __init_el2_mpam __init_el2_nvhe_idregs __init_el2_nvhe_cptr __init_el2_nvhe_sve diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 8ce6444d861ae..ef1cf41ea394f 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -82,6 +82,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___pkvm_iommu_driver_init, __KVM_HOST_SMCCC_FUNC___pkvm_iommu_register, __KVM_HOST_SMCCC_FUNC___pkvm_iommu_pm_notify, + __KVM_HOST_SMCCC_FUNC___pkvm_iommu_finalize, }; #define DECLARE_KVM_VHE_SYM(sym) extern char sym[] @@ -112,7 +113,7 @@ enum __kvm_host_smccc_func { #define per_cpu_ptr_nvhe_sym(sym, cpu) \ ({ \ unsigned long base, off; \ - base = kvm_arm_hyp_percpu_base[cpu]; \ + base = kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu]; \ off = (unsigned long)&CHOOSE_NVHE_SYM(sym) - \ (unsigned long)&CHOOSE_NVHE_SYM(__per_cpu_start); \ base ? (typeof(CHOOSE_NVHE_SYM(sym))*)(base + off) : NULL; \ @@ -200,7 +201,7 @@ DECLARE_KVM_HYP_SYM(__kvm_hyp_vector); #define __kvm_hyp_init CHOOSE_NVHE_SYM(__kvm_hyp_init) #define __kvm_hyp_vector CHOOSE_HYP_SYM(__kvm_hyp_vector) -extern unsigned long kvm_arm_hyp_percpu_base[NR_CPUS]; +extern unsigned long kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[]; DECLARE_KVM_NVHE_SYM(__per_cpu_start); DECLARE_KVM_NVHE_SYM(__per_cpu_end); diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 7e0ff042be886..f583373ff8abe 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -41,6 +41,11 @@ void kvm_inject_vabt(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); +unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode, + enum exception_type type); +unsigned long get_except64_cpsr(unsigned long old, bool has_mte, + unsigned long sctlr, unsigned long mode); + static inline int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) { /* diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 08bf6cc097431..f73ed0c867be0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -212,8 +212,6 @@ struct kvm_arch { u8 pfr0_csv3; struct kvm_protected_vm pkvm; - - u64 hypercall_exit_enabled; }; struct kvm_protected_vcpu { @@ -378,6 +376,7 @@ extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS]; enum pkvm_iommu_driver_id { PKVM_IOMMU_DRIVER_S2MPU, + PKVM_IOMMU_DRIVER_SYSMMU_SYNC, PKVM_IOMMU_NR_DRIVERS, }; @@ -388,11 +387,15 @@ enum pkvm_iommu_pm_event { int pkvm_iommu_driver_init(enum pkvm_iommu_driver_id drv_id, void *data, size_t size); int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, - phys_addr_t pa, size_t size); + phys_addr_t pa, size_t size, struct device *parent); int pkvm_iommu_suspend(struct device *dev); int pkvm_iommu_resume(struct device *dev); int pkvm_iommu_s2mpu_register(struct device *dev, phys_addr_t pa); +int pkvm_iommu_sysmmu_sync_register(struct device *dev, phys_addr_t pa, + struct device *parent); +/* Reject future calls to pkvm_iommu_driver_init() and pkvm_iommu_register(). */ +int pkvm_iommu_finalize(void); struct vcpu_reset_state { unsigned long pc; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 7a8dc3f343ec8..b3b03f1549ebf 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -118,6 +118,10 @@ alternative_cb_end void kvm_update_va_mask(struct alt_instr *alt, __le32 *origptr, __le32 *updptr, int nr_inst); +void kvm_get__text(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); +void kvm_get__etext(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); void kvm_compute_layout(void); void kvm_apply_hyp_relocations(void); diff --git a/arch/arm64/include/asm/kvm_s2mpu.h b/arch/arm64/include/asm/kvm_s2mpu.h index 4d517bc1d0ebf..b1075abd604ca 100644 --- a/arch/arm64/include/asm/kvm_s2mpu.h +++ b/arch/arm64/include/asm/kvm_s2mpu.h @@ -12,6 +12,10 @@ #include #define S2MPU_MMIO_SIZE SZ_64K +#define SYSMMU_SYNC_MMIO_SIZE SZ_64K +#define SYSMMU_SYNC_S2_OFFSET SZ_32K +#define SYSMMU_SYNC_S2_MMIO_SIZE (SYSMMU_SYNC_MMIO_SIZE - \ + SYSMMU_SYNC_S2_OFFSET) #define NR_VIDS 8 #define NR_CTX_IDS 8 @@ -24,6 +28,7 @@ #define REG_NS_INTERRUPT_ENABLE_PER_VID_SET 0x20 #define REG_NS_INTERRUPT_CLEAR 0x2c #define REG_NS_VERSION 0x60 +#define REG_NS_INFO 0x64 #define REG_NS_STATUS 0x68 #define REG_NS_NUM_CONTEXT 0x100 #define REG_NS_CONTEXT_CFG_VALID_VID 0x104 @@ -35,6 +40,10 @@ #define REG_NS_FAULT_PA_LOW(vid) (0x2004 + ((vid) * 0x20)) #define REG_NS_FAULT_PA_HIGH(vid) (0x2008 + ((vid) * 0x20)) #define REG_NS_FAULT_INFO(vid) (0x2010 + ((vid) * 0x20)) +#define REG_NS_READ_MPTC 0x3000 +#define REG_NS_READ_MPTC_TAG_PPN 0x3004 +#define REG_NS_READ_MPTC_TAG_OTHERS 0x3008 +#define REG_NS_READ_MPTC_DATA 0x3010 #define REG_NS_L1ENTRY_L2TABLE_ADDR(vid, gb) (0x4000 + ((vid) * 0x200) + ((gb) * 0x8)) #define REG_NS_L1ENTRY_ATTR(vid, gb) (0x4004 + ((vid) * 0x200) + ((gb) * 0x8)) @@ -42,15 +51,30 @@ #define CTRL0_INTERRUPT_ENABLE BIT(1) #define CTRL0_FAULT_RESP_TYPE_SLVERR BIT(2) /* for v8 */ #define CTRL0_FAULT_RESP_TYPE_DECERR BIT(2) /* for v9 */ +#define CTRL0_MASK (CTRL0_ENABLE | \ + CTRL0_INTERRUPT_ENABLE | \ + CTRL0_FAULT_RESP_TYPE_SLVERR | \ + CTRL0_FAULT_RESP_TYPE_DECERR) #define CTRL1_DISABLE_CHK_S1L1PTW BIT(0) #define CTRL1_DISABLE_CHK_S1L2PTW BIT(1) #define CTRL1_ENABLE_PAGE_SIZE_AWARENESS BIT(2) #define CTRL1_DISABLE_CHK_USER_MATCHED_REQ BIT(3) +#define CTRL1_MASK (CTRL1_DISABLE_CHK_S1L1PTW | \ + CTRL1_DISABLE_CHK_S1L2PTW | \ + CTRL1_ENABLE_PAGE_SIZE_AWARENESS | \ + CTRL1_DISABLE_CHK_USER_MATCHED_REQ) #define CFG_MPTW_CACHE_OVERRIDE BIT(0) +#define CFG_MPTW_CACHE_VALUE GENMASK(7, 4) #define CFG_MPTW_QOS_OVERRIDE BIT(8) +#define CFG_MPTW_QOS_VALUE GENMASK(15, 12) #define CFG_MPTW_SHAREABLE BIT(16) +#define CFG_MASK (CFG_MPTW_CACHE_OVERRIDE | \ + CFG_MPTW_CACHE_VALUE | \ + CFG_MPTW_QOS_OVERRIDE | \ + CFG_MPTW_QOS_VALUE | \ + CFG_MPTW_SHAREABLE) /* For use with hi_lo_readq_relaxed(). */ #define REG_NS_FAULT_PA_HIGH_LOW(vid) REG_NS_FAULT_PA_LOW(vid) @@ -68,6 +92,8 @@ VERSION_MINOR_ARCH_VER_MASK | \ VERSION_REV_ARCH_VER_MASK) +#define INFO_NUM_SET_MASK GENMASK(15, 0) + #define STATUS_BUSY BIT(0) #define STATUS_ON_INVALIDATING BIT(1) @@ -90,14 +116,31 @@ #define FAULT_INFO_LEN_MASK GENMASK(19, 16) #define FAULT_INFO_ID_MASK GENMASK(15, 0) -#define L1ENTRY_L2TABLE_ADDR(pa) ((pa) >> 4) +#define L1ENTRY_L2TABLE_ADDR_SHIFT 4 +#define L1ENTRY_L2TABLE_ADDR(pa) ((pa) >> L1ENTRY_L2TABLE_ADDR_SHIFT) + +#define READ_MPTC_WAY_MASK GENMASK(18, 16) +#define READ_MPTC_SET_MASK GENMASK(15, 0) +#define READ_MPTC_MASK (READ_MPTC_WAY_MASK | READ_MPTC_SET_MASK) +#define READ_MPTC_WAY(way) FIELD_PREP(READ_MPTC_WAY_MASK, (way)) +#define READ_MPTC_SET(set) FIELD_PREP(READ_MPTC_SET_MASK, (set)) +#define READ_MPTC(set, way) (READ_MPTC_SET(set) | READ_MPTC_WAY(way)) +#define READ_MPTC_TAG_PPN_MASK GENMASK(23, 0) +#define READ_MPTC_TAG_OTHERS_VID_MASK GENMASK(10, 8) +#define READ_MPTC_TAG_OTHERS_GRAN_MASK GENMASK(5, 4) +#define READ_MPTC_TAG_OTHERS_VALID_BIT BIT(0) +#define READ_MPTC_TAG_OTHERS_MASK (READ_MPTC_TAG_OTHERS_VID_MASK | \ + READ_MPTC_TAG_OTHERS_GRAN_MASK | \ + READ_MPTC_TAG_OTHERS_VALID_BIT) #define L1ENTRY_ATTR_L2TABLE_EN BIT(0) #define L1ENTRY_ATTR_GRAN_4K 0x0 #define L1ENTRY_ATTR_GRAN_64K 0x1 #define L1ENTRY_ATTR_GRAN_2M 0x2 -#define L1ENTRY_ATTR_PROT(prot) FIELD_PREP(GENMASK(2, 1), prot) -#define L1ENTRY_ATTR_GRAN(gran) FIELD_PREP(GENMASK(5, 4), gran) +#define L1ENTRY_ATTR_PROT_MASK GENMASK(2, 1) +#define L1ENTRY_ATTR_GRAN_MASK GENMASK(5, 4) +#define L1ENTRY_ATTR_PROT(prot) FIELD_PREP(L1ENTRY_ATTR_PROT_MASK, prot) +#define L1ENTRY_ATTR_GRAN(gran) FIELD_PREP(L1ENTRY_ATTR_GRAN_MASK, gran) #define L1ENTRY_ATTR_1G(prot) L1ENTRY_ATTR_PROT(prot) #define L1ENTRY_ATTR_L2(gran) (L1ENTRY_ATTR_GRAN(gran) | \ L1ENTRY_ATTR_L2TABLE_EN) @@ -128,6 +171,13 @@ static_assert(SMPT_GRAN <= PAGE_SIZE); #define SMPT_NUM_PAGES (SMPT_SIZE / PAGE_SIZE) #define SMPT_ORDER get_order(SMPT_SIZE) +/* SysMMU_SYNC registers, relative to SYSMMU_SYNC_S2_OFFSET. */ +#define REG_NS_SYNC_CMD 0x0 +#define REG_NS_SYNC_COMP 0x4 + +#define SYNC_CMD_SYNC BIT(0) +#define SYNC_COMP_COMPLETE BIT(0) + /* * Iterate over S2MPU gigabyte regions. Skip those that cannot be modified * (the MMIO registers are read only, with reset value MPT_PROT_NONE). diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 40321a57088df..e4796c3ad19ac 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1011,23 +1011,13 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, * page after fork() + CoW for pfn mappings. We don't always have a * hardware-managed access flag on arm64. */ -static inline bool arch_faults_on_old_pte(void) -{ - WARN_ON(preemptible()); - - return !cpu_has_hw_af(); -} -#define arch_faults_on_old_pte arch_faults_on_old_pte +#define arch_has_hw_pte_young cpu_has_hw_af /* * Experimentally, it's cheap to set the access flag in hardware and we * benefit from prefaulting mappings as 'old' to start with. */ -static inline bool arch_wants_old_prefaulted_pte(void) -{ - return !arch_faults_on_old_pte(); -} -#define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte +#define arch_wants_old_prefaulted_pte cpu_has_hw_af #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 3567520ac7012..e706e55c6494d 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -394,7 +394,10 @@ #define SYS_LOREA_EL1 sys_reg(3, 0, 10, 4, 1) #define SYS_LORN_EL1 sys_reg(3, 0, 10, 4, 2) #define SYS_LORC_EL1 sys_reg(3, 0, 10, 4, 3) +#define SYS_MPAMIDR_EL1 sys_reg(3, 0, 10, 4, 4) #define SYS_LORID_EL1 sys_reg(3, 0, 10, 4, 7) +#define SYS_MPAM1_EL1 sys_reg(3, 0, 10, 5, 0) +#define SYS_MPAM0_EL1 sys_reg(3, 0, 10, 5, 1) #define SYS_VBAR_EL1 sys_reg(3, 0, 12, 0, 0) #define SYS_DISR_EL1 sys_reg(3, 0, 12, 1, 1) @@ -536,6 +539,10 @@ #define SYS_TFSR_EL2 sys_reg(3, 4, 5, 6, 0) #define SYS_FAR_EL2 sys_reg(3, 4, 6, 0, 0) +#define SYS_MPAMHCR_EL2 sys_reg(3, 4, 10, 4, 0) +#define SYS_MPAMVPMV_EL2 sys_reg(3, 4, 10, 4, 1) +#define SYS_MPAM2_EL2 sys_reg(3, 4, 10, 5, 0) + #define SYS_VDISR_EL2 sys_reg(3, 4, 12, 1, 1) #define __SYS__AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) #define SYS_ICH_AP0R0_EL2 __SYS__AP0Rx_EL2(0) diff --git a/arch/arm64/include/asm/vectors.h b/arch/arm64/include/asm/vectors.h index bc9a2145f4194..f64613a96d530 100644 --- a/arch/arm64/include/asm/vectors.h +++ b/arch/arm64/include/asm/vectors.h @@ -56,14 +56,14 @@ enum arm64_bp_harden_el1_vectors { DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector); #ifndef CONFIG_UNMAP_KERNEL_AT_EL0 -#define TRAMP_VALIAS 0ul +#define TRAMP_VALIAS 0 #endif static inline const char * arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot) { if (arm64_kernel_unmapped_at_el0()) - return (char *)(TRAMP_VALIAS + SZ_2K * slot); + return (char *)TRAMP_VALIAS + SZ_2K * slot; WARN_ON_ONCE(slot == EL1_VECTOR_KPTI); diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index 3218ca17f819e..8bc48dec69528 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -72,6 +72,12 @@ void __hyp_reset_vectors(void); DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); +static inline bool is_pkvm_initialized(void) +{ + return IS_ENABLED(CONFIG_KVM) && + static_branch_likely(&kvm_protected_mode_initialized); +} + /* Reports the availability of HYP mode */ static inline bool is_hyp_mode_available(void) { @@ -79,8 +85,7 @@ static inline bool is_hyp_mode_available(void) * If KVM protected mode is initialized, all CPUs must have been booted * in EL2. Avoid checking __boot_cpu_mode as CPUs now come up in EL1. */ - if (IS_ENABLED(CONFIG_KVM) && - static_branch_likely(&kvm_protected_mode_initialized)) + if (is_pkvm_initialized()) return true; return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 && @@ -94,8 +99,7 @@ static inline bool is_hyp_mode_mismatched(void) * If KVM protected mode is initialized, all CPUs must have been booted * in EL2. Avoid checking __boot_cpu_mode as CPUs now come up in EL1. */ - if (IS_ENABLED(CONFIG_KVM) && - static_branch_likely(&kvm_protected_mode_initialized)) + if (is_pkvm_initialized()) return false; return __boot_cpu_mode[0] != __boot_cpu_mode[1]; diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 2858ed8a42206..8f674fbab573d 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -65,6 +65,8 @@ __efistub__ctype = _ctype; KVM_NVHE_ALIAS(kvm_patch_vector_branch); KVM_NVHE_ALIAS(kvm_update_va_mask); KVM_NVHE_ALIAS(kvm_get_kimage_voffset); +KVM_NVHE_ALIAS(kvm_get__text); +KVM_NVHE_ALIAS(kvm_get__etext); KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0); KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter); KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable); @@ -99,9 +101,6 @@ KVM_NVHE_ALIAS(gic_nonsecure_priorities); KVM_NVHE_ALIAS(__start___kvm_ex_table); KVM_NVHE_ALIAS(__stop___kvm_ex_table); -/* Array containing bases of nVHE per-CPU memory regions. */ -KVM_NVHE_ALIAS(kvm_arm_hyp_percpu_base); - /* PMU available static key */ KVM_NVHE_ALIAS(kvm_arm_pmu_available); @@ -116,12 +115,6 @@ KVM_NVHE_ALIAS_HYP(__memcpy, __pi_memcpy); KVM_NVHE_ALIAS_HYP(__memset, __pi_memset); #endif -/* Kernel memory sections */ -KVM_NVHE_ALIAS(__start_rodata); -KVM_NVHE_ALIAS(__end_rodata); -KVM_NVHE_ALIAS(__bss_start); -KVM_NVHE_ALIAS(__bss_stop); - /* Hyp memory sections */ KVM_NVHE_ALIAS(__hyp_idmap_text_start); KVM_NVHE_ALIAS(__hyp_idmap_text_end); diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c index c07d7a0349410..bd26866b86455 100644 --- a/arch/arm64/kernel/paravirt.c +++ b/arch/arm64/kernel/paravirt.c @@ -47,7 +47,9 @@ early_param("no-steal-acc", parse_no_stealacc); /* return stolen time in ns by asking the hypervisor */ static u64 pv_steal_clock(int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; + u64 ret = 0; reg = per_cpu_ptr(&stolen_time_region, cpu); @@ -56,28 +58,38 @@ static u64 pv_steal_clock(int cpu) * online notification callback runs. Until the callback * has run we just return zero. */ - if (!reg->kaddr) + rcu_read_lock(); + kaddr = rcu_dereference(reg->kaddr); + if (!kaddr) { + rcu_read_unlock(); return 0; + } - return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time)); + ret = le64_to_cpu(READ_ONCE(kaddr->stolen_time)); + rcu_read_unlock(); + return ret; } static int stolen_time_cpu_down_prepare(unsigned int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; reg = this_cpu_ptr(&stolen_time_region); if (!reg->kaddr) return 0; - memunmap(reg->kaddr); - memset(reg, 0, sizeof(*reg)); + kaddr = reg->kaddr; + rcu_assign_pointer(reg->kaddr, NULL); + synchronize_rcu(); + memunmap(kaddr); return 0; } static int stolen_time_cpu_online(unsigned int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; struct arm_smccc_res res; @@ -88,10 +100,12 @@ static int stolen_time_cpu_online(unsigned int cpu) if (res.a0 == SMCCC_RET_NOT_SUPPORTED) return -EINVAL; - reg->kaddr = memremap(res.a0, + kaddr = memremap(res.a0, sizeof(struct pvclock_vcpu_stolen_time), MEMREMAP_WB); + rcu_assign_pointer(reg->kaddr, kaddr); + if (!reg->kaddr) { pr_warn("Failed to map stolen time data structure\n"); return -ENOMEM; diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 0dab5679a97d5..e62005317ce29 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -572,12 +572,10 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, { int err; - if (system_supports_fpsimd()) { - err = sigframe_alloc(user, &user->fpsimd_offset, - sizeof(struct fpsimd_context)); - if (err) - return err; - } + err = sigframe_alloc(user, &user->fpsimd_offset, + sizeof(struct fpsimd_context)); + if (err) + return err; /* fault information, if valid */ if (add_all || current->thread.fault_code) { diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 26d52c39c15f9..f0e2822447527 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -50,7 +50,6 @@ DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector); static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -unsigned long kvm_arm_hyp_percpu_base[NR_CPUS]; DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); /* The VMID used in the VTTBR */ @@ -63,10 +62,6 @@ static bool vgic_present; static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled); DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use); -/* KVM "vendor" hypercalls which may be forwarded to userspace on request. */ -#define KVM_EXIT_HYPERCALL_VALID_MASK (BIT(ARM_SMCCC_KVM_FUNC_MEM_SHARE) | \ - BIT(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)) - int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) { return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE; @@ -117,16 +112,6 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, } mutex_unlock(&kvm->lock); break; - case KVM_CAP_EXIT_HYPERCALL: - if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) - return -EINVAL; - - if (cap->args[1] || cap->args[2] || cap->args[3]) - return -EINVAL; - - WRITE_ONCE(kvm->arch.hypercall_exit_enabled, cap->args[0]); - r = 0; - break; default: r = -EINVAL; break; @@ -314,9 +299,6 @@ static int kvm_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_PTRAUTH_GENERIC: r = system_has_full_ptr_auth(); break; - case KVM_CAP_EXIT_HYPERCALL: - r = KVM_EXIT_HYPERCALL_VALID_MASK; - break; default: r = 0; } @@ -341,7 +323,6 @@ static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap) case KVM_CAP_MAX_VCPU_ID: case KVM_CAP_MSI_DEVID: case KVM_CAP_ARM_VM_IPA_SIZE: - case KVM_CAP_EXIT_HYPERCALL: r = kvm_cap; break; case KVM_CAP_GUEST_DEBUG_HW_BPS: @@ -892,12 +873,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) ret = kvm_handle_mmio_return(vcpu); if (ret) return ret; - } else if (run->exit_reason == KVM_EXIT_HYPERCALL) { - smccc_set_retval(vcpu, - vcpu->run->hypercall.ret, - vcpu->run->hypercall.args[0], - vcpu->run->hypercall.args[1], - vcpu->run->hypercall.args[2]); } vcpu_load(vcpu); @@ -1923,13 +1898,13 @@ static void teardown_hyp_mode(void) free_hyp_pgds(); for_each_possible_cpu(cpu) { free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); - free_pages(kvm_arm_hyp_percpu_base[cpu], nvhe_percpu_order()); + free_pages(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu], nvhe_percpu_order()); } } static int do_pkvm_init(u32 hyp_va_bits) { - void *per_cpu_base = kvm_ksym_ref(kvm_arm_hyp_percpu_base); + void *per_cpu_base = kvm_ksym_ref(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)); int ret; preempt_disable(); @@ -2030,7 +2005,7 @@ static int init_hyp_mode(void) page_addr = page_address(page); memcpy(page_addr, CHOOSE_NVHE_SYM(__per_cpu_start), nvhe_percpu_size()); - kvm_arm_hyp_percpu_base[cpu] = (unsigned long)page_addr; + kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu] = (unsigned long)page_addr; } /* @@ -2098,7 +2073,7 @@ static int init_hyp_mode(void) } for_each_possible_cpu(cpu) { - char *percpu_begin = (char *)kvm_arm_hyp_percpu_base[cpu]; + char *percpu_begin = (char *)kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu]; char *percpu_end = percpu_begin + nvhe_percpu_size(); /* Map Hyp percpu pages */ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 2b988ba29f408..dbb7097396f12 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -349,3 +349,4 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n", spsr, elr_virt, esr, far, hpfar, par, vcpu); } +EXPORT_SYMBOL_GPL(nvhe_hyp_panic_handler); diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index c5d0097154020..14a80b0e2f91d 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -60,31 +60,12 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val) vcpu->arch.ctxt.spsr_und = val; } -/* - * This performs the exception entry at a given EL (@target_mode), stashing PC - * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE. - * The EL passed to this function *must* be a non-secure, privileged mode with - * bit 0 being set (PSTATE.SP == 1). - * - * When an exception is taken, most PSTATE fields are left unchanged in the - * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all - * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx - * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0. - * - * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429. - * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426. - * - * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from - * MSB to LSB. - */ -static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, - enum exception_type type) +unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode, + enum exception_type type) { - unsigned long sctlr, vbar, old, new, mode; + u64 mode = psr & (PSR_MODE_MASK | PSR_MODE32_BIT); u64 exc_offset; - mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT); - if (mode == target_mode) exc_offset = CURRENT_EL_SP_ELx_VECTOR; else if ((mode | PSR_MODE_THREAD_BIT) == target_mode) @@ -94,28 +75,32 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, else exc_offset = LOWER_EL_AArch32_VECTOR; - switch (target_mode) { - case PSR_MODE_EL1h: - vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1); - sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1); - __vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1); - break; - default: - /* Don't do that */ - BUG(); - } - - *vcpu_pc(vcpu) = vbar + exc_offset + type; + return exc_offset + type; +} - old = *vcpu_cpsr(vcpu); - new = 0; +/* + * When an exception is taken, most PSTATE fields are left unchanged in the + * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all + * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx + * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0. + * + * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429. + * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426. + * + * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from + * MSB to LSB. + */ +unsigned long get_except64_cpsr(unsigned long old, bool has_mte, + unsigned long sctlr, unsigned long target_mode) +{ + u64 new = 0; new |= (old & PSR_N_BIT); new |= (old & PSR_Z_BIT); new |= (old & PSR_C_BIT); new |= (old & PSR_V_BIT); - if (kvm_has_mte(vcpu->kvm)) + if (has_mte) new |= PSR_TCO_BIT; new |= (old & PSR_DIT_BIT); @@ -151,6 +136,36 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, new |= target_mode; + return new; +} + +/* + * This performs the exception entry at a given EL (@target_mode), stashing PC + * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE. + * The EL passed to this function *must* be a non-secure, privileged mode with + * bit 0 being set (PSTATE.SP == 1). + */ +static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, + enum exception_type type) +{ + u64 offset = get_except64_offset(*vcpu_cpsr(vcpu), target_mode, type); + unsigned long sctlr, vbar, old, new; + + switch (target_mode) { + case PSR_MODE_EL1h: + vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1); + sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1); + __vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1); + break; + default: + /* Don't do that */ + BUG(); + } + + *vcpu_pc(vcpu) = vbar + offset; + + old = *vcpu_cpsr(vcpu); + new = get_except64_cpsr(old, kvm_has_mte(vcpu->kvm), sctlr, target_mode); *vcpu_cpsr(vcpu) = new; __vcpu_write_spsr(vcpu, old); } diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index 2367fe153ad35..69bce1f017174 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -15,15 +15,24 @@ struct pkvm_iommu_ops { * Driver-specific arguments are passed in a buffer shared by the host. * The buffer memory has been pinned in EL2 but host retains R/W access. * Extra care must be taken when reading from it to avoid TOCTOU bugs. + * If the driver maintains its own page tables, it is expected to + * initialize them to all memory owned by the host. * Driver initialization lock held during callback. */ int (*init)(void *data, size_t size); /* - * Driver-specific validation of device registration inputs. - * This should be stateless. No locks are held at entry. + * Driver-specific validation of a device that is being registered. + * All fields of the device struct have been populated. + * Called with the host lock held. */ - int (*validate)(phys_addr_t base, size_t size); + int (*validate)(struct pkvm_iommu *dev); + + /* + * Validation of a new child device that is being register by + * the parent device the child selected. Called with the host lock held. + */ + int (*validate_child)(struct pkvm_iommu *dev, struct pkvm_iommu *child); /* * Callback to apply a host stage-2 mapping change at driver level. @@ -56,7 +65,10 @@ struct pkvm_iommu_ops { }; struct pkvm_iommu { + struct pkvm_iommu *parent; struct list_head list; + struct list_head siblings; + struct list_head children; unsigned long id; const struct pkvm_iommu_ops *ops; phys_addr_t pa; @@ -70,9 +82,11 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si int __pkvm_iommu_register(unsigned long dev_id, enum pkvm_iommu_driver_id drv_id, phys_addr_t dev_pa, size_t dev_size, + unsigned long parent_id, void *kern_mem_va, size_t mem_size); int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event); +int __pkvm_iommu_finalize(void); int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start, phys_addr_t *end); bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, @@ -81,5 +95,6 @@ void pkvm_iommu_host_stage2_idmap(phys_addr_t start, phys_addr_t end, enum kvm_pgtable_prot prot); extern const struct pkvm_iommu_ops pkvm_s2mpu_ops; +extern const struct pkvm_iommu_ops pkvm_sysmmu_sync_ops; #endif /* __ARM64_KVM_NVHE_IOMMU_H__ */ diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index 3f4f90f55c5c4..e796ff5e74fb1 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -91,6 +91,9 @@ int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, struct kvm_hyp_memcache *host_mc); void reclaim_guest_pages(struct kvm_shadow_vm *vm, struct kvm_hyp_memcache *mc); +void psci_mem_protect_inc(void); +void psci_mem_protect_dec(void); + static __always_inline void __load_host_stage2(void) { if (static_branch_likely(&kvm_protected_mode_initialized)) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 4dbd42a867565..1fd6c6e267bab 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -176,6 +176,7 @@ static void do_ffa_rxtx_map(struct arm_smccc_res *res, DECLARE_REG(phys_addr_t, rx, ctxt, 2); DECLARE_REG(u32, npages, ctxt, 3); int ret = 0; + void *rx_virt, *tx_virt; if (npages != (KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) / FFA_PAGE_SIZE) { ret = FFA_RET_INVALID_PARAMETERS; @@ -209,8 +210,22 @@ static void do_ffa_rxtx_map(struct arm_smccc_res *res, goto err_unshare_tx; } - host_kvm.ffa.tx = hyp_phys_to_virt(tx); - host_kvm.ffa.rx = hyp_phys_to_virt(rx); + tx_virt = hyp_phys_to_virt(tx); + ret = hyp_pin_shared_mem(tx_virt, tx_virt + 1); + if (ret) { + ret = FFA_RET_INVALID_PARAMETERS; + goto err_unshare_rx; + } + + rx_virt = hyp_phys_to_virt(rx); + ret = hyp_pin_shared_mem(rx_virt, rx_virt + 1); + if (ret) { + ret = FFA_RET_INVALID_PARAMETERS; + goto err_unpin_tx; + } + + host_kvm.ffa.tx = tx_virt; + host_kvm.ffa.rx = rx_virt; out_unlock: hyp_spin_unlock(&host_kvm.ffa.lock); @@ -218,6 +233,10 @@ out: ffa_to_smccc_res(res, ret); return; +err_unpin_tx: + hyp_unpin_shared_mem(tx_virt, tx_virt + 1); +err_unshare_rx: + __pkvm_host_unshare_hyp(hyp_phys_to_pfn(rx)); err_unshare_tx: __pkvm_host_unshare_hyp(hyp_phys_to_pfn(tx)); err_unmap: @@ -242,9 +261,11 @@ static void do_ffa_rxtx_unmap(struct arm_smccc_res *res, goto out_unlock; } + hyp_unpin_shared_mem(host_kvm.ffa.tx, host_kvm.ffa.tx + 1); WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_kvm.ffa.tx))); host_kvm.ffa.tx = NULL; + hyp_unpin_shared_mem(host_kvm.ffa.rx, host_kvm.ffa.rx + 1); WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_kvm.ffa.rx))); host_kvm.ffa.rx = NULL; @@ -263,10 +284,13 @@ static u32 __ffa_host_share_ranges(struct ffa_mem_region_addr_range *ranges, for (i = 0; i < nranges; ++i) { struct ffa_mem_region_addr_range *range = &ranges[i]; - u64 npages = (range->pg_cnt * FFA_PAGE_SIZE) / PAGE_SIZE; + u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE; u64 pfn = hyp_phys_to_pfn(range->address); - if (__pkvm_host_share_ffa(pfn, npages)) + if (!PAGE_ALIGNED(sz)) + break; + + if (__pkvm_host_share_ffa(pfn, sz / PAGE_SIZE)) break; } @@ -280,10 +304,13 @@ static u32 __ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges, for (i = 0; i < nranges; ++i) { struct ffa_mem_region_addr_range *range = &ranges[i]; - u64 npages = (range->pg_cnt * FFA_PAGE_SIZE) / PAGE_SIZE; + u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE; u64 pfn = hyp_phys_to_pfn(range->address); - if (__pkvm_host_unshare_ffa(pfn, npages)) + if (!PAGE_ALIGNED(sz)) + break; + + if (__pkvm_host_unshare_ffa(pfn, sz / PAGE_SIZE)) break; } diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S index 8fc25633d6cc9..85788e511156a 100644 --- a/arch/arm64/kvm/hyp/nvhe/host.S +++ b/arch/arm64/kvm/hyp/nvhe/host.S @@ -198,15 +198,15 @@ SYM_CODE_START(__kvm_hyp_host_vector) invalid_host_el2_vect // FIQ EL2h invalid_host_el2_vect // Error EL2h - host_el1_sync_vect // Synchronous 64-bit EL1 - invalid_host_el1_vect // IRQ 64-bit EL1 - invalid_host_el1_vect // FIQ 64-bit EL1 - invalid_host_el1_vect // Error 64-bit EL1 - - invalid_host_el1_vect // Synchronous 32-bit EL1 - invalid_host_el1_vect // IRQ 32-bit EL1 - invalid_host_el1_vect // FIQ 32-bit EL1 - invalid_host_el1_vect // Error 32-bit EL1 + host_el1_sync_vect // Synchronous 64-bit EL1/EL0 + invalid_host_el1_vect // IRQ 64-bit EL1/EL0 + invalid_host_el1_vect // FIQ 64-bit EL1/EL0 + invalid_host_el1_vect // Error 64-bit EL1/EL0 + + host_el1_sync_vect // Synchronous 32-bit EL1/EL0 + invalid_host_el1_vect // IRQ 32-bit EL1/EL0 + invalid_host_el1_vect // FIQ 32-bit EL1/EL0 + invalid_host_el1_vect // Error 32-bit EL1/EL0 SYM_CODE_END(__kvm_hyp_host_vector) /* diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index fae3dd83bbdf4..14f9da9f87b90 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -696,21 +696,63 @@ static void handle___pkvm_vcpu_sync_state(struct kvm_cpu_context *host_ctxt) } } +static struct kvm_vcpu *__get_current_vcpu(struct kvm_vcpu *vcpu, + struct pkvm_loaded_state **state) +{ + struct pkvm_loaded_state *sstate = NULL; + + vcpu = kern_hyp_va(vcpu); + + if (unlikely(is_protected_kvm_enabled())) { + sstate = this_cpu_ptr(&loaded_state); + + if (!sstate || vcpu != sstate->vcpu->arch.pkvm.host_vcpu) { + sstate = NULL; + vcpu = NULL; + } + } + + *state = sstate; + return vcpu; +} + +#define get_current_vcpu(ctxt, regnr, statepp) \ + ({ \ + DECLARE_REG(struct kvm_vcpu *, __vcpu, ctxt, regnr); \ + __get_current_vcpu(__vcpu, statepp); \ + }) + +#define get_current_vcpu_from_cpu_if(ctxt, regnr, statepp) \ + ({ \ + DECLARE_REG(struct vgic_v3_cpu_if *, cif, ctxt, regnr); \ + struct kvm_vcpu *__vcpu; \ + __vcpu = container_of(cif, \ + struct kvm_vcpu, \ + arch.vgic_cpu.vgic_v3); \ + \ + __get_current_vcpu(__vcpu, statepp); \ + }) + static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; int ret; - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); + vcpu = get_current_vcpu(host_ctxt, 1, &shadow_state); + if (!vcpu) { + cpu_reg(host_ctxt, 1) = -EINVAL; + return; + } - flush_shadow_state(state); + if (unlikely(shadow_state)) { + flush_shadow_state(shadow_state); - ret = __kvm_vcpu_run(state->vcpu); + ret = __kvm_vcpu_run(shadow_state->vcpu); - sync_shadow_state(state, ret); + sync_shadow_state(shadow_state, ret); - if (state->vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { + if (shadow_state->vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { /* * The guest has used the FP, trap all accesses * from the host (both FP and SVE). @@ -722,7 +764,7 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt) sysreg_clear_set(cptr_el2, 0, reg); } } else { - ret = __kvm_vcpu_run(kern_hyp_va(vcpu)); + ret = __kvm_vcpu_run(vcpu); } cpu_reg(host_ctxt, 1) = ret; @@ -759,20 +801,19 @@ out: static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1); - - vcpu = kern_hyp_va(vcpu); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); + vcpu = get_current_vcpu(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - /* - * A shadow vcpu can never be updated from EL1, and we - * must have a vcpu loaded when protected mode is - * enabled. - */ - if (!state->vcpu || state->is_protected) + if (shadow_state) { + /* This only applies to non-protected VMs */ + if (shadow_state->is_protected) return; + + vcpu = shadow_state->vcpu; } __kvm_adjust_pc(vcpu); @@ -835,56 +876,50 @@ static void handle___kvm_get_mdcr_el2(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __kvm_get_mdcr_el2(); } -static struct vgic_v3_cpu_if *get_shadow_vgic_v3_cpu_if(struct vgic_v3_cpu_if *cpu_if) -{ - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); - struct kvm_vcpu *host_vcpu; - - if (!state->vcpu) - return NULL; - - host_vcpu = state->vcpu->arch.pkvm.host_vcpu; - - if (&host_vcpu->arch.vgic_cpu.vgic_v3 != cpu_if) - return NULL; - } - - return cpu_if; -} - static void handle___vgic_v3_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1); - struct vgic_v3_cpu_if *shadow_cpu_if; - - cpu_if = kern_hyp_va(cpu_if); - shadow_cpu_if = get_shadow_vgic_v3_cpu_if(cpu_if); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - __vgic_v3_save_vmcr_aprs(shadow_cpu_if); + vcpu = get_current_vcpu_from_cpu_if(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - if (cpu_if != shadow_cpu_if) { + if (shadow_state) { + struct vgic_v3_cpu_if *shadow_cpu_if, *cpu_if; int i; + shadow_cpu_if = &shadow_state->vcpu->arch.vgic_cpu.vgic_v3; + __vgic_v3_save_vmcr_aprs(shadow_cpu_if); + + cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; + cpu_if->vgic_vmcr = shadow_cpu_if->vgic_vmcr; for (i = 0; i < ARRAY_SIZE(cpu_if->vgic_ap0r); i++) { cpu_if->vgic_ap0r[i] = shadow_cpu_if->vgic_ap0r[i]; cpu_if->vgic_ap1r[i] = shadow_cpu_if->vgic_ap1r[i]; } + } else { + __vgic_v3_save_vmcr_aprs(&vcpu->arch.vgic_cpu.vgic_v3); } } static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1); - struct vgic_v3_cpu_if *shadow_cpu_if; + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - cpu_if = kern_hyp_va(cpu_if); - shadow_cpu_if = get_shadow_vgic_v3_cpu_if(cpu_if); + vcpu = get_current_vcpu_from_cpu_if(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - if (cpu_if != shadow_cpu_if) { + if (shadow_state) { + struct vgic_v3_cpu_if *shadow_cpu_if, *cpu_if; int i; + shadow_cpu_if = &shadow_state->vcpu->arch.vgic_cpu.vgic_v3; + cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; + shadow_cpu_if->vgic_vmcr = cpu_if->vgic_vmcr; /* Should be a one-off */ shadow_cpu_if->vgic_sre = (ICC_SRE_EL1_DIB | @@ -894,9 +929,11 @@ static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt shadow_cpu_if->vgic_ap0r[i] = cpu_if->vgic_ap0r[i]; shadow_cpu_if->vgic_ap1r[i] = cpu_if->vgic_ap1r[i]; } - } - __vgic_v3_restore_vmcr_aprs(shadow_cpu_if); + __vgic_v3_restore_vmcr_aprs(shadow_cpu_if); + } else { + __vgic_v3_restore_vmcr_aprs(&vcpu->arch.vgic_cpu.vgic_v3); + } } static void handle___pkvm_init(struct kvm_cpu_context *host_ctxt) @@ -991,11 +1028,13 @@ static void handle___pkvm_iommu_register(struct kvm_cpu_context *host_ctxt) DECLARE_REG(enum pkvm_iommu_driver_id, drv_id, host_ctxt, 2); DECLARE_REG(phys_addr_t, dev_pa, host_ctxt, 3); DECLARE_REG(size_t, dev_size, host_ctxt, 4); - DECLARE_REG(void *, mem, host_ctxt, 5); - DECLARE_REG(size_t, mem_size, host_ctxt, 6); + DECLARE_REG(unsigned long, parent_id, host_ctxt, 5); + DECLARE_REG(void *, mem, host_ctxt, 6); + DECLARE_REG(size_t, mem_size, host_ctxt, 7); cpu_reg(host_ctxt, 1) = __pkvm_iommu_register(dev_id, drv_id, dev_pa, - dev_size, mem, mem_size); + dev_size, parent_id, + mem, mem_size); } static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) @@ -1006,6 +1045,11 @@ static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __pkvm_iommu_pm_notify(dev_id, event); } +static void handle___pkvm_iommu_finalize(struct kvm_cpu_context *host_ctxt) +{ + cpu_reg(host_ctxt, 1) = __pkvm_iommu_finalize(); +} + typedef void (*hcall_t)(struct kvm_cpu_context *); #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x @@ -1042,14 +1086,48 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__pkvm_iommu_driver_init), HANDLE_FUNC(__pkvm_iommu_register), HANDLE_FUNC(__pkvm_iommu_pm_notify), + HANDLE_FUNC(__pkvm_iommu_finalize), }; +static inline u64 kernel__text_addr(void) +{ + u64 val; + + asm volatile(ALTERNATIVE_CB("movz %0, #0\n" + "movk %0, #0, lsl #16\n" + "movk %0, #0, lsl #32\n" + "movk %0, #0, lsl #48\n", + kvm_get__text) + : "=r" (val)); + + return val; +} + +static inline u64 kernel__etext_addr(void) +{ + u64 val; + + asm volatile(ALTERNATIVE_CB("movz %0, #0\n" + "movk %0, #0, lsl #16\n" + "movk %0, #0, lsl #32\n" + "movk %0, #0, lsl #48\n", + kvm_get__etext) + : "=r" (val)); + + return val; +} + static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) { DECLARE_REG(unsigned long, id, host_ctxt, 0); + u64 elr = read_sysreg_el2(SYS_ELR) - 4; unsigned long hcall_min = 0; hcall_t hfn; + /* Check for the provenance of the HC */ + if (unlikely(elr < kernel__text_addr() || elr >= kernel__etext_addr())) + goto inval; + /* * If pKVM has been initialised then reject any calls to the * early "privileged" hypercalls. Note that we cannot reject diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-smp.c b/arch/arm64/kvm/hyp/nvhe/hyp-smp.c index 9f54833af4009..04d194583f1e4 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-smp.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-smp.c @@ -23,6 +23,8 @@ u64 cpu_logical_map(unsigned int cpu) return hyp_cpu_logical_map[cpu]; } +unsigned long __ro_after_init kvm_arm_hyp_percpu_base[NR_CPUS]; + unsigned long __hyp_per_cpu_offset(unsigned int cpu) { unsigned long *cpu_base_array; diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index 9b659abc79570..3fe47e5420883 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -31,6 +31,12 @@ static struct pkvm_iommu_driver iommu_drivers[PKVM_IOMMU_NR_DRIVERS]; /* IOMMU device list. Must only be accessed with host_kvm.lock held. */ static LIST_HEAD(iommu_list); +static bool iommu_finalized; +static DEFINE_HYP_SPINLOCK(iommu_registration_lock); + +static void *iommu_mem_pool; +static size_t iommu_mem_remaining; + static void assert_host_component_locked(void) { hyp_assert_lock_held(&host_kvm.lock); @@ -65,6 +71,8 @@ static const struct pkvm_iommu_ops *get_driver_ops(enum pkvm_iommu_driver_id id) switch (id) { case PKVM_IOMMU_DRIVER_S2MPU: return IS_ENABLED(CONFIG_KVM_S2MPU) ? &pkvm_s2mpu_ops : NULL; + case PKVM_IOMMU_DRIVER_SYSMMU_SYNC: + return IS_ENABLED(CONFIG_KVM_S2MPU) ? &pkvm_sysmmu_sync_ops : NULL; default: return NULL; } @@ -89,41 +97,56 @@ static inline bool is_driver_ready(struct pkvm_iommu_driver *drv) return atomic_read(&drv->state) == IOMMU_DRIVER_READY; } +static size_t __iommu_alloc_size(struct pkvm_iommu_driver *drv) +{ + return ALIGN(sizeof(struct pkvm_iommu) + drv->ops->data_size, + sizeof(unsigned long)); +} + /* Global memory pool for allocating IOMMU list entry structs. */ -static inline struct pkvm_iommu * -alloc_iommu_list_entry(struct pkvm_iommu_driver *drv, void *mem, size_t mem_size) +static inline struct pkvm_iommu *alloc_iommu(struct pkvm_iommu_driver *drv, + void *mem, size_t mem_size) { - static void *pool; - static size_t remaining; - static DEFINE_HYP_SPINLOCK(lock); - size_t size = sizeof(struct pkvm_iommu) + drv->ops->data_size; + size_t size = __iommu_alloc_size(drv); void *ptr; - size = ALIGN(size, sizeof(unsigned long)); - - hyp_spin_lock(&lock); + assert_host_component_locked(); /* * If new memory is being provided, replace the existing pool with it. * Any remaining memory in the pool is discarded. */ if (mem && mem_size) { - pool = mem; - remaining = mem_size; + iommu_mem_pool = mem; + iommu_mem_remaining = mem_size; } - if (size <= remaining) { - ptr = pool; - pool += size; - remaining -= size; - } else { - ptr = NULL; - } + if (size > iommu_mem_remaining) + return NULL; - hyp_spin_unlock(&lock); + ptr = iommu_mem_pool; + iommu_mem_pool += size; + iommu_mem_remaining -= size; return ptr; } +static inline void free_iommu(struct pkvm_iommu_driver *drv, struct pkvm_iommu *ptr) +{ + size_t size = __iommu_alloc_size(drv); + + assert_host_component_locked(); + + if (!ptr) + return; + + /* Only allow freeing the last allocated buffer. */ + if ((void*)ptr + size != iommu_mem_pool) + return; + + iommu_mem_pool -= size; + iommu_mem_remaining += size; +} + static bool is_overlap(phys_addr_t r1_start, size_t r1_size, phys_addr_t r2_start, size_t r2_size) { @@ -151,22 +174,23 @@ static bool is_mmio_range(phys_addr_t base, size_t size) return true; } -static int __snapshot_host_stage2(u64 start, u64 end, u32 level, +static int __snapshot_host_stage2(u64 start, u64 pa_max, u32 level, kvm_pte_t *ptep, enum kvm_pgtable_walk_flags flags, void * const arg) { struct pkvm_iommu_driver * const drv = arg; - enum kvm_pgtable_prot prot; + u64 end = start + kvm_granule_size(level); kvm_pte_t pte = *ptep; /* * Valid stage-2 entries are created lazily, invalid ones eagerly. * Note: In the future we may need to check if [start,end) is MMIO. + * Note: Drivers initialize their PTs to all memory owned by the host, + * so we only call the driver on regions where that is not the case. */ - prot = (!pte || kvm_pte_valid(pte)) ? PKVM_HOST_MEM_PROT : 0; - - drv->ops->host_stage2_idmap_prepare(start, end, prot); + if (pte && !kvm_pte_valid(pte)) + drv->ops->host_stage2_idmap_prepare(start, end, /*prot*/ 0); return 0; } @@ -231,13 +255,24 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si data = kern_hyp_va(data); + /* New driver initialization not allowed after __pkvm_iommu_finalize(). */ + hyp_spin_lock(&iommu_registration_lock); + if (iommu_finalized) { + ret = -EPERM; + goto out_unlock; + } + drv = get_driver(id); ops = get_driver_ops(id); - if (!drv || !ops) - return -EINVAL; + if (!drv || !ops) { + ret = -EINVAL; + goto out_unlock; + } - if (!driver_acquire_init(drv)) - return -EBUSY; + if (!driver_acquire_init(drv)) { + ret = -EBUSY; + goto out_unlock; + } drv->ops = ops; @@ -249,7 +284,7 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si hyp_unpin_shared_mem(data, data + size); } if (ret) - goto out; + goto out_release; } /* @@ -262,36 +297,47 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si driver_release_init(drv, /*success=*/true); host_unlock_component(); -out: +out_release: if (ret) driver_release_init(drv, /*success=*/false); + +out_unlock: + hyp_spin_unlock(&iommu_registration_lock); return ret; } int __pkvm_iommu_register(unsigned long dev_id, enum pkvm_iommu_driver_id drv_id, phys_addr_t dev_pa, size_t dev_size, + unsigned long parent_id, void *kern_mem_va, size_t mem_size) { struct pkvm_iommu *dev = NULL; struct pkvm_iommu_driver *drv; - void *dev_va, *mem_va = NULL; + void *mem_va = NULL; int ret = 0; - drv = get_driver(drv_id); - if (!drv || !is_driver_ready(drv)) - return -ENOENT; + /* New device registration not allowed after __pkvm_iommu_finalize(). */ + hyp_spin_lock(&iommu_registration_lock); + if (iommu_finalized) { + ret = -EPERM; + goto out_unlock; + } - if (!PAGE_ALIGNED(dev_pa) || !PAGE_ALIGNED(dev_size)) - return -EINVAL; + drv = get_driver(drv_id); + if (!drv || !is_driver_ready(drv)) { + ret = -ENOENT; + goto out_unlock; + } - if (!is_mmio_range(dev_pa, dev_size)) - return -EINVAL; + if (!PAGE_ALIGNED(dev_pa) || !PAGE_ALIGNED(dev_size)) { + ret = -EINVAL; + goto out_unlock; + } - if (drv->ops->validate) { - ret = drv->ops->validate(dev_pa, dev_size); - if (ret) - return ret; + if (!is_mmio_range(dev_pa, dev_size)) { + ret = -EINVAL; + goto out_unlock; } /* @@ -301,52 +347,102 @@ int __pkvm_iommu_register(unsigned long dev_id, if (kern_mem_va && mem_size) { mem_va = kern_hyp_va(kern_mem_va); - if (!PAGE_ALIGNED(mem_va) || !PAGE_ALIGNED(mem_size)) - return -EINVAL; + if (!PAGE_ALIGNED(mem_va) || !PAGE_ALIGNED(mem_size)) { + ret = -EINVAL; + goto out_unlock; + } ret = __pkvm_host_donate_hyp(hyp_virt_to_pfn(mem_va), mem_size >> PAGE_SHIFT); if (ret) - return ret; + goto out_unlock; } - /* Allocate memory for the new device entry. */ - dev = alloc_iommu_list_entry(drv, mem_va, mem_size); - if (!dev) - return -ENOMEM; + host_lock_component(); - /* Create EL2 mapping for the device. */ - dev_va = (void *)__pkvm_create_private_mapping(dev_pa, dev_size, - PAGE_HYP_DEVICE); - if (IS_ERR(dev_va)) - return PTR_ERR(dev_va); + /* Allocate memory for the new device entry. */ + dev = alloc_iommu(drv, mem_va, mem_size); + if (!dev) { + ret = -ENOMEM; + goto out_free; + } /* Populate the new device entry. */ *dev = (struct pkvm_iommu){ + .children = LIST_HEAD_INIT(dev->children), .id = dev_id, .ops = drv->ops, .pa = dev_pa, - .va = dev_va, .size = dev_size, }; - /* Take the host_kvm lock to block host stage-2 changes. */ - host_lock_component(); if (!validate_against_existing_iommus(dev)) { ret = -EBUSY; - goto out; + goto out_free; + } + + if (parent_id) { + dev->parent = find_iommu_by_id(parent_id); + if (!dev->parent) { + ret = -EINVAL; + goto out_free; + } + + if (dev->parent->ops->validate_child) { + ret = dev->parent->ops->validate_child(dev->parent, dev); + if (ret) + goto out_free; + } } - /* Unmap the device's MMIO range from host stage-2. */ + if (dev->ops->validate) { + ret = dev->ops->validate(dev); + if (ret) + goto out_free; + } + + /* + * Unmap the device's MMIO range from host stage-2. If registration + * is successful, future attempts to re-map will be blocked by + * pkvm_iommu_host_stage2_adjust_range. + */ ret = host_stage2_unmap_dev_locked(dev_pa, dev_size); if (ret) - goto out; + goto out_free; + + /* Create EL2 mapping for the device. Do it last as it is irreversible. */ + dev->va = (void *)__pkvm_create_private_mapping(dev_pa, dev_size, + PAGE_HYP_DEVICE); + if (IS_ERR(dev->va)) { + ret = PTR_ERR(dev->va); + goto out_free; + } /* Register device and prevent host from mapping the MMIO range. */ list_add_tail(&dev->list, &iommu_list); + if (dev->parent) + list_add_tail(&dev->siblings, &dev->parent->children); -out: +out_free: + if (ret) + free_iommu(drv, dev); host_unlock_component(); + +out_unlock: + hyp_spin_unlock(&iommu_registration_lock); + return ret; +} + +int __pkvm_iommu_finalize(void) +{ + int ret = 0; + + hyp_spin_lock(&iommu_registration_lock); + if (!iommu_finalized) + iommu_finalized = true; + else + ret = -EPERM; + hyp_spin_unlock(&iommu_registration_lock); return ret; } @@ -360,10 +456,12 @@ int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event) if (dev) { if (event == PKVM_IOMMU_PM_SUSPEND) { ret = dev->ops->suspend ? dev->ops->suspend(dev) : 0; - dev->powered = !!ret; + if (!ret) + dev->powered = false; } else if (event == PKVM_IOMMU_PM_RESUME) { ret = dev->ops->resume ? dev->ops->resume(dev) : 0; - dev->powered = !ret; + if (!ret) + dev->powered = true; } else { ret = -EINVAL; } @@ -418,7 +516,8 @@ bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, if (pa < dev->pa || pa >= dev->pa + dev->size) continue; - if (!dev->powered || !dev->ops->host_dabt_handler || + /* No 'powered' check - the host assumes it is powered. */ + if (!dev->ops->host_dabt_handler || !dev->ops->host_dabt_handler(dev, host_ctxt, esr, pa - dev->pa)) return false; diff --git a/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c b/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c index 3fbd68c842186..ff5d7d1044e52 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c @@ -28,6 +28,9 @@ (CONTEXT_CFG_VALID_VID_CTX_VID(ctxid, vid) \ | (((ctxid) < (nr_ctx)) ? CONTEXT_CFG_VALID_VID_CTX_VALID(ctxid) : 0)) +#define for_each_child(child, dev) \ + list_for_each_entry((child), &(dev)->children, siblings) + struct s2mpu_drv_data { u32 version; u32 context_cfg_valid_vid; @@ -155,6 +158,13 @@ static void __set_control_regs(struct pkvm_iommu *dev) writel_relaxed(ctrl0, dev->va + REG_NS_CTRL0); } +/* Poll the given SFR until its value has all bits of a given mask set. */ +static void __wait_until(void __iomem *addr, u32 mask) +{ + while ((readl_relaxed(addr) & mask) != mask) + continue; +} + /* Poll the given SFR as long as its value has all bits of a given mask set. */ static void __wait_while(void __iomem *addr, u32 mask) { @@ -164,6 +174,17 @@ static void __wait_while(void __iomem *addr, u32 mask) static void __wait_for_invalidation_complete(struct pkvm_iommu *dev) { + struct pkvm_iommu *sync; + + /* + * Wait for transactions to drain if SysMMU_SYNCs were registered. + * Assumes that they are in the same power domain as the S2MPU. + */ + for_each_child(sync, dev) { + writel_relaxed(SYNC_CMD_SYNC, sync->va + REG_NS_SYNC_CMD); + __wait_until(sync->va + REG_NS_SYNC_COMP, SYNC_COMP_COMPLETE); + } + /* Must not access SFRs while S2MPU is busy invalidating (v9 only). */ if (is_version(dev, S2MPU_VERSION_9)) { __wait_while(dev->va + REG_NS_STATUS, @@ -372,15 +393,44 @@ static u32 host_mmio_reg_access_mask(size_t off, bool is_write) const u32 write_only = is_write ? read_write : no_access; u32 masked_off; - /* IRQ handler can clear interrupts. */ - if (off == REG_NS_INTERRUPT_CLEAR) + switch (off) { + /* Allow reading control registers for debugging. */ + case REG_NS_CTRL0: + return read_only & CTRL0_MASK; + case REG_NS_CTRL1: + return read_only & CTRL1_MASK; + case REG_NS_CFG: + return read_only & CFG_MASK; + /* Allow EL1 IRQ handler to clear interrupts. */ + case REG_NS_INTERRUPT_CLEAR: return write_only & ALL_VIDS_BITMAP; - - /* IRQ handler can read bitmap of pending interrupts. */ - if (off == REG_NS_FAULT_STATUS) + /* Allow reading number of sets used by MPTC. */ + case REG_NS_INFO: + return read_only & INFO_NUM_SET_MASK; + /* Allow EL1 IRQ handler to read bitmap of pending interrupts. */ + case REG_NS_FAULT_STATUS: return read_only & ALL_VIDS_BITMAP; + /* + * Allow reading MPTC entries for debugging. That involves: + * - writing (set,way) to READ_MPTC + * - reading READ_MPTC_* + */ + case REG_NS_READ_MPTC: + return write_only & READ_MPTC_MASK; + case REG_NS_READ_MPTC_TAG_PPN: + return read_only & READ_MPTC_TAG_PPN_MASK; + case REG_NS_READ_MPTC_TAG_OTHERS: + return read_only & READ_MPTC_TAG_OTHERS_MASK; + case REG_NS_READ_MPTC_DATA: + return read_only; + } + + /* Allow reading L1ENTRY registers for debugging. */ + if (off >= REG_NS_L1ENTRY_L2TABLE_ADDR(0, 0) && + off < REG_NS_L1ENTRY_ATTR(NR_VIDS, 0)) + return read_only; - /* IRQ handler can read fault information. */ + /* Allow EL1 IRQ handler to read fault information. */ masked_off = off & ~REG_NS_FAULT_VID_MASK; if ((masked_off == REG_NS_FAULT_PA_LOW(0)) || (masked_off == REG_NS_FAULT_PA_HIGH(0)) || @@ -445,7 +495,7 @@ static int s2mpu_init(void *data, size_t size) host_mpt.fmpt[gb] = (struct fmpt){ .smpt = smpt, .gran_1g = true, - .prot = MPT_PROT_NONE, + .prot = MPT_PROT_RW, }; } @@ -465,9 +515,28 @@ static int s2mpu_init(void *data, size_t size) return ret; } -static int s2mpu_validate(phys_addr_t pa, size_t size) +static int s2mpu_validate(struct pkvm_iommu *dev) { - if (size != S2MPU_MMIO_SIZE) + if (dev->size != S2MPU_MMIO_SIZE) + return -EINVAL; + + return 0; +} + +static int s2mpu_validate_child(struct pkvm_iommu *dev, struct pkvm_iommu *child) +{ + if (child->ops != &pkvm_sysmmu_sync_ops) + return -EINVAL; + + return 0; +} + +static int sysmmu_sync_validate(struct pkvm_iommu *dev) +{ + if (dev->size != SYSMMU_SYNC_S2_MMIO_SIZE) + return -EINVAL; + + if (!dev->parent || dev->parent->ops != &pkvm_s2mpu_ops) return -EINVAL; return 0; @@ -476,6 +545,7 @@ static int s2mpu_validate(phys_addr_t pa, size_t size) const struct pkvm_iommu_ops pkvm_s2mpu_ops = (struct pkvm_iommu_ops){ .init = s2mpu_init, .validate = s2mpu_validate, + .validate_child = s2mpu_validate_child, .resume = s2mpu_resume, .suspend = s2mpu_suspend, .host_stage2_idmap_prepare = s2mpu_host_stage2_idmap_prepare, @@ -483,3 +553,7 @@ const struct pkvm_iommu_ops pkvm_s2mpu_ops = (struct pkvm_iommu_ops){ .host_dabt_handler = s2mpu_host_dabt_handler, .data_size = sizeof(struct s2mpu_drv_data), }; + +const struct pkvm_iommu_ops pkvm_sysmmu_sync_ops = (struct pkvm_iommu_ops){ + .validate = sysmmu_sync_validate, +}; diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 750eab9678f93..76703b2b6f3c5 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -620,6 +620,50 @@ static bool is_dabt(u64 esr) return ESR_ELx_EC(esr) == ESR_ELx_EC_DABT_LOW; } +static void host_inject_abort(struct kvm_cpu_context *host_ctxt) +{ + u64 spsr = read_sysreg_el2(SYS_SPSR); + u64 esr = read_sysreg_el2(SYS_ESR); + u64 ventry, ec; + + /* Repaint the ESR to report a same-level fault if taken from EL1 */ + if ((spsr & PSR_MODE_MASK) != PSR_MODE_EL0t) { + ec = ESR_ELx_EC(esr); + if (ec == ESR_ELx_EC_DABT_LOW) + ec = ESR_ELx_EC_DABT_CUR; + else if (ec == ESR_ELx_EC_IABT_LOW) + ec = ESR_ELx_EC_IABT_CUR; + else + WARN_ON(1); + esr &= ~ESR_ELx_EC_MASK; + esr |= ec << ESR_ELx_EC_SHIFT; + } + + /* + * Since S1PTW should only ever be set for stage-2 faults, we're pretty + * much guaranteed that it won't be set in ESR_EL1 by the hardware. So, + * let's use that bit to allow the host abort handler to differentiate + * this abort from normal userspace faults. + * + * Note: although S1PTW is RES0 at EL1, it is guaranteed by the + * architecture to be backed by flops, so it should be safe to use. + */ + esr |= ESR_ELx_S1PTW; + + write_sysreg_el1(esr, SYS_ESR); + write_sysreg_el1(spsr, SYS_SPSR); + write_sysreg_el1(read_sysreg_el2(SYS_ELR), SYS_ELR); + write_sysreg_el1(read_sysreg_el2(SYS_FAR), SYS_FAR); + + ventry = read_sysreg_el1(SYS_VBAR); + ventry += get_except64_offset(spsr, PSR_MODE_EL1h, except_type_sync); + write_sysreg_el2(ventry, SYS_ELR); + + spsr = get_except64_cpsr(spsr, system_supports_mte(), + read_sysreg_el1(SYS_SCTLR), PSR_MODE_EL1h); + write_sysreg_el2(spsr, SYS_SPSR); +} + void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) { struct kvm_vcpu_fault_info fault; @@ -644,7 +688,11 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) ret = host_stage2_idmap(addr); host_unlock_component(); - BUG_ON(ret && ret != -EAGAIN); + + if (ret == -EPERM) + host_inject_abort(host_ctxt); + else + BUG_ON(ret && ret != -EAGAIN); } /* This corresponds to locking order */ @@ -1073,10 +1121,14 @@ static int guest_complete_donation(u64 addr, const struct pkvm_mem_transition *t u64 size = tx->nr_pages * PAGE_SIZE; int err; - if (tx->initiator.id == PKVM_ID_HOST && ipa_in_pvmfw_region(vm, addr)) { - err = pkvm_load_pvmfw_pages(vm, addr, phys, size); - if (err) - return err; + if (tx->initiator.id == PKVM_ID_HOST) { + psci_mem_protect_inc(); + + if (ipa_in_pvmfw_region(vm, addr)) { + err = pkvm_load_pvmfw_pages(vm, addr, phys, size); + if (err) + return err; + } } return kvm_pgtable_stage2_map(&vm->pgt, addr, size, phys, prot, @@ -1893,6 +1945,7 @@ int __pkvm_host_reclaim_page(u64 pfn) if (ret) goto unlock; page->flags &= ~HOST_PAGE_NEED_POISONING; + psci_mem_protect_dec(); } ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, pkvm_host_id); diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 6239fea7496b9..4e86a2123c054 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -331,6 +331,12 @@ static void *admit_host_page(void *arg) int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, struct kvm_hyp_memcache *host_mc) { - return __topup_hyp_memcache(mc, min_pages, admit_host_page, - hyp_virt_to_phys, host_mc); + struct kvm_hyp_memcache tmp = *host_mc; + int ret; + + ret = __topup_hyp_memcache(mc, min_pages, admit_host_page, + hyp_virt_to_phys, &tmp); + *host_mc = tmp; + + return ret; } diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 6d1eeacc559bc..701684a2d24a0 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -225,6 +225,11 @@ static int index_to_shadow_handle(int index) extern unsigned long hyp_nr_cpus; +/* + * Track the vcpu most recently loaded on each physical CPU. + */ +static DEFINE_PER_CPU(struct kvm_vcpu *, last_loaded_vcpu); + /* * Spinlock for protecting the shadow table related state. * Protects writes to shadow_table, num_shadow_entries, and next_shadow_alloc, @@ -267,6 +272,7 @@ struct kvm_vcpu *get_shadow_vcpu(int shadow_handle, unsigned int vcpu_idx) { struct kvm_vcpu *vcpu = NULL; struct kvm_shadow_vm *vm; + bool flush_context = false; hyp_spin_lock(&shadow_lock); vm = find_shadow_by_handle(shadow_handle); @@ -279,12 +285,28 @@ struct kvm_vcpu *get_shadow_vcpu(int shadow_handle, unsigned int vcpu_idx) vcpu = NULL; goto unlock; } + + /* + * Guarantee that both TLBs and I-cache are private to each vcpu. + * The check below is conservative and could lead to over-invalidation, + * because there is no need to nuke the contexts if the vcpu belongs to + * a different vm. + */ + if (vcpu != __this_cpu_read(last_loaded_vcpu)) { + flush_context = true; + __this_cpu_write(last_loaded_vcpu, vcpu); + } + vcpu->arch.pkvm.loaded_on_cpu = true; hyp_page_ref_inc(hyp_virt_to_page(vm)); unlock: hyp_spin_unlock(&shadow_lock); + /* No need for the lock while flushing the context. */ + if (flush_context) + __kvm_flush_cpu_context(vcpu->arch.hw_mmu); + return vcpu; } @@ -354,8 +376,19 @@ static void unpin_host_vcpus(struct shadow_vcpu_state *shadow_vcpus, int nr_vcpu for (i = 0; i < nr_vcpus; i++) { struct kvm_vcpu *host_vcpu = shadow_vcpus[i].vcpu.arch.pkvm.host_vcpu; + struct kvm_vcpu *shadow_vcpu = &shadow_vcpus[i].vcpu; + size_t sve_state_size; + void *sve_state; hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1); + + if (!test_bit(KVM_ARM_VCPU_SVE, shadow_vcpu->arch.features)) + continue; + + sve_state = shadow_vcpu->arch.sve_state; + sve_state = kern_hyp_va(sve_state); + sve_state_size = vcpu_sve_state_size(shadow_vcpu); + hyp_unpin_shared_mem(sve_state, sve_state + sve_state_size); } } @@ -405,6 +438,27 @@ static int init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, if (ret) return ret; + if (test_bit(KVM_ARM_VCPU_SVE, shadow_vcpu->arch.features)) { + size_t sve_state_size; + void *sve_state; + + shadow_vcpu->arch.sve_state = READ_ONCE(host_vcpu->arch.sve_state); + shadow_vcpu->arch.sve_max_vl = READ_ONCE(host_vcpu->arch.sve_max_vl); + + sve_state = kern_hyp_va(shadow_vcpu->arch.sve_state); + sve_state_size = vcpu_sve_state_size(shadow_vcpu); + + if (!shadow_vcpu->arch.sve_state || !sve_state_size || + hyp_pin_shared_mem(sve_state, + sve_state + sve_state_size)) { + clear_bit(KVM_ARM_VCPU_SVE, + shadow_vcpu->arch.features); + shadow_vcpu->arch.sve_state = NULL; + shadow_vcpu->arch.sve_max_vl = 0; + return -EINVAL; + } + } + if (vm->arch.pkvm.enabled) pkvm_vcpu_init_traps(shadow_vcpu); kvm_reset_pvm_sys_regs(shadow_vcpu); @@ -664,6 +718,7 @@ int __pkvm_teardown_shadow(int shadow_handle) u64 pfn; u64 nr_pages; void *addr; + int i; /* Lookup then remove entry from the shadow table. */ hyp_spin_lock(&shadow_lock); @@ -678,6 +733,21 @@ int __pkvm_teardown_shadow(int shadow_handle) goto err_unlock; } + /* + * Clear the tracking for last_loaded_vcpu for all cpus for this vm in + * case the same addresses for those vcpus are reused for future vms. + */ + for (i = 0; i < hyp_nr_cpus; i++) { + struct kvm_vcpu **last_loaded_vcpu_ptr = + per_cpu_ptr(&last_loaded_vcpu, i); + struct kvm_vcpu *vcpu = *last_loaded_vcpu_ptr; + + if (vcpu && vcpu->arch.pkvm.shadow_handle == shadow_handle) + *last_loaded_vcpu_ptr = NULL; + } + + /* Ensure the VMID is clean before it can be reallocated */ + __kvm_tlb_flush_vmid(&vm->arch.mmu); remove_shadow_table(shadow_handle); hyp_spin_unlock(&shadow_lock); @@ -799,6 +869,10 @@ void pkvm_reset_vcpu(struct kvm_vcpu *vcpu) *vcpu_pc(vcpu) = entry; vm->pvmfw_entry_vcpu = NULL; + + /* Auto enroll MMIO guard */ + set_bit(KVM_ARCH_FLAG_MMIO_GUARD, + &vcpu->arch.pkvm.shadow_vm->arch.flags); } else { *vcpu_pc(vcpu) = reset_state->pc; vcpu_set_reg(vcpu, 0, reset_state->r0); diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c index cee6d4a2821fd..85f7cad956d54 100644 --- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c +++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c @@ -222,6 +222,44 @@ asmlinkage void __noreturn kvm_host_psci_cpu_entry(bool is_cpu_on) __host_enter(host_ctxt); } +static DEFINE_HYP_SPINLOCK(mem_protect_lock); + +static u64 psci_mem_protect(s64 offset) +{ + static u64 cnt; + u64 new = cnt + offset; + + hyp_assert_lock_held(&mem_protect_lock); + + if (!offset || kvm_host_psci_config.version < PSCI_VERSION(1, 1)) + return cnt; + + if (!cnt || !new) + psci_call(PSCI_1_1_FN64_MEM_PROTECT, offset < 0 ? 0 : 1, 0, 0); + + cnt = new; + return cnt; +} + +static bool psci_mem_protect_active(void) +{ + return psci_mem_protect(0); +} + +void psci_mem_protect_inc(void) +{ + hyp_spin_lock(&mem_protect_lock); + psci_mem_protect(1); + hyp_spin_unlock(&mem_protect_lock); +} + +void psci_mem_protect_dec(void) +{ + hyp_spin_lock(&mem_protect_lock); + psci_mem_protect(-1); + hyp_spin_unlock(&mem_protect_lock); +} + static unsigned long psci_0_1_handler(u64 func_id, struct kvm_cpu_context *host_ctxt) { if (is_psci_0_1(cpu_off, func_id) || is_psci_0_1(migrate, func_id)) @@ -251,6 +289,8 @@ static unsigned long psci_0_2_handler(u64 func_id, struct kvm_cpu_context *host_ case PSCI_0_2_FN_SYSTEM_OFF: case PSCI_0_2_FN_SYSTEM_RESET: pkvm_clear_pvmfw_pages(); + /* Avoid racing with a MEM_PROTECT call. */ + hyp_spin_lock(&mem_protect_lock); return psci_forward(host_ctxt); case PSCI_0_2_FN64_CPU_SUSPEND: return psci_cpu_suspend(func_id, host_ctxt); @@ -266,6 +306,11 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_ switch (func_id) { case PSCI_1_1_FN64_SYSTEM_RESET2: pkvm_clear_pvmfw_pages(); + hyp_spin_lock(&mem_protect_lock); + if (psci_mem_protect_active()) { + return psci_0_2_handler(PSCI_0_2_FN_SYSTEM_RESET, + host_ctxt); + } fallthrough; case PSCI_1_0_FN_PSCI_FEATURES: case PSCI_1_0_FN_SET_SUSPEND_MODE: diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 18638652f06d6..1a6f3eba50358 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -133,20 +133,16 @@ static int recreate_hyp_mappings(phys_addr_t phys, unsigned long size, } /* - * Map the host's .bss and .rodata sections RO in the hypervisor, but - * transfer the ownership from the host to the hypervisor itself to - * make sure it can't be donated or shared with another entity. + * Map the host sections RO in the hypervisor, but transfer the + * ownership from the host to the hypervisor itself to make sure they + * can't be donated or shared with another entity. * * The ownership transition requires matching changes in the host * stage-2. This will be done later (see finalize_host_mappings()) once * the hyp_vmemmap is addressable. */ prot = pkvm_mkstate(PAGE_HYP_RO, PKVM_PAGE_SHARED_OWNED); - ret = pkvm_create_mappings(__start_rodata, __end_rodata, prot); - if (ret) - return ret; - - ret = pkvm_create_mappings(__hyp_bss_end, __bss_stop, prot); + ret = pkvm_create_mappings(&kvm_vgic_global_state, &kvm_vgic_global_state + 1, prot); if (ret) return ret; diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index 024e663305846..1729b4d6059e0 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -232,15 +232,9 @@ u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id) case SYS_ID_AA64MMFR2_EL1: return get_pvm_id_aa64mmfr2(vcpu); default: - /* - * Should never happen because all cases are covered in - * pvm_sys_reg_descs[]. - */ - WARN_ON(1); - break; + /* Unhandled ID register, RAZ */ + return 0; } - - return 0; } static u64 read_id_reg(const struct kvm_vcpu *vcpu, @@ -321,6 +315,16 @@ static bool pvm_gic_read_sre(struct kvm_vcpu *vcpu, /* Mark the specified system register as an AArch64 feature id register. */ #define AARCH64(REG) { SYS_DESC(REG), .access = pvm_access_id_aarch64 } +/* + * sys_reg_desc initialiser for architecturally unallocated cpufeature ID + * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2 + * (1 <= crm < 8, 0 <= Op2 < 8). + */ +#define ID_UNALLOCATED(crm, op2) { \ + Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \ + .access = pvm_access_id_aarch64, \ +} + /* Mark the specified system register as Read-As-Zero/Write-Ignored */ #define RAZ_WI(REG) { SYS_DESC(REG), .access = pvm_access_raz_wi } @@ -375,24 +379,46 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = { AARCH32(SYS_MVFR0_EL1), AARCH32(SYS_MVFR1_EL1), AARCH32(SYS_MVFR2_EL1), + ID_UNALLOCATED(3,3), AARCH32(SYS_ID_PFR2_EL1), AARCH32(SYS_ID_DFR1_EL1), AARCH32(SYS_ID_MMFR5_EL1), + ID_UNALLOCATED(3,7), /* AArch64 ID registers */ /* CRm=4 */ AARCH64(SYS_ID_AA64PFR0_EL1), AARCH64(SYS_ID_AA64PFR1_EL1), + ID_UNALLOCATED(4,2), + ID_UNALLOCATED(4,3), AARCH64(SYS_ID_AA64ZFR0_EL1), + ID_UNALLOCATED(4,5), + ID_UNALLOCATED(4,6), + ID_UNALLOCATED(4,7), AARCH64(SYS_ID_AA64DFR0_EL1), AARCH64(SYS_ID_AA64DFR1_EL1), + ID_UNALLOCATED(5,2), + ID_UNALLOCATED(5,3), AARCH64(SYS_ID_AA64AFR0_EL1), AARCH64(SYS_ID_AA64AFR1_EL1), + ID_UNALLOCATED(5,6), + ID_UNALLOCATED(5,7), AARCH64(SYS_ID_AA64ISAR0_EL1), AARCH64(SYS_ID_AA64ISAR1_EL1), + AARCH64(SYS_ID_AA64ISAR2_EL1), + ID_UNALLOCATED(6,3), + ID_UNALLOCATED(6,4), + ID_UNALLOCATED(6,5), + ID_UNALLOCATED(6,6), + ID_UNALLOCATED(6,7), AARCH64(SYS_ID_AA64MMFR0_EL1), AARCH64(SYS_ID_AA64MMFR1_EL1), AARCH64(SYS_ID_AA64MMFR2_EL1), + ID_UNALLOCATED(7,3), + ID_UNALLOCATED(7,4), + ID_UNALLOCATED(7,5), + ID_UNALLOCATED(7,6), + ID_UNALLOCATED(7,7), /* Scalable Vector Registers are restricted. */ diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index e7c71396b7e06..bb04eb91e5e61 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -58,24 +58,6 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) val[3] = lower_32_bits(cycles); } -static int kvm_vcpu_exit_hcall(struct kvm_vcpu *vcpu, u32 nr, u32 nr_args) -{ - u64 mask = vcpu->kvm->arch.hypercall_exit_enabled; - u32 i; - - if (nr_args > 6 || !(mask & BIT(nr))) - return -EINVAL; - - vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; - vcpu->run->hypercall.nr = nr; - - for (i = 0; i < nr_args; ++i) - vcpu->run->hypercall.args[i] = vcpu_get_reg(vcpu, i + 1); - - vcpu->run->hypercall.longmode = !vcpu_mode_is_32bit(vcpu); - return 0; -} - int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); @@ -163,14 +145,6 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: kvm_ptp_get_time(vcpu, val); break; - case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID: - if (!kvm_vcpu_exit_hcall(vcpu, ARM_SMCCC_KVM_FUNC_MEM_SHARE, 3)) - return 0; - break; - case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID: - if (!kvm_vcpu_exit_hcall(vcpu, ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, 3)) - return 0; - break; case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID: if (kvm_vm_is_protected(vcpu->kvm) && !topup_hyp_memcache(vcpu)) val[0] = SMCCC_RET_SUCCESS; diff --git a/arch/arm64/kvm/iommu.c b/arch/arm64/kvm/iommu.c index e13d36ec57e71..6ca171327b289 100644 --- a/arch/arm64/kvm/iommu.c +++ b/arch/arm64/kvm/iommu.c @@ -18,7 +18,7 @@ int pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t size } int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, - phys_addr_t pa, size_t size) + phys_addr_t pa, size_t size, struct device *parent) { void *mem; int ret; @@ -29,14 +29,15 @@ int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, * We assume that hyp never allocates more than a page per hypcall. */ ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv_id, pa, size, NULL, 0); + drv_id, pa, size, dev_to_id(parent), NULL, 0); if (ret == -ENOMEM) { mem = (void *)__get_free_page(GFP_KERNEL); if (!mem) return -ENOMEM; ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv_id, pa, size, mem, PAGE_SIZE); + drv_id, pa, size, dev_to_id(parent), + mem, PAGE_SIZE); } return ret; } @@ -54,3 +55,9 @@ int pkvm_iommu_resume(struct device *dev) PKVM_IOMMU_PM_RESUME); } EXPORT_SYMBOL_GPL(pkvm_iommu_resume); + +int pkvm_iommu_finalize(void) +{ + return kvm_call_hyp_nvhe(__pkvm_iommu_finalize); +} +EXPORT_SYMBOL_GPL(pkvm_iommu_finalize); diff --git a/arch/arm64/kvm/iommu/s2mpu.c b/arch/arm64/kvm/iommu/s2mpu.c index be2b1ad094808..733451d741007 100644 --- a/arch/arm64/kvm/iommu/s2mpu.c +++ b/arch/arm64/kvm/iommu/s2mpu.c @@ -81,6 +81,40 @@ int pkvm_iommu_s2mpu_register(struct device *dev, phys_addr_t addr) return ret; return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_S2MPU, - addr, S2MPU_MMIO_SIZE); + addr, S2MPU_MMIO_SIZE, NULL); } EXPORT_SYMBOL_GPL(pkvm_iommu_s2mpu_register); + +static int init_sysmmu_sync_driver(void) +{ + static DEFINE_MUTEX(lock); + static bool init_done; + + int ret = 0; + + mutex_lock(&lock); + if (!init_done) { + ret = pkvm_iommu_driver_init(PKVM_IOMMU_DRIVER_SYSMMU_SYNC, NULL, 0); + init_done = !ret; + } + mutex_unlock(&lock); + return ret; +} + +int pkvm_iommu_sysmmu_sync_register(struct device *dev, phys_addr_t addr, + struct device *parent) +{ + int ret; + + if (!is_protected_kvm_enabled()) + return -ENODEV; + + ret = init_sysmmu_sync_driver(); + if (ret) + return ret; + + return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_SYSMMU_SYNC, + addr + SYSMMU_SYNC_S2_OFFSET, + SYSMMU_SYNC_S2_MMIO_SIZE, parent); +} +EXPORT_SYMBOL_GPL(pkvm_iommu_sysmmu_sync_register); diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 80fed4cf0512a..69771a6f7c830 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1163,10 +1163,7 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, unsigned long hva) { struct mm_struct *mm = current->mm; - unsigned int flags = FOLL_FORCE | - FOLL_HWPOISON | - FOLL_LONGTERM | - FOLL_WRITE; + unsigned int flags = FOLL_HWPOISON | FOLL_LONGTERM | FOLL_WRITE; struct kvm_pinned_page *ppage; struct kvm *kvm = vcpu->kvm; struct page *page; @@ -1196,6 +1193,21 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } else if (ret != 1) { ret = -EFAULT; goto dec_account; + } else if (!PageSwapBacked(page)) { + /* + * We really can't deal with page-cache pages returned by GUP + * because (a) we may trigger writeback of a page for which we + * no longer have access and (b) page_mkclean() won't find the + * stage-2 mapping in the rmap so we can get out-of-whack with + * the filesystem when marking the page dirty during unpinning. + * + * Ideally we'd just restrict ourselves to anonymous pages, but + * we also want to allow memfd (i.e. shmem) pages, so check for + * pages backed by swap in the knowledge that the GUP pin will + * prevent try_to_unmap() from succeeding. + */ + ret = -EIO; + goto dec_account; } spin_lock(&kvm->mmu_lock); @@ -1841,6 +1853,13 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, hva_t reg_end = hva + mem->memory_size; int ret = 0; + /* In protected mode, cannot modify memslots once a VM has run. */ + if (is_protected_kvm_enabled() && + (change == KVM_MR_DELETE || change == KVM_MR_MOVE) && + kvm->arch.pkvm.shadow_handle) { + return -EPERM; + } + if (change != KVM_MR_CREATE && change != KVM_MR_MOVE && change != KVM_MR_FLAGS_ONLY) return 0; @@ -1914,6 +1933,10 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, gpa_t gpa = slot->base_gfn << PAGE_SHIFT; phys_addr_t size = slot->npages << PAGE_SHIFT; + /* Stage-2 is managed by hyp in protected mode. */ + if (is_protected_kvm_enabled()) + return; + spin_lock(&kvm->mmu_lock); unmap_stage2_range(&kvm->arch.mmu, gpa, size); spin_unlock(&kvm->mmu_lock); diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c index 03a6c1f4a09af..a8878fd8b696c 100644 --- a/arch/arm64/kvm/pmu.c +++ b/arch/arm64/kvm/pmu.c @@ -31,9 +31,13 @@ static bool kvm_pmu_switch_needed(struct perf_event_attr *attr) */ void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) { - struct kvm_host_data *ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + struct kvm_host_data *ctx; - if (!kvm_arm_support_pmu_v3() || !ctx || !kvm_pmu_switch_needed(attr)) + if (!kvm_arm_support_pmu_v3()) + return; + + ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + if (!ctx || !kvm_pmu_switch_needed(attr)) return; if (!attr->exclude_host) @@ -47,9 +51,13 @@ void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) */ void kvm_clr_pmu_events(u32 clr) { - struct kvm_host_data *ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + struct kvm_host_data *ctx; + + if (!kvm_arm_support_pmu_v3()) + return; - if (!kvm_arm_support_pmu_v3() || !ctx) + ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + if (!ctx) return; ctx->pmu_events.events_host &= ~clr; diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c index acdb7b3cc97d6..f0b678d24e25d 100644 --- a/arch/arm64/kvm/va_layout.c +++ b/arch/arm64/kvm/va_layout.c @@ -295,3 +295,15 @@ void kvm_compute_final_ctr_el0(struct alt_instr *alt, generate_mov_q(read_sanitised_ftr_reg(SYS_CTR_EL0), origptr, updptr, nr_inst); } + +void kvm_get__text(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + generate_mov_q((u64)_text, origptr, updptr, nr_inst); +} + +void kvm_get__etext(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + generate_mov_q((u64)_etext, origptr, updptr, nr_inst); +} diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 540ef3cd0a36a..9af359f683561 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -253,6 +254,15 @@ static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr, return false; } +static bool is_pkvm_stage2_abort(unsigned int esr) +{ + /* + * S1PTW should only ever be set in ESR_EL1 if the pkvm hypervisor + * injected a stage-2 abort -- see host_inject_abort(). + */ + return is_pkvm_initialized() && (esr & ESR_ELx_S1PTW); +} + static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) @@ -264,6 +274,9 @@ static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr, (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT) return false; + if (is_pkvm_stage2_abort(esr)) + return false; + local_irq_save(flags); asm volatile("at s1e1r, %0" :: "r" (addr)); isb(); @@ -379,6 +392,8 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, msg = "read from unreadable memory"; } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; + } else if (is_pkvm_stage2_abort(esr)) { + msg = "access to hypervisor-protected memory"; } else { if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs)) return; @@ -557,6 +572,13 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr, addr, esr, regs); } + if (is_pkvm_stage2_abort(esr)) { + if (!user_mode(regs)) + goto no_context; + arm64_force_sig_fault(SIGSEGV, SEGV_ACCERR, far, "stage-2 fault"); + return 0; + } + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); /* diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 0cbb63cf955f1..33d93f800734a 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -59,34 +59,8 @@ EXPORT_SYMBOL(memstart_addr); * unless restricted on specific platforms (e.g. 30-bit on Raspberry Pi 4). * In such case, ZONE_DMA32 covers the rest of the 32-bit addressable memory, * otherwise it is empty. - * - * Memory reservation for crash kernel either done early or deferred - * depending on DMA memory zones configs (ZONE_DMA) -- - * - * In absence of ZONE_DMA configs arm64_dma_phys_limit initialized - * here instead of max_zone_phys(). This lets early reservation of - * crash kernel memory which has a dependency on arm64_dma_phys_limit. - * Reserving memory early for crash kernel allows linear creation of block - * mappings (greater than page-granularity) for all the memory bank rangs. - * In this scheme a comparatively quicker boot is observed. - * - * If ZONE_DMA configs are defined, crash kernel memory reservation - * is delayed until DMA zone memory range size initilazation performed in - * zone_sizes_init(). The defer is necessary to steer clear of DMA zone - * memory range to avoid overlap allocation. So crash kernel memory boundaries - * are not known when mapping all bank memory ranges, which otherwise means - * not possible to exclude crash kernel range from creating block mappings - * so page-granularity mappings are created for the entire memory range. - * Hence a slightly slower boot is observed. - * - * Note: Page-granularity mapppings are necessary for crash kernel memory - * range for shrinking its size via /sys/kernel/kexec_crash_size interface. */ -#if IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32) -phys_addr_t __ro_after_init arm64_dma_phys_limit; -#else -phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1; -#endif +phys_addr_t arm64_dma_phys_limit __ro_after_init; /* * Provide a run-time mean of disabling ZONE_DMA32 if it is enabled via @@ -243,6 +217,8 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) if (!arm64_dma_phys_limit) arm64_dma_phys_limit = dma32_phys_limit; #endif + if (!arm64_dma_phys_limit) + arm64_dma_phys_limit = PHYS_MASK + 1; max_zone_pfns[ZONE_NORMAL] = max; free_area_init(max_zone_pfns); @@ -453,9 +429,6 @@ void __init arm64_memblock_init(void) reserve_elfcorehdr(); - if (!IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) - reserve_crashkernel(); - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; } @@ -502,8 +475,7 @@ void __init bootmem_init(void) * request_standard_resources() depends on crashkernel's memory being * reserved, so do it here. */ - if (IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32)) - reserve_crashkernel(); + reserve_crashkernel(); memblock_dump_all(); } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 10ef44c938b73..52483efde97f2 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -61,7 +61,6 @@ static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused; static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused; static DEFINE_SPINLOCK(swapper_pgdir_lock); -static DEFINE_MUTEX(fixmap_lock); void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd) { @@ -316,12 +315,6 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, } BUG_ON(p4d_bad(p4d)); - /* - * No need for locking during early boot. And it doesn't work as - * expected with KASLR enabled. - */ - if (system_state != SYSTEM_BOOTING) - mutex_lock(&fixmap_lock); pudp = pud_set_fixmap_offset(p4dp, addr); do { pud_t old_pud = READ_ONCE(*pudp); @@ -352,8 +345,6 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, } while (pudp++, addr = next, addr != end); pud_clear_fixmap(); - if (system_state != SYSTEM_BOOTING) - mutex_unlock(&fixmap_lock); } static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, @@ -502,7 +493,7 @@ static void __init map_mem(pgd_t *pgdp) int flags = 0; u64 i; - if (rodata_full || debug_pagealloc_enabled() || + if (rodata_full || crash_mem_map || debug_pagealloc_enabled() || IS_ENABLED(CONFIG_KFENCE)) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; @@ -514,17 +505,6 @@ static void __init map_mem(pgd_t *pgdp) */ memblock_mark_nomap(kernel_start, kernel_end - kernel_start); -#ifdef CONFIG_KEXEC_CORE - if (crash_mem_map) { - if (IS_ENABLED(CONFIG_ZONE_DMA) || - IS_ENABLED(CONFIG_ZONE_DMA32)) - flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; - else if (crashk_res.end) - memblock_mark_nomap(crashk_res.start, - resource_size(&crashk_res)); - } -#endif - /* map all the memory banks */ for_each_mem_range(i, &start, &end) { if (start >= end) @@ -551,25 +531,6 @@ static void __init map_mem(pgd_t *pgdp) __map_memblock(pgdp, kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS); memblock_clear_nomap(kernel_start, kernel_end - kernel_start); - - /* - * Use page-level mappings here so that we can shrink the region - * in page granularity and put back unused memory to buddy system - * through /sys/kernel/kexec_crash_size interface. - */ -#ifdef CONFIG_KEXEC_CORE - if (crash_mem_map && - !IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) { - if (crashk_res.end) { - __map_memblock(pgdp, crashk_res.start, - crashk_res.end + 1, - PAGE_KERNEL, - NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS); - memblock_clear_nomap(crashk_res.start, - resource_size(&crashk_res)); - } - } -#endif } void mark_rodata_ro(void) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 56b020b7ec59a..8e1d5a37e5c94 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1041,18 +1041,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) goto out_off; } - /* - * 1. Initial fake pass to compute ctx->idx and ctx->offset. - * - * BPF line info needs ctx->offset[i] to be the offset of - * instruction[i] in jited image, so build prologue first. - */ - if (build_prologue(&ctx, was_classic)) { + /* 1. Initial fake pass to compute ctx->idx. */ + + /* Fake pass to fill in ctx->offset. */ + if (build_body(&ctx, extra_pass)) { prog = orig_prog; goto out_off; } - if (build_body(&ctx, extra_pass)) { + if (build_prologue(&ctx, was_classic)) { prog = orig_prog; goto out_off; } @@ -1127,11 +1124,6 @@ skip_init_ctx: prog->jited_len = prog_size; if (!prog->is_func || extra_pass) { - int i; - - /* offset[prog->len] is the size of program */ - for (i = 0; i <= prog->len; i++) - ctx.offset[i] *= AARCH64_INSN_SIZE; bpf_prog_fill_jited_linfo(prog, ctx.offset + 1); out_off: kfree(ctx.offset); diff --git a/arch/csky/kernel/perf_callchain.c b/arch/csky/kernel/perf_callchain.c index 75e1f9df5f604..35318a635a5fa 100644 --- a/arch/csky/kernel/perf_callchain.c +++ b/arch/csky/kernel/perf_callchain.c @@ -49,7 +49,7 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, { struct stackframe buftail; unsigned long lr = 0; - unsigned long __user *user_frame_tail = (unsigned long __user *)fp; + unsigned long *user_frame_tail = (unsigned long *)fp; /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c index 243228b0aa075..0ca49b5e3dd37 100644 --- a/arch/csky/kernel/signal.c +++ b/arch/csky/kernel/signal.c @@ -136,7 +136,7 @@ static inline void __user *get_sigframe(struct ksignal *ksig, static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame; int err = 0; struct csky_vdso *vdso = current->mm->context.vdso; diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index a055616942a1e..59f7dfe50a4d0 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -480,7 +480,7 @@ static struct platform_device mcf_i2c5 = { #endif /* MCFI2C_BASE5 */ #endif /* IS_ENABLED(CONFIG_I2C_IMX) */ -#ifdef MCFEDMA_BASE +#if IS_ENABLED(CONFIG_MCF_EDMA) static const struct dma_slave_map mcf_edma_map[] = { { "dreq0", "rx-tx", MCF_EDMA_FILTER_PARAM(0) }, @@ -552,7 +552,7 @@ static struct platform_device mcf_edma = { .platform_data = &mcf_edma_data, } }; -#endif /* MCFEDMA_BASE */ +#endif /* IS_ENABLED(CONFIG_MCF_EDMA) */ #ifdef MCFSDHC_BASE static struct mcf_esdhc_platform_data mcf_esdhc_data = { @@ -610,7 +610,7 @@ static struct platform_device *mcf_devices[] __initdata = { &mcf_i2c5, #endif #endif -#ifdef MCFEDMA_BASE +#if IS_ENABLED(CONFIG_MCF_EDMA) &mcf_edma, #endif #ifdef MCFSDHC_BASE diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 7c5d92e2915ca..304b04ffea2fa 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -167,27 +167,27 @@ extern long __user_bad(void); #define __get_user(x, ptr) \ ({ \ + unsigned long __gu_val = 0; \ long __gu_err; \ switch (sizeof(*(ptr))) { \ case 1: \ - __get_user_asm("lbu", (ptr), x, __gu_err); \ + __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ break; \ case 2: \ - __get_user_asm("lhu", (ptr), x, __gu_err); \ + __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ break; \ case 4: \ - __get_user_asm("lw", (ptr), x, __gu_err); \ + __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ break; \ - case 8: { \ - __u64 __x = 0; \ - __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \ - -EFAULT : 0; \ - (x) = (typeof(x))(typeof((x) - (x)))__x; \ + case 8: \ + __gu_err = __copy_from_user(&__gu_val, ptr, 8); \ + if (__gu_err) \ + __gu_err = -EFAULT; \ break; \ - } \ default: \ /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ + x = (__force __typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 011d1d678840a..ea5b5a83f1e11 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -131,7 +131,7 @@ */ mfc0 t0,CP0_CAUSE # get pending interrupts mfc0 t1,CP0_STATUS -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT lw t2,cpu_fpu_mask #endif andi t0,ST0_IM # CAUSE.CE may be non-zero! @@ -139,7 +139,7 @@ beqz t0,spurious -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT and t2,t0 bnez t2,fpu # handle FPU immediately #endif @@ -280,7 +280,7 @@ handle_it: j dec_irq_dispatch nop -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT fpu: lw t0,fpu_kstat_irq nop diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile index 2bad87551203b..d95016016b42b 100644 --- a/arch/mips/dec/prom/Makefile +++ b/arch/mips/dec/prom/Makefile @@ -6,4 +6,4 @@ lib-y += init.o memory.o cmdline.o identify.o console.o -lib-$(CONFIG_CPU_R3000) += locore.o +lib-$(CONFIG_32BIT) += locore.o diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 99b9b29750db3..eaad0ed4b523b 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -746,8 +746,7 @@ void __init arch_init_irq(void) dec_interrupt[DEC_IRQ_HALT] = -1; /* Register board interrupts: FPU and cascade. */ - if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) && - dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) { + if (dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) { struct irq_desc *desc_fpu; int irq_fpu; diff --git a/arch/mips/include/asm/dec/prom.h b/arch/mips/include/asm/dec/prom.h index 1e1247add1cf8..62c7dfb90e06c 100644 --- a/arch/mips/include/asm/dec/prom.h +++ b/arch/mips/include/asm/dec/prom.h @@ -43,11 +43,16 @@ */ #define REX_PROM_MAGIC 0x30464354 -/* KN04 and KN05 are REX PROMs, so only do the check for R3k systems. */ -static inline bool prom_is_rex(u32 magic) -{ - return !IS_ENABLED(CONFIG_CPU_R3000) || magic == REX_PROM_MAGIC; -} +#ifdef CONFIG_64BIT + +#define prom_is_rex(magic) 1 /* KN04 and KN05 are REX PROMs. */ + +#else /* !CONFIG_64BIT */ + +#define prom_is_rex(magic) ((magic) == REX_PROM_MAGIC) + +#endif /* !CONFIG_64BIT */ + /* * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's and diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h index 71153c369f294..139b4050259fa 100644 --- a/arch/mips/include/asm/pgalloc.h +++ b/arch/mips/include/asm/pgalloc.h @@ -15,7 +15,6 @@ #define __HAVE_ARCH_PMD_ALLOC_ONE #define __HAVE_ARCH_PUD_ALLOC_ONE -#define __HAVE_ARCH_PGD_FREE #include static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, @@ -50,11 +49,6 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) extern void pgd_init(unsigned long page); extern pgd_t *pgd_alloc(struct mm_struct *mm); -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - free_pages((unsigned long)pgd, PGD_ORDER); -} - #define __pte_free_tlb(tlb,pte,address) \ do { \ pgtable_pte_page_dtor(pte); \ diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 0e3c8d761a451..dd34f1b32b797 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -310,9 +310,11 @@ static int __init plat_setup_devices(void) static int __init setup_kmac(char *s) { printk(KERN_INFO "korina mac = %s\n", s); - if (!mac_pton(s, korina_dev0_data.mac)) + if (!mac_pton(s, korina_dev0_data.mac)) { printk(KERN_ERR "Invalid mac\n"); - return 1; + return -EINVAL; + } + return 0; } __setup("kmac=", setup_kmac); diff --git a/arch/nds32/include/asm/uaccess.h b/arch/nds32/include/asm/uaccess.h index 54500e81efe59..010ba5f1d7dd6 100644 --- a/arch/nds32/include/asm/uaccess.h +++ b/arch/nds32/include/asm/uaccess.h @@ -70,7 +70,9 @@ static inline void set_fs(mm_segment_t fs) * versions are void (ie, don't return a value as such). */ -#define get_user(x, ptr) \ +#define get_user __get_user \ + +#define __get_user(x, ptr) \ ({ \ long __gu_err = 0; \ __get_user_check((x), (ptr), __gu_err); \ @@ -83,14 +85,6 @@ static inline void set_fs(mm_segment_t fs) (void)0; \ }) -#define __get_user(x, ptr) \ -({ \ - long __gu_err = 0; \ - const __typeof__(*(ptr)) __user *__p = (ptr); \ - __get_user_err((x), __p, (__gu_err)); \ - __gu_err; \ -}) - #define __get_user_check(x, ptr, err) \ ({ \ const __typeof__(*(ptr)) __user *__p = (ptr); \ @@ -171,18 +165,12 @@ do { \ : "r"(addr), "i"(-EFAULT) \ : "cc") -#define put_user(x, ptr) \ -({ \ - long __pu_err = 0; \ - __put_user_check((x), (ptr), __pu_err); \ - __pu_err; \ -}) +#define put_user __put_user \ #define __put_user(x, ptr) \ ({ \ long __pu_err = 0; \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - __put_user_err((x), __p, __pu_err); \ + __put_user_err((x), (ptr), __pu_err); \ __pu_err; \ }) diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h index 8a386e6c07df1..a741abbed6fbf 100644 --- a/arch/nios2/include/asm/uaccess.h +++ b/arch/nios2/include/asm/uaccess.h @@ -89,7 +89,6 @@ extern __must_check long strnlen_user(const char __user *s, long n); /* Optimized macros */ #define __get_user_asm(val, insn, addr, err) \ { \ - unsigned long __gu_val; \ __asm__ __volatile__( \ " movi %0, %3\n" \ "1: " insn " %1, 0(%2)\n" \ @@ -98,20 +97,14 @@ extern __must_check long strnlen_user(const char __user *s, long n); " .section __ex_table,\"a\"\n" \ " .word 1b, 2b\n" \ " .previous" \ - : "=&r" (err), "=r" (__gu_val) \ + : "=&r" (err), "=r" (val) \ : "r" (addr), "i" (-EFAULT)); \ - val = (__force __typeof__(*(addr)))__gu_val; \ } -extern void __get_user_unknown(void); - -#define __get_user_8(val, ptr, err) do { \ - u64 __val = 0; \ +#define __get_user_unknown(val, size, ptr, err) do { \ err = 0; \ - if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ + if (__copy_from_user(&(val), ptr, size)) { \ err = -EFAULT; \ - } else { \ - val = (typeof(val))(typeof((val) - (val)))__val; \ } \ } while (0) @@ -127,11 +120,8 @@ do { \ case 4: \ __get_user_asm(val, "ldw", ptr, err); \ break; \ - case 8: \ - __get_user_8(val, ptr, err); \ - break; \ default: \ - __get_user_unknown(); \ + __get_user_unknown(val, size, ptr, err); \ break; \ } \ } while (0) @@ -140,7 +130,9 @@ do { \ ({ \ long __gu_err = -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ - __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ + unsigned long __gu_val = 0; \ + __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ + (x) = (__force __typeof__(x))__gu_val; \ __gu_err; \ }) @@ -148,9 +140,11 @@ do { \ ({ \ long __gu_err = -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + unsigned long __gu_val = 0; \ if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ - __get_user_common(x, sizeof(*__gu_ptr), \ + __get_user_common(__gu_val, sizeof(*__gu_ptr), \ __gu_ptr, __gu_err); \ + (x) = (__force __typeof__(x))__gu_val; \ __gu_err; \ }) diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c index e45491d1d3e44..cf2dca2ac7c37 100644 --- a/arch/nios2/kernel/signal.c +++ b/arch/nios2/kernel/signal.c @@ -36,10 +36,10 @@ struct rt_sigframe { static inline int rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, - struct ucontext __user *uc, int *pr2) + struct ucontext *uc, int *pr2) { int temp; - unsigned long __user *gregs = uc->uc_mcontext.gregs; + unsigned long *gregs = uc->uc_mcontext.gregs; int err; /* Always make any pending restarted system calls return -EINTR */ @@ -102,11 +102,10 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *sw) { struct pt_regs *regs = (struct pt_regs *)(sw + 1); /* Verify, can we follow the stack back */ - struct rt_sigframe __user *frame; + struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; sigset_t set; int rval; - frame = (struct rt_sigframe __user *) regs->sp; if (!access_ok(frame, sizeof(*frame))) goto badframe; @@ -125,10 +124,10 @@ badframe: return 0; } -static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) +static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long __user *gregs = uc->uc_mcontext.gregs; + unsigned long *gregs = uc->uc_mcontext.gregs; int err = 0; err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); @@ -163,9 +162,8 @@ static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs * return err; } -static inline void __user *get_sigframe(struct ksignal *ksig, - struct pt_regs *regs, - size_t frame_size) +static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, + size_t frame_size) { unsigned long usp; @@ -176,13 +174,13 @@ static inline void __user *get_sigframe(struct ksignal *ksig, usp = sigsp(usp, ksig); /* Verify, is it 32 or 64 bit aligned */ - return (void __user *)((usp - frame_size) & -8UL); + return (void *)((usp - frame_size) & -8UL); } static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame; int err = 0; frame = get_sigframe(ksig, regs, sizeof(*frame)); diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/traps.h index d0e090a2c000d..8ecc1f0c0483d 100644 --- a/arch/parisc/include/asm/traps.h +++ b/arch/parisc/include/asm/traps.h @@ -17,7 +17,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err); const char *trap_name(unsigned long code); void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address); -int handle_nadtlb_fault(struct pt_regs *regs); #endif #endif diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index bce47e0fb692c..269b737d26299 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -661,8 +661,6 @@ void notrace handle_interruption(int code, struct pt_regs *regs) by hand. Technically we need to emulate: fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw */ - if (code == 17 && handle_nadtlb_fault(regs)) - return; fault_address = regs->ior; fault_space = regs->isr; break; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 5faa3cff47387..716960f5d92ea 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -424,92 +424,3 @@ no_context: goto no_context; pagefault_out_of_memory(); } - -/* Handle non-access data TLB miss faults. - * - * For probe instructions, accesses to userspace are considered allowed - * if they lie in a valid VMA and the access type matches. We are not - * allowed to handle MM faults here so there may be situations where an - * actual access would fail even though a probe was successful. - */ -int -handle_nadtlb_fault(struct pt_regs *regs) -{ - unsigned long insn = regs->iir; - int breg, treg, xreg, val = 0; - struct vm_area_struct *vma, *prev_vma; - struct task_struct *tsk; - struct mm_struct *mm; - unsigned long address; - unsigned long acc_type; - - switch (insn & 0x380) { - case 0x280: - /* FDC instruction */ - fallthrough; - case 0x380: - /* PDC and FIC instructions */ - if (printk_ratelimit()) { - pr_warn("BUG: nullifying cache flush/purge instruction\n"); - show_regs(regs); - } - if (insn & 0x20) { - /* Base modification */ - breg = (insn >> 21) & 0x1f; - xreg = (insn >> 16) & 0x1f; - if (breg && xreg) - regs->gr[breg] += regs->gr[xreg]; - } - regs->gr[0] |= PSW_N; - return 1; - - case 0x180: - /* PROBE instruction */ - treg = insn & 0x1f; - if (regs->isr) { - tsk = current; - mm = tsk->mm; - if (mm) { - /* Search for VMA */ - address = regs->ior; - mmap_read_lock(mm); - vma = find_vma_prev(mm, address, &prev_vma); - mmap_read_unlock(mm); - - /* - * Check if access to the VMA is okay. - * We don't allow for stack expansion. - */ - acc_type = (insn & 0x40) ? VM_WRITE : VM_READ; - if (vma - && address >= vma->vm_start - && (vma->vm_flags & acc_type) == acc_type) - val = 1; - } - } - if (treg) - regs->gr[treg] = val; - regs->gr[0] |= PSW_N; - return 1; - - case 0x300: - /* LPA instruction */ - if (insn & 0x20) { - /* Base modification */ - breg = (insn >> 21) & 0x1f; - xreg = (insn >> 16) & 0x1f; - if (breg && xreg) - regs->gr[breg] += regs->gr[xreg]; - } - treg = insn & 0x1f; - if (treg) - regs->gr[treg] = 0; - regs->gr[0] |= PSW_N; - return 1; - - default: - break; - } - - return 0; -} diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 2f98df296843e..6a9a852c3d566 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -172,7 +172,7 @@ else CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,$(call cc-option,-mtune=power5)) CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mcpu=power5,-mcpu=power4) endif -else ifdef CONFIG_PPC_BOOK3E_64 +else CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64 endif diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts b/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts deleted file mode 100644 index 73f8c998c64df..0000000000000 --- a/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * T1040RDB-REV-A Device Tree Source - * - * Copyright 2014 - 2015 Freescale Semiconductor Inc. - * - */ - -#include "t1040rdb.dts" - -/ { - model = "fsl,T1040RDB-REV-A"; - compatible = "fsl,T1040RDB-REV-A"; -}; - -&seville_port0 { - label = "ETH5"; -}; - -&seville_port2 { - label = "ETH7"; -}; - -&seville_port4 { - label = "ETH9"; -}; - -&seville_port6 { - label = "ETH11"; -}; diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts index b6733e7e65805..af0c8a6f56138 100644 --- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts +++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts @@ -119,7 +119,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_0>; phy-mode = "qsgmii"; - label = "ETH3"; + label = "ETH5"; status = "okay"; }; @@ -135,7 +135,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_2>; phy-mode = "qsgmii"; - label = "ETH5"; + label = "ETH7"; status = "okay"; }; @@ -151,7 +151,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_4>; phy-mode = "qsgmii"; - label = "ETH7"; + label = "ETH9"; status = "okay"; }; @@ -167,7 +167,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_6>; phy-mode = "qsgmii"; - label = "ETH9"; + label = "ETH11"; status = "okay"; }; diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 0182b291248ac..58635960403c0 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -344,37 +344,25 @@ static inline void __raw_writeq_be(unsigned long v, volatile void __iomem *addr) */ static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stbcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stbcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - sthcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("sthcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stwcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stwcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stdcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stdcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } @@ -386,10 +374,7 @@ static inline void __raw_rm_writeq_be(u64 val, volatile void __iomem *paddr) static inline u8 __raw_rm_readb(volatile void __iomem *paddr) { u8 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lbzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lbzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -397,10 +382,7 @@ static inline u8 __raw_rm_readb(volatile void __iomem *paddr) static inline u16 __raw_rm_readw(volatile void __iomem *paddr) { u16 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lhzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lhzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -408,10 +390,7 @@ static inline u16 __raw_rm_readw(volatile void __iomem *paddr) static inline u32 __raw_rm_readl(volatile void __iomem *paddr) { u32 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lwzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lwzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -419,10 +398,7 @@ static inline u32 __raw_rm_readl(volatile void __iomem *paddr) static inline u64 __raw_rm_readq(volatile void __iomem *paddr) { u64 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - ldcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("ldcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 6b808bcdecd52..f53bfefb4a577 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -229,11 +229,8 @@ extern long __get_user_bad(void); */ #define __get_user_atomic_128_aligned(kaddr, uaddr, err) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine altivec\n" \ "1: lvx 0,0,%1 # get user\n" \ " stvx 0,0,%2 # put kernel\n" \ - ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index d89cf802d9aa7..617eba82531cb 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -669,7 +669,7 @@ static void __init kvm_use_magic_page(void) on_each_cpu(kvm_map_magic_page, &features, 1); /* Quick self-test to see if the mapping works */ - if (fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) { + if (!fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) { kvm_patching_worked = false; return; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 38b7a3491aac0..527c205d5a5f5 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -5752,11 +5752,8 @@ static int kvmppc_book3s_init_hv(void) if (r) return r; - if (kvmppc_radix_possible()) { + if (kvmppc_radix_possible()) r = kvmppc_radix_init(); - if (r) - return r; - } /* * POWER9 chips before version 2.02 can't have some threads in diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index ef8077a739b88..543db9157f3b1 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -1500,7 +1500,7 @@ int kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu, { enum emulation_result emulated = EMULATE_DONE; - if (vcpu->arch.mmio_vmx_copy_nums > 2) + if (vcpu->arch.mmio_vsx_copy_nums > 2) return EMULATE_FAIL; while (vcpu->arch.mmio_vmx_copy_nums) { @@ -1597,7 +1597,7 @@ int kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu, unsigned int index = rs & KVM_MMIO_REG_MASK; enum emulation_result emulated = EMULATE_DONE; - if (vcpu->arch.mmio_vmx_copy_nums > 2) + if (vcpu->arch.mmio_vsx_copy_nums > 2) return EMULATE_FAIL; vcpu->arch.io_gpr = rs; diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 2d19655328f12..0edebbbffcdca 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -108,9 +108,9 @@ static nokprobe_inline long address_ok(struct pt_regs *regs, { if (!user_mode(regs)) return 1; - if (access_ok((void __user *)ea, nb)) + if (__access_ok(ea, nb)) return 1; - if (access_ok((void __user *)ea, 1)) + if (__access_ok(ea, 1)) /* Access overlaps the end of the user region */ regs->dar = TASK_SIZE_MAX - 1; else @@ -949,10 +949,7 @@ NOKPROBE_SYMBOL(emulate_dcbz); #define __put_user_asmx(x, addr, err, op, cr) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine power8\n" \ "1: " op " %2,0,%3\n" \ - ".machine pop\n" \ " mfcr %1\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ @@ -965,10 +962,7 @@ NOKPROBE_SYMBOL(emulate_dcbz); #define __get_user_asmx(x, addr, err, op) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine power8\n" \ "1: "op" %1,0,%2\n" \ - ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ @@ -3193,7 +3187,7 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) __put_user_asmx(op->val, ea, err, "stbcx.", cr); break; case 2: - __put_user_asmx(op->val, ea, err, "sthcx.", cr); + __put_user_asmx(op->val, ea, err, "stbcx.", cr); break; #endif case 4: diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/kasan_init_32.c index f3e4d069e0ba7..cf8770b1a692e 100644 --- a/arch/powerpc/mm/kasan/kasan_init_32.c +++ b/arch/powerpc/mm/kasan/kasan_init_32.c @@ -83,12 +83,13 @@ void __init kasan_update_early_region(unsigned long k_start, unsigned long k_end, pte_t pte) { unsigned long k_cur; + phys_addr_t pa = __pa(kasan_early_shadow_page); for (k_cur = k_start; k_cur != k_end; k_cur += PAGE_SIZE) { pmd_t *pmd = pmd_off_k(k_cur); pte_t *ptep = pte_offset_kernel(pmd, k_cur); - if (pte_page(*ptep) != virt_to_page(lm_alias(kasan_early_shadow_page))) + if ((pte_val(*ptep) & PTE_RPN_MASK) != pa) continue; __set_pte_at(&init_mm, k_cur, ptep, pte, 0); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 275c60f92a7ce..094a1076fd1fe 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -742,9 +742,7 @@ static int __init parse_numa_properties(void) of_node_put(cpu); } - /* node_set_online() is an UB if 'nid' is negative */ - if (likely(nid >= 0)) - node_set_online(nid); + node_set_online(nid); } get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index e8074d7f2401b..7b25548ec42b0 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1457,11 +1457,7 @@ static int trace_imc_event_init(struct perf_event *event) event->hw.idx = -1; - /* - * There can only be a single PMU for perf_hw_context events which is assigned to - * core PMU. Hence use "perf_sw_context" for trace_imc. - */ - event->pmu->task_ctx_nr = perf_sw_context; + event->pmu->task_ctx_nr = perf_hw_context; event->destroy = reset_global_refc; return 0; } diff --git a/arch/powerpc/platforms/8xx/pic.c b/arch/powerpc/platforms/8xx/pic.c index 04a6abf14c295..f2ba837249d69 100644 --- a/arch/powerpc/platforms/8xx/pic.c +++ b/arch/powerpc/platforms/8xx/pic.c @@ -153,7 +153,6 @@ int __init mpc8xx_pic_init(void) if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; - goto out; } ret = 0; diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 69c344c8884f3..72c25295c1c2b 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c @@ -43,11 +43,7 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) unsigned long parity; /* Calculate the parity of the value */ - asm (".machine push; \ - .machine power7; \ - popcntd %0,%1; \ - .machine pop;" - : "=r" (parity) : "r" (val)); + asm ("popcntd %0,%1" : "=r" (parity) : "r" (val)); /* xor our value with the previous mask */ val ^= rng->mask; diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index 39186ad6b3c3a..8963eaffb1b7b 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -86,7 +86,7 @@ static LIST_HEAD(gtms); */ struct gtm_timer *gtm_get_timer16(void) { - struct gtm *gtm; + struct gtm *gtm = NULL; int i; list_for_each_entry(gtm, >ms, list_node) { @@ -103,7 +103,7 @@ struct gtm_timer *gtm_get_timer16(void) spin_unlock_irq(>m->lock); } - if (!list_empty(>ms)) + if (gtm) return ERR_PTR(-EBUSY); return ERR_PTR(-ENODEV); } diff --git a/arch/riscv/include/asm/module.lds.h b/arch/riscv/include/asm/module.lds.h index 1075beae1ac64..4254ff2ff0494 100644 --- a/arch/riscv/include/asm/module.lds.h +++ b/arch/riscv/include/asm/module.lds.h @@ -2,8 +2,8 @@ /* Copyright (C) 2017 Andes Technology Corporation */ #ifdef CONFIG_MODULE_SECTIONS SECTIONS { - .plt : { BYTE(0) } - .got : { BYTE(0) } - .got.plt : { BYTE(0) } + .plt (NOLOAD) : { BYTE(0) } + .got (NOLOAD) : { BYTE(0) } + .got.plt (NOLOAD) : { BYTE(0) } } #endif diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index d79ae9d98999f..a390711129de6 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -11,17 +11,11 @@ #include #include -#ifdef CONFIG_KASAN -#define KASAN_STACK_ORDER 1 -#else -#define KASAN_STACK_ORDER 0 -#endif - /* thread information allocation */ #ifdef CONFIG_64BIT -#define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER) +#define THREAD_SIZE_ORDER (2) #else -#define THREAD_SIZE_ORDER (1 + KASAN_STACK_ORDER) +#define THREAD_SIZE_ORDER (1) #endif #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c index fb02811df7143..ad3001cbdf618 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -19,8 +19,8 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, { struct stackframe buftail; unsigned long ra = 0; - unsigned long __user *user_frame_tail = - (unsigned long __user *)(fp - sizeof(struct stackframe)); + unsigned long *user_frame_tail = + (unsigned long *)(fp - sizeof(struct stackframe)); /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) @@ -77,7 +77,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, bool fill_callchain(unsigned long pc, void *entry) { - return perf_callchain_store(entry, pc) == 0; + return perf_callchain_store(entry, pc); } void notrace walk_stackframe(struct task_struct *task, diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 1da36dd34990b..741d0701003af 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -65,7 +65,7 @@ struct rt_signal_frame { */ static inline bool invalid_frame_pointer(void __user *fp, int fplen) { - if ((((unsigned long) fp) & 15) || !access_ok(fp, fplen)) + if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen)) return true; return false; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 2d20773b7d8ee..a2e680f7d39f2 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -223,7 +223,7 @@ void mconsole_go(struct mc_request *req) void mconsole_stop(struct mc_request *req) { - block_signals(); + deactivate_fd(req->originating_fd, MCONSOLE_IRQ); os_set_fd_block(req->originating_fd, 1); mconsole_reply(req, "stopped", 0, 0); for (;;) { @@ -246,7 +246,6 @@ void mconsole_stop(struct mc_request *req) } os_set_fd_block(req->originating_fd, 0); mconsole_reply(req, "", 0, 0); - unblock_signals(); } static DEFINE_SPINLOCK(mc_devices_lock); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5e28d4a0dff5a..f6fb0f6277b95 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -76,6 +76,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_NONLEAF_PMD_YOUNG select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_COPY_MC if X86_64 select ARCH_HAS_SET_MEMORY diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig index 76cb80cb70c3f..103720489453e 100644 --- a/arch/x86/configs/gki_defconfig +++ b/arch/x86/configs/gki_defconfig @@ -99,6 +99,10 @@ CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=16 CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_ANON_VMA_NAME=y +CONFIG_LRU_GEN=y +CONFIG_DAMON=y +CONFIG_DAMON_PADDR=y +CONFIG_DAMON_RECLAIM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -302,6 +306,7 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_WIREGUARD=y CONFIG_IFB=y +CONFIG_MACSEC=y CONFIG_TUN=y CONFIG_VETH=y CONFIG_PPP=y @@ -313,7 +318,6 @@ CONFIG_PPPOL2TP=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y -# CONFIG_USB_NET_AX88179_178A is not set CONFIG_USB_NET_CDC_EEM=y # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set @@ -505,6 +509,7 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_F2FS_UNFAIR_RWSEM=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index cc3b79c066853..c084899e95825 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -472,7 +472,7 @@ static u64 pt_config_filters(struct perf_event *event) pt->filters.filter[range].msr_b = filter->msr_b; } - rtit_ctl |= (u64)filter->config << pt_address_ranges[range].reg_off; + rtit_ctl |= filter->config << pt_address_ranges[range].reg_off; } return rtit_ctl; diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h index 97bbb4a9083a7..05b48b33baf0b 100644 --- a/arch/x86/include/asm/kfence.h +++ b/arch/x86/include/asm/kfence.h @@ -56,8 +56,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) else set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); - /* Flush this CPU's TLB. */ + /* + * Flush this CPU's TLB, assuming whoever did the allocation/free is + * likely to continue running on this CPU. + */ + preempt_disable(); flush_tlb_one_kernel(addr); + preempt_enable(); return true; } diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 87de9f2d71cf2..ed09aca6203ad 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -846,7 +846,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) static inline int pmd_bad(pmd_t pmd) { - return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE; + return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) != + (_KERNPG_TABLE & ~_PAGE_ACCESSED); } static inline unsigned long pages_to_mb(unsigned long npg) @@ -1452,10 +1453,10 @@ static inline bool arch_has_pfn_modify_check(void) return boot_cpu_has_bug(X86_BUG_L1TF); } -#define arch_faults_on_old_pte arch_faults_on_old_pte -static inline bool arch_faults_on_old_pte(void) +#define arch_has_hw_pte_young arch_has_hw_pte_young +static inline bool arch_has_hw_pte_young(void) { - return false; + return true; } #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 55562a9b7f92e..14cd3186dc77d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1340,17 +1340,6 @@ static int __init disable_acpi_pci(const struct dmi_system_id *d) return 0; } -static int __init disable_acpi_xsdt(const struct dmi_system_id *d) -{ - if (!acpi_force) { - pr_notice("%s detected: force use of acpi=rsdt\n", d->ident); - acpi_gbl_do_not_use_xsdt = TRUE; - } else { - pr_notice("Warning: DMI blacklist says broken, but acpi XSDT forced\n"); - } - return 0; -} - static int __init dmi_disable_acpi(const struct dmi_system_id *d) { if (!acpi_force) { @@ -1475,19 +1464,6 @@ static const struct dmi_system_id acpi_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, - /* - * Boxes that need ACPI XSDT use disabled due to corrupted tables - */ - { - .callback = disable_acpi_xsdt, - .ident = "Advantech DAC-BJ01", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "NEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "Bearlake CRB Board"), - DMI_MATCH(DMI_BIOS_VERSION, "V1.12"), - DMI_MATCH(DMI_BIOS_DATE, "02/01/2011"), - }, - }, {} }; diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 18e952fed021b..7462b79c39de6 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -532,7 +532,7 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector) } else if (apic_id < min && max - apic_id < KVM_IPI_CLUSTER_SIZE) { ipi_bitmap <<= min - apic_id; min = apic_id; - } else if (apic_id > min && apic_id < min + KVM_IPI_CLUSTER_SIZE) { + } else if (apic_id < min + KVM_IPI_CLUSTER_SIZE) { max = apic_id < max ? max : apic_id; } else { ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index a63df19ef4dad..e82151ba95c09 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1718,6 +1718,11 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, goto exception; } + if (!seg_desc.p) { + err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; + goto exception; + } + dpl = seg_desc.dpl; switch (seg) { @@ -1757,10 +1762,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, case VCPU_SREG_TR: if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9)) goto exception; - if (!seg_desc.p) { - err_vec = NP_VECTOR; - goto exception; - } old_desc = seg_desc; seg_desc.type |= 2; /* busy */ ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, @@ -1785,11 +1786,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, break; } - if (!seg_desc.p) { - err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; - goto exception; - } - if (seg_desc.s) { /* mark segment as accessed */ if (!(seg_desc.type & 1)) { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d806139377bc6..328f37e4fd3a7 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -207,7 +207,7 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, struct kvm_vcpu *vcpu = synic_to_vcpu(synic); int ret; - if (!synic->active && (!host || data)) + if (!synic->active && !host) return 1; trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host); @@ -253,9 +253,6 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, case HV_X64_MSR_EOM: { int i; - if (!synic->active) - break; - for (i = 0; i < ARRAY_SIZE(synic->sint); i++) kvm_hv_notify_acked_sint(vcpu, i); break; @@ -639,7 +636,7 @@ static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config, struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || config)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id, @@ -663,7 +660,7 @@ static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count, struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || count)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id, diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index de11149e28e09..677d21082454f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2227,7 +2227,10 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { - apic_set_tpr(vcpu->arch.apic, (cr8 & 0x0f) << 4); + struct kvm_lapic *apic = vcpu->arch.apic; + + apic_set_tpr(apic, ((cr8 & 0x0f) << 4) + | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index c6daeeff1d9c9..f8829134bf341 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -34,8 +34,9 @@ #define PT_HAVE_ACCESSED_DIRTY(mmu) true #ifdef CONFIG_X86_64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL - #define CMPXCHG "cmpxchgq" + #define CMPXCHG cmpxchg #else + #define CMPXCHG cmpxchg64 #define PT_MAX_FULL_LEVELS 2 #endif #elif PTTYPE == 32 @@ -51,7 +52,7 @@ #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true - #define CMPXCHG "cmpxchgl" + #define CMPXCHG cmpxchg #elif PTTYPE == PTTYPE_EPT #define pt_element_t u64 #define guest_walker guest_walkerEPT @@ -64,9 +65,7 @@ #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 #define PT_HAVE_ACCESSED_DIRTY(mmu) ((mmu)->ept_ad) - #ifdef CONFIG_X86_64 - #define CMPXCHG "cmpxchgq" - #endif + #define CMPXCHG cmpxchg64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL #else #error Invalid PTTYPE value @@ -148,39 +147,43 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, pt_element_t __user *ptep_user, unsigned index, pt_element_t orig_pte, pt_element_t new_pte) { - int r = -EFAULT; - - if (!user_access_begin(ptep_user, sizeof(pt_element_t))) - return -EFAULT; - -#ifdef CMPXCHG - asm volatile("1:" LOCK_PREFIX CMPXCHG " %[new], %[ptr]\n" - "mov $0, %[r]\n" - "setnz %b[r]\n" - "2:" - _ASM_EXTABLE_UA(1b, 2b) - : [ptr] "+m" (*ptep_user), - [old] "+a" (orig_pte), - [r] "+q" (r) - : [new] "r" (new_pte) - : "memory"); -#else - asm volatile("1:" LOCK_PREFIX "cmpxchg8b %[ptr]\n" - "movl $0, %[r]\n" - "jz 2f\n" - "incl %[r]\n" - "2:" - _ASM_EXTABLE_UA(1b, 2b) - : [ptr] "+m" (*ptep_user), - [old] "+A" (orig_pte), - [r] "+rm" (r) - : [new_lo] "b" ((u32)new_pte), - [new_hi] "c" ((u32)(new_pte >> 32)) - : "memory"); -#endif + int npages; + pt_element_t ret; + pt_element_t *table; + struct page *page; + + npages = get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &page); + if (likely(npages == 1)) { + table = kmap_atomic(page); + ret = CMPXCHG(&table[index], orig_pte, new_pte); + kunmap_atomic(table); + + kvm_release_page_dirty(page); + } else { + struct vm_area_struct *vma; + unsigned long vaddr = (unsigned long)ptep_user & PAGE_MASK; + unsigned long pfn; + unsigned long paddr; + + mmap_read_lock(current->mm); + vma = find_vma_intersection(current->mm, vaddr, vaddr + PAGE_SIZE); + if (!vma || !(vma->vm_flags & VM_PFNMAP)) { + mmap_read_unlock(current->mm); + return -EFAULT; + } + pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + paddr = pfn << PAGE_SHIFT; + table = memremap(paddr, PAGE_SIZE, MEMREMAP_WB); + if (!table) { + mmap_read_unlock(current->mm); + return -EFAULT; + } + ret = CMPXCHG(&table[index], orig_pte, new_pte); + memunmap(table); + mmap_read_unlock(current->mm); + } - user_access_end(); - return r; + return (ret != orig_pte); } static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 073514bbb5f71..7e08efb068393 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -902,9 +902,6 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, if (tdp_mmu_iter_cond_resched(kvm, &iter, false)) continue; - if (!is_shadow_present_pte(iter.old_spte)) - continue; - if (spte_ad_need_write_protect(iter.old_spte)) { if (is_writable_pte(iter.old_spte)) new_spte = iter.old_spte & ~PT_WRITABLE_MASK; diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 3e5cb74c0b538..a8b5533cf601d 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -806,7 +806,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, { struct kvm_kernel_irq_routing_entry *e; struct kvm_irq_routing_table *irq_rt; - int idx, ret = 0; + int idx, ret = -EINVAL; if (!kvm_arch_has_assigned_device(kvm) || !irq_remapping_cap(IRQ_POSTING_CAP)) @@ -817,13 +817,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, idx = srcu_read_lock(&kvm->irq_srcu); irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); - - if (guest_irq >= irq_rt->nr_rt_entries || - hlist_empty(&irq_rt->map[guest_irq])) { - pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", - guest_irq, irq_rt->nr_rt_entries); - goto out; - } + WARN_ON(guest_irq >= irq_rt->nr_rt_entries); hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { struct vcpu_data vcpu_info; diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index f6a9e2e366425..fd0f1cb6fc6c9 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, return ret; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { @@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, return ret; } +#endif + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE int pudp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pud_t *pudp) { diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index d7249f4c90f1b..e13b0b49fcdfc 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -512,7 +512,10 @@ irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id) return ret; } -bool is_xen_pmu; +bool is_xen_pmu(int cpu) +{ + return (get_xenpmu_data() != NULL); +} void xen_pmu_init(int cpu) { @@ -523,7 +526,7 @@ void xen_pmu_init(int cpu) BUILD_BUG_ON(sizeof(struct xen_pmu_data) > PAGE_SIZE); - if (xen_hvm_domain() || (cpu != 0 && !is_xen_pmu)) + if (xen_hvm_domain()) return; xenpmu_data = (struct xen_pmu_data *)get_zeroed_page(GFP_KERNEL); @@ -544,8 +547,7 @@ void xen_pmu_init(int cpu) per_cpu(xenpmu_shared, cpu).xenpmu_data = xenpmu_data; per_cpu(xenpmu_shared, cpu).flags = 0; - if (!is_xen_pmu) { - is_xen_pmu = true; + if (cpu == 0) { perf_register_guest_info_callbacks(&xen_guest_cbs); xen_pmu_arch_init(); } diff --git a/arch/x86/xen/pmu.h b/arch/x86/xen/pmu.h index 65c58894fc79f..0e83a160589bc 100644 --- a/arch/x86/xen/pmu.h +++ b/arch/x86/xen/pmu.h @@ -4,8 +4,6 @@ #include -extern bool is_xen_pmu; - irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id); #ifdef CONFIG_XEN_HAVE_VPMU void xen_pmu_init(int cpu); @@ -14,6 +12,7 @@ void xen_pmu_finish(int cpu); static inline void xen_pmu_init(int cpu) {} static inline void xen_pmu_finish(int cpu) {} #endif +bool is_xen_pmu(int cpu); bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err); bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err); int pmu_apic_update(uint32_t reg); diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index 35b6d15d874d0..8f9e7e2407c87 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -130,7 +130,7 @@ int xen_smp_intr_init_pv(unsigned int cpu) per_cpu(xen_irq_work, cpu).irq = rc; per_cpu(xen_irq_work, cpu).name = callfunc_name; - if (is_xen_pmu) { + if (is_xen_pmu(cpu)) { pmu_name = kasprintf(GFP_KERNEL, "pmu%d", cpu); rc = bind_virq_to_irqhandler(VIRQ_XENPMU, cpu, xen_pmu_irq_handler, diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 9dd4efe1bf0bd..7f63aca6a0d34 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -226,8 +226,8 @@ extern unsigned long get_wchan(struct task_struct *p); #define xtensa_set_sr(x, sr) \ ({ \ - __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: \ - "a"((unsigned int)(x))); \ + unsigned int v = (unsigned int)(x); \ + __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: "a"(v)); \ }) #define xtensa_get_sr(sr) \ diff --git a/arch/xtensa/kernel/jump_label.c b/arch/xtensa/kernel/jump_label.c index 0dde21e0d3de4..61cf6497a646b 100644 --- a/arch/xtensa/kernel/jump_label.c +++ b/arch/xtensa/kernel/jump_label.c @@ -61,7 +61,7 @@ static void patch_text(unsigned long addr, const void *data, size_t sz) .data = data, }; stop_machine_cpuslocked(patch_text_stop_machine, - &patch, cpu_online_mask); + &patch, NULL); } else { unsigned long flags; diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index c2fdd6fcdaee6..b791e2041e49b 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -642,12 +642,6 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, { struct bfq_entity *entity = &bfqq->entity; - /* - * oom_bfqq is not allowed to move, oom_bfqq will hold ref to root_group - * until elevator exit. - */ - if (bfqq == &bfqd->oom_bfqq) - return; /* * Get extra reference to prevent bfqq from being freed in * next possible expire or deactivate. diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 4edec39ba1ba9..481b80a609942 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -2526,15 +2526,6 @@ bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) * are likely to increase the throughput. */ bfqq->new_bfqq = new_bfqq; - /* - * The above assignment schedules the following redirections: - * each time some I/O for bfqq arrives, the process that - * generated that I/O is disassociated from bfqq and - * associated with new_bfqq. Here we increases new_bfqq->ref - * in advance, adding the number of processes that are - * expected to be associated with new_bfqq as they happen to - * issue I/O. - */ new_bfqq->ref += process_refs; return new_bfqq; } @@ -2594,10 +2585,6 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, { struct bfq_queue *in_service_bfqq, *new_bfqq; - /* if a merge has already been setup, then proceed with that first */ - if (bfqq->new_bfqq) - return bfqq->new_bfqq; - /* * Do not perform queue merging if the device is non * rotational and performs internal queueing. In fact, such a @@ -2652,6 +2639,9 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, if (bfq_too_late_for_merging(bfqq)) return NULL; + if (bfqq->new_bfqq) + return bfqq->new_bfqq; + if (!io_struct || unlikely(bfqq == &bfqd->oom_bfqq)) return NULL; @@ -4806,7 +4796,7 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx) struct bfq_data *bfqd = hctx->queue->elevator->elevator_data; struct request *rq; struct bfq_queue *in_serv_queue; - bool waiting_rq, idle_timer_disabled = false; + bool waiting_rq, idle_timer_disabled; spin_lock_irq(&bfqd->lock); @@ -4814,15 +4804,14 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx) waiting_rq = in_serv_queue && bfq_bfqq_wait_request(in_serv_queue); rq = __bfq_dispatch_request(hctx); - if (in_serv_queue == bfqd->in_service_queue) { - idle_timer_disabled = - waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); - } + + idle_timer_disabled = + waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); spin_unlock_irq(&bfqd->lock); - bfq_update_dispatch_stats(hctx->queue, rq, - idle_timer_disabled ? in_serv_queue : NULL, - idle_timer_disabled); + + bfq_update_dispatch_stats(hctx->queue, rq, in_serv_queue, + idle_timer_disabled); return rq; } diff --git a/block/blk-merge.c b/block/blk-merge.c index 006b1f0a59bc5..26f4bcc10de9d 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -7,7 +7,6 @@ #include #include #include -#include #include @@ -555,9 +554,6 @@ static inline unsigned int blk_rq_get_max_segments(struct request *rq) static inline int ll_new_hw_segment(struct request *req, struct bio *bio, unsigned int nr_phys_segs) { - if (!blk_cgroup_mergeable(req, bio)) - goto no_merge; - if (blk_integrity_merge_bio(req->q, req, bio) == false) goto no_merge; @@ -654,9 +650,6 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, if (total_phys_segments > blk_rq_get_max_segments(req)) return 0; - if (!blk_cgroup_mergeable(req, next->bio)) - return 0; - if (blk_integrity_merge_rq(q, req, next) == false) return 0; @@ -868,10 +861,6 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (rq->rq_disk != bio->bi_disk) return false; - /* don't merge across cgroup boundaries */ - if (!blk_cgroup_mergeable(rq, bio)) - return false; - /* only merge integrity protected bio into ditto rq */ if (blk_integrity_merge_bio(rq->q, rq, bio) == false) return false; diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e0117f5f969de..24c08963890e9 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -194,18 +194,11 @@ static int __blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx) static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx) { - unsigned long end = jiffies + HZ; int ret; do { ret = __blk_mq_do_dispatch_sched(hctx); - if (ret != 1) - break; - if (need_resched() || time_is_before_jiffies(end)) { - blk_mq_delay_run_hw_queue(hctx, 0); - break; - } - } while (1); + } while (ret == 1); return ret; } diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 8c5816364dd17..b513f1683af06 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -958,17 +958,15 @@ void blk_unregister_queue(struct gendisk *disk) */ if (queue_is_mq(q)) blk_mq_unregister_dev(disk_to_dev(disk), q); + + kobject_uevent(&q->kobj, KOBJ_REMOVE); + kobject_del(&q->kobj); blk_trace_remove_sysfs(disk_to_dev(disk)); mutex_lock(&q->sysfs_lock); if (q->elevator) elv_unregister_queue(q); mutex_unlock(&q->sysfs_lock); - - /* Now that we've deleted all child objects, we can delete the queue. */ - kobject_uevent(&q->kobj, KOBJ_REMOVE); - kobject_del(&q->kobj); - mutex_unlock(&q->sysfs_dir_lock); kobject_put(&disk_to_dev(disk)->kobj); diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 0c6e2b3cf98eb..6556aa2182a53 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -860,7 +860,7 @@ SHOW_JIFFIES(deadline_write_expire_show, dd->fifo_expire[DD_WRITE]); SHOW_JIFFIES(deadline_prio_aging_expire_show, dd->prio_aging_expire); SHOW_INT(deadline_writes_starved_show, dd->writes_starved); SHOW_INT(deadline_front_merges_show, dd->front_merges); -SHOW_INT(deadline_async_depth_show, dd->front_merges); +SHOW_INT(deadline_async_depth_show, dd->async_depth); SHOW_INT(deadline_fifo_batch_show, dd->fifo_batch); #undef SHOW_INT #undef SHOW_JIFFIES @@ -890,7 +890,7 @@ STORE_JIFFIES(deadline_write_expire_store, &dd->fifo_expire[DD_WRITE], 0, INT_MA STORE_JIFFIES(deadline_prio_aging_expire_store, &dd->prio_aging_expire, 0, INT_MAX); STORE_INT(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX); STORE_INT(deadline_front_merges_store, &dd->front_merges, 0, 1); -STORE_INT(deadline_async_depth_store, &dd->front_merges, 1, INT_MAX); +STORE_INT(deadline_async_depth_store, &dd->async_depth, 1, INT_MAX); STORE_INT(deadline_fifo_batch_store, &dd->fifo_batch, 0, INT_MAX); #undef STORE_FUNCTION #undef STORE_INT diff --git a/build.config.common b/build.config.common index 3885d4604ab2e..a07fb7f8c0120 100644 --- a/build.config.common +++ b/build.config.common @@ -1,6 +1,6 @@ . ${ROOT_DIR}/${KERNEL_DIR}/build.config.constants -KMI_GENERATION=1 +KMI_GENERATION=4 LLVM=1 DEPMOD=depmod @@ -8,6 +8,7 @@ CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-${CLANG_VERSION}/bin BUILDTOOLS_PREBUILT_BIN=build/kernel/build-tools/path/linux-x86 DTC=${ROOT_DIR}/${BUILDTOOLS_PREBUILT_BIN}/dtc +KCFLAGS="${KCFLAGS} -D__ANDROID_COMMON_KERNEL__" EXTRA_CMDS='' STOP_SHIP_TRACEPRINTK=1 IN_KERNEL_MODULES=1 diff --git a/build.config.constants b/build.config.constants index 5094eea3655f5..028ad6a847497 100644 --- a/build.config.constants +++ b/build.config.constants @@ -1,2 +1,2 @@ BRANCH=android13-5.10 -CLANG_VERSION=r445002 +CLANG_VERSION=r450784e diff --git a/build.config.gki.aarch64 b/build.config.gki.aarch64 index ad0078a7fee7f..2e7f202446bf3 100644 --- a/build.config.gki.aarch64 +++ b/build.config.gki.aarch64 @@ -35,3 +35,5 @@ MODULES_ORDER=android/gki_aarch64_modules if [ -n "${GKI_DEFCONFIG_FRAGMENT}" ]; then source ${GKI_DEFCONFIG_FRAGMENT} fi + +BUILD_GKI_CERTIFICATION_TOOLS=1 diff --git a/build.config.gki.x86_64 b/build.config.gki.x86_64 index b8f7773108e40..739ae0b86e0d2 100644 --- a/build.config.gki.x86_64 +++ b/build.config.gki.x86_64 @@ -4,3 +4,5 @@ BUILD_SYSTEM_DLKM=1 MODULES_LIST=${ROOT_DIR}/${KERNEL_DIR}/android/gki_system_dlkm_modules + +BUILD_GKI_CERTIFICATION_TOOLS=1 diff --git a/crypto/authenc.c b/crypto/authenc.c index 17f674a7cdff5..670bf1a01d00e 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -253,7 +253,7 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req, dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); skcipher_request_set_tfm(skreq, ctx->enc); - skcipher_request_set_callback(skreq, flags, + skcipher_request_set_callback(skreq, aead_request_flags(req), req->base.complete, req->base.data); skcipher_request_set_crypt(skreq, src, dst, req->cryptlen - authsize, req->iv); diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 9d804831c8b3f..8ac3e73e8ea65 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -476,8 +476,6 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) pos++; if (digest_info) { - if (digest_info->size > dst_len - pos) - goto done; if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) goto done; @@ -497,7 +495,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) sg_nents_for_len(req->src, req->src_len + req->dst_len), req_ctx->out_buf + ctx->key_size, - req->dst_len, req->src_len); + req->dst_len, ctx->key_size); /* Do the actual verification step. */ if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos, req->dst_len) != 0) @@ -540,7 +538,7 @@ static int pkcs1pad_verify(struct akcipher_request *req) if (WARN_ON(req->dst) || WARN_ON(!req->dst_len) || - !ctx->key_size || req->src_len != ctx->key_size) + !ctx->key_size || req->src_len < ctx->key_size) return -EINVAL; req_ctx->out_buf = kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL); @@ -623,11 +621,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn); - if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) { - err = -EINVAL; - goto err_free_inst; - } - err = -ENAMETOOLONG; hash_name = crypto_attr_alg_name(tb[2]); if (IS_ERR(hash_name)) { diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 901fa5ca284d2..b7f3e8603ad84 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -169,9 +169,6 @@ acpi_ns_walk_namespace(acpi_object_type type, if (start_node == ACPI_ROOT_OBJECT) { start_node = acpi_gbl_root_node; - if (!start_node) { - return_ACPI_STATUS(AE_NO_NAMESPACE); - } } /* Null child means "get first node" */ diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c index 598fd19b65fa4..19e50fcbf4d6f 100644 --- a/drivers/acpi/apei/bert.c +++ b/drivers/acpi/apei/bert.c @@ -29,7 +29,6 @@ #undef pr_fmt #define pr_fmt(fmt) "BERT: " fmt -#define ACPI_BERT_PRINT_MAX_LEN 1024 static int bert_disable; @@ -59,11 +58,8 @@ static void __init bert_print_all(struct acpi_bert_region *region, } pr_info_once("Error records from previous boot:\n"); - if (region_len < ACPI_BERT_PRINT_MAX_LEN) - cper_estatus_print(KERN_INFO HW_ERR, estatus); - else - pr_info_once("Max print length exceeded, table data is available at:\n" - "/sys/firmware/acpi/tables/data/BERT"); + + cper_estatus_print(KERN_INFO HW_ERR, estatus); /* * Because the boot error source is "one-time polled" type, @@ -81,7 +77,7 @@ static int __init setup_bert_disable(char *str) { bert_disable = 1; - return 1; + return 0; } __setup("bert_disable", setup_bert_disable); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 83efb52a3f31d..2e0b0fcad9607 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -891,7 +891,7 @@ EXPORT_SYMBOL_GPL(erst_clear); static int __init setup_erst_disable(char *str) { erst_disable = 1; - return 1; + return 0; } __setup("erst_disable", setup_erst_disable); diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 7bf48c2776fbf..6e980fe16772c 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -219,7 +219,7 @@ err: static int __init setup_hest_disable(char *str) { hest_disable = HEST_DISABLED; - return 1; + return 0; } __setup("hest_disable", setup_hest_disable); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index be743d177bcbf..2376f57b3617a 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -66,10 +66,6 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, - - /* Microsoft Surface Go 3 */ - {"MSHW0146", 0}, - {"", 0}, }; @@ -1175,14 +1171,6 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"), }, }, - { - /* Microsoft Surface Go 3 */ - .callback = battery_notification_delay_quirk, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"), - }, - }, {}, }; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 2ac0773326e9a..0a2da06e9d8bf 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -719,11 +719,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj = &out_obj->package.elements[0]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { num_ent = cpc_obj->integer.value; - if (num_ent <= 1) { - pr_debug("Unexpected _CPC NumEntries value (%d) for CPU:%d\n", - num_ent, pr->id); - goto out_free; - } } else { pr_debug("Unexpected entry type(%d) for NumEntries\n", cpc_obj->type); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 35ecb57514cac..592e1ee9b338d 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -685,7 +685,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, */ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) { if (index) - return -ENOENT; + return -EINVAL; ret = acpi_bus_get_device(obj->reference.handle, &device); if (ret) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 7b9793cb55c50..33474fd969913 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -409,81 +409,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), }, }, - /* - * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a - * working native and video interface. However the default detection - * mechanism first registers the video interface before unregistering - * it again and switching to the native interface during boot. This - * results in a dangling SBIOS request for backlight change for some - * reason, causing the backlight to switch to ~2% once per boot on the - * first power cord connect or disconnect event. Setting the native - * interface explicitly circumvents this buggy behaviour, by avoiding - * the unregistering process. - */ - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "AURA1501"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, /* * Desktops which falsely report a backlight and which our heuristics diff --git a/drivers/android/binder.c b/drivers/android/binder.c index bcf0ae355bc64..f13562617e638 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2723,6 +2723,12 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_binder; } e->to_node = target_node->debug_id; + if (WARN_ON(proc == target_proc)) { + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } trace_android_vh_binder_trans(target_proc, proc, thread, tr); if (security_binder_transaction(proc->cred, target_proc->cred) < 0) { @@ -2892,7 +2898,7 @@ static void binder_transaction(struct binder_proc *proc, if (extra_buffers_size < added_size) { /* integer overflow of extra_buffers_size */ return_error = BR_FAILED_REPLY; - return_error_param = EINVAL; + return_error_param = -EINVAL; return_error_line = __LINE__; goto err_bad_extra_size; } @@ -3420,10 +3426,17 @@ static int binder_thread_write(struct binder_proc *proc, struct binder_node *ctx_mgr_node; mutex_lock(&context->context_mgr_node_lock); ctx_mgr_node = context->binder_context_mgr_node; - if (ctx_mgr_node) + if (ctx_mgr_node) { + if (ctx_mgr_node->proc == proc) { + binder_user_error("%d:%d context manager tried to acquire desc 0\n", + proc->pid, thread->pid); + mutex_unlock(&context->context_mgr_node_lock); + return -EINVAL; + } ret = binder_inc_ref_for_node( proc, ctx_mgr_node, strong, NULL, &rdata); + } mutex_unlock(&context->context_mgr_node_lock); } if (ret) diff --git a/drivers/android/vendor_hooks.c b/drivers/android/vendor_hooks.c index a72414c52a5a1..e8773213ed4c5 100644 --- a/drivers/android/vendor_hooks.c +++ b/drivers/android/vendor_hooks.c @@ -8,6 +8,7 @@ #define CREATE_TRACE_POINTS #include +#include #include #include #include @@ -72,6 +73,8 @@ #include #include #include +#include +#include /* * Export tracepoints that act as a bare tracehook (ie: have no trace event @@ -382,3 +385,15 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_enable_thermal_power_throttle); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_thermal_power_cap); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_thermal_zone_device); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpm_modify_src_caps); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_grab_compound_head); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh___get_user_pages_remote); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_user_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_internal_get_user_pages_fast); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_pin_user_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_attach_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_detach_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_remove_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_blocked_fair); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_rt_rq_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 9fcc49be499f1..b574cce98dc36 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1112,8 +1112,6 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); skb_data3 = skb->data[3]; paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) - return enq_next; ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b1b8f480a752a..d3b33edc40ece 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -771,7 +771,7 @@ static int __init save_async_options(char *buf) pr_warn("Too long list of driver names for 'driver_async_probe'!\n"); strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); - return 1; + return 0; } __setup("driver_async_probe=", save_async_options); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a1ae1c43f3c0d..1ec4520d77a93 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -2005,9 +2005,7 @@ static bool pm_ops_is_empty(const struct dev_pm_ops *ops) void device_pm_check_callbacks(struct device *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->power.lock, flags); + spin_lock_irq(&dev->power.lock); dev->power.no_pm_callbacks = (!dev->bus || (pm_ops_is_empty(dev->bus->pm) && !dev->bus->suspend && !dev->bus->resume)) && @@ -2016,7 +2014,7 @@ void device_pm_check_callbacks(struct device *dev) (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && (!dev->driver || (pm_ops_is_empty(dev->driver->pm) && !dev->driver->suspend && !dev->driver->resume)); - spin_unlock_irqrestore(&dev->power.lock, flags); + spin_unlock_irq(&dev->power.lock); } bool dev_pm_skip_suspend(struct device *dev) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 69638146f949c..330f851cb8f0b 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -177,8 +177,7 @@ void start_new_tl_epoch(struct drbd_connection *connection) void complete_master_bio(struct drbd_device *device, struct bio_and_error *m) { - if (unlikely(m->error)) - m->bio->bi_status = errno_to_blk_status(m->error); + m->bio->bi_status = errno_to_blk_status(m->error); bio_endio(m->bio); dec_ap_bio(device); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 64994c39a1174..dea24990d270b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -797,33 +797,33 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) { - return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_offset); + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset); } static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) { - return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); } static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) { int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR); - return sysfs_emit(buf, "%s\n", autoclear ? "1" : "0"); + return sprintf(buf, "%s\n", autoclear ? "1" : "0"); } static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) { int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN); - return sysfs_emit(buf, "%s\n", partscan ? "1" : "0"); + return sprintf(buf, "%s\n", partscan ? "1" : "0"); } static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf) { int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO); - return sysfs_emit(buf, "%s\n", dio ? "1" : "0"); + return sprintf(buf, "%s\n", dio ? "1" : "0"); } LOOP_ATTR_RO(backing_file); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 263c0cd1aa167..73f30b5c2f523 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -843,7 +843,7 @@ static int virtblk_probe(struct virtio_device *vdev) dev_err(&vdev->dev, "virtio_blk: invalid block size: 0x%x\n", blk_size); - goto out_free_tags; + goto out_cleanup_disk; } blk_queue_logical_block_size(q, blk_size); @@ -914,6 +914,8 @@ static int virtblk_probe(struct virtio_device *vdev) device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); return 0; +out_cleanup_disk: + blk_cleanup_queue(vblk->disk->queue); out_free_tags: blk_mq_free_tag_set(&vblk->tag_set); out_put_disk: diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index c41560be39fb6..74856a5862162 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -981,8 +981,6 @@ static int btmtksdio_probe(struct sdio_func *func, hdev->manufacturer = 70; set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); - sdio_set_drvdata(func, bdev); - err = hci_register_dev(hdev); if (err < 0) { dev_err(&func->dev, "Can't register HCI device\n"); @@ -990,6 +988,8 @@ static int btmtksdio_probe(struct sdio_func *func, return err; } + sdio_set_drvdata(func, bdev); + /* pm_runtime_enable would be done after the firmware is being * downloaded because the core layer probably already enables * runtime PM for this func such as the case host->caps & diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index e9a44ab3812df..9e03402ef1b37 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -305,8 +305,6 @@ int hci_uart_register_device(struct hci_uart *hu, if (err) return err; - percpu_init_rwsem(&hu->proto_lock); - err = p->open(hu); if (err) goto err_open; @@ -329,6 +327,7 @@ int hci_uart_register_device(struct hci_uart *hu, INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); + percpu_init_rwsem(&hu->proto_lock); /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index fca0d0669aa97..626dedd110cbc 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -351,7 +351,6 @@ phys_addr_t __weak mips_cdmm_phys_base(void) np = of_find_compatible_node(NULL, NULL, "mti,mips-cdmm"); if (np) { err = of_address_to_resource(np, 0, &res); - of_node_put(np); if (!err) return res.start; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index a7d9e4600d40e..5952210526aaa 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -427,7 +427,7 @@ config HW_RANDOM_MESON config HW_RANDOM_CAVIUM tristate "Cavium ThunderX Random Number Generator support" - depends on HW_RANDOM && PCI && ARCH_THUNDER + depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT)) default HW_RANDOM help This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 8cf0ef501341e..ecb71c4317a50 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -114,7 +114,6 @@ static int atmel_trng_probe(struct platform_device *pdev) err_register: clk_disable_unprepare(trng->clk); - atmel_trng_disable(trng); return ret; } diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c index 6f66919652bf5..3de4a6a443ef9 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -1,7 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support. - * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. + * Hardware Random Number Generator support for Cavium, Inc. + * Thunder processor family. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * * Copyright (C) 2016 Cavium, Inc. */ @@ -12,146 +15,16 @@ #include #include -#include - -/* PCI device IDs */ -#define PCI_DEVID_CAVIUM_RNG_PF 0xA018 -#define PCI_DEVID_CAVIUM_RNG_VF 0xA033 - -#define HEALTH_STATUS_REG 0x38 - -/* RST device info */ -#define PCI_DEVICE_ID_RST_OTX2 0xA085 -#define RST_BOOT_REG 0x1600ULL -#define CLOCK_BASE_RATE 50000000ULL -#define MSEC_TO_NSEC(x) (x * 1000000) - struct cavium_rng { struct hwrng ops; void __iomem *result; - void __iomem *pf_regbase; - struct pci_dev *pdev; - u64 clock_rate; - u64 prev_error; - u64 prev_time; }; -static inline bool is_octeontx(struct pci_dev *pdev) -{ - if (midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_83XX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0)) || - midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_81XX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0)) || - midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0))) - return true; - - return false; -} - -static u64 rng_get_coprocessor_clkrate(void) -{ - u64 ret = CLOCK_BASE_RATE * 16; /* Assume 800Mhz as default */ - struct pci_dev *pdev; - void __iomem *base; - - pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVICE_ID_RST_OTX2, NULL); - if (!pdev) - goto error; - - base = pci_ioremap_bar(pdev, 0); - if (!base) - goto error_put_pdev; - - /* RST: PNR_MUL * 50Mhz gives clockrate */ - ret = CLOCK_BASE_RATE * ((readq(base + RST_BOOT_REG) >> 33) & 0x3F); - - iounmap(base); - -error_put_pdev: - pci_dev_put(pdev); - -error: - return ret; -} - -static int check_rng_health(struct cavium_rng *rng) -{ - u64 cur_err, cur_time; - u64 status, cycles; - u64 time_elapsed; - - - /* Skip checking health for OcteonTx */ - if (!rng->pf_regbase) - return 0; - - status = readq(rng->pf_regbase + HEALTH_STATUS_REG); - if (status & BIT_ULL(0)) { - dev_err(&rng->pdev->dev, "HWRNG: Startup health test failed\n"); - return -EIO; - } - - cycles = status >> 1; - if (!cycles) - return 0; - - cur_time = arch_timer_read_counter(); - - /* RNM_HEALTH_STATUS[CYCLES_SINCE_HEALTH_FAILURE] - * Number of coprocessor cycles times 2 since the last failure. - * This field doesn't get cleared/updated until another failure. - */ - cycles = cycles / 2; - cur_err = (cycles * 1000000000) / rng->clock_rate; /* In nanosec */ - - /* Ignore errors that happenned a long time ago, these - * are most likely false positive errors. - */ - if (cur_err > MSEC_TO_NSEC(10)) { - rng->prev_error = 0; - rng->prev_time = 0; - return 0; - } - - if (rng->prev_error) { - /* Calculate time elapsed since last error - * '1' tick of CNTVCT is 10ns, since it runs at 100Mhz. - */ - time_elapsed = (cur_time - rng->prev_time) * 10; - time_elapsed += rng->prev_error; - - /* Check if current error is a new one or the old one itself. - * If error is a new one then consider there is a persistent - * issue with entropy, declare hardware failure. - */ - if (cur_err < time_elapsed) { - dev_err(&rng->pdev->dev, "HWRNG failure detected\n"); - rng->prev_error = cur_err; - rng->prev_time = cur_time; - return -EIO; - } - } - - rng->prev_error = cur_err; - rng->prev_time = cur_time; - return 0; -} - /* Read data from the RNG unit */ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) { struct cavium_rng *p = container_of(rng, struct cavium_rng, ops); unsigned int size = max; - int err = 0; - - err = check_rng_health(p); - if (err) - return err; while (size >= 8) { *((u64 *)dat) = readq(p->result); @@ -166,39 +39,6 @@ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) return max; } -static int cavium_map_pf_regs(struct cavium_rng *rng) -{ - struct pci_dev *pdev; - - /* Health status is not supported on 83xx, skip mapping PF CSRs */ - if (is_octeontx(rng->pdev)) { - rng->pf_regbase = NULL; - return 0; - } - - pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVID_CAVIUM_RNG_PF, NULL); - if (!pdev) { - dev_err(&pdev->dev, "Cannot find RNG PF device\n"); - return -EIO; - } - - rng->pf_regbase = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!rng->pf_regbase) { - dev_err(&pdev->dev, "Failed to map PF CSR region\n"); - pci_dev_put(pdev); - return -ENOMEM; - } - - pci_dev_put(pdev); - - /* Get co-processor clock rate */ - rng->clock_rate = rng_get_coprocessor_clkrate(); - - return 0; -} - /* Map Cavium RNG to an HWRNG object */ static int cavium_rng_probe_vf(struct pci_dev *pdev, const struct pci_device_id *id) @@ -210,8 +50,6 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, if (!rng) return -ENOMEM; - rng->pdev = pdev; - /* Map the RNG result */ rng->result = pcim_iomap(pdev, 0, 0); if (!rng->result) { @@ -229,11 +67,6 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, pci_set_drvdata(pdev, rng); - /* Health status is available only at PF, hence map PF registers. */ - ret = cavium_map_pf_regs(rng); - if (ret) - return ret; - ret = devm_hwrng_register(&pdev->dev, &rng->ops); if (ret) { dev_err(&pdev->dev, "Error registering device as HWRNG.\n"); @@ -243,18 +76,10 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return 0; } -/* Remove the VF */ -static void cavium_rng_remove_vf(struct pci_dev *pdev) -{ - struct cavium_rng *rng; - - rng = pci_get_drvdata(pdev); - iounmap(rng->pf_regbase); -} static const struct pci_device_id cavium_rng_vf_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CAVIUM_RNG_VF) }, - { 0, } + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0}, + {0,}, }; MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table); @@ -262,9 +87,8 @@ static struct pci_driver cavium_rng_vf_driver = { .name = "cavium_rng_vf", .id_table = cavium_rng_vf_id_table, .probe = cavium_rng_probe_vf, - .remove = cavium_rng_remove_vf, }; module_pci_driver(cavium_rng_vf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c index b96579222408b..63d6e68c24d2f 100644 --- a/drivers/char/hw_random/cavium-rng.c +++ b/drivers/char/hw_random/cavium-rng.c @@ -1,7 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support. - * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. + * Hardware Random Number Generator support for Cavium Inc. + * Thunder processor family. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * * Copyright (C) 2016 Cavium, Inc. */ @@ -88,4 +91,4 @@ static struct pci_driver cavium_rng_pf_driver = { module_pci_driver(cavium_rng_pf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index e8f9621e79541..67947a19aa225 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -65,14 +65,14 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) out_release: amba_release_regions(dev); out_clk: - clk_disable_unprepare(rng_clk); + clk_disable(rng_clk); return ret; } static void nmk_rng_remove(struct amba_device *dev) { amba_release_regions(dev); - clk_disable_unprepare(rng_clk); + clk_disable(rng_clk); } static const struct amba_id nmk_rng_ids[] = { diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ed600473ad7e3..ddaeceb7e1091 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -274,6 +274,14 @@ static void tpm_dev_release(struct device *dev) kfree(chip); } +static void tpm_devs_release(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); + + /* release the master device reference */ + put_device(&chip->dev); +} + /** * tpm_class_shutdown() - prepare the TPM device for loss of power. * @dev: device to which the chip is associated. @@ -336,6 +344,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev_num = rc; device_initialize(&chip->dev); + device_initialize(&chip->devs); chip->dev.class = tpm_class; chip->dev.class->shutdown_pre = tpm_class_shutdown; @@ -343,12 +352,29 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev.parent = pdev; chip->dev.groups = chip->groups; + chip->devs.parent = pdev; + chip->devs.class = tpmrm_class; + chip->devs.release = tpm_devs_release; + /* get extra reference on main device to hold on + * behalf of devs. This holds the chip structure + * while cdevs is in use. The corresponding put + * is in the tpm_devs_release (TPM2 only) + */ + if (chip->flags & TPM_CHIP_FLAG_TPM2) + get_device(&chip->dev); + if (chip->dev_num == 0) chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); else chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + chip->devs.devt = + MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); + rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); + if (rc) + goto out; + rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); if (rc) goto out; @@ -356,7 +382,9 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->flags |= TPM_CHIP_FLAG_VIRTUAL; cdev_init(&chip->cdev, &tpm_fops); + cdev_init(&chip->cdevs, &tpmrm_fops); chip->cdev.owner = THIS_MODULE; + chip->cdevs.owner = THIS_MODULE; rc = tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE); if (rc) { @@ -368,6 +396,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, return chip; out: + put_device(&chip->devs); put_device(&chip->dev); return ERR_PTR(rc); } @@ -416,9 +445,14 @@ static int tpm_add_char_device(struct tpm_chip *chip) } if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm_devs_add(chip); - if (rc) - goto err_del_cdev; + rc = cdev_device_add(&chip->cdevs, &chip->devs); + if (rc) { + dev_err(&chip->devs, + "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", + dev_name(&chip->devs), MAJOR(chip->devs.devt), + MINOR(chip->devs.devt), rc); + return rc; + } } /* Make the chip available. */ @@ -426,10 +460,6 @@ static int tpm_add_char_device(struct tpm_chip *chip) idr_replace(&dev_nums_idr, chip, chip->dev_num); mutex_unlock(&idr_lock); - return 0; - -err_del_cdev: - cdev_device_del(&chip->cdev, &chip->dev); return rc; } @@ -611,7 +641,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm_devs_remove(chip); + cdev_device_del(&chip->cdevs, &chip->devs); tpm_del_char_device(chip); } EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index b99e1941c52c9..1784530b8387b 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -70,13 +70,7 @@ static void tpm_dev_async_work(struct work_struct *work) ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); - - /* - * If ret is > 0 then tpm_dev_transmit returned the size of the - * response. If ret is < 0 then tpm_dev_transmit failed and - * returned an error code. - */ - if (ret != 0) { + if (ret > 0) { priv->response_length = ret; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2163c6ee0d364..283f78211c3a7 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -234,8 +234,6 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd, size_t cmdsiz); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf, size_t *bufsiz); -int tpm_devs_add(struct tpm_chip *chip); -void tpm_devs_remove(struct tpm_chip *chip); void tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index ffb35f0154c16..97e916856cf3e 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -58,12 +58,12 @@ int tpm2_init_space(struct tpm_space *space, unsigned int buf_size) void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) { - - if (tpm_try_get_ops(chip) == 0) { + mutex_lock(&chip->tpm_mutex); + if (!tpm_chip_start(chip)) { tpm2_flush_sessions(chip, space); - tpm_put_ops(chip); + tpm_chip_stop(chip); } - + mutex_unlock(&chip->tpm_mutex); kfree(space->context_buf); kfree(space->session_buf); } @@ -574,68 +574,3 @@ out: dev_err(&chip->dev, "%s: error %d\n", __func__, rc); return rc; } - -/* - * Put the reference to the main device. - */ -static void tpm_devs_release(struct device *dev) -{ - struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); - - /* release the master device reference */ - put_device(&chip->dev); -} - -/* - * Remove the device file for exposed TPM spaces and release the device - * reference. This may also release the reference to the master device. - */ -void tpm_devs_remove(struct tpm_chip *chip) -{ - cdev_device_del(&chip->cdevs, &chip->devs); - put_device(&chip->devs); -} - -/* - * Add a device file to expose TPM spaces. Also take a reference to the - * main device. - */ -int tpm_devs_add(struct tpm_chip *chip) -{ - int rc; - - device_initialize(&chip->devs); - chip->devs.parent = chip->dev.parent; - chip->devs.class = tpmrm_class; - - /* - * Get extra reference on main device to hold on behalf of devs. - * This holds the chip structure while cdevs is in use. The - * corresponding put is in the tpm_devs_release. - */ - get_device(&chip->dev); - chip->devs.release = tpm_devs_release; - chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); - cdev_init(&chip->cdevs, &tpmrm_fops); - chip->cdevs.owner = THIS_MODULE; - - rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); - if (rc) - goto err_put_devs; - - rc = cdev_device_add(&chip->cdevs, &chip->devs); - if (rc) { - dev_err(&chip->devs, - "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", - dev_name(&chip->devs), MAJOR(chip->devs.devt), - MINOR(chip->devs.devt), rc); - goto err_put_devs; - } - - return 0; - -err_put_devs: - put_device(&chip->devs); - - return rc; -} diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index c90db9fb5d8d7..a5e9d1a8a53c2 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1960,13 +1960,6 @@ static void virtcons_remove(struct virtio_device *vdev) list_del(&portdev->list); spin_unlock_irq(&pdrvdata_lock); - /* Device is going away, exit any polling for buffers */ - virtio_break_device(vdev); - if (use_multiport(portdev)) - flush_work(&portdev->control_work); - else - flush_work(&portdev->config_work); - /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c index 6ea7da1d6d755..a2f34d13fb543 100644 --- a/drivers/clk/actions/owl-s700.c +++ b/drivers/clk/actions/owl-s700.c @@ -162,7 +162,6 @@ static struct clk_div_table hdmia_div_table[] = { static struct clk_div_table rmii_div_table[] = { {0, 4}, {1, 10}, - {0, 0} }; /* divider clocks */ diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c index 5144ada2c7e1a..790890978424a 100644 --- a/drivers/clk/actions/owl-s900.c +++ b/drivers/clk/actions/owl-s900.c @@ -140,7 +140,7 @@ static struct clk_div_table rmii_ref_div_table[] = { static struct clk_div_table usb3_mac_div_table[] = { { 1, 2 }, { 2, 3 }, { 3, 4 }, - { 0, 0 } + { 0, 8 }, }; static struct clk_div_table i2s_div_table[] = { diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 9d25b23fb99d7..a092a940baa40 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -606,16 +606,16 @@ static const struct { { .n = "pdmc0_gclk", .id = 68, .r = { .max = 50000000 }, - .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, - .pp_mux_table = { 5, 9, }, + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, + .pp_mux_table = { 5, 8, }, .pp_count = 2, .pp_chg_id = INT_MIN, }, { .n = "pdmc1_gclk", .id = 69, .r = { .max = 50000000, }, - .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, - .pp_mux_table = { 5, 9, }, + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, + .pp_mux_table = { 5, 8, }, .pp_count = 2, .pp_chg_id = INT_MIN, }, diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index f8417ee2961aa..a2c6486ef1708 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -28,13 +28,11 @@ static const struct clk_div_table spi_div_table[] = { { .val = 1, .div = 8, }, { .val = 2, .div = 2, }, { .val = 3, .div = 1, }, - { /* sentinel */ } }; static const struct clk_div_table timer_div_table[] = { { .val = 0, .div = 256, }, { .val = 1, .div = 1, }, - { /* sentinel */ } }; struct clps711x_clk { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 67ff7d9b74e96..411ca7a1c0882 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3446,19 +3446,6 @@ static void clk_core_reparent_orphans_nolock(void) __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); __clk_core_update_orphan_hold_state(orphan); - - /* - * __clk_init_parent() will set the initial req_rate to - * 0 if the clock doesn't have clk_ops::recalc_rate and - * is an orphan when it's registered. - * - * 'req_rate' is used by clk_set_rate_range() and - * clk_put() to trigger a clk_set_rate() call whenever - * the boundaries are modified. Let's make sure - * 'req_rate' is set to something non-zero so that - * clk_set_rate_range() doesn't drop the frequency. - */ - orphan->req_rate = orphan->rate; } } } diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 3f6fd7ef2a68f..c4e0f1c07192f 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -849,6 +849,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0); hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0); hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0); + hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0); hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0); hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0); hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0); diff --git a/drivers/clk/loongson1/clk-loongson1c.c b/drivers/clk/loongson1/clk-loongson1c.c index 1ebf740380efb..703f87622cf5f 100644 --- a/drivers/clk/loongson1/clk-loongson1c.c +++ b/drivers/clk/loongson1/clk-loongson1c.c @@ -37,7 +37,6 @@ static const struct clk_div_table ahb_div_table[] = { [1] = { .val = 1, .div = 4 }, [2] = { .val = 2, .div = 3 }, [3] = { .val = 3, .div = 3 }, - [4] = { /* sentinel */ } }; void __init ls1x_clk_init(void) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 71a0d30cf44df..59a5a0f261f33 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -264,7 +264,7 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw *hw, static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) { - u32 cfg, mask, d_val, not2d_val, n_minus_m; + u32 cfg, mask; struct clk_hw *hw = &rcg->clkr.hw; int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src); @@ -283,17 +283,8 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) if (ret) return ret; - /* Calculate 2d value */ - d_val = f->n; - - n_minus_m = f->n - f->m; - n_minus_m *= 2; - - d_val = clamp_t(u32, d_val, f->m, n_minus_m); - not2d_val = ~d_val & mask; - ret = regmap_update_bits(rcg->clkr.regmap, - RCG_D_OFFSET(rcg), mask, not2d_val); + RCG_D_OFFSET(rcg), mask, ~f->n); if (ret) return ret; } @@ -648,7 +639,6 @@ static const struct frac_entry frac_table_pixel[] = { { 2, 9 }, { 4, 9 }, { 1, 1 }, - { 2, 3 }, { } }; diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 541016db3c4bb..108fe27bee10f 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -60,6 +60,11 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = { { P_GPLL0_DIV2, 4 }, }; +static const char * const gcc_xo_gpll0[] = { + "xo", + "gpll0", +}; + static const struct parent_map gcc_xo_gpll0_map[] = { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -951,11 +956,6 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src = { }, }; -static const struct clk_parent_data gcc_xo_gpll0[] = { - { .fw_name = "xo" }, - { .hw = &gpll0.clkr.hw }, -}; - static const struct freq_tbl ftbl_pcie_axi_clk_src[] = { F(19200000, P_XO, 1, 0, 0), F(200000000, P_GPLL0, 4, 0, 0), @@ -969,7 +969,7 @@ static struct clk_rcg2 pcie0_axi_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie0_axi_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -1016,7 +1016,7 @@ static struct clk_rcg2 pcie1_axi_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie1_axi_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -1074,7 +1074,7 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2, .num_parents = 4, - .ops = &clk_rcg2_floor_ops, + .ops = &clk_rcg2_ops, }, }; @@ -1330,7 +1330,7 @@ static struct clk_rcg2 nss_ce_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "nss_ce_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -4329,7 +4329,8 @@ static struct clk_rcg2 pcie0_rchng_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie0_rchng_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_hws = (const struct clk_hw *[]) { + &gpll0.clkr.hw }, .num_parents = 2, .ops = &clk_rcg2_ops, }, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 463a444c8a7e4..144d2ba7a9bef 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -108,7 +108,6 @@ static struct clk_alpha_pll gpll4_early = { static struct clk_alpha_pll_postdiv gpll4 = { .offset = 0x1dc0, - .width = 4, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data) { diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c index 733a962ff521a..745f9faa98d8e 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -191,7 +191,6 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) tegra->emc = platform_get_drvdata(pdev); if (!tegra->emc) { - put_device(&pdev->dev); pr_err("%s: cannot find EMC driver\n", __func__); return NULL; } diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c index 3bc55ab75314b..5319cd3804801 100644 --- a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c @@ -24,7 +24,6 @@ struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, init.name = name; init.ops = &clk_fixed_rate_ops; - init.flags = 0; init.parent_names = NULL; init.num_parents = 0; diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 279ddff81ab49..eb596ff9e7bb3 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -229,10 +229,8 @@ static int __init parse_pmtmr(char *arg) int ret; ret = kstrtouint(arg, 16, &base); - if (ret) { - pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg); - return 1; - } + if (ret) + return ret; pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport, base); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index df194b05e944c..fabad79baafce 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -494,14 +494,11 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) return 0; } -static int __init exynos4_timer_resources(struct device_node *np) +static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { + int err, cpu; struct clk *mct_clk, *tick_clk; - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: unable to ioremap mct address space\n", __func__); - tick_clk = of_clk_get_by_name(np, "fin_pll"); if (IS_ERR(tick_clk)) panic("%s: unable to determine tick clock rate\n", __func__); @@ -512,32 +509,9 @@ static int __init exynos4_timer_resources(struct device_node *np) panic("%s: unable to retrieve mct clock instance\n", __func__); clk_prepare_enable(mct_clk); - return 0; -} - -static int __init exynos4_timer_interrupts(struct device_node *np, - unsigned int int_type) -{ - int nr_irqs, i, err, cpu; - - mct_int_type = int_type; - - /* This driver uses only one global timer interrupt */ - mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); - - /* - * Find out the number of local irqs specified. The local - * timer irqs are specified after the four global timer - * irqs are specified. - */ - nr_irqs = of_irq_count(np); - if (nr_irqs > ARRAY_SIZE(mct_irqs)) { - pr_err("exynos-mct: too many (%d) interrupts configured in DT\n", - nr_irqs); - nr_irqs = ARRAY_SIZE(mct_irqs); - } - for (i = MCT_L0_IRQ; i < nr_irqs; i++) - mct_irqs[i] = irq_of_parse_and_map(np, i); + reg_base = base; + if (!reg_base) + panic("%s: unable to ioremap mct address space\n", __func__); if (mct_int_type == MCT_INT_PPI) { @@ -548,14 +522,11 @@ static int __init exynos4_timer_interrupts(struct device_node *np, mct_irqs[MCT_L0_IRQ], err); } else { for_each_possible_cpu(cpu) { - int mct_irq; + int mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu); pcpu_mevt->evt.irq = -1; - if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs)) - break; - mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; irq_set_status_flags(mct_irq, IRQ_NOAUTOEN); if (request_irq(mct_irq, @@ -600,13 +571,24 @@ out_irq: static int __init mct_init_dt(struct device_node *np, unsigned int int_type) { + u32 nr_irqs, i; int ret; - ret = exynos4_timer_resources(np); - if (ret) - return ret; + mct_int_type = int_type; + + /* This driver uses only one global timer interrupt */ + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); + + /* + * Find out the number of local irqs specified. The local + * timer irqs are specified after the four global timer + * irqs are specified. + */ + nr_irqs = of_irq_count(np); + for (i = MCT_L0_IRQ; i < nr_irqs; i++) + mct_irqs[i] = irq_of_parse_and_map(np, i); - ret = exynos4_timer_interrupts(np, int_type); + ret = exynos4_timer_resources(np, of_iomap(np, 0)); if (ret) return ret; diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index 5c9485cb4e059..59e11ca8ee73e 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -121,7 +121,7 @@ static u64 mchp_pit64b_clksrc_read(struct clocksource *cs) return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } -static u64 notrace mchp_pit64b_sched_read_clk(void) +static u64 mchp_pit64b_sched_read_clk(void) { return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index c5c84c7895f05..fd3b8686cba38 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -157,9 +157,9 @@ static int timer_of_base_init(struct device_node *np, of_base->base = of_base->name ? of_io_request_and_map(np, of_base->index, of_base->name) : of_iomap(np, of_base->index); - if (IS_ERR_OR_NULL(of_base->base)) { - pr_err("Failed to iomap (%s:%s)\n", np->name, of_base->name); - return of_base->base ? PTR_ERR(of_base->base) : -ENOMEM; + if (IS_ERR(of_base->base)) { + pr_err("Failed to iomap (%s)\n", of_base->name); + return PTR_ERR(of_base->base); } return 0; diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index 2737407ff0698..1fccb457fcc54 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -694,9 +694,9 @@ static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) return 0; } - if (pa == 0x4882c000) /* dra7 dmtimer15 */ + if (pa == 0x48034000) /* dra7 dmtimer3 */ return dmtimer_percpu_timer_init(np, 0); - else if (pa == 0x4882e000) /* dra7 dmtimer16 */ + else if (pa == 0x48036000) /* dra7 dmtimer4 */ return dmtimer_percpu_timer_init(np, 1); return 0; diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index 7fdd30e92e429..fba9937a406b3 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -130,7 +130,7 @@ static void get_krait_bin_format_b(struct device *cpu_dev, } /* Check PVS_BLOW_STATUS */ - pte_efuse = *(((u32 *)buf) + 1); + pte_efuse = *(((u32 *)buf) + 4); pte_efuse &= BIT(21); if (pte_efuse) { dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 64133d4da3d56..33707a2e55ff0 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -11,7 +11,6 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -281,9 +280,7 @@ static int sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) flow = rctx->flow; err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 62c07a724d40e..4c5a2c11d7141 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -9,7 +9,6 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -413,8 +412,6 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) theend: kfree(buf); kfree(result); - local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index f783748462f94..7c355bc2fb066 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -11,7 +11,6 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -272,9 +271,7 @@ static int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *ar struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); err = sun8i_ss_cipher(breq); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c index 319fe3279a716..80e89066dbd1a 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -30,8 +30,6 @@ static const struct ss_variant ss_a80_variant = { .alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES, }, - .alg_hash = { SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, - }, .op_mode = { SS_OP_ECB, SS_OP_CBC, }, .ss_clks = { diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c index c9edecd43ef96..756d5a7835482 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -9,7 +9,6 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -441,8 +440,6 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq) theend: kfree(pad); kfree(result); - local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c index 652e72d030bb0..8b5e07316352c 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c +++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c @@ -265,9 +265,7 @@ static int meson_handle_cipher_request(struct crypto_engine *engine, struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); err = meson_cipher(breq); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c index b3eea329f840f..0770a83bf1a57 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -633,20 +633,6 @@ static int ccp_terminate_all(struct dma_chan *dma_chan) return 0; } -static void ccp_dma_release(struct ccp_device *ccp) -{ - struct ccp_dma_chan *chan; - struct dma_chan *dma_chan; - unsigned int i; - - for (i = 0; i < ccp->cmd_q_count; i++) { - chan = ccp->ccp_dma_chan + i; - dma_chan = &chan->dma_chan; - tasklet_kill(&chan->cleanup_tasklet); - list_del_rcu(&dma_chan->device_node); - } -} - int ccp_dmaengine_register(struct ccp_device *ccp) { struct ccp_dma_chan *chan; @@ -751,7 +737,6 @@ int ccp_dmaengine_register(struct ccp_device *ccp) return 0; err_reg: - ccp_dma_release(ccp); kmem_cache_destroy(ccp->dma_desc_cache); err_cache: @@ -768,7 +753,6 @@ void ccp_dmaengine_unregister(struct ccp_device *ccp) return; dma_async_device_unregister(dma_dev); - ccp_dma_release(ccp); kmem_cache_destroy(ccp->dma_desc_cache); kmem_cache_destroy(ccp->dma_cmd_cache); diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c index 11e0278c8631d..a5e041d9d2cf1 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.c +++ b/drivers/crypto/ccree/cc_buffer_mgr.c @@ -258,13 +258,6 @@ static int cc_map_sg(struct device *dev, struct scatterlist *sg, { int ret = 0; - if (!nbytes) { - *mapped_nents = 0; - *lbytes = 0; - *nents = 0; - return 0; - } - *nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes); if (*nents > max_sg_nents) { *nents = 0; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index c289e4d5cbdc0..dafa6577a8451 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -254,8 +254,8 @@ static void cc_cipher_exit(struct crypto_tfm *tfm) &ctx_p->user.key_dma_addr); /* Free key buffer in context */ - dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); kfree_sensitive(ctx_p->user.key); + dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); } struct tdes_keys { diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index a9d3e675f7ff4..5edc91cdb4e65 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -330,7 +330,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); } - for_each_sg(req->src, src, sg_nents(req->src), i) { + for_each_sg(req->src, src, sg_nents(src), i) { src_buf = sg_virt(src); len = sg_dma_len(src); tlen += len; diff --git a/drivers/crypto/qat/qat_common/qat_crypto.c b/drivers/crypto/qat/qat_common/qat_crypto.c index 9210af8a1f58c..ab621b7dbd203 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/qat/qat_common/qat_crypto.c @@ -126,14 +126,6 @@ int qat_crypto_dev_config(struct adf_accel_dev *accel_dev) goto err; if (adf_cfg_section_add(accel_dev, "Accelerator0")) goto err; - - /* Temporarily set the number of crypto instances to zero to avoid - * registering the crypto algorithms. - * This will be removed when the algorithms will support the - * CRYPTO_TFM_REQ_MAY_BACKLOG flag - */ - instances = 0; - for (i = 0; i < instances; i++) { val = i; snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_BANK_NUM, i); diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index 11f30fd48c141..99ba8d51d1020 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -44,19 +43,16 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) { unsigned int currsize = 0; u32 val; - int ret; /* read random data from hardware */ do { - ret = readl_poll_timeout(rng->base + PRNG_STATUS, val, - val & PRNG_STATUS_DATA_AVAIL, - 200, 10000); - if (ret) - return ret; + val = readl_relaxed(rng->base + PRNG_STATUS); + if (!(val & PRNG_STATUS_DATA_AVAIL)) + break; val = readl_relaxed(rng->base + PRNG_DATA_OUT); if (!val) - return -EINVAL; + break; if ((max - currsize) >= WORD_SZ) { memcpy(data, &val, WORD_SZ); @@ -65,10 +61,11 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) } else { /* copy only remaining bytes */ memcpy(data, &val, max - currsize); + break; } } while (currsize < max); - return 0; + return currsize; } static int qcom_rng_generate(struct crypto_rng *tfm, @@ -90,7 +87,7 @@ static int qcom_rng_generate(struct crypto_rng *tfm, mutex_unlock(&rng->lock); clk_disable_unprepare(rng->clk); - return ret; + return 0; } static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed, diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c index 5bbf0d2722e11..1cece1a7d3f00 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c @@ -506,6 +506,7 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg = { .exit = rk_ablk_exit_tfm, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, .setkey = rk_tdes_setkey, .encrypt = rk_des3_ede_ecb_encrypt, .decrypt = rk_des3_ede_ecb_decrypt, diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig index b2c28b87f14b3..c85fab7ef0bdd 100644 --- a/drivers/crypto/vmx/Kconfig +++ b/drivers/crypto/vmx/Kconfig @@ -2,11 +2,7 @@ config CRYPTO_DEV_VMX_ENCRYPT tristate "Encryption acceleration support on P8 CPU" depends on CRYPTO_DEV_VMX - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_CTR select CRYPTO_GHASH - select CRYPTO_XTS default m help Support for VMX cryptographic acceleration instructions on Power8 CPU. diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 260a247c60d2d..cadbd0a1a1ef0 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -723,7 +723,6 @@ static int dax_fs_init(void) static void dax_fs_exit(void) { kern_unmount(dax_mnt); - rcu_barrier(); kmem_cache_destroy(dax_cache); } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a44db03329391..d3451a41d1ecb 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -606,10 +606,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) file->f_mode |= FMODE_LSEEK; dmabuf->file = file; - ret = dma_buf_stats_setup(dmabuf); - if (ret) - goto err_sysfs; - mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); @@ -617,6 +613,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); + ret = dma_buf_stats_setup(dmabuf); + if (ret) + goto err_sysfs; + return dmabuf; err_sysfs: diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index cfbf10128aaed..db732f71e59ad 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -181,10 +181,6 @@ static long udmabuf_create(struct miscdevice *device, if (ubuf->pagecount > pglimit) goto err; } - - if (!ubuf->pagecount) - goto err; - ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), GFP_KERNEL); if (!ubuf->pages) { diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index 3e83769615d1c..e1a958ae79254 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -30,7 +30,7 @@ #define HISI_DMA_MODE 0x217c #define HISI_DMA_OFFSET 0x100 -#define HISI_DMA_MSI_NUM 32 +#define HISI_DMA_MSI_NUM 30 #define HISI_DMA_CHAN_NUM 30 #define HISI_DMA_Q_DEPTH_VAL 1024 diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index e51838d749e2e..e1926483ae2fd 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -24,7 +24,7 @@ static bool dump_properties __initdata; static int __init dump_properties_enable(char *arg) { dump_properties = true; - return 1; + return 0; } __setup("dump_apple_properties", dump_properties_enable); diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 7e771c56c13c6..0ef086e43090b 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -266,7 +266,7 @@ static int efi_pstore_write(struct pstore_record *record) efi_name[i] = name[i]; ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, - false, record->size, record->psi->buf); + preemptible(), record->size, record->psi->buf); if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE)) if (!schedule_work(&efivar_work)) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index e3df82d5d37a8..9fa86288b78a9 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -209,7 +209,7 @@ static int __init efivar_ssdt_setup(char *str) memcpy(efivar_ssdt, str, strlen(str)); else pr_warn("efivar_ssdt: name too long: %s\n", str); - return 1; + return 0; } __setup("efivar_ssdt=", efivar_ssdt_setup); diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 983e07dc022ed..931544c9f63d4 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -21,7 +21,7 @@ config GOOGLE_SMI config GOOGLE_COREBOOT_TABLE tristate "Coreboot Table Access" - depends on HAS_IOMEM && (ACPI || OF) + depends on ACPI || OF help This option enables the coreboot_table module, which provides other firmware modules access to the coreboot table. The coreboot table diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d3a1d4ce66c7a..0de70a6f8b2a5 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -749,6 +749,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) }; int ret; + desc.args[0] = addr; + desc.args[1] = size; + desc.args[2] = spare; + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_VAL); + ret = qcom_scm_call(__scm->dev, &desc, NULL); /* the pg table has been initialized already, ignore the error */ diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 53c7e3f8cfde2..2a7687911c097 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -477,7 +477,7 @@ static int svc_normal_to_secure_thread(void *data) case INTEL_SIP_SMC_RSU_ERROR: pr_err("%s: STATUS_ERROR\n", __func__); cbdata->status = BIT(SVC_STATUS_ERROR); - cbdata->kaddr1 = &res.a1; + cbdata->kaddr1 = NULL; cbdata->kaddr2 = NULL; cbdata->kaddr3 = NULL; pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata); diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 87edc77260d20..dbad73162c833 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -525,6 +525,7 @@ static int tacoma_cabled_fsi_fixup(struct device *dev) static int fsi_master_aspeed_probe(struct platform_device *pdev) { struct fsi_master_aspeed *aspeed; + struct resource *res; int rc, links, reg; __be32 raw; @@ -534,28 +535,26 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) return rc; } - aspeed = kzalloc(sizeof(*aspeed), GFP_KERNEL); + aspeed = devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL); if (!aspeed) return -ENOMEM; aspeed->dev = &pdev->dev; - aspeed->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aspeed->base)) { - rc = PTR_ERR(aspeed->base); - goto err_free_aspeed; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + aspeed->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(aspeed->base)) + return PTR_ERR(aspeed->base); aspeed->clk = devm_clk_get(aspeed->dev, NULL); if (IS_ERR(aspeed->clk)) { dev_err(aspeed->dev, "couldn't get clock\n"); - rc = PTR_ERR(aspeed->clk); - goto err_free_aspeed; + return PTR_ERR(aspeed->clk); } rc = clk_prepare_enable(aspeed->clk); if (rc) { dev_err(aspeed->dev, "couldn't enable clock\n"); - goto err_free_aspeed; + return rc; } rc = setup_cfam_reset(aspeed); @@ -590,7 +589,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw); if (rc) { dev_err(&pdev->dev, "failed to read hub version\n"); - goto err_release; + return rc; } reg = be32_to_cpu(raw); @@ -629,8 +628,6 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) err_release: clk_disable_unprepare(aspeed->clk); -err_free_aspeed: - kfree(aspeed); return rc; } 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 e828f9414ba2c..6c8f141103da4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6396,9 +6396,6 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder, mode = amdgpu_dm_create_common_mode(encoder, common_modes[i].name, common_modes[i].w, common_modes[i].h); - if (!mode) - continue; - drm_mode_probed_add(connector, mode); amdgpu_dm_connector->num_modes++; } @@ -8615,13 +8612,10 @@ static int dm_update_plane_state(struct dc *dc, static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc) { struct drm_connector *connector; - struct drm_connector_state *conn_state, *old_conn_state; + struct drm_connector_state *conn_state; struct amdgpu_dm_connector *aconnector = NULL; int i; - for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) { - if (!conn_state->crtc) - conn_state = old_conn_state; - + for_each_new_connector_in_state(state, connector, conn_state, i) { if (conn_state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index b037fd57fd366..0e0f494fbb5e1 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -227,6 +227,14 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { .funcs = &pflip_irq_info_funcs\ } +#define vupdate_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ + .funcs = &vblank_irq_info_funcs\ + } + /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic * of DCE's DC_IRQ_SOURCE_VUPDATEx. */ @@ -340,6 +348,12 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = { dc_underflow_int_entry(6), [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), + vupdate_int_entry(0), + vupdate_int_entry(1), + vupdate_int_entry(2), + vupdate_int_entry(3), + vupdate_int_entry(4), + vupdate_int_entry(5), vupdate_no_lock_int_entry(0), vupdate_no_lock_int_entry(1), vupdate_no_lock_int_entry(2), diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5abb68017f6ed..49109614510b8 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2098,8 +2098,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } } - /* setting should not be allowed from VF if not in one VF mode */ - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { + /* setting should not be allowed from VF */ + if (amdgpu_sriov_vf(adev)) { dev_attr->attr.mode &= ~S_IWUGO; dev_attr->store = NULL; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ee27970cfff95..e5893218fa4bb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -115,7 +115,7 @@ int smu_get_dpm_freq_range(struct smu_context *smu, uint32_t *min, uint32_t *max) { - int ret = -ENOTSUPP; + int ret = 0; if (!min && !max) return -EINVAL; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index a0f6ee15c2485..a9bb734366ae6 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -169,7 +169,6 @@ #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) -#define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6) #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 338c6a2ad322b..940448fce41cd 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -351,17 +351,11 @@ static void __adv7511_power_on(struct adv7511 *adv7511) * from standby or are enabled. When the HPD goes low the adv7511 is * reset and the outputs are disabled which might cause the monitor to * go to standby again. To avoid this we ignore the HPD pin for the - * first few seconds after enabling the output. On the other hand - * adv7535 require to enable HPD Override bit for proper HPD. + * first few seconds after enabling the output. */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, - ADV7535_REG_POWER2_HPD_OVERRIDE); - else - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_NONE); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_NONE); /* HACK: If we don't delay here edid probing doesn't work properly */ msleep(200); @@ -384,10 +378,6 @@ static void adv7511_power_on(struct adv7511 *adv7511) static void __adv7511_power_off(struct adv7511 *adv7511) { /* TODO: setup additional power down modes */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, 0); - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); @@ -685,14 +675,9 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) status = connector_status_disconnected; } else { /* Renable HPD sensing */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, - ADV7535_REG_POWER2_HPD_OVERRIDE); - else - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_BOTH); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_BOTH); } adv7511->status = status; diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 0ced08d81d7a2..b31281f76117c 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -1286,7 +1286,6 @@ static const struct of_device_id cdns_dsi_of_match[] = { { .compatible = "cdns,dsi" }, { }, }; -MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); static struct platform_driver cdns_dsi_platform_driver = { .probe = cdns_dsi_drm_probe, diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index b68d335981588..6cac2e58cd15f 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -1188,7 +1188,6 @@ static int nwl_dsi_probe(struct platform_device *pdev) ret = nwl_dsi_select_input(dsi); if (ret < 0) { - pm_runtime_disable(dev); mipi_dsi_host_unregister(&dsi->dsi_host); return ret; } diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index ec7745c31da07..843265d7f1b12 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) if (ret) { dev_err(ctx->dev, "Failed to register RC device\n"); ctx->error = ret; - rc_free_device(rc_dev); + rc_free_device(ctx->rc_dev); return; } ctx->rc_dev = rc_dev; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index b10228b9e3a93..29c0eb4bd7546 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2566,9 +2566,8 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, if (!output_fmts) return NULL; - /* If dw-hdmi is the first or only bridge, avoid negociating with ourselves */ - if (list_is_singular(&bridge->encoder->bridge_chain) || - list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) { + /* If dw-hdmi is the only bridge, avoid negociating with ourselves */ + if (list_is_singular(&bridge->encoder->bridge_chain)) { *num_output_fmts = 1; output_fmts[0] = MEDIA_BUS_FMT_FIXED; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 376fa6eb46f69..6b268f9445b36 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1172,7 +1172,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); - pm_runtime_disable(dev); dw_mipi_dsi_debugfs_remove(dsi); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 862e173d34315..3d7593ea79f14 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4806,8 +4806,7 @@ bool drm_detect_monitor_audio(struct edid *edid) if (!edid_ext) goto end; - has_audio = (edid_ext[0] == CEA_EXT && - (edid_ext[3] & EDID_BASIC_AUDIO) != 0); + has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0); if (has_audio) { DRM_DEBUG_KMS("Monitor has basic audio support\n"); @@ -4960,8 +4959,16 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, connector->name, dc_bpc); info->bpc = dc_bpc; + /* + * Deep color support mandates RGB444 support for all video + * modes and forbids YCRCB422 support for all video modes per + * HDMI 1.3 spec. + */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; + /* YCRCB444 is optional according to spec. */ if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", connector->name); } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 6d083b98f6ae6..abff2d6cedd12 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -376,21 +376,6 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, return -EINVAL; } - /* - * The port numbering and mapping here is bizarre. The now-obsolete - * swsci spec supports ports numbered [0..4]. Port E is handled as a - * special case, but port F and beyond are not. The functionality is - * supposed to be obsolete for new platforms. Just bail out if the port - * number is out of bounds after mapping. - */ - if (port > 4) { - drm_dbg_kms(&dev_priv->drm, - "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power state notification\n", - intel_encoder->base.base.id, intel_encoder->base.name, - port_name(intel_encoder->port), port); - return -EINVAL; - } - if (!enable) parm |= 4 << 8; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 92dd65befbcb8..5754bccff4d15 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -423,7 +423,7 @@ vm_access(struct vm_area_struct *area, unsigned long addr, return -EACCES; addr -= area->vm_start; - if (range_overflows_t(u64, addr, len, obj->base.size)) + if (addr >= obj->base.size) return -EINVAL; /* As this is primarily for debugging, let's focus on simplicity */ diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 605ac8825a591..2eb8df4697dfa 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -212,6 +212,14 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, if (!imx_pd_format_supported(bus_fmt)) return -EINVAL; + if (bus_flags & + ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) { + dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags); + return -EINVAL; + } + bridge_state->output_bus_cfg.flags = bus_flags; bridge_state->input_bus_cfg.flags = bus_flags; imx_crtc_state->bus_flags = bus_flags; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 728fea5094124..2753067c08e68 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -396,8 +396,10 @@ static void meson_drv_unbind(struct device *dev) drm_irq_uninstall(drm); drm_dev_put(drm); - if (priv->afbcd.ops) - priv->afbcd.ops->exit(priv); + if (priv->afbcd.ops) { + priv->afbcd.ops->reset(priv); + meson_rdma_free(priv); + } } static const struct component_master_ops meson_drv_master_ops = { diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meson/meson_osd_afbcd.c index 0cdbe899402f8..ffc6b584dbf85 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.c +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c @@ -79,6 +79,11 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; } +static int meson_gxm_afbcd_init(struct meson_drm *priv) +{ + return 0; +} + static int meson_gxm_afbcd_reset(struct meson_drm *priv) { writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, @@ -88,16 +93,6 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) return 0; } -static int meson_gxm_afbcd_init(struct meson_drm *priv) -{ - return 0; -} - -static void meson_gxm_afbcd_exit(struct meson_drm *priv) -{ - meson_gxm_afbcd_reset(priv); -} - static int meson_gxm_afbcd_enable(struct meson_drm *priv) { writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | @@ -177,7 +172,6 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_gxm_ops = { .init = meson_gxm_afbcd_init, - .exit = meson_gxm_afbcd_exit, .reset = meson_gxm_afbcd_reset, .enable = meson_gxm_afbcd_enable, .disable = meson_gxm_afbcd_disable, @@ -275,18 +269,6 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; } -static int meson_g12a_afbcd_reset(struct meson_drm *priv) -{ - meson_rdma_reset(priv); - - meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | - VIU_SW_RESET_G12A_OSD1_AFBCD, - VIU_SW_RESET); - meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); - - return 0; -} - static int meson_g12a_afbcd_init(struct meson_drm *priv) { int ret; @@ -304,10 +286,16 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv) return 0; } -static void meson_g12a_afbcd_exit(struct meson_drm *priv) +static int meson_g12a_afbcd_reset(struct meson_drm *priv) { - meson_g12a_afbcd_reset(priv); - meson_rdma_free(priv); + meson_rdma_reset(priv); + + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | + VIU_SW_RESET_G12A_OSD1_AFBCD, + VIU_SW_RESET); + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); + + return 0; } static int meson_g12a_afbcd_enable(struct meson_drm *priv) @@ -392,7 +380,6 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_g12a_ops = { .init = meson_g12a_afbcd_init, - .exit = meson_g12a_afbcd_exit, .reset = meson_g12a_afbcd_reset, .enable = meson_g12a_afbcd_enable, .disable = meson_g12a_afbcd_disable, diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meson/meson_osd_afbcd.h index e77ddeb6416f3..5e5523304f42f 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.h +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h @@ -14,7 +14,6 @@ struct meson_afbcd_ops { int (*init)(struct meson_drm *priv); - void (*exit)(struct meson_drm *priv); int (*reset)(struct meson_drm *priv); int (*enable)(struct meson_drm *priv); int (*disable)(struct meson_drm *priv); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 2a13e297e16df..509968c0d16bc 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1243,10 +1243,7 @@ static void mgag200_set_format_regs(struct mga_device *mdev, WREG_GFX(3, 0x00); WREG_GFX(4, 0x00); WREG_GFX(5, 0x40); - /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode), - * so that it doesn't hang when running kexec/kdump on G200_SE rev42. - */ - WREG_GFX(6, 0x0d); + WREG_GFX(6, 0x05); WREG_GFX(7, 0x0f); WREG_GFX(8, 0x0f); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index a0274fcfe9c9d..f7f5c258b5537 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1113,7 +1113,7 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) } - if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS && + if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort && dpu_enc->cur_master->hw_mdptop && dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 74a13ccad34c0..9b2b5044e8e05 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -34,14 +34,6 @@ int dpu_rm_destroy(struct dpu_rm *rm) { int i; - for (i = 0; i < ARRAY_SIZE(rm->dspp_blks); i++) { - struct dpu_hw_dspp *hw; - - if (rm->dspp_blks[i]) { - hw = to_dpu_hw_dspp(rm->dspp_blks[i]); - dpu_hw_dspp_destroy(hw); - } - } for (i = 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) { struct dpu_hw_pingpong *hw; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 6cd6934c8c9f1..66f2ea3d42fc2 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1336,7 +1336,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv; - struct dp_display_private *dp_priv; int ret; if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) @@ -1345,8 +1344,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, priv = dev->dev_private; dp_display->drm_dev = dev; - dp_priv = container_of(dp_display, struct dp_display_private, dp_display); - ret = dp_display_request_irq(dp_display); if (ret) { DRM_ERROR("request_irq failed, ret=%d\n", ret); @@ -1364,8 +1361,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, return ret; } - dp_priv->panel->connector = dp_display->connector; - priv->connectors[priv->num_connectors++] = dp_display->connector; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c index a6ea89a5d51ab..667fa016496ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c @@ -142,12 +142,11 @@ nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver, hsfw->imem_size = desc->code_size; hsfw->imem_tag = desc->start_tag; - hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL); + hsfw->imem = kmalloc(desc->code_size, GFP_KERNEL); + memcpy(hsfw->imem, data + desc->code_off, desc->code_size); + nvkm_firmware_put(fw); - if (!hsfw->imem) - return -ENOMEM; - else - return 0; + return 0; } int diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 959dcbd8a29c1..7ffd2a04ab23a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2132,7 +2132,7 @@ static const struct display_timing innolux_g070y2_l01_timing = { static const struct panel_desc innolux_g070y2_l01 = { .timings = &innolux_g070y2_l01_timing, .num_timings = 1, - .bpc = 8, + .bpc = 6, .size = { .width = 152, .height = 91, diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 107ad2d764ec0..2aae636f1cf5c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -359,11 +359,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) panfrost_gpu_init_features(pfdev); - err = dma_set_mask_and_coherent(pfdev->dev, + dma_set_mask_and_coherent(pfdev->dev, DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); - if (err) - return err; - dma_set_max_seg_size(pfdev->dev, UINT_MAX); irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index de1333dc0d867..f46d377f0c304 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1538,10 +1538,8 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) dsi->slave = platform_get_drvdata(gangster); of_node_put(np); - if (!dsi->slave) { - put_device(&gangster->dev); + if (!dsi->slave) return -EPROBE_DEFER; - } dsi->slave->master = dsi; } diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 8659558b518d6..a2c09dca4eef9 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -520,7 +520,6 @@ static int host1x_remove(struct platform_device *pdev) host1x_syncpt_deinit(host); reset_control_assert(host->rst); clk_disable_unprepare(host->clk); - host1x_channel_list_free(&host->channel_list); host1x_iommu_exit(host); return 0; diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c index 51d0875a34800..ce7740ef449ba 100644 --- a/drivers/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -866,14 +866,8 @@ static int gb_svc_hello(struct gb_operation *op) gb_svc_debugfs_init(svc); - ret = gb_svc_queue_deferred_request(op); - if (ret) - goto err_remove_debugfs; - - return 0; + return gb_svc_queue_deferred_request(op); -err_remove_debugfs: - gb_svc_debugfs_exit(svc); err_unregister_device: gb_svc_watchdog_destroy(svc); device_del(&svc->dev); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 587259b3db97c..a311b0a33eba7 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1000,7 +1000,6 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, workitem.reports_supported |= STD_KEYBOARD; break; case 0x0f: - case 0x11: device_type = "eQUAD Lightspeed 1.2"; logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); workitem.reports_supported |= STD_KEYBOARD; diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 14811d42a5a91..998aad8a9e608 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -620,17 +620,6 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, if (report_type == HID_OUTPUT_REPORT) return -EINVAL; - /* - * In case of unnumbered reports the response from the device will - * not have the report ID that the upper layers expect, so we need - * to stash it the buffer ourselves and adjust the data size. - */ - if (!report_number) { - buf[0] = 0; - buf++; - count--; - } - /* +2 bytes to include the size of the reply in the query buffer */ ask_count = min(count + 2, (size_t)ihid->bufsize); @@ -652,9 +641,6 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, count = min(count, ret_count - 2); memcpy(buf, ihid->rawbuf + 2, count); - if (!report_number) - count++; - return count; } @@ -671,19 +657,17 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, mutex_lock(&ihid->reset_lock); - /* - * Note that both numbered and unnumbered reports passed here - * are supposed to have report ID stored in the 1st byte of the - * buffer, so we strip it off unconditionally before passing payload - * to i2c_hid_set_or_send_report which takes care of encoding - * everything properly. - */ + if (report_id) { + buf++; + count--; + } + ret = i2c_hid_set_or_send_report(client, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf + 1, count - 1, use_data); + report_id, buf, count, use_data); - if (ret >= 0) - ret++; /* add report_id to the number of transferred bytes */ + if (report_id && ret >= 0) + ret++; /* add report_id to the number of transfered bytes */ mutex_unlock(&ihid->reset_lock); diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index b6d6d119035ca..6cf59fd26ad78 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -656,12 +656,21 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, */ payload_max_size &= ~(L1_CACHE_BYTES - 1); - dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL); + dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32); if (!dma_buf) { client_data->flag_retry = true; return -ENOMEM; } + dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size, + DMA_TO_DEVICE); + if (dma_mapping_error(devc, dma_buf_phy)) { + dev_err(cl_data_to_dev(client_data), "DMA map failed\n"); + client_data->flag_retry = true; + rv = -ENOMEM; + goto end_err_dma_buf_release; + } + ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT; ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA; ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy; @@ -681,7 +690,14 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, ldr_xfer_dma_frag.fragment.size = fragment_size; memcpy(dma_buf, &fw->data[fragment_offset], fragment_size); - /* Flush cache to be sure the data is in main memory. */ + dma_sync_single_for_device(devc, dma_buf_phy, + payload_max_size, + DMA_TO_DEVICE); + + /* + * Flush cache here because the dma_sync_single_for_device() + * does not do for x86. + */ clflush_cache_range(dma_buf, payload_max_size); dev_dbg(cl_data_to_dev(client_data), @@ -704,8 +720,15 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, fragment_offset += fragment_size; } + dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); + kfree(dma_buf); + return 0; + end_err_resp_buf_release: - dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy); + /* Free ISH buffer if not done already, in error case */ + dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); +end_err_dma_buf_release: + kfree(dma_buf); return rv; } diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 210e532ac277f..79e5356a737a2 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -17,7 +17,6 @@ config HYPERV_TIMER config HYPERV_UTILS tristate "Microsoft Hyper-V Utilities driver" depends on HYPERV && CONNECTOR && NLS - depends on PTP_1588_CLOCK_OPTIONAL help Select this option to enable the Hyper-V Utilities. diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 6a716996a6250..eb56e09ae15f3 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1558,7 +1558,7 @@ static void balloon_onchannelcallback(void *context) break; default: - pr_warn_ratelimited("Unhandled message: type: %d\n", dm_hdr->type); + pr_warn("Unhandled message: type: %d\n", dm_hdr->type); } } diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index de27837e85271..88a5df2633fb2 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -319,7 +319,6 @@ enum pmbus_fan_mode { percent = 0, rpm }; /* * STATUS_VOUT, STATUS_INPUT */ -#define PB_VOLTAGE_VIN_OFF BIT(3) #define PB_VOLTAGE_UV_FAULT BIT(4) #define PB_VOLTAGE_UV_WARNING BIT(5) #define PB_VOLTAGE_OV_WARNING BIT(6) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 117e3ce9c76ad..71798fde2ef0c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1360,7 +1360,7 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { .reg = PMBUS_VIN_UV_FAULT_LIMIT, .attr = "lcrit", .alarm = "lcrit_alarm", - .sbit = PB_VOLTAGE_UV_FAULT | PB_VOLTAGE_VIN_OFF, + .sbit = PB_VOLTAGE_UV_FAULT, }, { .reg = PMBUS_VIN_OV_WARN_LIMIT, .attr = "max", @@ -2255,14 +2255,10 @@ static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); - struct pmbus_data *data = i2c_get_clientdata(client); u8 page = rdev_get_id(rdev); int ret; - mutex_lock(&data->update_lock); ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION); - mutex_unlock(&data->update_lock); - if (ret < 0) return ret; @@ -2273,17 +2269,11 @@ static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); - struct pmbus_data *data = i2c_get_clientdata(client); u8 page = rdev_get_id(rdev); - int ret; - mutex_lock(&data->update_lock); - ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION, - PB_OPERATION_CONTROL_ON, - enable ? PB_OPERATION_CONTROL_ON : 0); - mutex_unlock(&data->update_lock); - - return ret; + return pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); } static int pmbus_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index 066b12990fbfb..6c84780e358e8 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -424,7 +424,7 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent, if (nowayout) set_bit(WDOG_NO_WAY_OUT, &data->wddev.status); if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) - set_bit(WDOG_HW_RUNNING, &data->wddev.status); + set_bit(WDOG_ACTIVE, &data->wddev.status); /* Since the watchdog uses a downcounter there is no register to read the BIOS set timeout from (if any was set at all) -> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 19dbb794f7c8a..bfcf9e0415c26 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2056,7 +2056,7 @@ static void clear_etmdrvdata(void *info) etmdrvdata[cpu] = NULL; } -static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) +static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) { etm_perf_symlink(drvdata->csdev, false); /* @@ -2076,6 +2076,8 @@ static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) cpus_read_unlock(); coresight_unregister(drvdata->csdev); + + return 0; } static void __exit etm4_remove_amba(struct amba_device *adev) @@ -2092,7 +2094,7 @@ static int __exit etm4_remove_platform_dev(struct platform_device *pdev) struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (drvdata) - etm4_remove_dev(drvdata); + ret = etm4_remove_dev(drvdata); pm_runtime_disable(&pdev->dev); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index b8dd7ea111c1e..007bad9e7ad81 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -364,12 +364,8 @@ static ssize_t mode_store(struct device *dev, mode = ETM_MODE_QELEM(config->mode); /* start by clearing QE bits */ config->cfg &= ~(BIT(13) | BIT(14)); - /* - * if supported, Q elements with instruction counts are enabled. - * Always set the low bit for any requested mode. Valid combos are - * 0b00, 0b01 and 0b11. - */ - if (mode && drvdata->q_support) + /* if supported, Q elements with instruction counts are enabled */ + if ((mode & BIT(0)) && (drvdata->q_support & BIT(0))) config->cfg |= BIT(13); /* * if supported, Q elements with and without instruction diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 07eb819072c4f..ef73a42577cc7 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -465,18 +465,18 @@ static int meson_i2c_probe(struct platform_device *pdev) */ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); - /* Disable filtering */ - meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, - REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); - - meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); - ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { clk_disable_unprepare(i2c->clk); return ret; } + /* Disable filtering */ + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, + REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); + + meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); + return 0; } diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 8dabb6ffb1a4f..2a8568b97c14d 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -756,6 +756,7 @@ static const struct i2c_adapter_quirks xiic_quirks = { static const struct i2c_adapter xiic_adapter = { .owner = THIS_MODULE, + .name = DRIVER_NAME, .class = I2C_CLASS_DEPRECATED, .algo = &xiic_algorithm, .quirks = &xiic_quirks, @@ -792,8 +793,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = pdev->dev.of_node; - snprintf(i2c->adap.name, sizeof(i2c->adap.name), - DRIVER_NAME " %s", pdev->name); mutex_init(&i2c->lock); init_waitqueue_head(&i2c->wait); diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index f7a7405d4350a..5365199a31f41 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -261,7 +261,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err = device_create_file(&pdev->dev, &dev_attr_available_masters); if (err) - goto err_rollback_activation; + goto err_rollback; err = device_create_file(&pdev->dev, &dev_attr_current_master); if (err) @@ -271,9 +271,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err_rollback_available: device_remove_file(&pdev->dev, &dev_attr_available_masters); -err_rollback_activation: - i2c_demux_deactivate_master(priv); err_rollback: + i2c_demux_deactivate_master(priv); for (j = 0; j < i; j++) { of_node_put(priv->chan[j].parent_np); of_changeset_destroy(&priv->chan[j].chgset); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index e7e2802827740..a7208704d31c9 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -176,7 +176,6 @@ static const struct mma8452_event_regs trans_ev_regs = { * @enabled_events: event flags enabled and handled by this driver */ struct mma_chip_info { - const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1304,7 +1303,6 @@ enum { static const struct mma_chip_info mma_chip_info_table[] = { [mma8451] = { - .name = "mma8451", .chip_id = MMA8451_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1329,7 +1327,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8452] = { - .name = "mma8452", .chip_id = MMA8452_DEVICE_ID, .channels = mma8452_channels, .num_channels = ARRAY_SIZE(mma8452_channels), @@ -1346,7 +1343,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8453] = { - .name = "mma8453", .chip_id = MMA8453_DEVICE_ID, .channels = mma8453_channels, .num_channels = ARRAY_SIZE(mma8453_channels), @@ -1363,7 +1359,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8652] = { - .name = "mma8652", .chip_id = MMA8652_DEVICE_ID, .channels = mma8652_channels, .num_channels = ARRAY_SIZE(mma8652_channels), @@ -1373,7 +1368,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [mma8653] = { - .name = "mma8653", .chip_id = MMA8653_DEVICE_ID, .channels = mma8653_channels, .num_channels = ARRAY_SIZE(mma8653_channels), @@ -1388,7 +1382,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [fxls8471] = { - .name = "fxls8471", .chip_id = FXLS8471_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1532,6 +1525,13 @@ static int mma8452_probe(struct i2c_client *client, struct mma8452_data *data; struct iio_dev *indio_dev; int ret; + const struct of_device_id *match; + + match = of_match_device(mma8452_dt_ids, &client->dev); + if (!match) { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1540,14 +1540,7 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); - - data->chip_info = device_get_match_data(&client->dev); - if (!data->chip_info && id) { - data->chip_info = &mma_chip_info_table[id->driver_data]; - } else { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } + data->chip_info = match->data; data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -1591,11 +1584,11 @@ static int mma8452_probe(struct i2c_client *client, } dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", - data->chip_info->name, data->chip_info->chip_id); + match->compatible, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; - indio_dev->name = data->chip_info->name; + indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; @@ -1821,7 +1814,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id); static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", - .of_match_table = mma8452_dt_ids, + .of_match_table = of_match_ptr(mma8452_dt_ids), .pm = &mma8452_pm_ops, }, .probe = mma8452_probe, diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 256177b15c511..c6416ad795ca4 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -911,8 +911,6 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, IRQF_ONESHOT, "twl6030_gpadc", indio_dev); - if (ret) - return ret; ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); if (ret < 0) { diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 3809f98894a51..e42ea2b1707db 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -38,7 +38,7 @@ static int rescale_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct rescale *rescale = iio_priv(indio_dev); - s64 tmp; + unsigned long long tmp; int ret; switch (mask) { @@ -59,10 +59,10 @@ static int rescale_read_raw(struct iio_dev *indio_dev, *val2 = rescale->denominator; return IIO_VAL_FRACTIONAL; case IIO_VAL_FRACTIONAL_LOG2: - tmp = (s64)*val * 1000000000LL; - tmp = div_s64(tmp, rescale->denominator); + tmp = *val * 1000000000LL; + do_div(tmp, rescale->denominator); tmp *= rescale->numerator; - tmp = div_s64(tmp, 1000000000LL); + do_div(tmp, 1000000000LL); *val = tmp; return ret; default: diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 8c3faa7972842..ede99e0d53714 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -561,50 +561,28 @@ EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { - int scale_type, scale_val, scale_val2; - int offset_type, offset_val, offset_val2; + int scale_type, scale_val, scale_val2, offset; s64 raw64 = raw; + int ret; - offset_type = iio_channel_read(chan, &offset_val, &offset_val2, - IIO_CHAN_INFO_OFFSET); - if (offset_type >= 0) { - switch (offset_type) { - case IIO_VAL_INT: - break; - case IIO_VAL_INT_PLUS_MICRO: - case IIO_VAL_INT_PLUS_NANO: - /* - * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO - * implicitely truncate the offset to it's integer form. - */ - break; - case IIO_VAL_FRACTIONAL: - offset_val /= offset_val2; - break; - case IIO_VAL_FRACTIONAL_LOG2: - offset_val >>= offset_val2; - break; - default: - return -EINVAL; - } - - raw64 += offset_val; - } + ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); + if (ret >= 0) + raw64 += offset; scale_type = iio_channel_read(chan, &scale_val, &scale_val2, IIO_CHAN_INFO_SCALE); if (scale_type < 0) { /* - * If no channel scaling is available apply consumer scale to - * raw value and return. + * Just pass raw values as processed if no scaling is + * available. */ - *processed = raw * scale; + *processed = raw; return 0; } switch (scale_type) { case IIO_VAL_INT: - *processed = raw64 * scale_val * scale; + *processed = raw64 * scale_val; break; case IIO_VAL_INT_PLUS_MICRO: if (scale_val2 < 0) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 3c40aa50cd60c..fbb0efbe25f84 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2635,7 +2635,7 @@ int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout) { struct rdma_id_private *id_priv; - if (id->qp_type != IB_QPT_RC && id->qp_type != IB_QPT_XRC_INI) + if (id->qp_type != IB_QPT_RC) return -EINVAL; id_priv = container_of(id, struct rdma_id_private, id); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 597e889ba8312..3d895cc41c3ad 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2078,7 +2078,6 @@ struct ib_mr *ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return mr; mr->device = pd->device; - mr->type = IB_MR_TYPE_USER; mr->pd = pd; mr->dm = NULL; atomic_inc(&pd->usecnt); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 5f3edd255ca3c..3591923abebb9 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1439,7 +1439,8 @@ static int query_port(struct rvt_dev_info *rdi, u8 port_num, 4096 : hfi1_max_mtu), IB_MTU_4096); props->active_mtu = !valid_ib_mtu(ppd->ibmtu) ? props->max_mtu : mtu_to_enum(ppd->ibmtu, IB_MTU_4096); - props->phys_mtu = hfi1_max_mtu; + props->phys_mtu = HFI1_CAP_IS_KSET(AIP) ? hfi1_max_mtu : + ib_mtu_enum_to_int(props->max_mtu); return 0; } diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 2f053f48f1beb..343e6709d9fc3 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -1792,10 +1792,8 @@ subscribe_event_xa_alloc(struct mlx5_devx_event_table *devx_event_table, key_level2, obj_event, GFP_KERNEL); - if (err) { - kfree(obj_event); + if (err) return err; - } INIT_LIST_HEAD(&obj_event->obj_sub_list); } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 6cd0cbd4fc9f6..19346693c1da4 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -575,8 +575,6 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, ent = &cache->ent[entry]; spin_lock_irq(&ent->lock); if (list_empty(&ent->head)) { - queue_adjust_cache_locked(ent); - ent->miss++; spin_unlock_irq(&ent->lock); mr = create_cache_mr(ent); if (IS_ERR(mr)) diff --git a/drivers/input/input.c b/drivers/input/input.c index 3cfd2c18eebd9..ff9dc37eff345 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2179,6 +2179,12 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); + /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */ + if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) { + __clear_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + } + /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 8afeefcea67bb..e08b0ef078e81 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1801,13 +1801,15 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); - err = usb_find_common_endpoints(intf->cur_altsetting, - NULL, NULL, &endpoint, NULL); - if (err) { + /* Verify that a device really has an endpoint */ + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, - "interface has no int in endpoints, but must have minimum 1\n"); + "interface has %d endpoints, but must have minimum 1\n", + intf->cur_altsetting->desc.bNumEndpoints); + err = -EINVAL; goto fail3; } + endpoint = &intf->cur_altsetting->endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives * input. diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 17b10b81c7131..6df6f07f1ac66 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -135,7 +135,7 @@ struct point_coord { struct touch_event { __le16 status; - u8 finger_mask; + u8 finger_cnt; u8 time_stamp; struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM]; }; @@ -311,32 +311,11 @@ static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541) static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot, const struct point_coord *p) { - u16 x, y; - - if (unlikely(!(p->sub_status & - (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) { - dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n", - p->sub_status); - return; - } - - x = le16_to_cpu(p->x); - y = le16_to_cpu(p->y); - input_mt_slot(bt541->input_dev, slot); - if (input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, - !(p->sub_status & SUB_BIT_UP))) { - touchscreen_report_pos(bt541->input_dev, - &bt541->prop, x, y, true); - input_report_abs(bt541->input_dev, - ABS_MT_TOUCH_MAJOR, p->width); - dev_dbg(&bt541->client->dev, "finger %d %s (%u, %u)\n", - slot, p->sub_status & SUB_BIT_DOWN ? "down" : "move", - x, y); - } else { - dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n", - slot, x, y); - } + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); + touchscreen_report_pos(bt541->input_dev, &bt541->prop, + le16_to_cpu(p->x), le16_to_cpu(p->y), true); + input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width); } static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) @@ -344,7 +323,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) struct bt541_ts_data *bt541 = bt541_handler; struct i2c_client *client = bt541->client; struct touch_event touch_event; - unsigned long finger_mask; int error; int i; @@ -357,14 +335,10 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) goto out; } - finger_mask = touch_event.finger_mask; - for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) { - const struct point_coord *p = &touch_event.point_coord[i]; - - /* Only process contacts that are actually reported */ - if (p->sub_status & SUB_BIT_EXIST) - zinitix_report_finger(bt541, i, p); - } + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) + if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST) + zinitix_report_finger(bt541, i, + &touch_event.point_coord[i]); input_mt_sync_frame(bt541->input_dev); input_sync(bt541->input_dev); diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index d9068e8f2db4f..d71f10257f159 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1012,9 +1012,7 @@ static int ipmmu_probe(struct platform_device *pdev) bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(&pdev->dev); memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs); - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); - if (ret) - return ret; + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index e903c44edb64a..21cb31ff2bbf2 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -94,7 +94,6 @@ static int __init nvic_of_init(struct device_node *node, if (!nvic_irq_domain) { pr_warn("Failed to allocate irq domain\n"); - iounmap(nvic_base); return -ENOMEM; } @@ -104,7 +103,6 @@ static int __init nvic_of_init(struct device_node *node, if (ret) { pr_warn("Failed to allocate irq chips\n"); irq_domain_remove(nvic_irq_domain); - iounmap(nvic_base); return ret; } diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 1530cce617a41..afdf0d6600ba3 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -88,18 +88,17 @@ static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d, static void pdc_enable_intr(struct irq_data *d, bool on) { int pin_out = d->hwirq; - unsigned long flags; u32 index, mask; u32 enable; index = pin_out / 32; mask = pin_out % 32; - raw_spin_lock_irqsave(&pdc_lock, flags); + raw_spin_lock(&pdc_lock); enable = pdc_reg_read(IRQ_ENABLE_BANK, index); enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); pdc_reg_write(IRQ_ENABLE_BANK, index, enable); - raw_spin_unlock_irqrestore(&pdc_lock, flags); + raw_spin_unlock(&pdc_lock); } static void qcom_pdc_gic_disable(struct irq_data *d) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index c5663398c6b7d..2543c7b6948b6 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x))) @@ -67,7 +66,6 @@ struct imx_mu_priv { const struct imx_mu_dcfg *dcfg; struct clk *clk; int irq; - bool suspend; u32 xcr; @@ -279,9 +277,6 @@ static irqreturn_t imx_mu_isr(int irq, void *p) return IRQ_NONE; } - if (priv->suspend) - pm_system_wakeup(); - return IRQ_HANDLED; } @@ -331,8 +326,6 @@ static int imx_mu_startup(struct mbox_chan *chan) break; } - priv->suspend = true; - return 0; } @@ -550,8 +543,6 @@ static int imx_mu_probe(struct platform_device *pdev) clk_disable_unprepare(priv->clk); - priv->suspend = false; - return 0; disable_runtime_pm: diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 4895d80740022..e07091d71986a 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -410,11 +410,6 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX); if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) { mbox_chan_txdone(chan, 0); - - /* Wait until channel is empty */ - if (chan->active_req != NULL) - continue; - return 0; } diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 418914373a513..fe6dce125aba2 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -2060,11 +2060,9 @@ int bch_btree_check(struct cache_set *c) } } - /* - * Must wait for all threads to stop. - */ wait_event_interruptible(check_state->wait, - atomic_read(&check_state->started) == 0); + atomic_read(&check_state->started) == 0 || + test_bit(CACHE_SET_IO_DISABLE, &c->flags)); for (i = 0; i < check_state->total_threads; i++) { if (check_state->infos[i].result) { diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 952253f24175a..3c74996978dad 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -952,11 +952,9 @@ void bch_sectors_dirty_init(struct bcache_device *d) } } - /* - * Must wait for all threads to stop. - */ wait_event_interruptible(state->wait, - atomic_read(&state->started) == 0); + atomic_read(&state->started) == 0 || + test_bit(CACHE_SET_IO_DISABLE, &c->flags)); out: kfree(state); diff --git a/drivers/md/dm-bow.c b/drivers/md/dm-bow.c index e666ca01d2200..2e95d61496920 100644 --- a/drivers/md/dm-bow.c +++ b/drivers/md/dm-bow.c @@ -236,7 +236,6 @@ static void set_type(struct bow_context *bc, struct bow_range **br, int type) (*br)->type = type; - mutex_lock(&bc->ranges_lock); if (next->type == type) { if (type == TRIMMED) list_del(&next->trimmed_list); @@ -250,7 +249,6 @@ static void set_type(struct bow_context *bc, struct bow_range **br, int type) rb_erase(&(*br)->node, &bc->ranges); kfree(*br); } - mutex_unlock(&bc->ranges_lock); *br = NULL; } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b9677f701b6a1..2aa4acd33af39 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2561,7 +2561,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string static int get_key_size(char **key_string) { - return (*key_string[0] == ':') ? -EINVAL : (int)(strlen(*key_string) >> 1); + return (*key_string[0] == ':') ? -EINVAL : strlen(*key_string) >> 1; } #endif /* CONFIG_KEYS */ diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index f7471a2642dd4..4c7da1c4e6cb9 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -2354,11 +2354,9 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, dm_integrity_io_error(ic, "invalid sector in journal", -EIO); sec &= ~(sector_t)(ic->sectors_per_block - 1); } - if (unlikely(sec >= ic->provided_data_sectors)) { - journal_entry_set_unused(je); - continue; - } } + if (unlikely(sec >= ic->provided_data_sectors)) + continue; get_area_and_offset(ic, sec, &area, &offset); restore_last_bytes(ic, access_journal_data(ic, i, j), je); for (k = j + 1; k < ic->journal_section_entries; k++) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 10eb0544f1cba..9fd176e225aff 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -608,18 +608,17 @@ static void start_io_acct(struct dm_io *io) false, 0, &io->stats_aux); } -static void end_io_acct(struct dm_io *io) +static void end_io_acct(struct mapped_device *md, struct bio *bio, + unsigned long start_time, struct dm_stats_aux *stats_aux) { - struct mapped_device *md = io->md; - struct bio *bio = io->orig_bio; - unsigned long duration = jiffies - io->start_time; + unsigned long duration = jiffies - start_time; - bio_end_io_acct(bio, io->start_time); + bio_end_io_acct(bio, start_time); if (unlikely(dm_stats_used(&md->stats))) dm_stats_account_io(&md->stats, bio_data_dir(bio), bio->bi_iter.bi_sector, bio_sectors(bio), - true, duration, &io->stats_aux); + true, duration, stats_aux); /* nudge anyone waiting on suspend queue */ if (unlikely(wq_has_sleeper(&md->wait))) @@ -904,6 +903,8 @@ static void dec_pending(struct dm_io *io, blk_status_t error) blk_status_t io_error; struct bio *bio; struct mapped_device *md = io->md; + unsigned long start_time = 0; + struct dm_stats_aux stats_aux; /* Push-back supersedes any I/O errors */ if (unlikely(error)) { @@ -930,8 +931,10 @@ static void dec_pending(struct dm_io *io, blk_status_t error) io_error = io->status; bio = io->orig_bio; - end_io_acct(io); + start_time = io->start_time; + stats_aux = io->stats_aux; free_io(md, io); + end_io_acct(md, bio, start_time, &stats_aux); if (io_error == BLK_STS_DM_REQUEUE) return; diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 9f5713b76794d..ab7883cff8b22 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -555,7 +555,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_ buffer[3] = 0; buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); - if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8cf1704308bf5..d1f58795794fd 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2454,7 +2454,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, buffer[i + 3] = infoframe_read(sd, adv76xx_cri[index].payload_addr + i); - if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) { + if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, adv76xx_cri[index].desc); return -ENOENT; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index a870117feb44c..f7d2b6cd3008b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2574,7 +2574,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_ for (i = 0; i < len; i++) buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); - if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 1f0e4b913a053..35a51e9b539da 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3898,7 +3898,7 @@ static int bttv_register_video(struct bttv *btv) /* video */ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); - btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (btv->tuner_type != TUNER_ABSENT) btv->video_dev.device_caps |= V4L2_CAP_TUNER; @@ -3919,7 +3919,7 @@ static int bttv_register_video(struct bttv *btv) /* vbi */ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + V4L2_CAP_STREAMING | V4L2_CAP_TUNER; if (btv->tuner_type != TUNER_ABSENT) btv->vbi_dev.device_caps |= V4L2_CAP_TUNER; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 10d2971ef0624..a57c991b165b1 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -162,9 +162,6 @@ int cx8802_start_dma(struct cx8802_dev *dev, cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); q->count = 0; - /* clear interrupt status register */ - cx_write(MO_TS_INTSTAT, 0x1f1111); - /* enable irqs */ dprintk(1, "setting the interrupt mask\n"); cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index 00caf60ff9890..e5efe525ad7bf 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -332,6 +332,7 @@ struct ivtv_stream { struct ivtv *itv; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ + u32 caps; /* V4L2 capabilities */ struct v4l2_fh *fh; /* pointer to the streaming filehandle */ spinlock_t qlock; /* locks access to the queues */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index a9d69b253516b..35dccb31174c1 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -443,7 +443,7 @@ static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct v4l2_window *winfmt = &fmt->fmt.win; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -554,7 +554,7 @@ static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2 u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -1388,7 +1388,7 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) 0, }; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1455,7 +1455,7 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct yuv_playback_info *yi = &itv->yuv_info; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1475,7 +1475,7 @@ static int ivtv_overlay(struct file *file, void *fh, unsigned int on) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index f9de5d1605fe3..f04ee84bab5fd 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -176,7 +176,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->itv = itv; s->type = type; s->name = ivtv_stream_info[type].name; - s->vdev.device_caps = ivtv_stream_info[type].v4l2_caps; + s->caps = ivtv_stream_info[type].v4l2_caps; if (ivtv_stream_info[type].pio) s->dma = PCI_DMA_NONE; @@ -299,9 +299,12 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) if (s_mpg->vdev.v4l2_dev) num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } - if (itv->osd_video_pbase && (type == IVTV_DEC_STREAM_TYPE_YUV || - type == IVTV_DEC_STREAM_TYPE_MPG)) { - s->vdev.device_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + s->vdev.device_caps = s->caps; + if (itv->osd_video_pbase) { + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; } video_set_drvdata(&s->vdev, s); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index d3cde05a6ebab..7a1fb067b0e09 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1214,14 +1214,16 @@ static int alsa_device_exit(struct saa7134_dev *dev) static int saa7134_alsa_init(void) { - struct saa7134_dev *dev; + struct saa7134_dev *dev = NULL; + struct list_head *list; saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; pr_info("saa7134 ALSA driver for DMA sound loaded\n"); - list_for_each_entry(dev, &saa7134_devlist, devlist) { + list_for_each(list,&saa7134_devlist) { + dev = list_entry(list, struct saa7134_dev, devlist); if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); @@ -1229,7 +1231,7 @@ static int saa7134_alsa_init(void) alsa_device_init(dev); } - if (list_empty(&saa7134_devlist)) + if (dev == NULL) pr_info("saa7134 ALSA: no saa7134 cards found\n"); return 0; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 757a58829a512..debc7509c173c 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -151,7 +151,7 @@ #define VE_SRC_TB_EDGE_DET_BOT GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF) #define VE_MODE_DETECT_STATUS 0x098 -#define VE_MODE_DETECT_H_PERIOD GENMASK(11, 0) +#define VE_MODE_DETECT_H_PIXELS GENMASK(11, 0) #define VE_MODE_DETECT_V_LINES_SHF 16 #define VE_MODE_DETECT_V_LINES GENMASK(27, VE_MODE_DETECT_V_LINES_SHF) #define VE_MODE_DETECT_STATUS_VSYNC BIT(28) @@ -162,8 +162,6 @@ #define VE_SYNC_STATUS_VSYNC_SHF 16 #define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF) -#define VE_H_TOTAL_PIXELS 0x0A0 - #define VE_INTERRUPT_CTRL 0x304 #define VE_INTERRUPT_STATUS 0x308 #define VE_INTERRUPT_MODE_DETECT_WD BIT(0) @@ -767,7 +765,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) u32 src_lr_edge; u32 src_tb_edge; u32 sync; - u32 htotal; struct v4l2_bt_timings *det = &video->detected_timings; det->width = MIN_WIDTH; @@ -812,7 +809,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET); mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS); sync = aspeed_video_read(video, VE_SYNC_STATUS); - htotal = aspeed_video_read(video, VE_H_TOTAL_PIXELS); video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >> VE_SRC_TB_EDGE_DET_BOT_SHF; @@ -829,7 +825,8 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) VE_SRC_LR_EDGE_DET_RT_SHF; video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT; det->hfrontporch = video->frame_left; - det->hbackporch = htotal - video->frame_right; + det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) - + video->frame_right; det->hsync = sync & VE_SYNC_STATUS_HSYNC; if (video->frame_left > video->frame_right) continue; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 2333079a83c71..1eed69d29149f 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -408,7 +408,6 @@ static struct vdoa_data *coda_get_vdoa_data(void) if (!vdoa_data) vdoa_data = ERR_PTR(-EPROBE_DEFER); - put_device(&vdoa_pdev->dev); out: of_node_put(vdoa_node); diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index ee610daf90a3c..5e67994e62cca 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -428,7 +428,6 @@ static int vpif_probe(struct platform_device *pdev) static struct resource *res, *res_irq; struct platform_device *pdev_capture, *pdev_display; struct device_node *endpoint = NULL; - int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); vpif_base = devm_ioremap_resource(&pdev->dev, res); @@ -459,8 +458,8 @@ static int vpif_probe(struct platform_device *pdev) res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) { dev_warn(&pdev->dev, "Missing IRQ resource.\n"); - ret = -EINVAL; - goto err_put_rpm; + pm_runtime_put(&pdev->dev); + return -EINVAL; } pdev_capture = devm_kzalloc(&pdev->dev, sizeof(*pdev_capture), @@ -494,17 +493,10 @@ static int vpif_probe(struct platform_device *pdev) } return 0; - -err_put_rpm: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - return ret; } static int vpif_remove(struct platform_device *pdev) { - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c index cfc7ebed8fb7a..cd27f637dbe7c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c @@ -102,8 +102,6 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev, vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id); fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); - if (!fw) - return ERR_PTR(-ENOMEM); fw->type = VPU; fw->ops = &mtk_vcodec_vpu_msg; fw->pdev = fw_pdev; diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index a50701cfbbd7b..c6cd2e6d8e654 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -48,29 +48,11 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) return 0; } -static void delay_until(ktime_t until) -{ - /* - * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on - * m68k ndelay(s64) does not compile; so use s32 rather than s64. - */ - s32 delta; - - while (true) { - delta = ktime_us_delta(until, ktime_get()); - if (delta <= 0) - return; - - /* udelay more than 1ms may not work */ - delta = min(delta, 1000); - udelay(delta); - } -} - static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, uint count) { ktime_t edge; + s32 delta; int i; local_irq_disable(); @@ -81,7 +63,9 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, gpiod_set_value(gpio_ir->gpio, !(i % 2)); edge = ktime_add_us(edge, txbuf[i]); - delay_until(edge); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 0) + udelay(delta); } gpiod_set_value(gpio_ir->gpio, 0); @@ -113,7 +97,9 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, if (i % 2) { // space edge = ktime_add_us(edge, txbuf[i]); - delay_until(edge); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 0) + udelay(delta); } else { // pulse ktime_t last = ktime_add_us(edge, txbuf[i]); diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 7f394277478b3..1aa7989e756cc 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -429,7 +429,7 @@ static int irtoy_probe(struct usb_interface *intf, err = usb_submit_urb(irtoy->urb_in, GFP_KERNEL); if (err != 0) { dev_err(irtoy->dev, "fail to submit in urb: %d\n", err); - goto free_rcdev; + return err; } err = irtoy_setup(irtoy); diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media/test-drivers/vidtv/vidtv_s302m.c index 4676083cee3b8..d79b65854627c 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_s302m.c +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c @@ -455,9 +455,6 @@ struct vidtv_encoder e->name = kstrdup(args.name, GFP_KERNEL); e->encoder_buf = vzalloc(VIDTV_S302M_BUF_SZ); - if (!e->encoder_buf) - goto out_kfree_e; - e->encoder_buf_sz = VIDTV_S302M_BUF_SZ; e->encoder_buf_offset = 0; @@ -470,8 +467,10 @@ struct vidtv_encoder e->is_video_encoder = false; ctx = kzalloc(priv_sz, GFP_KERNEL); - if (!ctx) - goto out_kfree_buf; + if (!ctx) { + kfree(e); + return NULL; + } e->ctx = ctx; ctx->last_duration = 0; @@ -499,14 +498,6 @@ struct vidtv_encoder e->next = NULL; return e; - -out_kfree_buf: - kfree(e->encoder_buf); - -out_kfree_e: - kfree(e->name); - kfree(e); - return NULL; } void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 26408a972b443..87e375562dbb2 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3881,8 +3881,6 @@ static int em28xx_usb_probe(struct usb_interface *intf, goto err_free; } - kref_init(&dev->ref); - dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; @@ -3983,8 +3981,6 @@ static int em28xx_usb_probe(struct usb_interface *intf, } if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) { - kref_init(&dev->dev_next->ref); - dev->dev_next->ts = SECONDARY_TS; dev->dev_next->alt = -1; dev->dev_next->is_audio_only = has_vendor_audio && @@ -4039,8 +4035,12 @@ static int em28xx_usb_probe(struct usb_interface *intf, em28xx_write_reg(dev, 0x0b, 0x82); mdelay(100); } + + kref_init(&dev->dev_next->ref); } + kref_init(&dev->ref); + request_modules(dev); /* @@ -4095,8 +4095,11 @@ static void em28xx_usb_disconnect(struct usb_interface *intf) em28xx_close_extension(dev); - if (dev->dev_next) + if (dev->dev_next) { + em28xx_close_extension(dev->dev_next); em28xx_release_resources(dev->dev_next); + } + em28xx_release_resources(dev); if (dev->dev_next) { diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 2e5913bccb38f..b9e45124673b6 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -504,7 +504,6 @@ static int s2250_probe(struct i2c_client *client, u8 *data; struct go7007 *go = i2c_get_adapdata(adapter); struct go7007_usb *usb = go->hpi_context; - int err = -EIO; audio = i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1); if (IS_ERR(audio)) @@ -533,8 +532,11 @@ static int s2250_probe(struct i2c_client *client, V4L2_CID_HUE, -512, 511, 1, 0); sd->ctrl_handler = &state->hdl; if (state->hdl.error) { - err = state->hdl.error; - goto fail; + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; } state->std = V4L2_STD_NTSC; @@ -598,7 +600,7 @@ fail: i2c_unregister_device(audio); v4l2_ctrl_handler_free(&state->hdl); kfree(state); - return err; + return -EIO; } static int s2250_remove(struct i2c_client *client) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 60e57e0f19272..563128d117317 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -308,6 +308,7 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev) dev->status = STATUS_STREAMING; + INIT_WORK(&dev->worker, hdpvr_transmit_buffers); schedule_work(&dev->worker); v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, @@ -1164,9 +1165,6 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; int res; - // initialize dev->worker - INIT_WORK(&dev->worker, hdpvr_transmit_buffers); - dev->cur_std = V4L2_STD_525_60; dev->width = 720; dev->height = 480; diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index ce717502ea4c3..4e1698f788187 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -403,7 +403,7 @@ static void stk1160_disconnect(struct usb_interface *interface) /* Here is the only place where isoc get released */ stk1160_uninit_isoc(dev); - stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); + stk1160_clear_queue(dev); video_unregister_device(&dev->vdev); v4l2_device_disconnect(&dev->v4l2_dev); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 1aa953469402f..6a4eb616d5160 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -258,7 +258,7 @@ out_uninit: stk1160_uninit_isoc(dev); out_stop_hw: usb_set_interface(dev->udev, 0, 0); - stk1160_clear_queue(dev, VB2_BUF_STATE_QUEUED); + stk1160_clear_queue(dev); mutex_unlock(&dev->v4l_lock); @@ -306,7 +306,7 @@ static int stk1160_stop_streaming(struct stk1160 *dev) stk1160_stop_hw(dev); - stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); + stk1160_clear_queue(dev); stk1160_dbg("streaming stopped\n"); @@ -745,7 +745,7 @@ static const struct video_device v4l_template = { /********************************************************************/ /* Must be called with both v4l_lock and vb_queue_lock hold */ -void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) +void stk1160_clear_queue(struct stk1160 *dev) { struct stk1160_buffer *buf; unsigned long flags; @@ -756,7 +756,7 @@ void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) buf = list_first_entry(&dev->avail_bufs, struct stk1160_buffer, list); list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } @@ -766,7 +766,7 @@ void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) buf = dev->isoc_ctl.buf; dev->isoc_ctl.buf = NULL; - vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index a70963ce87533..a31ea1c80f255 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -166,7 +166,7 @@ struct regval { int stk1160_vb2_setup(struct stk1160 *dev); int stk1160_video_register(struct stk1160 *dev); void stk1160_video_unregister(struct stk1160 *dev); -void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state); +void stk1160_clear_queue(struct stk1160 *dev); /* Provided by stk1160-video.c */ int stk1160_alloc_isoc(struct stk1160 *dev); diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 5a059be3516c9..ddb1879f07d3f 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1403,7 +1403,7 @@ static struct emif_data *__init_or_module get_device_details( temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL); - if (!emif || !temp || !dev_info) { + if (!emif || !pd || !dev_info) { dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__); goto error; } @@ -1495,7 +1495,7 @@ static int __init_or_module emif_probe(struct platform_device *pdev) { struct emif_data *emif; struct resource *res; - int irq, ret; + int irq; if (pdev->dev.of_node) emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev); @@ -1526,9 +1526,7 @@ static int __init_or_module emif_probe(struct platform_device *pdev) emif_onetime_settings(emif); emif_debugfs_init(emif); disable_and_clear_all_interrupts(emif); - ret = setup_interrupts(emif, irq); - if (ret) - goto error; + setup_interrupts(emif, irq); /* One-time actions taken on probing the first device */ if (!emif1) { diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 14e4bbe6a9da3..a6bd2134cea2a 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -914,14 +914,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); if (ret < 0) - goto out_unmap; + goto out; } if (mem_sdio && (irq >= 0)) { ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq, NULL); if (ret < 0) - goto out_unmap; + goto out; } ret = 0; @@ -935,12 +935,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, 0, asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); } - return ret; -out_unmap: - if (asic->tmio_cnf) - iounmap(asic->tmio_cnf); -out: + out: return ret; } diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index e281a9202f110..1abe7432aad82 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -323,10 +323,8 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, adc1 |= MC13783_ADC1_ATOX; dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__); - ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, + mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, mc13xxx_handler_adcdone, __func__, &adcdone_data); - if (ret) - goto out; mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0); mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index 3f514d77a843f..de6d44a158bba 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -266,7 +266,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, if (!priv) return -ENOMEM; - ret = ida_alloc(&alcor_pci_idr, GFP_KERNEL); + ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL); if (ret < 0) return ret; priv->id = ret; @@ -280,8 +280,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); if (ret) { dev_err(&pdev->dev, "Cannot request region\n"); - ret = -ENOMEM; - goto error_free_ida; + return -ENOMEM; } if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { @@ -325,8 +324,6 @@ static int alcor_pci_probe(struct pci_dev *pdev, error_release_regions: pci_release_regions(pdev); -error_free_ida: - ida_free(&alcor_pci_idr, priv->id); return ret; } @@ -340,7 +337,7 @@ static void alcor_pci_remove(struct pci_dev *pdev) mfd_remove_devices(&pdev->dev); - ida_free(&alcor_pci_idr, priv->id); + ida_simple_remove(&alcor_pci_idr, priv->id); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 9716b0728b306..912ddfa360b13 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -859,8 +859,6 @@ static ssize_t hl_set_power_state(struct file *f, const char __user *buf, pci_set_power_state(hdev->pdev, PCI_D0); pci_restore_state(hdev->pdev); rc = pci_enable_device(hdev->pdev); - if (rc < 0) - return rc; } else if (value == 2) { pci_save_state(hdev->pdev); pci_disable_device(hdev->pdev); diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 3e4d894719380..49489153cd162 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1060,10 +1060,10 @@ static int kgdbts_option_setup(char *opt) { if (strlen(opt) >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdbts: config string too long\n"); - return 1; + return -ENOSPC; } strcpy(config, opt); - return 1; + return 0; } __setup("kgdbts=", kgdbts_option_setup); diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index d81d75a20b8f2..67bb6a25fd0a0 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -107,7 +107,6 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ #define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ -#define MEI_DEV_ID_ADP_N 0x54E0 /* Alder Lake Point N */ /* * MEI HW Section diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index ca3067fa6f0e0..fee603039e872 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -427,26 +427,31 @@ int mei_irq_read_handler(struct mei_device *dev, list_for_each_entry(cl, &dev->file_list, link) { if (mei_cl_hbm_equal(cl, mei_hdr)) { cl_dbg(dev, cl, "got a message\n"); - ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); - goto reset_slots; + break; } } /* if no recipient cl was found we assume corrupted header */ - /* A message for not connected fixed address clients - * should be silently discarded - * On power down client may be force cleaned, - * silently discard such messages - */ - if (hdr_is_fixed(mei_hdr) || - dev->dev_state == MEI_DEV_POWER_DOWN) { - mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); - ret = 0; - goto reset_slots; + if (&cl->link == &dev->file_list) { + /* A message for not connected fixed address clients + * should be silently discarded + * On power down client may be force cleaned, + * silently discard such messages + */ + if (hdr_is_fixed(mei_hdr) || + dev->dev_state == MEI_DEV_POWER_DOWN) { + mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); + ret = 0; + goto reset_slots; + } + dev_err(dev->dev, "no destination client found 0x%08X\n", + dev->rd_msg_hdr[0]); + ret = -EBADMSG; + goto end; } - dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]); - ret = -EBADMSG; - goto end; + + ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); + reset_slots: /* reset the number of slots and header */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a738253dbd056..3a45aaf002ac8 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -113,7 +113,6 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_N, MEI_ME_PCH15_CFG)}, /* required last entry */ {0, } diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b7717fd8cb2ac..d0b71aecaee86 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -514,16 +514,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) EXPORT_SYMBOL(mmc_alloc_host); -static int mmc_validate_host_caps(struct mmc_host *host) -{ - if (host->caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) { - dev_warn(host->parent, "missing ->enable_sdio_irq() ops\n"); - return -EINVAL; - } - - return 0; -} - /** * mmc_add_host - initialise host hardware * @host: mmc host @@ -536,9 +526,8 @@ int mmc_add_host(struct mmc_host *host) { int err; - err = mmc_validate_host_caps(host); - if (err) - return err; + WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && + !host->ops->enable_sdio_irq); err = device_add(&host->class_dev); if (err) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 647928ab00a30..90cd179625fc2 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1375,12 +1375,8 @@ static int davinci_mmcsd_suspend(struct device *dev) static int davinci_mmcsd_resume(struct device *dev) { struct mmc_davinci_host *host = dev_get_drvdata(dev); - int ret; - - ret = clk_enable(host->clk); - if (ret) - return ret; + clk_enable(host->clk); mmc_davinci_reset_ctrl(host, 0); return 0; diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c index a4b8b65fe15f5..8b6f4da5d7201 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -53,12 +53,7 @@ static int generic_onenand_probe(struct platform_device *pdev) } info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL; - - err = platform_get_irq(pdev, 0); - if (err < 0) - goto out_iounmap; - - info->onenand.irq = err; + info->onenand.irq = platform_get_irq(pdev, 0); info->mtd.dev.parent = &pdev->dev; info->mtd.priv = &info->onenand; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index c048e826746a9..8aab1017b4600 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2057,15 +2057,13 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, nc->mck = of_clk_get(dev->parent->of_node, 0); if (IS_ERR(nc->mck)) { dev_err(dev, "Failed to retrieve MCK clk\n"); - ret = PTR_ERR(nc->mck); - goto out_release_dma; + return PTR_ERR(nc->mck); } np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0); if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); - ret = -EINVAL; - goto out_release_dma; + return -EINVAL; } nc->smc = syscon_node_to_regmap(np); @@ -2073,16 +2071,10 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, if (IS_ERR(nc->smc)) { ret = PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret); - goto out_release_dma; + return ret; } return 0; - -out_release_dma: - if (nc->dmac) - dma_release_channel(nc->dmac); - - return ret; } static int diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 92e8ca56f5665..cb7631145700a 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -646,7 +646,6 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, const struct nand_sdr_timings *sdr) { struct gpmi_nfc_hardware_timing *hw = &this->hw; - struct resources *r = &this->resources; unsigned int dll_threshold_ps = this->devdata->max_chain_delay; unsigned int period_ps, reference_period_ps; unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; @@ -670,8 +669,6 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; } - hw->clk_rate = clk_round_rate(r->clock[0], hw->clk_rate); - /* SDR core timings are given in picoseconds */ period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c41c0ff611b1b..1f0d542d59230 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -297,19 +297,16 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) * * Return: -EBUSY if the chip has been suspended, 0 otherwise */ -static void nand_get_device(struct nand_chip *chip) +static int nand_get_device(struct nand_chip *chip) { - /* Wait until the device is resumed. */ - while (1) { - mutex_lock(&chip->lock); - if (!chip->suspended) { - mutex_lock(&chip->controller->lock); - return; - } + mutex_lock(&chip->lock); + if (chip->suspended) { mutex_unlock(&chip->lock); - - wait_event(chip->resume_wq, !chip->suspended); + return -EBUSY; } + mutex_lock(&chip->controller->lock); + + return 0; } /** @@ -534,7 +531,9 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; ret = nand_markbad_bbm(chip, ofs); nand_release_device(chip); @@ -3535,7 +3534,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->mode != MTD_OPS_RAW) return -ENOTSUPP; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; if (!ops->datbuf) ret = nand_do_read_oob(chip, from, ops); @@ -4118,11 +4119,13 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct nand_chip *chip = mtd_to_nand(mtd); - int ret = 0; + int ret; ops->retlen = 0; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4178,7 +4181,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, return -EINVAL; /* Grab the lock and see if the device is available */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -4265,7 +4270,7 @@ static void nand_sync(struct mtd_info *mtd) pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ - nand_get_device(chip); + WARN_ON(nand_get_device(chip)); /* Release it and go back */ nand_release_device(chip); } @@ -4282,7 +4287,9 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) int ret; /* Select the NAND device */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; nand_select_target(chip, chipnr); @@ -4353,8 +4360,6 @@ static void nand_resume(struct mtd_info *mtd) __func__); } mutex_unlock(&chip->lock); - - wake_up_all(&chip->resume_wq); } /** @@ -5063,7 +5068,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, chip->cur_cs = -1; mutex_init(&chip->lock); - init_waitqueue_head(&chip->resume_wq); /* Enforce the right timings for reset/detection */ chip->current_interface_config = nand_get_reset_interface_config(); diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 9a9f1c24d8321..9e7cf9f360579 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2453,5 +2453,6 @@ static void __exit ns_cleanup_module(void) module_exit(ns_cleanup_module); MODULE_LICENSE ("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR ("Artem B. Bityuckiy"); MODULE_DESCRIPTION ("The NAND flash simulator"); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4153e0d15c5f9..0597478129ffe 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -350,6 +350,9 @@ static ssize_t dev_attribute_show(struct device *dev, * we still can use 'ubi->ubi_num'. */ ubi = container_of(dev, struct ubi_device, dev); + ubi = ubi_get_device(ubi->ubi_num); + if (!ubi) + return -ENODEV; if (attr == &dev_eraseblock_size) ret = sprintf(buf, "%d\n", ubi->leb_size); @@ -378,6 +381,7 @@ static ssize_t dev_attribute_show(struct device *dev, else ret = -EINVAL; + ubi_put_device(ubi); return ret; } @@ -976,6 +980,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, goto out_detach; } + /* Make device "available" before it becomes accessible via sysfs */ + ubi_devices[ubi_num] = ubi; + err = uif_init(ubi); if (err) goto out_detach; @@ -1020,7 +1027,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, wake_up_process(ubi->bgt_thread); spin_unlock(&ubi->wl_lock); - ubi_devices[ubi_num] = ubi; ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); return ubi_num; @@ -1029,6 +1035,7 @@ out_debugfs: out_uif: uif_close(ubi); out_detach: + ubi_devices[ubi_num] = NULL; ubi_wl_close(ubi); ubi_free_all_volumes(ubi); vfree(ubi->vtbl); @@ -1469,3 +1476,4 @@ MODULE_VERSION(__stringify(UBI_VERSION)); MODULE_DESCRIPTION("UBI - Unsorted Block Images"); MODULE_AUTHOR("Artem Bityutskiy"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 6b5f1ffd961b9..022af59906aa9 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -468,9 +468,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, if (err == UBI_IO_FF_BITFLIPS) scrub = 1; - ret = add_aeb(ai, free, pnum, ec, scrub); - if (ret) - goto out; + add_aeb(ai, free, pnum, ec, scrub); continue; } else if (err == 0 || err == UBI_IO_BITFLIPS) { dbg_bld("Found non empty PEB:%i in pool", pnum); @@ -640,10 +638,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); - if (ret) - goto fail; + add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); } /* read EC values from used list */ @@ -653,10 +649,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); - if (ret) - goto fail; + add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); } /* read EC values from scrub list */ @@ -666,10 +660,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); - if (ret) - goto fail; + add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); } /* read EC values from erase list */ @@ -679,10 +671,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); - if (ret) - goto fail; + add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); } ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 1bc7b3a056046..139ee132bfbcf 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -56,11 +56,16 @@ static ssize_t vol_attribute_show(struct device *dev, { int ret; struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); - struct ubi_device *ubi = vol->ubi; + struct ubi_device *ubi; + + ubi = ubi_get_device(vol->ubi->ubi_num); + if (!ubi) + return -ENODEV; spin_lock(&ubi->volumes_lock); if (!ubi->volumes[vol->vol_id]) { spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); return -ENODEV; } /* Take a reference to prevent volume removal */ @@ -98,6 +103,7 @@ static ssize_t vol_attribute_show(struct device *dev, vol->ref_count -= 1; ubi_assert(vol->ref_count >= 0); spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); return ret; } diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 53ef48588e59a..39b128205f255 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -140,14 +140,14 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) oiph = skb_network_header(skb); skb_reset_network_header(skb); - if (!ipv6_mod_enabled() || family == AF_INET) + if (!IS_ENABLED(CONFIG_IPV6) || family == AF_INET) err = IP_ECN_decapsulate(oiph, skb); else err = IP6_ECN_decapsulate(oiph, skb); if (unlikely(err)) { if (log_ecn_error) { - if (!ipv6_mod_enabled() || family == AF_INET) + if (!IS_ENABLED(CONFIG_IPV6) || family == AF_INET) net_info_ratelimited("non-ECT from %pI4 " "with TOS=%#x\n", &((struct iphdr *)oiph)->saddr, @@ -213,12 +213,11 @@ static struct socket *bareudp_create_sock(struct net *net, __be16 port) int err; memset(&udp_conf, 0, sizeof(udp_conf)); - - if (ipv6_mod_enabled()) - udp_conf.family = AF_INET6; - else - udp_conf.family = AF_INET; - +#if IS_ENABLED(CONFIG_IPV6) + udp_conf.family = AF_INET6; +#else + udp_conf.family = AF_INET; +#endif udp_conf.local_udp_port = port; /* Open UDP socket */ err = udp_sock_create(net, &udp_conf, &sock); @@ -247,6 +246,12 @@ static int bareudp_socket_create(struct bareudp_dev *bareudp, __be16 port) tunnel_cfg.encap_destroy = NULL; setup_udp_tunnel_sock(bareudp->net, sock, &tunnel_cfg); + /* As the setup_udp_tunnel_sock does not call udp_encap_enable if the + * socket type is v6 an explicit call to udp_encap_enable is needed. + */ + if (sock->sk->sk_family == AF_INET6) + udp_encap_enable(); + rcu_assign_pointer(bareudp->sock, sock); return 0; } @@ -440,7 +445,7 @@ static netdev_tx_t bareudp_xmit(struct sk_buff *skb, struct net_device *dev) } rcu_read_lock(); - if (ipv6_mod_enabled() && info->mode & IP_TUNNEL_INFO_IPV6) + if (IS_ENABLED(CONFIG_IPV6) && info->mode & IP_TUNNEL_INFO_IPV6) err = bareudp6_xmit_skb(skb, dev, bareudp, info); else err = bareudp_xmit_skb(skb, dev, bareudp, info); @@ -470,7 +475,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, use_cache = ip_tunnel_dst_cache_usable(skb, info); - if (!ipv6_mod_enabled() || ip_tunnel_info_af(info) == AF_INET) { + if (!IS_ENABLED(CONFIG_IPV6) || ip_tunnel_info_af(info) == AF_INET) { struct rtable *rt; __be32 saddr; diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 19a19a7b7deb8..19a7e4adb9338 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1491,6 +1491,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) M_CAN_FIFO_DATA(i / 4), *(u32 *)(cf->data + i)); + can_put_echo_skb(skb, dev, 0); + if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { cccr = m_can_read(cdev, M_CAN_CCCR); cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT); @@ -1507,9 +1509,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) m_can_write(cdev, M_CAN_CCCR, cccr); } m_can_write(cdev, M_CAN_TXBTIE, 0x1); - - can_put_echo_skb(skb, dev, 0); - m_can_write(cdev, M_CAN_TXBAR, 0x1); /* End of xmit function for version 3.0.x */ } else { diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 189d226588133..abe00a085f6fc 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -2578,7 +2578,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, out_kfree_buf_rx: kfree(buf_rx); - return err; + return 0; } #define MCP251XFD_QUIRK_ACTIVE(quirk) \ diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 6458da9c13b95..249d2fba28c7f 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -823,6 +823,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); + dev_kfree_skb(skb); atomic_dec(&dev->active_tx_urbs); diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 21063335ab599..912160fd2ca02 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -33,6 +33,10 @@ #define MCBA_USB_RX_BUFF_SIZE 64 #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg)) +/* MCBA endpoint numbers */ +#define MCBA_USB_EP_IN 1 +#define MCBA_USB_EP_OUT 1 + /* Microchip command id */ #define MBCA_CMD_RECEIVE_MESSAGE 0xE3 #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5 @@ -80,8 +84,6 @@ struct mcba_priv { atomic_t free_ctx_cnt; void *rxbuf[MCBA_MAX_RX_URBS]; dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS]; - int rx_pipe; - int tx_pipe; }; /* CAN frame */ @@ -270,8 +272,10 @@ static netdev_tx_t mcba_usb_xmit(struct mcba_priv *priv, memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE); - usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE, - mcba_usb_write_bulk_callback, ctx); + usb_fill_bulk_urb(urb, priv->udev, + usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf, + MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback, + ctx); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &priv->tx_submitted); @@ -364,6 +368,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, xmit_failed: can_free_echo_skb(priv->netdev, ctx->ndx); mcba_usb_free_ctx(ctx); + dev_kfree_skb(skb); stats->tx_dropped++; return NETDEV_TX_OK; @@ -606,7 +611,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb) resubmit_urb: usb_fill_bulk_urb(urb, priv->udev, - priv->rx_pipe, + usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_OUT), urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); @@ -651,7 +656,7 @@ static int mcba_usb_start(struct mcba_priv *priv) urb->transfer_dma = buf_dma; usb_fill_bulk_urb(urb, priv->udev, - priv->rx_pipe, + usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN), buf, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -805,13 +810,6 @@ static int mcba_usb_probe(struct usb_interface *intf, struct mcba_priv *priv; int err; struct usb_device *usbdev = interface_to_usbdev(intf); - struct usb_endpoint_descriptor *in, *out; - - err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL); - if (err) { - dev_err(&intf->dev, "Can't find endpoints\n"); - return err; - } netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS); if (!netdev) { @@ -857,9 +855,6 @@ static int mcba_usb_probe(struct usb_interface *intf, goto cleanup_free_candev; } - priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress); - priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress); - devm_can_led_init(netdev); /* Start USB dev only if we have successfully registered CAN device */ diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 985e00aee4ee1..ca7c55d6a41db 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -670,20 +670,9 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, atomic_inc(&priv->active_tx_urbs); err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - can_free_echo_skb(netdev, context->echo_index); - - usb_unanchor_urb(urb); - usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); - - atomic_dec(&priv->active_tx_urbs); - - if (err == -ENODEV) - netif_device_detach(netdev); - else - netdev_warn(netdev, "failed tx_urb %d\n", err); - stats->tx_dropped++; - } else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) + if (unlikely(err)) + goto failed; + else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) /* Slow down tx path */ netif_stop_queue(netdev); @@ -702,6 +691,19 @@ nofreecontext: return NETDEV_TX_BUSY; +failed: + can_free_echo_skb(netdev, context->echo_index); + + usb_unanchor_urb(urb); + usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + + atomic_dec(&priv->active_tx_urbs); + + if (err == -ENODEV) + netif_device_detach(netdev); + else + netdev_warn(netdev, "failed tx_urb %d\n", err); + nomembuf: usb_free_urb(urb); diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 282c53ef76d23..7000c6cd1e48b 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -148,7 +148,7 @@ static void vxcan_setup(struct net_device *dev) dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0; - dev->flags = IFF_NOARP; + dev->flags = (IFF_NOARP|IFF_ECHO); dev->netdev_ops = &vxcan_netdev_ops; dev->needs_free_netdev = true; diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index cbf44fc7d03aa..d82cee5d92022 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -567,14 +567,14 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, static struct cfp_rule *bcm_sf2_cfp_rule_find(struct bcm_sf2_priv *priv, int port, u32 location) { - struct cfp_rule *rule; + struct cfp_rule *rule = NULL; list_for_each_entry(rule, &priv->cfp.rules_list, next) { if (rule->port == port && rule->fs.location == location) - return rule; + break; } - return NULL; + return rule; } static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port, diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index 5639c5c59e255..8b00f8e6c02f4 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -86,23 +86,12 @@ static const struct of_device_id ksz8795_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); -static const struct spi_device_id ksz8795_spi_ids[] = { - { "ksz8765" }, - { "ksz8794" }, - { "ksz8795" }, - { "ksz8863" }, - { "ksz8873" }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); - static struct spi_driver ksz8795_spi_driver = { .driver = { .name = "ksz8795-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz8795_dt_ids), }, - .id_table = ksz8795_spi_ids, .probe = ksz8795_spi_probe, .remove = ksz8795_spi_remove, .shutdown = ksz8795_spi_shutdown, diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 9bda83d063e8e..1142768969c20 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -88,24 +88,12 @@ static const struct of_device_id ksz9477_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); -static const struct spi_device_id ksz9477_spi_ids[] = { - { "ksz9477" }, - { "ksz9897" }, - { "ksz9893" }, - { "ksz9563" }, - { "ksz8563" }, - { "ksz9567" }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids); - static struct spi_driver ksz9477_spi_driver = { .driver = { .name = "ksz9477-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz9477_dt_ids), }, - .id_table = ksz9477_spi_ids, .probe = ksz9477_spi_probe, .remove = ksz9477_spi_remove, .shutdown = ksz9477_spi_shutdown, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e79a808375fc8..1992be77522ac 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3297,7 +3297,6 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_set_link = mv88e6xxx_port_set_link, .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, - .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c index 065fdbe66c425..4ad8031ab6695 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -406,12 +406,12 @@ static int mcf8390_init(struct net_device *dev) static int mcf8390_probe(struct platform_device *pdev) { struct net_device *dev; - struct resource *mem; + struct resource *mem, *irq; resource_size_t msize; - int ret, irq; + int ret; - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq == NULL) { dev_err(&pdev->dev, "no IRQ specified?\n"); return -ENXIO; } @@ -434,7 +434,7 @@ static int mcf8390_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); - dev->irq = irq; + dev->irq = irq->start; dev->base_addr = mem->start; ret = mcf8390_init(dev); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 78c7cbc372b05..5f1fc6582d74a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -696,12 +696,6 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, buf_pool->rx_skb[skb_index] = NULL; datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1)); - - /* strip off CRC as HW isn't doing this */ - nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0)); - if (!nv) - datalen -= 4; - skb_put(skb, datalen); prefetch(skb->data - NET_IP_ALIGN); skb->protocol = eth_type_trans(skb, ndev); @@ -723,8 +717,12 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, } } - if (!nv) + nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0)); + if (!nv) { + /* strip off CRC as HW isn't doing this */ + datalen -= 4; goto skip_jumbo; + } slots = page_pool->slots - 1; head = page_pool->head; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2a61229d3f976..bb3ba614fb174 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2534,4 +2534,6 @@ void bnx2x_register_phc(struct bnx2x *bp); * Meant for implicit re-load flows. */ int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp); +int bnx2x_init_firmware(struct bnx2x *bp); +void bnx2x_release_firmware(struct bnx2x *bp); #endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 198e041d84109..41ebbb2c7d3ac 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2363,30 +2363,24 @@ int bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err) /* is another pf loaded on this engine? */ if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { - u8 loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng; - u32 loaded_fw; + /* build my FW version dword */ + u32 my_fw = (bp->fw_major) + (bp->fw_minor << 8) + + (bp->fw_rev << 16) + (bp->fw_eng << 24); /* read loaded FW from chip */ - loaded_fw = REG_RD(bp, XSEM_REG_PRAM); + u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); - loaded_fw_major = loaded_fw & 0xff; - loaded_fw_minor = (loaded_fw >> 8) & 0xff; - loaded_fw_rev = (loaded_fw >> 16) & 0xff; - loaded_fw_eng = (loaded_fw >> 24) & 0xff; - - DP(BNX2X_MSG_SP, "loaded fw 0x%x major 0x%x minor 0x%x rev 0x%x eng 0x%x\n", - loaded_fw, loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng); + DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n", + loaded_fw, my_fw); /* abort nic load if version mismatch */ - if (loaded_fw_major != BCM_5710_FW_MAJOR_VERSION || - loaded_fw_minor != BCM_5710_FW_MINOR_VERSION || - loaded_fw_eng != BCM_5710_FW_ENGINEERING_VERSION || - loaded_fw_rev < BCM_5710_FW_REVISION_VERSION_V15) { + if (my_fw != loaded_fw) { if (print_err) - BNX2X_ERR("loaded FW incompatible. Aborting\n"); + BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n", + loaded_fw, my_fw); else - BNX2X_DEV_INFO("loaded FW incompatible, possibly due to MF UNDI\n"); - + BNX2X_DEV_INFO("bnx2x with FW %x was already loaded which mismatches my %x FW, possibly due to MF UNDI\n", + loaded_fw, my_fw); return -EBUSY; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 6333471916be1..7fa271db41b07 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12366,6 +12366,15 @@ static int bnx2x_init_bp(struct bnx2x *bp) bnx2x_read_fwinfo(bp); + if (IS_PF(bp)) { + rc = bnx2x_init_firmware(bp); + + if (rc) { + bnx2x_free_mem_bp(bp); + return rc; + } + } + func = BP_FUNC(bp); /* need to reset chip if undi was active */ @@ -12378,6 +12387,7 @@ static int bnx2x_init_bp(struct bnx2x *bp) rc = bnx2x_prev_unload(bp); if (rc) { + bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); return rc; } @@ -13459,7 +13469,7 @@ do { \ (u8 *)bp->arr, len); \ } while (0) -static int bnx2x_init_firmware(struct bnx2x *bp) +int bnx2x_init_firmware(struct bnx2x *bp) { const char *fw_file_name, *fw_file_name_v15; struct bnx2x_fw_file_hdr *fw_hdr; @@ -13559,7 +13569,7 @@ request_firmware_exit: return rc; } -static void bnx2x_release_firmware(struct bnx2x *bp) +void bnx2x_release_firmware(struct bnx2x *bp) { kfree(bp->init_ops_offsets); kfree(bp->init_ops); @@ -14076,6 +14086,7 @@ static int bnx2x_init_one(struct pci_dev *pdev, return 0; init_one_freemem: + bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); init_one_exit: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 7dcd5613ee56f..e19cf020e5ae1 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -76,7 +76,7 @@ static inline void bcmgenet_writel(u32 value, void __iomem *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) __raw_writel(value, offset); else - writel(value, offset); + writel_relaxed(value, offset); } static inline u32 bcmgenet_readl(void __iomem *offset) @@ -84,7 +84,7 @@ static inline u32 bcmgenet_readl(void __iomem *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) return __raw_readl(offset); else - return readl(offset); + return readl_relaxed(offset); } static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, @@ -2239,10 +2239,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, dma_length_status = status->length_status; if (dev->features & NETIF_F_RXCSUM) { rx_csum = (__force __be16)(status->rx_csum & 0xffff); - if (rx_csum) { - skb->csum = (__force __wsum)ntohs(rx_csum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + skb->csum = (__force __wsum)ntohs(rx_csum); + skb->ip_summed = CHECKSUM_COMPLETE; } /* DMA flags and length are still valid no matter how diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index cf98a00296edf..9c1690f64a027 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -651,10 +651,7 @@ static int enetc_get_ts_info(struct net_device *ndev, #ifdef CONFIG_FSL_ENETC_PTP_CLOCK info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE | - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; + SOF_TIMESTAMPING_RAW_HARDWARE; info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2070e26a3a358..7b94764b4f5d9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7616,11 +7616,12 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport, hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hclge_prepare_mac_addr(&req, addr, false); ret = hclge_remove_mac_vlan_tbl(vport, &req); - if (!ret || ret == -ENOENT) { + if (!ret) { mutex_lock(&hdev->vport_lock); hclge_update_umv_space(vport, true); mutex_unlock(&hdev->vport_lock); - return 0; + } else if (ret == -ENOENT) { + ret = 0; } return ret; @@ -9197,11 +9198,11 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, } if (!ret) { - if (!is_kill) + if (is_kill) + hclge_rm_vport_vlan_table(vport, vlan_id, false); + else hclge_add_vport_vlan_table(vport, vlan_id, writen_to_tbl); - else if (is_kill && vlan_id != 0) - hclge_rm_vport_vlan_table(vport, vlan_id, false); } else if (is_kill) { /* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 75e4a698c3db2..86c79f71c685a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -247,25 +247,21 @@ no_buffers: static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp) { - unsigned int totalsize = xdp->data_end - xdp->data_meta; unsigned int metasize = xdp->data - xdp->data_meta; + unsigned int datasize = xdp->data_end - xdp->data; struct sk_buff *skb; - net_prefetch(xdp->data_meta); - /* allocate a skb to store the frags */ - skb = __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, + skb = __napi_alloc_skb(&rx_ring->q_vector->napi, + xdp->data_end - xdp->data_hard_start, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; - memcpy(__skb_put(skb, totalsize), xdp->data_meta, - ALIGN(totalsize, sizeof(long))); - - if (metasize) { + skb_reserve(skb, xdp->data - xdp->data_hard_start); + memcpy(__skb_put(skb, datasize), xdp->data, datasize); + if (metasize) skb_metadata_set(skb, metasize); - __skb_pull(skb, metasize); - } xsk_buff_free(xdp); return skb; diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index c4c4649b2088e..217e8333de6c6 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -54,12 +54,6 @@ static int ocelot_chain_to_block(int chain, bool ingress) */ static int ocelot_chain_to_lookup(int chain) { - /* Backwards compatibility with older, single-chain tc-flower - * offload support in Ocelot - */ - if (chain == 0) - return 0; - return (chain / VCAP_LOOKUP) % 10; } @@ -68,15 +62,7 @@ static int ocelot_chain_to_lookup(int chain) */ static int ocelot_chain_to_pag(int chain) { - int lookup; - - /* Backwards compatibility with older, single-chain tc-flower - * offload support in Ocelot - */ - if (chain == 0) - return 0; - - lookup = ocelot_chain_to_lookup(chain); + int lookup = ocelot_chain_to_lookup(chain); /* calculate PAG value as chain index relative to the first PAG */ return chain - VCAP_IS2_CHAIN(lookup, 0); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index e14869a2e24a5..d355676f6c160 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -311,10 +311,10 @@ int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) static void ionic_dev_cmd_clean(struct ionic *ionic) { - struct ionic_dev *idev = &ionic->idev; + union __iomem ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; - iowrite32(0, &idev->dev_cmd_regs->doorbell); - memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd)); + iowrite32(0, ®s->doorbell); + memset_io(®s->cmd, 0, sizeof(regs->cmd)); } int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 3541bc95493f0..ef0ad4cf82e60 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -2982,16 +2982,12 @@ static int qed_iov_pre_update_vport(struct qed_hwfn *hwfn, u8 mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED; struct qed_filter_accept_flags *flags = ¶ms->accept_flags; struct qed_public_vf_info *vf_info; - u16 tlv_mask; - - tlv_mask = BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) | - BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN); /* Untrusted VFs can't even be trusted to know that fact. * Simply indicate everything is configured fine, and trace * configuration 'behind their back'. */ - if (!(*tlvs & tlv_mask)) + if (!(*tlvs & BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM))) return 0; vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); @@ -3008,13 +3004,6 @@ static int qed_iov_pre_update_vport(struct qed_hwfn *hwfn, flags->tx_accept_filter &= ~mask; } - if (params->update_accept_any_vlan_flg) { - vf_info->accept_any_vlan = params->accept_any_vlan; - - if (vf_info->forced_vlan && !vf_info->is_trusted_configured) - params->accept_any_vlan = false; - } - return 0; } @@ -4702,7 +4691,6 @@ static int qed_get_vf_config(struct qed_dev *cdev, tx_rate = vf_info->tx_rate; ivi->max_tx_rate = tx_rate ? tx_rate : link.speed; ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id); - ivi->trusted = vf_info->is_trusted_request; return 0; } @@ -5132,12 +5120,6 @@ static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn) params.update_ctl_frame_check = 1; params.mac_chk_en = !vf_info->is_trusted_configured; - params.update_accept_any_vlan_flg = 0; - - if (vf_info->accept_any_vlan && vf_info->forced_vlan) { - params.update_accept_any_vlan_flg = 1; - params.accept_any_vlan = vf_info->accept_any_vlan; - } if (vf_info->rx_accept_mode & mask) { flags->update_rx_mode_config = 1; @@ -5153,20 +5135,13 @@ static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn) if (!vf_info->is_trusted_configured) { flags->rx_accept_filter &= ~mask; flags->tx_accept_filter &= ~mask; - params.accept_any_vlan = false; } if (flags->update_rx_mode_config || flags->update_tx_mode_config || - params.update_ctl_frame_check || - params.update_accept_any_vlan_flg) { - DP_VERBOSE(hwfn, QED_MSG_IOV, - "vport update config for %s VF[abs 0x%x rel 0x%x]\n", - vf_info->is_trusted_configured ? "trusted" : "untrusted", - vf->abs_vf_id, vf->relative_vf_id); + params.update_ctl_frame_check) qed_sp_vport_update(hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); - } } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 7ff23ef8ccc17..eacd6457f195c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -62,7 +62,6 @@ struct qed_public_vf_info { bool is_trusted_request; u8 rx_accept_mode; u8 tx_accept_mode; - bool accept_any_vlan; }; struct qed_iov_vf_init_params { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h index 7519773eaca6e..5d79ee4370bcd 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -51,7 +51,7 @@ static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->get_hw_capability) return dcb->ops->get_hw_capability(dcb); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_free(struct qlcnic_dcb *dcb) @@ -65,7 +65,7 @@ static inline int qlcnic_dcb_attach(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->attach) return dcb->ops->attach(dcb); - return -EOPNOTSUPP; + return 0; } static inline int @@ -74,7 +74,7 @@ qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *dcb, char *buf) if (dcb && dcb->ops->query_hw_capability) return dcb->ops->query_hw_capability(dcb, buf); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_get_info(struct qlcnic_dcb *dcb) @@ -89,7 +89,7 @@ qlcnic_dcb_query_cee_param(struct qlcnic_dcb *dcb, char *buf, u8 type) if (dcb && dcb->ops->query_cee_param) return dcb->ops->query_cee_param(dcb, buf, type); - return -EOPNOTSUPP; + return 0; } static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) @@ -97,7 +97,7 @@ static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->get_cee_cfg) return dcb->ops->get_cee_cfg(dcb); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *msg) diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 69fc47089e625..54b53dbdb33cd 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -3163,7 +3163,7 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR "happymeal(PCI): Cannot register net device, " "aborting.\n"); - goto err_out_free_coherent; + goto err_out_iounmap; } pci_set_drvdata(pdev, hp); @@ -3196,10 +3196,6 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, return 0; -err_out_free_coherent: - dma_free_coherent(hp->dma_dev, PAGE_SIZE, - hp->happy_block, hp->hblock_dvma); - err_out_iounmap: iounmap(hp->gregs); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index bbdcba88c021e..0baf85122f5ac 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -857,53 +857,46 @@ static void axienet_recv(struct net_device *ndev) while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { dma_addr_t phys; + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + /* Ensure we see complete descriptor update */ dma_rmb(); + phys = desc_get_phys_addr(lp, cur_p); + dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, + DMA_FROM_DEVICE); skb = cur_p->skb; cur_p->skb = NULL; - - /* skb could be NULL if a previous pass already received the - * packet for this slot in the ring, but failed to refill it - * with a newly allocated buffer. In this case, don't try to - * receive it again. - */ - if (likely(skb)) { - length = cur_p->app4 & 0x0000FFFF; - - phys = desc_get_phys_addr(lp, cur_p); - dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, - DMA_FROM_DEVICE); - - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, ndev); - /*skb_checksum_none_assert(skb);*/ - skb->ip_summed = CHECKSUM_NONE; - - /* if we're doing Rx csum offload, set it up */ - if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { - csumstatus = (cur_p->app2 & - XAE_FULL_CSUM_STATUS_MASK) >> 3; - if (csumstatus == XAE_IP_TCP_CSUM_VALIDATED || - csumstatus == XAE_IP_UDP_CSUM_VALIDATED) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == htons(ETH_P_IP) && - skb->len > 64) { - skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); - skb->ip_summed = CHECKSUM_COMPLETE; + length = cur_p->app4 & 0x0000FFFF; + + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, ndev); + /*skb_checksum_none_assert(skb);*/ + skb->ip_summed = CHECKSUM_NONE; + + /* if we're doing Rx csum offload, set it up */ + if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { + csumstatus = (cur_p->app2 & + XAE_FULL_CSUM_STATUS_MASK) >> 3; + if ((csumstatus == XAE_IP_TCP_CSUM_VALIDATED) || + (csumstatus == XAE_IP_UDP_CSUM_VALIDATED)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; } + } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && + skb->protocol == htons(ETH_P_IP) && + skb->len > 64) { + skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); + skb->ip_summed = CHECKSUM_COMPLETE; + } - netif_rx(skb); + netif_rx(skb); - size += length; - packets++; - } + size += length; + packets++; new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); if (!new_skb) - break; + return; phys = dma_map_single(ndev->dev.parent, new_skb->data, lp->max_frm_size, @@ -912,7 +905,7 @@ static void axienet_recv(struct net_device *ndev) if (net_ratelimit()) netdev_err(ndev, "RX DMA mapping error\n"); dev_kfree_skb(new_skb); - break; + return; } desc_set_phys_addr(lp, phys, cur_p); @@ -920,11 +913,6 @@ static void axienet_recv(struct net_device *ndev) cur_p->status = 0; cur_p->skb = new_skb; - /* Only update tail_p to mark this slot as usable after it has - * been successfully refilled. - */ - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; - if (++lp->rx_bd_ci >= lp->rx_bd_num) lp->rx_bd_ci = 0; cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 02d6f3ad9aca8..bd0beb16d68a9 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -674,14 +674,14 @@ static void sixpack_close(struct tty_struct *tty) */ netif_stop_queue(sp->dev); - unregister_netdev(sp->dev); - del_timer_sync(&sp->tx_t); del_timer_sync(&sp->resync_t); /* Free all 6pack frame buffers. */ kfree(sp->rbuff); kfree(sp->xbuff); + + unregister_netdev(sp->dev); } /* Perform I/O control on an active 6pack channel. */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e3676386d0eeb..261e6e55a907b 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1562,9 +1562,6 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, pcpu_sum = kvmalloc_array(num_possible_cpus(), sizeof(struct netvsc_ethtool_pcpu_stats), GFP_KERNEL); - if (!pcpu_sum) - return; - netvsc_get_pcpu_stats(dev, pcpu_sum); for_each_present_cpu(cpu) { struct netvsc_ethtool_pcpu_stats *this_sum = &pcpu_sum[cpu]; diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 0cde17bd743f3..644861366d544 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -11,7 +11,6 @@ */ #include "bcm-phy-lib.h" -#include #include #include #include @@ -623,26 +622,6 @@ static int brcm_fet_config_init(struct phy_device *phydev) if (err < 0) return err; - /* The datasheet indicates the PHY needs up to 1us to complete a reset, - * build some slack here. - */ - usleep_range(1000, 2000); - - /* The PHY requires 65 MDC clock cycles to complete a write operation - * and turnaround the line properly. - * - * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) - * may flag the lack of turn-around as a read failure. This is - * particularly true with this combination since the MDIO controller - * only used 64 MDC cycles. This is not a critical failure in this - * specific case and it has no functional impact otherwise, so we let - * that one go through. If there is a genuine bus error, the next read - * of MII_BRCM_FET_INTREG will error out. - */ - err = phy_read(phydev, MII_BMCR); - if (err < 0 && err != -EIO) - return err; - reg = phy_read(phydev, MII_BRCM_FET_INTREG); if (reg < 0) return reg; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 54786712a9913..cb9d1852a75c8 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1536,8 +1536,8 @@ static int marvell_suspend(struct phy_device *phydev) int err; /* Suspend the fiber mode first */ - if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1571,8 +1571,8 @@ static int marvell_resume(struct phy_device *phydev) int err; /* Resume the fiber mode first */ - if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index e14fa72791b0e..41a410124437d 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2584,6 +2584,3 @@ MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl); MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver"); MODULE_AUTHOR("Nagaraju Lakkaraju"); MODULE_LICENSE("Dual MIT/GPL"); - -MODULE_FIRMWARE(MSCC_VSC8584_REVB_INT8051_FW); -MODULE_FIRMWARE(MSCC_VSC8574_REVB_INT8051_FW); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index e5b7448511467..465e11dcdf129 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -84,10 +84,9 @@ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, &buf, 4); - if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", - index, ret); + if (unlikely(ret < 0)) { + netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", + index, ret); return ret; } @@ -117,7 +116,7 @@ static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index, ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, &buf, 4); - if (ret < 0 && ret != -ENODEV) + if (unlikely(ret < 0)) netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n", index, ret); @@ -160,9 +159,6 @@ static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev, do { ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm); if (ret < 0) { - /* Ignore -ENODEV error during disconnect() */ - if (ret == -ENODEV) - return 0; netdev_warn(dev->net, "Error reading MII_ACCESS\n"); return ret; } @@ -198,8 +194,7 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, addr = mii_address_cmd(phy_id, idx, MII_READ_ | MII_BUSY_); ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_ADDR\n"); + netdev_warn(dev->net, "Error writing MII_ADDR\n"); goto done; } @@ -211,8 +206,7 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error reading MII_DATA\n"); + netdev_warn(dev->net, "Error reading MII_DATA\n"); goto done; } @@ -220,10 +214,6 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, done: mutex_unlock(&dev->phy_mutex); - - /* Ignore -ENODEV error during disconnect() */ - if (ret == -ENODEV) - return 0; return ret; } @@ -245,8 +235,7 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id, val = regval; ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_DATA\n"); + netdev_warn(dev->net, "Error writing MII_DATA\n"); goto done; } @@ -254,8 +243,7 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id, addr = mii_address_cmd(phy_id, idx, MII_WRITE_ | MII_BUSY_); ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_ADDR\n"); + netdev_warn(dev->net, "Error writing MII_ADDR\n"); goto done; } @@ -1061,14 +1049,6 @@ static const struct net_device_ops smsc95xx_netdev_ops = { .ndo_set_features = smsc95xx_set_features, }; -static void smsc95xx_handle_link_change(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - phy_print_status(net->phydev); - usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); -} - static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) { struct smsc95xx_priv *pdata; @@ -1173,17 +1153,6 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->min_mtu = ETH_MIN_MTU; dev->net->max_mtu = ETH_DATA_LEN; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - - ret = phy_connect_direct(dev->net, pdata->phydev, - &smsc95xx_handle_link_change, - PHY_INTERFACE_MODE_MII); - if (ret) { - netdev_err(dev->net, "can't attach PHY to %s\n", pdata->mdiobus->id); - goto unregister_mdio; - } - - phy_attached_info(dev->net->phydev); - return 0; unregister_mdio: @@ -1201,25 +1170,47 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) { struct smsc95xx_priv *pdata = dev->driver_priv; - phy_disconnect(dev->net->phydev); mdiobus_unregister(pdata->mdiobus); mdiobus_free(pdata->mdiobus); netif_dbg(dev, ifdown, dev->net, "free pdata\n"); kfree(pdata); } +static void smsc95xx_handle_link_change(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + phy_print_status(net->phydev); + usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); +} + static int smsc95xx_start_phy(struct usbnet *dev) { - phy_start(dev->net->phydev); + struct smsc95xx_priv *pdata = dev->driver_priv; + struct net_device *net = dev->net; + int ret; + + ret = smsc95xx_reset(dev); + if (ret < 0) + return ret; + ret = phy_connect_direct(net, pdata->phydev, + &smsc95xx_handle_link_change, + PHY_INTERFACE_MODE_MII); + if (ret) { + netdev_err(net, "can't attach PHY to %s\n", pdata->mdiobus->id); + return ret; + } + + phy_attached_info(net->phydev); + phy_start(net->phydev); return 0; } -static int smsc95xx_stop(struct usbnet *dev) +static int smsc95xx_disconnect_phy(struct usbnet *dev) { - if (dev->net->phydev) - phy_stop(dev->net->phydev); - + phy_stop(dev->net->phydev); + phy_disconnect(dev->net->phydev); return 0; } @@ -1973,9 +1964,8 @@ static const struct driver_info smsc95xx_info = { .bind = smsc95xx_bind, .unbind = smsc95xx_unbind, .link_reset = smsc95xx_link_reset, - .reset = smsc95xx_reset, - .check_connect = smsc95xx_start_phy, - .stop = smsc95xx_stop, + .reset = smsc95xx_start_phy, + .stop = smsc95xx_disconnect_phy, .rx_fixup = smsc95xx_rx_fixup, .tx_fixup = smsc95xx_tx_fixup, .status = smsc95xx_status, diff --git a/drivers/net/wireguard/queueing.c b/drivers/net/wireguard/queueing.c index 8084e7408c0ae..1de413b19e342 100644 --- a/drivers/net/wireguard/queueing.c +++ b/drivers/net/wireguard/queueing.c @@ -4,7 +4,6 @@ */ #include "queueing.h" -#include struct multicore_worker __percpu * wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) @@ -43,7 +42,7 @@ void wg_packet_queue_free(struct crypt_queue *queue, bool purge) { free_percpu(queue->worker); WARN_ON(!purge && !__ptr_ring_empty(&queue->ring)); - ptr_ring_cleanup(&queue->ring, purge ? __skb_array_destroy_skb : NULL); + ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL); } #define NEXT(skb) ((skb)->prev) diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index 473221aa22368..52b9bc83abcbc 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -160,7 +160,6 @@ out: rcu_read_unlock_bh(); return ret; #else - kfree_skb(skb); return -EAFNOSUPPORT; #endif } @@ -242,7 +241,7 @@ int wg_socket_endpoint_from_skb(struct endpoint *endpoint, endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; endpoint->src4.s_addr = ip_hdr(skb)->daddr; endpoint->src_if4 = skb->skb_iif; - } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6)) { + } else if (skb->protocol == htons(ETH_P_IPV6)) { endpoint->addr6.sin6_family = AF_INET6; endpoint->addr6.sin6_port = udp_hdr(skb)->source; endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr; @@ -285,7 +284,7 @@ void wg_socket_set_peer_endpoint(struct wg_peer *peer, peer->endpoint.addr4 = endpoint->addr4; peer->endpoint.src4 = endpoint->src4; peer->endpoint.src_if4 = endpoint->src_if4; - } else if (IS_ENABLED(CONFIG_IPV6) && endpoint->addr.sa_family == AF_INET6) { + } else if (endpoint->addr.sa_family == AF_INET6) { peer->endpoint.addr6 = endpoint->addr6; peer->endpoint.src6 = endpoint->src6; } else { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index e5a296039f714..daae470ecf5aa 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1477,11 +1477,11 @@ static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size) node = of_parse_phandle(dev->of_node, "memory-region", 0); if (node) { ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(dev, "failed to resolve msa fixed region\n"); return ret; } + of_node_put(node); ar->msa.paddr = r.start; ar->msa.mem_size = resource_size(&r); diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 20b9aa8ddf7d5..7d65c115669fe 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -337,15 +337,14 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, if (patterns[i].mask[j / 8] & BIT(j % 8)) bitmask[j] = 0xff; old_pattern.mask = bitmask; + new_pattern = old_pattern; if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { - if (patterns[i].pkt_offset < ETH_HLEN) { + if (patterns[i].pkt_offset < ETH_HLEN) ath10k_wow_convert_8023_to_80211(&new_pattern, &old_pattern); - } else { - new_pattern = old_pattern; + else new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; - } } if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 994ec48b2f669..510e61e97dbcb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -30,7 +30,6 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, hdr->endpoint_id = epid; hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); - memset(hdr->control, 0, sizeof(hdr->control)); status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); @@ -273,10 +272,6 @@ int htc_connect_service(struct htc_target *target, conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid; - /* To prevent infoleak */ - conn_msg->svc_meta_len = 0; - conn_msg->pad = 0; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index b903b856bcf7b..dbef9d8fc893b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1916,7 +1916,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) WARN_ON(!(tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)); - tx_params |= (tx_streams - 1) << + tx_params = (tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 20f4f8ea9f894..bee9110b91f38 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -666,14 +666,14 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, /* * Some users have reported their EEPROM programmed with - * 0x8000 set, this is not a supported regulatory domain - * but since we have more than one user with it we need - * a solution for them. We default to 0x64, which is the - * default Atheros world regulatory domain. + * 0x8000 or 0x0 set, this is not a supported regulatory + * domain but since we have more than one user with it we + * need a solution for them. We default to 0x64, which is + * the default Atheros world regulatory domain. */ static void ath_regd_sanitize(struct ath_regulatory *reg) { - if (reg->current_rd != COUNTRY_ERD_FLAG) + if (reg->current_rd != COUNTRY_ERD_FLAG && reg->current_rd != 0) return; printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n"); reg->current_rd = 0x64; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 37e6e49de3366..9aaf6f7473333 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1362,9 +1362,6 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, if (iris_node) { if (of_device_is_compatible(iris_node, "qcom,wcn3620")) wcn->rf_id = RF_IRIS_WCN3620; - if (of_device_is_compatible(iris_node, "qcom,wcn3660") || - of_device_is_compatible(iris_node, "qcom,wcn3660b")) - wcn->rf_id = RF_IRIS_WCN3660; if (of_device_is_compatible(iris_node, "qcom,wcn3680")) wcn->rf_id = RF_IRIS_WCN3680; of_node_put(iris_node); diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 82be08265c06c..5c40d0bdee245 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -96,7 +96,6 @@ enum wcn36xx_ampdu_state { #define RF_UNKNOWN 0x0000 #define RF_IRIS_WCN3620 0x3620 -#define RF_IRIS_WCN3660 0x3660 #define RF_IRIS_WCN3680 0x3680 static inline void buff_to_be(u32 *buf, size_t len) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index a2b8d9171af2a..d821a4758f8cf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -207,8 +207,6 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp, size = BRCMF_FW_MAX_NVRAM_SIZE; else size = data_len; - /* Add space for properties we may add */ - size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1; /* Alloc for extra 0 byte + roundup by 4 + length field */ size += 1 + 3 + sizeof(u32); nvp->nvram = kzalloc(size, GFP_KERNEL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 61febc9bfa14a..1f12dfb33938a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -447,6 +446,47 @@ brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, } +static void +brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + void *srcaddr, u32 len) +{ + void __iomem *address = devinfo->tcm + mem_offset; + __le32 *src32; + __le16 *src16; + u8 *src8; + + if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) { + if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) { + src8 = (u8 *)srcaddr; + while (len) { + iowrite8(*src8, address); + address++; + src8++; + len--; + } + } else { + len = len / 2; + src16 = (__le16 *)srcaddr; + while (len) { + iowrite16(le16_to_cpu(*src16), address); + address += 2; + src16++; + len--; + } + } + } else { + len = len / 4; + src32 = (__le32 *)srcaddr; + while (len) { + iowrite32(le32_to_cpu(*src32), address); + address += 4; + src32++; + len--; + } + } +} + + static void brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, void *dstaddr, u32 len) @@ -1306,18 +1346,6 @@ static void brcmf_pcie_down(struct device *dev) { } -static int brcmf_pcie_preinit(struct device *dev) -{ - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; - - brcmf_dbg(PCIE, "Enter\n"); - - brcmf_pcie_intr_enable(buspub->devinfo); - brcmf_pcie_hostready(buspub->devinfo); - - return 0; -} static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb) { @@ -1426,7 +1454,6 @@ static int brcmf_pcie_reset(struct device *dev) } static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { - .preinit = brcmf_pcie_preinit, .txdata = brcmf_pcie_tx, .stop = brcmf_pcie_down, .txctl = brcmf_pcie_tx_ctlpkt, @@ -1534,8 +1561,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, return err; brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name); - memcpy_toio(devinfo->tcm + devinfo->ci->rambase, - (void *)fw->data, fw->size); + brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase, + (void *)fw->data, fw->size); resetintr = get_unaligned_le32(fw->data); release_firmware(fw); @@ -1549,7 +1576,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); address = devinfo->ci->rambase + devinfo->ci->ramsize - nvram_len; - memcpy_toio(devinfo->tcm + address, nvram, nvram_len); + brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); } else { brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", @@ -1748,8 +1775,6 @@ static void brcmf_pcie_setup(struct device *dev, int ret, ret = brcmf_chip_get_raminfo(devinfo->ci); if (ret) { brcmf_err(bus, "Failed to get RAM info\n"); - release_firmware(fw); - brcmf_fw_nvram_free(nvram); goto fail; } @@ -1799,6 +1824,9 @@ static void brcmf_pcie_setup(struct device *dev, int ret, init_waitqueue_head(&devinfo->mbdata_resp_wait); + brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); + ret = brcmf_attach(&devinfo->pdev->dev); if (ret) goto fail; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 1e21cdbb7313b..423d3c396b2d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -304,7 +304,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); - return ret; + return 0; } static void iwlagn_mac_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 54b28f0932e25..6348dfa61724a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1495,10 +1495,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) while (!sband && i < NUM_NL80211_BANDS) sband = mvm->hw->wiphy->bands[i++]; - if (WARN_ON_ONCE(!sband)) { - ret = -ENODEV; + if (WARN_ON_ONCE(!sband)) goto error; - } chan = &sband->channels[0]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index bdff89cc3105e..c9226dceb510c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -618,9 +618,6 @@ mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; - if (!sta_rates) - return; - spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index defa207f53d6f..88cdc2badeae7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -673,9 +673,6 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; - if (!sta_rates) - return; - spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 41054ee43dbfa..9a7f317a098fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1259,11 +1259,8 @@ mt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, generic = (struct wtbl_generic *)tlv; if (sta) { - if (vif->type == NL80211_IFTYPE_STATION) - generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); - else - generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); + generic->partial_aid = cpu_to_le16(sta->aid); generic->muar_idx = mvif->omac_idx; generic->qos = sta->wme; } else { @@ -1317,15 +1314,12 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); - basic->aid = cpu_to_le16(sta->aid); break; case NL80211_IFTYPE_STATION: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); - basic->aid = cpu_to_le16(vif->bss_conf.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - basic->aid = cpu_to_le16(sta->aid); break; default: WARN_ON(1); @@ -1333,6 +1327,7 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } memcpy(basic->peer_addr, sta->addr, ETH_ALEN); + basic->aid = cpu_to_le16(sta->aid); basic->qos = sta->wme; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 091eea0d958d1..bf3fbd14eda3c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -382,8 +382,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->sram = ioremap(link->resource[2]->start, resource_size(link->resource[2])); - if (!local->sram) - goto failed; /*** Set up 16k window for shared memory (receive buffer) ***************/ link->resource[3]->flags |= @@ -398,8 +396,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->rmem = ioremap(link->resource[3]->start, resource_size(link->resource[3])); - if (!local->rmem) - goto failed; /*** Set up window for attribute memory ***********************************/ link->resource[4]->flags |= @@ -414,8 +410,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->amem = ioremap(link->resource[4]->start, resource_size(link->resource[4])); - if (!local->amem) - goto failed; dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index 0841e0e370a03..c8bdf078d1115 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -320,11 +320,6 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, return -ENOMEM; transaction->aid_len = skb->data[1]; - - /* Checking if the length of the AID is valid */ - if (transaction->aid_len > sizeof(transaction->aid)) - return -EINVAL; - memcpy(transaction->aid, &skb->data[2], transaction->aid_len); @@ -334,11 +329,6 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, return -EPROTO; transaction->params_len = skb->data[transaction->aid_len + 3]; - - /* Total size is allocated (skb->len - 2) minus fixed array members */ - if (transaction->params_len > ((skb->len - 2) - sizeof(struct nfc_evt_transaction))) - return -EINVAL; - memcpy(transaction->params, skb->data + transaction->aid_len + 4, transaction->params_len); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 1d72653b5c8d1..e05cc9f8a9fd1 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -1018,9 +1018,6 @@ static unsigned long default_align(struct nd_region *nd_region) } } - if (nd_region->ndr_size < MEMREMAP_COMPAT_ALIGN_MAX) - align = PAGE_SIZE; - mappings = max_t(u16, 1, nd_region->ndr_mappings); div_u64_rem(align, mappings, &remainder); if (remainder) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 853b9a24f744e..71c85c99e86c6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3681,15 +3681,16 @@ static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys, return NULL; } -static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys, - struct nvme_ns_ids *ids) +static int __nvme_check_ids(struct nvme_subsystem *subsys, + struct nvme_ns_head *new) { struct nvme_ns_head *h; lockdep_assert_held(&subsys->lock); list_for_each_entry(h, &subsys->nsheads, entry) { - if (nvme_ns_ids_valid(ids) && nvme_ns_ids_equal(ids, &h->ids)) + if (nvme_ns_ids_valid(&new->ids) && + nvme_ns_ids_equal(&new->ids, &h->ids)) return -EINVAL; } @@ -3723,7 +3724,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, head->ids = *ids; kref_init(&head->ref); - ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, &head->ids); + ret = __nvme_check_ids(ctrl->subsys, head); if (ret) { dev_err(ctrl->device, "duplicate IDs for nsid %d\n", nsid); diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 7e39320337072..6105894a218a5 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -30,44 +30,6 @@ static int so_priority; module_param(so_priority, int, 0644); MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); -#ifdef CONFIG_DEBUG_LOCK_ALLOC -/* lockdep can detect a circular dependency of the form - * sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock - * because dependencies are tracked for both nvme-tcp and user contexts. Using - * a separate class prevents lockdep from conflating nvme-tcp socket use with - * user-space socket API use. - */ -static struct lock_class_key nvme_tcp_sk_key[2]; -static struct lock_class_key nvme_tcp_slock_key[2]; - -static void nvme_tcp_reclassify_socket(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (WARN_ON_ONCE(!sock_allow_reclassification(sk))) - return; - - switch (sk->sk_family) { - case AF_INET: - sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME", - &nvme_tcp_slock_key[0], - "sk_lock-AF_INET-NVME", - &nvme_tcp_sk_key[0]); - break; - case AF_INET6: - sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME", - &nvme_tcp_slock_key[1], - "sk_lock-AF_INET6-NVME", - &nvme_tcp_sk_key[1]); - break; - default: - WARN_ON_ONCE(1); - } -} -#else -static void nvme_tcp_reclassify_socket(struct socket *sock) { } -#endif - enum nvme_tcp_send_state { NVME_TCP_SEND_CMD_PDU = 0, NVME_TCP_SEND_H2C_PDU, @@ -1460,8 +1422,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, goto err_destroy_mutex; } - nvme_tcp_reclassify_socket(queue->sock); - /* Single syn retry */ tcp_sock_set_syncnt(queue->sock->sk, 1); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 9a8fa2e582d5b..f0f9d9007d49c 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1602,3 +1602,4 @@ module_init(nvmet_init); module_exit(nvmet_exit); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 8d0d1f61c650d..46935695cfb90 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -160,12 +160,9 @@ int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, * write happen to have any RW1C (write-one-to-clear) bits set, we * just inadvertently cleared something we shouldn't have. */ - if (!bus->unsafe_warn) { - dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", - size, pci_domain_nr(bus), bus->number, - PCI_SLOT(devfn), PCI_FUNC(devfn), where); - bus->unsafe_warn = 1; - } + dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", + size, pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where); mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); tmp = readl(addr) & mask; diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 49ff8bf10c740..f30144c8c0bd2 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -851,9 +851,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, case PCI_EXP_RTSTA: { u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG); u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG); - *value = msglog >> 16; - if (isr0 & PCIE_MSG_PM_PME_MASK) - *value |= PCI_EXP_RTSTA_PME; + *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16); return PCI_BRIDGE_EMUL_HANDLED; } diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index e1c2daa50b498..b651b6f444691 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -467,7 +467,7 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) return 1; } - if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) { + if ((size > SZ_1K) && (size < SZ_4G) && !(*ib_reg_mask & (1 << 0))) { *ib_reg_mask |= (1 << 0); return 0; } @@ -481,27 +481,28 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) } static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, - struct of_pci_range *range, u8 *ib_reg_mask) + struct resource_entry *entry, + u8 *ib_reg_mask) { void __iomem *cfg_base = port->cfg_base; struct device *dev = port->dev; void *bar_addr; u32 pim_reg; - u64 cpu_addr = range->cpu_addr; - u64 pci_addr = range->pci_addr; - u64 size = range->size; + u64 cpu_addr = entry->res->start; + u64 pci_addr = cpu_addr - entry->offset; + u64 size = resource_size(entry->res); u64 mask = ~(size - 1) | EN_REG; u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64; u32 bar_low; int region; - region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); + region = xgene_pcie_select_ib_reg(ib_reg_mask, size); if (region < 0) { dev_warn(dev, "invalid pcie dma-range config\n"); return; } - if (range->flags & IORESOURCE_PREFETCH) + if (entry->res->flags & IORESOURCE_PREFETCH) flags |= PCI_BASE_ADDRESS_MEM_PREFETCH; bar_low = pcie_bar_low_val((u32)cpu_addr, flags); @@ -532,25 +533,13 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) { - struct device_node *np = port->node; - struct of_pci_range range; - struct of_pci_range_parser parser; - struct device *dev = port->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port); + struct resource_entry *entry; u8 ib_reg_mask = 0; - if (of_pci_dma_range_parser_init(&parser, np)) { - dev_err(dev, "missing dma-ranges property\n"); - return -EINVAL; - } - - /* Get the dma-ranges from DT */ - for_each_of_pci_range(&parser, &range) { - u64 end = range.cpu_addr + range.size - 1; + resource_list_for_each_entry(entry, &bridge->dma_ranges) + xgene_pcie_setup_ib_reg(port, entry, &ib_reg_mask); - dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", - range.flags, range.cpu_addr, end, range.pci_addr); - xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); - } return 0; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index af4c4cc837fcd..30708af975adc 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -98,8 +98,6 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout) if (slot_status & PCI_EXP_SLTSTA_CC) { pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); - ctrl->cmd_busy = 0; - smp_mb(); return 1; } msleep(10); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0d7109018a91f..fbb4d765b43c8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "pci.h" DEFINE_MUTEX(pci_slot_mutex); @@ -68,8 +69,11 @@ static void pci_dev_d3_sleep(struct pci_dev *dev) if (delay < pci_pm_d3hot_delay) delay = pci_pm_d3hot_delay; - if (delay) - msleep(delay); + if (delay) { + trace_android_rvh_pci_d3_sleep(dev, &delay); + if (delay) + msleep(delay); + } } #ifdef CONFIG_PCI_DOMAINS diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 52d454ec9bd29..d6974502d9622 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1816,18 +1816,6 @@ static void quirk_alder_ioapic(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif -static void quirk_no_msi(struct pci_dev *dev) -{ - pci_info(dev, "avoiding MSI to work around a hardware defect\n"); - dev->no_msi = 1; -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4386, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4387, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4388, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4389, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438a, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438b, quirk_no_msi); - static void quirk_pcie_mch(struct pci_dev *pdev) { pdev->no_msi = 1; diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c index 0aa740b73d0db..14e0551cd3190 100644 --- a/drivers/phy/phy-core-mipi-dphy.c +++ b/drivers/phy/phy-core-mipi-dphy.c @@ -66,10 +66,10 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock, cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui); cfg->init = 100; - cfg->lpx = 50000; + cfg->lpx = 60000; cfg->ta_get = 5 * cfg->lpx; cfg->ta_go = 4 * cfg->lpx; - cfg->ta_sure = cfg->lpx; + cfg->ta_sure = 2 * cfg->lpx; cfg->wakeup = 1000; cfg->hs_clk_rate = hs_clk_rate; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 730581d130649..a02ad10ec6fad 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1039,7 +1039,6 @@ int mtk_pctrl_init(struct platform_device *pdev, node = of_parse_phandle(np, "mediatek,pctl-regmap", 0); if (node) { pctl->regmap1 = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(pctl->regmap1)) return PTR_ERR(pctl->regmap1); } else if (regmap) { @@ -1053,7 +1052,6 @@ int mtk_pctrl_init(struct platform_device *pdev, node = of_parse_phandle(np, "mediatek,pctl-regmap", 1); if (node) { pctl->regmap2 = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(pctl->regmap2)) return PTR_ERR(pctl->regmap2); } diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c index d0a4ebbe1e7e6..623af4410b07c 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.c +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -96,16 +96,20 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); if (err) goto out; - if (ret == MTK_PUPD_SET_R1R0_00) - ret = MTK_DISABLE; if (param == PIN_CONFIG_BIAS_DISABLE) { - if (ret != MTK_DISABLE) - err = -EINVAL; + if (ret == MTK_PUPD_SET_R1R0_00) + ret = MTK_DISABLE; } else if (param == PIN_CONFIG_BIAS_PULL_UP) { - if (!pullup || ret == MTK_DISABLE) + /* When desire to get pull-up value, return + * error if current setting is pull-down + */ + if (!pullup) err = -EINVAL; } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { - if (pullup || ret == MTK_DISABLE) + /* When desire to get pull-down value, return + * error if current setting is pull-up + */ + if (pullup) err = -EINVAL; } } else { @@ -184,7 +188,8 @@ out: } static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - enum pin_config_param param, u32 arg) + enum pin_config_param param, + enum pin_config_param arg) { struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); const struct mtk_pin_desc *desc; @@ -580,9 +585,6 @@ ssize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, if (gpio >= hw->soc->npins) return -EINVAL; - if (mtk_is_virt_gpio(hw, gpio)) - return -EINVAL; - desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; pinmux = mtk_pctrl_get_pinmux(hw, gpio); if (pinmux >= hw->soc->nfuncs) @@ -717,10 +719,10 @@ static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, unsigned long *config) { struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - struct mtk_pinctrl_group *grp = &hw->groups[group]; - /* One pin per group only */ - return mtk_pinconf_get(pctldev, grp->pin, config); + *config = hw->groups[group].config; + + return 0; } static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, @@ -736,6 +738,8 @@ static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, pinconf_to_config_argument(configs[i])); if (ret < 0) return ret; + + grp->config = configs[i]; } return 0; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 6d77feda9090a..657e35a75d84a 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1883,10 +1883,8 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) } prcm_np = of_parse_phandle(np, "prcm", 0); - if (prcm_np) { + if (prcm_np) npct->prcm_base = of_iomap(prcm_np, 0); - of_node_put(prcm_np); - } if (!npct->prcm_base) { if (version == PINCTRL_NMK_STN8815) { dev_info(&pdev->dev, diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index ce36b6ff7b95e..6de31b5ee358c 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -78,6 +78,7 @@ struct npcm7xx_gpio { struct gpio_chip gc; int irqbase; int irq; + void *priv; struct irq_chip irq_chip; u32 pinctrl_id; int (*direction_input)(struct gpio_chip *chip, unsigned offset); @@ -225,7 +226,7 @@ static void npcmgpio_irq_handler(struct irq_desc *desc) chained_irq_enter(chip, desc); sts = ioread32(bank->base + NPCM7XX_GP_N_EVST); en = ioread32(bank->base + NPCM7XX_GP_N_EVEN); - dev_dbg(bank->gc.parent, "==> got irq sts %.8x %.8x\n", sts, + dev_dbg(chip->parent_device, "==> got irq sts %.8x %.8x\n", sts, en); sts &= en; @@ -240,33 +241,33 @@ static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio = BIT(d->hwirq); - dev_dbg(bank->gc.parent, "setirqtype: %u.%u = %u\n", gpio, + dev_dbg(d->chip->parent_device, "setirqtype: %u.%u = %u\n", gpio, d->irq, type); switch (type) { case IRQ_TYPE_EDGE_RISING: - dev_dbg(bank->gc.parent, "edge.rising\n"); + dev_dbg(d->chip->parent_device, "edge.rising\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_FALLING: - dev_dbg(bank->gc.parent, "edge.falling\n"); + dev_dbg(d->chip->parent_device, "edge.falling\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_BOTH: - dev_dbg(bank->gc.parent, "edge.both\n"); + dev_dbg(d->chip->parent_device, "edge.both\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); break; case IRQ_TYPE_LEVEL_LOW: - dev_dbg(bank->gc.parent, "level.low\n"); + dev_dbg(d->chip->parent_device, "level.low\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_LEVEL_HIGH: - dev_dbg(bank->gc.parent, "level.high\n"); + dev_dbg(d->chip->parent_device, "level.high\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; default: - dev_dbg(bank->gc.parent, "invalid irq type\n"); + dev_dbg(d->chip->parent_device, "invalid irq type\n"); return -EINVAL; } @@ -288,7 +289,7 @@ static void npcmgpio_irq_ack(struct irq_data *d) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio = d->hwirq; - dev_dbg(bank->gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_ack: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); } @@ -300,7 +301,7 @@ static void npcmgpio_irq_mask(struct irq_data *d) unsigned int gpio = d->hwirq; /* Clear events */ - dev_dbg(bank->gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_mask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); } @@ -312,7 +313,7 @@ static void npcmgpio_irq_unmask(struct irq_data *d) unsigned int gpio = d->hwirq; /* Enable events */ - dev_dbg(bank->gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_unmask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); } @@ -322,7 +323,7 @@ static unsigned int npcmgpio_irq_startup(struct irq_data *d) unsigned int gpio = d->hwirq; /* active-high, input, clear interrupt, enable interrupt */ - dev_dbg(gc->parent, "startup: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "startup: %u.%u\n", gpio, d->irq); npcmgpio_direction_input(gc, gpio); npcmgpio_irq_ack(d); npcmgpio_irq_unmask(d); @@ -904,7 +905,7 @@ static struct npcm7xx_func npcm7xx_funcs[] = { #define DRIVE_STRENGTH_HI_SHIFT 12 #define DRIVE_STRENGTH_MASK 0x0000FF00 -#define DSTR(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ +#define DS(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ ((hi) << DRIVE_STRENGTH_HI_SHIFT)) #define DSLO(x) (((x) >> DRIVE_STRENGTH_LO_SHIFT) & 0xF) #define DSHI(x) (((x) >> DRIVE_STRENGTH_HI_SHIFT) & 0xF) @@ -924,31 +925,31 @@ struct npcm7xx_pincfg { static const struct npcm7xx_pincfg pincfg[] = { /* PIN FUNCTION 1 FUNCTION 2 FUNCTION 3 FLAGS */ NPCM7XX_PINCFG(0, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(3, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(4, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), NPCM7XX_PINCFG(5, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), NPCM7XX_PINCFG(6, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), NPCM7XX_PINCFG(7, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(12, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), NPCM7XX_PINCFG(13, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), NPCM7XX_PINCFG(14, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), NPCM7XX_PINCFG(15, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(20, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), NPCM7XX_PINCFG(21, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), NPCM7XX_PINCFG(22, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), NPCM7XX_PINCFG(23, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), - NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0), @@ -964,12 +965,12 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(39, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), NPCM7XX_PINCFG(40, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), NPCM7XX_PINCFG(41, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DSTR(2, 4) | GPO), + NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DS(2, 4) | GPO), NPCM7XX_PINCFG(43, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), NPCM7XX_PINCFG(44, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), NPCM7XX_PINCFG(45, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DSTR(2, 8)), - NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DSTR(2, 8)), + NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), + NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), NPCM7XX_PINCFG(48, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, GPO), NPCM7XX_PINCFG(49, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, 0), NPCM7XX_PINCFG(50, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), @@ -979,8 +980,8 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(54, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(55, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), NPCM7XX_PINCFG(59, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(60, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(61, uart1, MFSEL1, 10, none, NONE, 0, none, NONE, 0, GPO), @@ -1003,19 +1004,19 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(77, fanin13, MFSEL2, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(78, fanin14, MFSEL2, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(79, fanin15, MFSEL2, 15, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(87, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(88, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(89, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), NPCM7XX_PINCFG(93, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), NPCM7XX_PINCFG(94, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), NPCM7XX_PINCFG(95, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), @@ -1061,34 +1062,34 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(133, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(134, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(135, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(141, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(143, sd1, MFSEL3, 12, sd1pwr, MFSEL4, 5, none, NONE, 0, 0), - NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(153, mmcwp, FLOCKR1, 24, none, NONE, 0, none, NONE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(155, mmccd, MFSEL3, 25, mmcrst, MFSEL4, 6, none, NONE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - - NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DSTR(8, 12)), - NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + + NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DS(8, 12)), + NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(163, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), NPCM7XX_PINCFG(164, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), NPCM7XX_PINCFG(165, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), @@ -1101,25 +1102,25 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(172, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(173, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(174, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(181, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(182, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), /* XX */ - - NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), /* XX */ + NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ + + NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ NPCM7XX_PINCFG(193, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(194, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(195, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), @@ -1130,11 +1131,11 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(200, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(201, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(202, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(204, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), NPCM7XX_PINCFG(205, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DSTR(4, 8)), + NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), NPCM7XX_PINCFG(208, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(209, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(210, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), @@ -1146,20 +1147,20 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(216, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(217, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(218, wdog1, MFSEL3, 19, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), + NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), NPCM7XX_PINCFG(220, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(221, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(222, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(223, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(224, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(253, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC1 power */ NPCM7XX_PINCFG(254, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC2 power */ NPCM7XX_PINCFG(255, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* DACOSEL */ @@ -1560,7 +1561,7 @@ static int npcm7xx_get_groups_count(struct pinctrl_dev *pctldev) { struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); - dev_dbg(npcm->dev, "group size: %zu\n", ARRAY_SIZE(npcm7xx_groups)); + dev_dbg(npcm->dev, "group size: %d\n", ARRAY_SIZE(npcm7xx_groups)); return ARRAY_SIZE(npcm7xx_groups); } diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 42e27dba62e26..1e225d5139888 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -30,10 +30,10 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, - "input bias pull to pin specific state", "ohms", true), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true), + "input bias pull to pin specific state", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 9df48e0cf4cb4..53a0badc6b035 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3774,7 +3774,6 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) node = of_parse_phandle(np, "rockchip,grf", 0); if (node) { info->regmap_base = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(info->regmap_base)) return PTR_ERR(info->regmap_base); } else { @@ -3811,7 +3810,6 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) node = of_parse_phandle(np, "rockchip,pmu", 0); if (node) { info->regmap_pmu = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(info->regmap_pmu)) return PTR_ERR(info->regmap_pmu); } diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c index 258972672eda1..9d168b90cd281 100644 --- a/drivers/pinctrl/renesas/core.c +++ b/drivers/pinctrl/renesas/core.c @@ -739,7 +739,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; } #ifdef DEBUG #define SH_PFC_MAX_REGS 300 -#define SH_PFC_MAX_ENUMS 5000 +#define SH_PFC_MAX_ENUMS 3000 static unsigned int sh_pfc_errors __initdata = 0; static unsigned int sh_pfc_warnings __initdata = 0; @@ -851,8 +851,7 @@ static void __init sh_pfc_check_cfg_reg(const char *drvname, sh_pfc_check_reg(drvname, cfg_reg->reg); if (cfg_reg->field_width) { - fw = cfg_reg->field_width; - n = (cfg_reg->reg_width / fw) << fw; + n = cfg_reg->reg_width / cfg_reg->field_width; /* Skip field checks (done at build time) */ goto check_enum_ids; } diff --git a/drivers/pinctrl/renesas/pfc-r8a77470.c b/drivers/pinctrl/renesas/pfc-r8a77470.c index 14005725a726b..b3b116da1bb0d 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77470.c +++ b/drivers/pinctrl/renesas/pfc-r8a77470.c @@ -2121,7 +2121,7 @@ static const unsigned int vin0_clk_mux[] = { VI0_CLK_MARK, }; /* - VIN1 ------------------------------------------------------------------- */ -static const union vin_data12 vin1_data_pins = { +static const union vin_data vin1_data_pins = { .data12 = { RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4), @@ -2131,7 +2131,7 @@ static const union vin_data12 vin1_data_pins = { RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16), }, }; -static const union vin_data12 vin1_data_mux = { +static const union vin_data vin1_data_mux = { .data12 = { VI1_DATA0_MARK, VI1_DATA1_MARK, VI1_DATA2_MARK, VI1_DATA3_MARK, diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 56fff83a143bd..7f809a57bee50 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1002,16 +1002,6 @@ samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device *pdev) return &(of_data->ctrl[id]); } -static void samsung_banks_of_node_put(struct samsung_pinctrl_drv_data *d) -{ - struct samsung_pin_bank *bank; - unsigned int i; - - bank = d->pin_banks; - for (i = 0; i < d->nr_banks; ++i, ++bank) - of_node_put(bank->of_node); -} - /* retrieve the soc specific data */ static const struct samsung_pin_ctrl * samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, @@ -1126,19 +1116,19 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) if (ctrl->retention_data) { drvdata->retention_ctrl = ctrl->retention_data->init(drvdata, ctrl->retention_data); - if (IS_ERR(drvdata->retention_ctrl)) { - ret = PTR_ERR(drvdata->retention_ctrl); - goto err_put_banks; - } + if (IS_ERR(drvdata->retention_ctrl)) + return PTR_ERR(drvdata->retention_ctrl); } ret = samsung_pinctrl_register(pdev, drvdata); if (ret) - goto err_put_banks; + return ret; ret = samsung_gpiolib_register(pdev, drvdata); - if (ret) - goto err_unregister; + if (ret) { + samsung_pinctrl_unregister(pdev, drvdata); + return ret; + } if (ctrl->eint_gpio_init) ctrl->eint_gpio_init(drvdata); @@ -1148,12 +1138,6 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); return 0; - -err_unregister: - samsung_pinctrl_unregister(pdev, drvdata); -err_put_banks: - samsung_banks_of_node_put(drvdata); - return ret; } /* diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 88cbc434c06b2..f901d2e43166c 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,7 +2,6 @@ # tell define_trace.h where to find the cros ec trace header CFLAGS_cros_ec_trace.o:= -I$(src) -CFLAGS_cros_ec_sensorhub_ring.o:= -I$(src) obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o @@ -21,7 +20,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o -cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o +cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o cros_ec_trace.o obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c index 71948dade0e2a..98e37080f7609 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -17,8 +17,7 @@ #include #include -#define CREATE_TRACE_POINTS -#include "cros_ec_sensorhub_trace.h" +#include "cros_ec_trace.h" /* Precision of fixed point for the m values from the filter */ #define M_PRECISION BIT(23) diff --git a/drivers/platform/chrome/cros_ec_sensorhub_trace.h b/drivers/platform/chrome/cros_ec_sensorhub_trace.h deleted file mode 100644 index 57d9b47859692..0000000000000 --- a/drivers/platform/chrome/cros_ec_sensorhub_trace.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Trace events for the ChromeOS Sensorhub kernel module - * - * Copyright 2021 Google LLC. - */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM cros_ec - -#if !defined(_CROS_EC_SENSORHUB_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) -#define _CROS_EC_SENSORHUB_TRACE_H_ - -#include -#include - -#include - -TRACE_EVENT(cros_ec_sensorhub_timestamp, - TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp, - current_time), - TP_STRUCT__entry( - __field(u32, ec_sample_timestamp) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sample_timestamp = ec_sample_timestamp; - __entry->ec_fifo_timestamp = ec_fifo_timestamp; - __entry->fifo_timestamp = fifo_timestamp; - __entry->current_timestamp = current_timestamp; - __entry->current_time = current_time; - __entry->delta = current_timestamp - current_time; - ), - TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", - __entry->ec_sample_timestamp, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_data, - TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time), - TP_STRUCT__entry( - __field(u32, ec_sensor_num) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sensor_num = ec_sensor_num; - __entry->ec_fifo_timestamp = ec_fifo_timestamp; - __entry->fifo_timestamp = fifo_timestamp; - __entry->current_timestamp = current_timestamp; - __entry->current_time = current_time; - __entry->delta = current_timestamp - current_time; - ), - TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", - __entry->ec_sensor_num, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_filter, - TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy), - TP_ARGS(state, dx, dy), - TP_STRUCT__entry( - __field(s64, dx) - __field(s64, dy) - __field(s64, median_m) - __field(s64, median_error) - __field(s64, history_len) - __field(s64, x) - __field(s64, y) - ), - TP_fast_assign( - __entry->dx = dx; - __entry->dy = dy; - __entry->median_m = state->median_m; - __entry->median_error = state->median_error; - __entry->history_len = state->history_len; - __entry->x = state->x_offset; - __entry->y = state->y_offset; - ), - TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %lld x: %12lld y: %12lld", - __entry->dx, - __entry->dy, - __entry->median_m, - __entry->median_error, - __entry->history_len, - __entry->x, - __entry->y - ) -); - - -#endif /* _CROS_EC_SENSORHUB_TRACE_H_ */ - -/* this part must be outside header guard */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . - -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE cros_ec_sensorhub_trace - -#include diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h index 9bb5cd2c98b8b..7e7cfc98657a4 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -70,6 +71,100 @@ TRACE_EVENT(cros_ec_request_done, __entry->retval) ); +TRACE_EVENT(cros_ec_sensorhub_timestamp, + TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp, + current_time), + TP_STRUCT__entry( + __field(u32, ec_sample_timestamp) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sample_timestamp = ec_sample_timestamp; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sample_timestamp, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_data, + TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time), + TP_STRUCT__entry( + __field(u32, ec_sensor_num) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sensor_num = ec_sensor_num; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sensor_num, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_filter, + TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy), + TP_ARGS(state, dx, dy), + TP_STRUCT__entry( + __field(s64, dx) + __field(s64, dy) + __field(s64, median_m) + __field(s64, median_error) + __field(s64, history_len) + __field(s64, x) + __field(s64, y) + ), + TP_fast_assign( + __entry->dx = dx; + __entry->dy = dy; + __entry->median_m = state->median_m; + __entry->median_error = state->median_error; + __entry->history_len = state->history_len; + __entry->x = state->x_offset; + __entry->y = state->y_offset; + ), + TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %lld x: %12lld y: %12lld", + __entry->dx, + __entry->dy, + __entry->median_m, + __entry->median_error, + __entry->history_len, + __entry->x, + __entry->y + ) +); + + #endif /* _CROS_EC_TRACE_H_ */ /* this part must be outside header guard */ diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 935db0e2f1cd8..f0cf5e76597e9 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -711,13 +711,7 @@ static int cros_typec_probe(struct platform_device *pdev) return -ENOMEM; typec->dev = dev; - typec->ec = dev_get_drvdata(pdev->dev.parent); - if (!typec->ec) { - dev_err(dev, "couldn't find parent EC device\n"); - return -ENODEV; - } - platform_set_drvdata(pdev, typec); ret = cros_typec_get_cmd_version(typec); diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index eac3e6b4ea113..a2d846c4a7eef 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -470,17 +470,10 @@ static DEVICE_ATTR_RW(charge_control_thresholds); static int huawei_wmi_battery_add(struct power_supply *battery) { - int err = 0; + device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); + device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); - err = device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); - if (err) - return err; - - err = device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); - if (err) - device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); - - return err; + return 0; } static int huawei_wmi_battery_remove(struct power_supply *battery) diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c index b7f7a8225f22e..90e35c07240ae 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c @@ -107,8 +107,8 @@ static int gemini_poweroff_probe(struct platform_device *pdev) return PTR_ERR(gpw->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (!irq) + return -EINVAL; gpw->dev = dev; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index a6b4a94c27662..f1da757c939f8 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2541,10 +2541,8 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di) ret = kobject_init_and_add(&di->fg_kobject, &ab8500_fg_ktype, NULL, "battery"); - if (ret < 0) { - kobject_put(&di->fg_kobject); + if (ret < 0) dev_err(di->dev, "failed to create sysfs entry\n"); - } return ret; } diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 8c3c378dce0d5..845af0f44c022 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -41,7 +41,6 @@ #define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0 #define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1 #define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 -#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3 #define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1)) #define BQ24190_REG_POC_SYS_MIN_SHIFT 1 #define BQ24190_REG_POC_SYS_MIN_MIN 3000 @@ -553,11 +552,7 @@ static int bq24190_vbus_is_enabled(struct regulator_dev *dev) pm_runtime_mark_last_busy(bdi->dev); pm_runtime_put_autosuspend(bdi->dev); - if (ret) - return ret; - - return (val == BQ24190_REG_POC_CHG_CONFIG_OTG || - val == BQ24190_REG_POC_CHG_CONFIG_OTG_ALT); + return ret ? ret : val == BQ24190_REG_POC_CHG_CONFIG_OTG; } static const struct regulator_ops bq24190_vbus_ops = { diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index 908cfd45d2624..e05cee457471b 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -408,112 +408,44 @@ static const struct power_supply_desc wm8350_usb_desc = { * Initialisation *********************************************************************/ -static int wm8350_init_charger(struct wm8350 *wm8350) +static void wm8350_init_charger(struct wm8350 *wm8350) { - int ret; - /* register our interest in charger events */ - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350_charger_handler, 0, "Battery hot", wm8350); - if (ret) - goto err; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350_charger_handler, 0, "Battery cold", wm8350); - if (ret) - goto free_chg_bat_hot; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350_charger_handler, 0, "Battery fail", wm8350); - if (ret) - goto free_chg_bat_cold; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350_charger_handler, 0, "Charger timeout", wm8350); - if (ret) - goto free_chg_bat_fail; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, wm8350_charger_handler, 0, "Charge end", wm8350); - if (ret) - goto free_chg_to; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, wm8350_charger_handler, 0, "Charge start", wm8350); - if (ret) - goto free_chg_end; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350_charger_handler, 0, "Fast charge ready", wm8350); - if (ret) - goto free_chg_start; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350_charger_handler, 0, "Battery <3.9V", wm8350); - if (ret) - goto free_chg_fast_rdy; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350_charger_handler, 0, "Battery <3.1V", wm8350); - if (ret) - goto free_chg_vbatt_lt_3p9; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350_charger_handler, 0, "Battery <2.85V", wm8350); - if (ret) - goto free_chg_vbatt_lt_3p1; /* and supply change events */ - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350_charger_handler, 0, "USB", wm8350); - if (ret) - goto free_chg_vbatt_lt_2p85; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350_charger_handler, 0, "Wall", wm8350); - if (ret) - goto free_ext_usb_fb; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350_charger_handler, 0, "Battery", wm8350); - if (ret) - goto free_ext_wall_fb; - - return 0; - -free_ext_wall_fb: - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); -free_ext_usb_fb: - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); -free_chg_vbatt_lt_2p85: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); -free_chg_vbatt_lt_3p1: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); -free_chg_vbatt_lt_3p9: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); -free_chg_fast_rdy: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); -free_chg_start: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); -free_chg_end: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); -free_chg_to: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); -free_chg_bat_fail: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); -free_chg_bat_cold: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); -free_chg_bat_hot: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); -err: - return ret; } static void free_charger_irq(struct wm8350 *wm8350) @@ -524,7 +456,6 @@ static void free_charger_irq(struct wm8350 *wm8350) wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 9b15b6a79082a..5ff11145c1a30 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -400,6 +400,12 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT, BIT(lpc18xx_pwm->period_event)); + ret = pwmchip_add(&lpc18xx_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); + goto disable_pwmclk; + } + for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { struct lpc18xx_pwm_data *data; @@ -409,12 +415,14 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) GFP_KERNEL); if (!data) { ret = -ENOMEM; - goto disable_pwmclk; + goto remove_pwmchip; } pwm_set_chip_data(pwm, data); } + platform_set_drvdata(pdev, lpc18xx_pwm); + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); val &= ~LPC18XX_PWM_BIDIR; val &= ~LPC18XX_PWM_CTRL_HALT; @@ -422,16 +430,10 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) val |= LPC18XX_PWM_PRE(0); lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); - ret = pwmchip_add(&lpc18xx_pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); - goto disable_pwmclk; - } - - platform_set_drvdata(pdev, lpc18xx_pwm); - return 0; +remove_pwmchip: + pwmchip_remove(&lpc18xx_pwm->chip); disable_pwmclk: clk_disable_unprepare(lpc18xx_pwm->pwm_clk); return ret; diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 8d784a2a09d86..03e146e98abd5 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -1185,10 +1185,8 @@ static int rpm_reg_probe(struct platform_device *pdev) for_each_available_child_of_node(dev->of_node, node) { vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - of_node_put(node); + if (!vreg) return -ENOMEM; - } ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data); diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 991b4730d7687..ee46bfbf5eee7 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -37,24 +37,11 @@ static const struct regmap_config attiny_regmap_config = { static int attiny_lcd_power_enable(struct regulator_dev *rdev) { unsigned int data; - int ret, i; regmap_write(rdev->regmap, REG_POWERON, 1); - msleep(80); - /* Wait for nPWRDWN to go low to indicate poweron is done. */ - for (i = 0; i < 20; i++) { - ret = regmap_read(rdev->regmap, REG_PORTB, &data); - if (!ret) { - if (data & BIT(0)) - break; - } - usleep_range(10000, 12000); - } - usleep_range(10000, 12000); - - if (ret) - pr_err("%s: regmap_read_poll_timeout failed %d\n", __func__, ret); + regmap_read_poll_timeout(rdev->regmap, REG_PORTB, data, + data & BIT(0), 10, 1000000); /* Default to the same orientation as the closed source * firmware used for the panel. Runtime rotation @@ -70,34 +57,23 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) { regmap_write(rdev->regmap, REG_PWM, 0); regmap_write(rdev->regmap, REG_POWERON, 0); - msleep(30); + udelay(1); return 0; } static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { unsigned int data; - int ret, i; + int ret; - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_POWERON, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } + ret = regmap_read(rdev->regmap, REG_POWERON, &data); if (ret < 0) return ret; if (!(data & BIT(0))) return 0; - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTB, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } - + ret = regmap_read(rdev->regmap, REG_PORTB, &data); if (ret < 0) return ret; @@ -127,32 +103,20 @@ static int attiny_update_status(struct backlight_device *bl) { struct regmap *regmap = bl_get_data(bl); int brightness = bl->props.brightness; - int ret, i; if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK) brightness = 0; - for (i = 0; i < 10; i++) { - ret = regmap_write(regmap, REG_PWM, brightness); - if (!ret) - break; - } - - return ret; + return regmap_write(regmap, REG_PWM, brightness); } static int attiny_get_brightness(struct backlight_device *bl) { struct regmap *regmap = bl_get_data(bl); - int ret, brightness, i; - - for (i = 0; i < 10; i++) { - ret = regmap_read(regmap, REG_PWM, &brightness); - if (!ret) - break; - } + int ret, brightness; + ret = regmap_read(regmap, REG_PWM, &brightness); if (ret) return ret; @@ -202,7 +166,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c, } regmap_write(regmap, REG_POWERON, 0); - msleep(30); + mdelay(1); config.dev = &i2c->dev; config.regmap = regmap; diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index d7478c6bc0c89..44aebfc3bf712 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -406,7 +406,6 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) return ret; diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 1b3aa84e36e7a..ebc3e755bcbcd 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1594,20 +1594,18 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) * reserved memory regions from device's memory-region property. */ child = of_get_child_by_name(qproc->dev->of_node, "mba"); - if (!child) { + if (!child) node = of_parse_phandle(qproc->dev->of_node, "memory-region", 0); - } else { + else node = of_parse_phandle(child, "memory-region", 0); - of_node_put(child); - } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mba region\n"); return ret; } + of_node_put(node); qproc->mba_phys = r.start; qproc->mba_size = resource_size(&r); @@ -1624,15 +1622,14 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) } else { child = of_get_child_by_name(qproc->dev->of_node, "mpss"); node = of_parse_phandle(child, "memory-region", 0); - of_node_put(child); } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mpss region\n"); return ret; } + of_node_put(node); qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_size = resource_size(&r); diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 4e2527fcae3c2..e2501687a945c 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -448,7 +448,6 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) return ret; diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 581930483ef84..b5a1e3b697d9f 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -76,7 +76,7 @@ static ssize_t rproc_coredump_write(struct file *filp, int ret, err = 0; char buf[20]; - if (count < 1 || count > sizeof(buf)) + if (count > sizeof(buf)) return -EINVAL; ret = copy_from_user(buf, user_buf, count); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 146056858135e..794a4f036b998 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -807,13 +807,9 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); struct rtc_time tm; ktime_t now; - int err; - - err = __rtc_read_time(rtc, &tm); - if (err) - return err; timer->enabled = 1; + __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); /* Skip over expired timers */ @@ -827,6 +823,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) trace_rtc_timer_enqueue(timer); if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; + int err; alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index a8998b016b862..50a1c3478a6e0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -514,7 +514,7 @@ MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)"); /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ static int prot_mask; -module_param(prot_mask, int, 0444); +module_param(prot_mask, int, 0); MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=0x0 "); static bool auto_affine_msi_experimental; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a1a06a832d866..8b9a39077dbab 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -202,7 +202,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) task->total_xfer_len = qc->nbytes; task->num_scatter = qc->n_elem; task->data_dir = qc->dma_dir; - } else if (!ata_is_data(qc->tf.protocol)) { + } else if (qc->tf.protocol == ATA_PROT_NODATA) { task->data_dir = DMA_NONE; } else { for_each_sg(qc->sg, sg, qc->n_elem, si) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 3153f164554aa..3fbbdf084d67a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1832,10 +1832,9 @@ mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc, u8 poll) enable_irq(reply_q->os_irq); } } - - if (poll) - _base_process_reply_queue(reply_q); } + if (poll) + _base_process_reply_queue(reply_q); } /** diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index cd0e1d31db701..9b318958d78cc 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1727,7 +1727,6 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; circularQ = &pm8001_ha->inbnd_q_tbl[0]; @@ -1789,7 +1788,6 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; @@ -1806,7 +1804,7 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.tag = cpu_to_le32(ccb_tag); sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m = cpu_to_le32((0x1 << 7) | (0x5 << 9)); + sata_cmd.ncqtag_atap_dir_m |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2367,8 +2365,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) len = sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len = %d\n", len); - } else if (t->ata_task.use_ncq && - t->data_dir != DMA_NONE) { + } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", len); @@ -4223,22 +4220,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 opc = OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); circularQ = &pm8001_ha->inbnd_q_tbl[0]; - - if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.use_ncq && - dev->sata_dev.class != ATA_DEV_ATAPI) { - ATAP = 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } else if (task->ata_task.dma_xfer) { + if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } + if (task->ata_task.use_ncq && + dev->sata_dev.class != ATA_DEV_ATAPI) { + ATAP = 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); @@ -4578,7 +4575,7 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8); sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag); if (pm8001_ha->chip_id != chip_8001) - sspTMCmd.ds_ads_m = cpu_to_le32(0x08); + sspTMCmd.ds_ads_m = 0x08; circularQ = &pm8001_ha->inbnd_q_tbl[0]; ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, sizeof(sspTMCmd), 0); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index b5e60553acdc5..2a3ce4680734b 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1199,11 +1199,9 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) else page_code = THERMAL_PAGE_CODE_8H; - payload.cfg_pg[0] = - cpu_to_le32((THERMAL_LOG_ENABLE << 9) | - (THERMAL_ENABLE << 8) | page_code); - payload.cfg_pg[1] = - cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8)); + payload.cfg_pg[0] = (THERMAL_LOG_ENABLE << 9) | + (THERMAL_ENABLE << 8) | page_code; + payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); pm8001_dbg(pm8001_ha, DEV, "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", @@ -1243,41 +1241,43 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) circularQ = &pm8001_ha->inbnd_q_tbl[0]; payload.tag = cpu_to_le32(tag); - SASConfigPage.pageCode = cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE); - SASConfigPage.MST_MSI = cpu_to_le32(3 << 15); - SASConfigPage.STP_SSP_MCT_TMO = - cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO); - SASConfigPage.STP_FRM_TMO = - cpu_to_le32((SAS_MAX_OPEN_TIME << 24) | - (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER); - SASConfigPage.STP_IDLE_TMO = cpu_to_le32(STP_IDLE_TIME); - - SASConfigPage.OPNRJT_RTRY_INTVL = - cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL); - SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = - cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO); - SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = - cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR); - SASConfigPage.MAX_AIP = cpu_to_le32(SAS_MAX_AIP); + SASConfigPage.pageCode = SAS_PROTOCOL_TIMER_CONFIG_PAGE; + SASConfigPage.MST_MSI = 3 << 15; + SASConfigPage.STP_SSP_MCT_TMO = (STP_MCT_TMO << 16) | SSP_MCT_TMO; + SASConfigPage.STP_FRM_TMO = (SAS_MAX_OPEN_TIME << 24) | + (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER; + SASConfigPage.STP_IDLE_TMO = STP_IDLE_TIME; + + if (SASConfigPage.STP_IDLE_TMO > 0x3FFFFFF) + SASConfigPage.STP_IDLE_TMO = 0x3FFFFFF; + + + SASConfigPage.OPNRJT_RTRY_INTVL = (SAS_MFD << 16) | + SAS_OPNRJT_RTRY_INTVL; + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = (SAS_DOPNRJT_RTRY_TMO << 16) + | SAS_COPNRJT_RTRY_TMO; + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = (SAS_DOPNRJT_RTRY_THR << 16) + | SAS_COPNRJT_RTRY_THR; + SASConfigPage.MAX_AIP = SAS_MAX_AIP; pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n", - le32_to_cpu(SASConfigPage.pageCode)); + SASConfigPage.pageCode); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n", - le32_to_cpu(SASConfigPage.MST_MSI)); + SASConfigPage.MST_MSI); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO)); + SASConfigPage.STP_SSP_MCT_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_FRM_TMO)); + SASConfigPage.STP_FRM_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_IDLE_TMO)); + SASConfigPage.STP_IDLE_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n", - le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL)); + SASConfigPage.OPNRJT_RTRY_INTVL); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n", - le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n", - le32_to_cpu(SASConfigPage.MAX_AIP)); + SASConfigPage.MAX_AIP); memcpy(&payload.cfg_pg, &SASConfigPage, sizeof(SASProtocolTimerConfig_t)); @@ -1403,13 +1403,12 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) /* Currently only one key is used. New KEK index is 1. * Current KEK index is 1. Store KEK to NVRAM is 1. */ - payload.new_curidx_ksop = - cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) | - KEK_MGMT_SUBOP_KEYCARDUPDATE)); + payload.new_curidx_ksop = ((1 << 24) | (1 << 16) | (1 << 8) | + KEK_MGMT_SUBOP_KEYCARDUPDATE); pm8001_dbg(pm8001_ha, DEV, "Saving Encryption info to flash. payload 0x%x\n", - le32_to_cpu(payload.new_curidx_ksop)); + payload.new_curidx_ksop); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); @@ -1750,7 +1749,6 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; circularQ = &pm8001_ha->inbnd_q_tbl[0]; @@ -1832,7 +1830,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.tag = cpu_to_le32(ccb_tag); sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m_dad = cpu_to_le32(((0x1 << 7) | (0x5 << 9))); + sata_cmd.ncqtag_atap_dir_m_dad |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2466,8 +2464,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) len = sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len = %d\n", len); - } else if (t->ata_task.use_ncq && - t->data_dir != DMA_NONE) { + } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", len); @@ -4310,15 +4307,13 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, struct ssp_ini_io_start_req ssp_cmd; u32 tag = ccb->ccb_tag; int ret; - u64 phys_addr, end_addr; + u64 phys_addr, start_addr, end_addr; u32 end_addr_high, end_addr_low; struct inbound_queue_table *circularQ; u32 q_index, cpu_id; u32 opc = OPC_INB_SSPINIIOSTART; - memset(&ssp_cmd, 0, sizeof(ssp_cmd)); memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); - /* data address domain added for spcv; set to 0 by host, * used internally by controller * 0 for SAS 1.1 and SAS 2.0 compatible TLR @@ -4329,7 +4324,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id); ssp_cmd.tag = cpu_to_le32(tag); if (task->ssp_task.enable_first_burst) - ssp_cmd.ssp_iu.efb_prio_attr = 0x80; + ssp_cmd.ssp_iu.efb_prio_attr |= 0x80; ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3); ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7); memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd, @@ -4361,24 +4356,21 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.enc_esgl = cpu_to_le32(1<<31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - ssp_cmd.enc_addr_low = cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.enc_addr_high = cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - - if (end_addr_high != le32_to_cpu(ssp_cmd.enc_addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + ssp_cmd.enc_len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != ssp_cmd.enc_addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(ssp_cmd.enc_len), + start_addr, ssp_cmd.enc_len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4387,7 +4379,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, cpu_to_le32(lower_32_bits(phys_addr)); ssp_cmd.enc_addr_high = cpu_to_le32(upper_32_bits(phys_addr)); - ssp_cmd.enc_esgl = cpu_to_le32(1U<<31); + ssp_cmd.enc_esgl = cpu_to_le32(1<<31); } } else if (task->num_scatter == 0) { ssp_cmd.enc_addr_low = 0; @@ -4395,10 +4387,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl = 0; } - /* XTS mode. All other fields are 0 */ - ssp_cmd.key_cmode = cpu_to_le32(0x6 << 4); - + ssp_cmd.key_cmode = 0x6 << 4; /* set tweak values. Should be the start lba */ ssp_cmd.twk_val0 = cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) | (task->ssp_task.cmd->cmnd[3] << 16) | @@ -4420,22 +4410,20 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.esgl = cpu_to_le32(1<<31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.len = cpu_to_le32(task->total_xfer_len); ssp_cmd.esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(ssp_cmd.len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - if (end_addr_high != le32_to_cpu(ssp_cmd.addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + ssp_cmd.len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != ssp_cmd.addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(ssp_cmd.len), + start_addr, ssp_cmd.len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4469,7 +4457,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 q_index, cpu_id; struct sata_start_req sata_cmd; u32 hdr_tag, ncg_tag = 0; - u64 phys_addr, end_addr; + u64 phys_addr, start_addr, end_addr; u32 end_addr_high, end_addr_low; u32 ATAP = 0x0; u32 dir; @@ -4481,21 +4469,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, q_index = (u32) (cpu_id) % (pm8001_ha->max_q_num); circularQ = &pm8001_ha->inbnd_q_tbl[q_index]; - if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.use_ncq && - dev->sata_dev.class != ATA_DEV_ATAPI) { - ATAP = 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } else if (task->ata_task.dma_xfer) { + if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } + if (task->ata_task.use_ncq && + dev->sata_dev.class != ATA_DEV_ATAPI) { + ATAP = 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); @@ -4529,38 +4518,32 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; - sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(phys_addr)); - sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(phys_addr)); + sata_cmd.enc_addr_low = lower_32_bits(phys_addr); + sata_cmd.enc_addr_high = upper_32_bits(phys_addr); sata_cmd.enc_esgl = cpu_to_le32(1 << 31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - - sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(dma_addr)); - sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(dma_addr)); + sata_cmd.enc_addr_low = lower_32_bits(dma_addr); + sata_cmd.enc_addr_high = upper_32_bits(dma_addr); sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); sata_cmd.enc_esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - if (end_addr_high != le32_to_cpu(sata_cmd.enc_addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + sata_cmd.enc_len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != sata_cmd.enc_addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(sata_cmd.enc_len), + start_addr, sata_cmd.enc_len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(phys_addr)); + lower_32_bits(phys_addr); sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(phys_addr)); + upper_32_bits(phys_addr); sata_cmd.enc_esgl = cpu_to_le32(1 << 31); } @@ -4571,8 +4554,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.enc_esgl = 0; } /* XTS mode. All other fields are 0 */ - sata_cmd.key_index_mode = cpu_to_le32(0x6 << 4); - + sata_cmd.key_index_mode = 0x6 << 4; /* set tweak values. Should be the start lba */ sata_cmd.twk_val0 = cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) | @@ -4598,31 +4580,31 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, phys_addr = ccb->ccb_dma_handle; sata_cmd.addr_low = lower_32_bits(phys_addr); sata_cmd.addr_high = upper_32_bits(phys_addr); - sata_cmd.esgl = cpu_to_le32(1U << 31); + sata_cmd.esgl = cpu_to_le32(1 << 31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - sata_cmd.addr_low = lower_32_bits(dma_addr); sata_cmd.addr_high = upper_32_bits(dma_addr); sata_cmd.len = cpu_to_le32(task->total_xfer_len); sata_cmd.esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(sata_cmd.len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + sata_cmd.len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != sata_cmd.addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(sata_cmd.len), + start_addr, sata_cmd.len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; - sata_cmd.addr_low = lower_32_bits(phys_addr); - sata_cmd.addr_high = upper_32_bits(phys_addr); - sata_cmd.esgl = cpu_to_le32(1U << 31); + sata_cmd.addr_low = + lower_32_bits(phys_addr); + sata_cmd.addr_high = + upper_32_bits(phys_addr); + sata_cmd.esgl = cpu_to_le32(1 << 31); } } else if (task->num_scatter == 0) { sata_cmd.addr_low = 0; @@ -4630,28 +4612,27 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.len = cpu_to_le32(task->total_xfer_len); sata_cmd.esgl = 0; } - /* scsi cdb */ sata_cmd.atapi_scsi_cdb[0] = cpu_to_le32(((task->ata_task.atapi_packet[0]) | - (task->ata_task.atapi_packet[1] << 8) | - (task->ata_task.atapi_packet[2] << 16) | - (task->ata_task.atapi_packet[3] << 24))); + (task->ata_task.atapi_packet[1] << 8) | + (task->ata_task.atapi_packet[2] << 16) | + (task->ata_task.atapi_packet[3] << 24))); sata_cmd.atapi_scsi_cdb[1] = cpu_to_le32(((task->ata_task.atapi_packet[4]) | - (task->ata_task.atapi_packet[5] << 8) | - (task->ata_task.atapi_packet[6] << 16) | - (task->ata_task.atapi_packet[7] << 24))); + (task->ata_task.atapi_packet[5] << 8) | + (task->ata_task.atapi_packet[6] << 16) | + (task->ata_task.atapi_packet[7] << 24))); sata_cmd.atapi_scsi_cdb[2] = cpu_to_le32(((task->ata_task.atapi_packet[8]) | - (task->ata_task.atapi_packet[9] << 8) | - (task->ata_task.atapi_packet[10] << 16) | - (task->ata_task.atapi_packet[11] << 24))); + (task->ata_task.atapi_packet[9] << 8) | + (task->ata_task.atapi_packet[10] << 16) | + (task->ata_task.atapi_packet[11] << 24))); sata_cmd.atapi_scsi_cdb[3] = cpu_to_le32(((task->ata_task.atapi_packet[12]) | - (task->ata_task.atapi_packet[13] << 8) | - (task->ata_task.atapi_packet[14] << 16) | - (task->ata_task.atapi_packet[15] << 24))); + (task->ata_task.atapi_packet[13] << 8) | + (task->ata_task.atapi_packet[14] << 16) | + (task->ata_task.atapi_packet[15] << 24))); } /* Check for read log for failed drive and return */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d0407f44de78d..e40a37236aa10 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -555,7 +555,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EINVAL; - if (!IS_NOCACHE_VPD_TYPE(ha)) + if (IS_NOCACHE_VPD_TYPE(ha)) goto skip; faddr = ha->flt_region_vpd << 2; @@ -739,7 +739,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, ql_log(ql_log_info, vha, 0x706f, "Issuing MPI reset.\n"); - if (IS_QLA83XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { uint32_t idc_control; qla83xx_idc_lock(vha, 0); @@ -1050,6 +1050,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon) continue; if (iter->type == 3 && !(IS_CNA_CAPABLE(ha))) continue; + if (iter->type == 0x27 && + (!IS_QLA27XX(ha) || !IS_QLA28XX(ha))) + continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, iter->attr); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8a8e0920d2b41..e1fd91a581202 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2796,11 +2796,7 @@ struct ct_fdmi2_hba_attributes { #define FDMI_PORT_SPEED_8GB 0x10 #define FDMI_PORT_SPEED_16GB 0x20 #define FDMI_PORT_SPEED_32GB 0x40 -#define FDMI_PORT_SPEED_20GB 0x80 -#define FDMI_PORT_SPEED_40GB 0x100 -#define FDMI_PORT_SPEED_128GB 0x200 -#define FDMI_PORT_SPEED_64GB 0x400 -#define FDMI_PORT_SPEED_256GB 0x800 +#define FDMI_PORT_SPEED_64GB 0x80 #define FDMI_PORT_SPEED_UNKNOWN 0x8000 #define FC_CLASS_2 0x04 @@ -5175,8 +5171,4 @@ struct sff_8247_a0 { #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" - -#define IS_SESSION_DELETED(_fcport) (_fcport->disc_state == DSC_DELETE_PEND || \ - _fcport->disc_state == DSC_DELETED) - #endif diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 73015c69b5e89..e28c4b7ec55ff 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -676,7 +676,8 @@ qla2x00_rff_id(scsi_qla_host_t *vha, u8 type) return (QLA_SUCCESS); } - return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), type); + return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), + FC4_TYPE_FCP_SCSI); } static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, @@ -726,7 +727,7 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ ct_req->req.rff_id.port_id = port_id_to_be_id(*d_id); ct_req->req.rff_id.fc4_feature = fc4feature; - ct_req->req.rff_id.fc4_type = fc4type; /* SCSI-FCP or FC-NVMe */ + ct_req->req.rff_id.fc4_type = fc4type; /* SCSI - FCP */ sp->u.iocb_cmd.u.ctarg.req_size = RFF_ID_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.rsp_size = RFF_ID_RSP_SIZE; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9452848ede3f8..fdae25ec554d9 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -570,14 +570,6 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, struct srb_iocb *lio; int rval = QLA_FUNCTION_FAILED; - if (IS_SESSION_DELETED(fcport)) { - ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC is being delete - not sending command.\n", - __func__, fcport->port_name); - fcport->flags &= ~FCF_ASYNC_ACTIVE; - return rval; - } - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; @@ -961,9 +953,6 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, set_bit(RELOGIN_NEEDED, &vha->dpc_flags); } break; - case ISP_CFG_NL: - qla24xx_fcport_handle_login(vha, fcport); - break; default: break; } @@ -1324,21 +1313,14 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) struct port_database_24xx *pd; struct qla_hw_data *ha = vha->hw; - if (IS_SESSION_DELETED(fcport)) { + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) || + fcport->loop_id == FC_NO_LOOP_ID) { ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC is being delete - not sending command.\n", - __func__, fcport->port_name); - fcport->flags &= ~FCF_ASYNC_ACTIVE; + "%s: %8phC - not sending command.\n", + __func__, fcport->port_name); return rval; } - if (!vha->flags.online || fcport->flags & FCF_ASYNC_SENT) { - ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC online %d flags %x - not sending command.\n", - __func__, fcport->port_name, vha->flags.online, fcport->flags); - goto done; - } - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -1498,11 +1480,6 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) u8 login = 0; int rc; - ql_dbg(ql_dbg_disc, vha, 0x307b, - "%s %8phC DS %d LS %d lid %d retries=%d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state, fcport->loop_id, fcport->login_retry); - if (qla_tgt_mode_enabled(vha)) return; @@ -1560,8 +1537,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen, fcport->login_gen, fcport->loop_id, fcport->scan_state); - if (fcport->scan_state != QLA_FCPORT_FOUND || - fcport->disc_state == DSC_DELETE_PEND) + if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; if ((fcport->loop_id != FC_NO_LOOP_ID) && @@ -1582,7 +1558,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (vha->host->active_mode == MODE_TARGET && !N2N_TOPO(vha->hw)) return 0; - if (fcport->flags & (FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE)) { + if (fcport->flags & FCF_ASYNC_SENT) { set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return 0; } @@ -2138,7 +2114,12 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n", __func__, __LINE__, ea->fcport->port_name, ea->data[1]); - qlt_schedule_sess_for_deletion(ea->fcport); + ea->fcport->flags &= ~FCF_ASYNC_SENT; + qla2x00_set_fcport_disc_state(ea->fcport, DSC_LOGIN_FAILED); + if (ea->data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else + qla2x00_mark_device_lost(vha, ea->fcport, 1); break; case MBS_LOOP_ID_USED: /* data[1] = IO PARAM 1 = nport ID */ @@ -3328,14 +3309,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) struct rsp_que *rsp = ha->rsp_q_map[0]; struct qla2xxx_fw_dump *fw_dump; - if (ha->fw_dump) { - ql_dbg(ql_dbg_init, vha, 0x00bd, - "Firmware dump already allocated.\n"); - return; - } - - ha->fw_dumped = 0; - ha->fw_dump_cap_flags = 0; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3346,7 +3319,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - if (IS_QLA83XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); else if (IS_QLA81XX(ha)) fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); @@ -3358,7 +3331,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) { - if (!IS_QLA83XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && + !IS_QLA28XX(ha)) mq_size = sizeof(struct qla2xxx_mq_chain); /* * Allocate maximum buffer size for all queues - Q0. @@ -3919,7 +3893,8 @@ enable_82xx_npiv: ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); - if (IS_QLA83XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ha->flags.fac_supported = 0; rval = QLA_SUCCESS; } @@ -5407,13 +5382,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) memcpy(fcport->node_name, new_fcport->node_name, WWN_SIZE); fcport->scan_state = QLA_FCPORT_FOUND; - if (fcport->login_retry == 0) { - fcport->login_retry = vha->hw->login_retry_count; - ql_dbg(ql_dbg_disc, vha, 0x2135, - "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", - fcport->port_name, fcport->loop_id, - fcport->login_retry); - } found++; break; } @@ -5547,8 +5515,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) if (atomic_read(&fcport->state) == FCS_ONLINE) return; - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - rport_ids.node_name = wwn_to_u64(fcport->node_name); rport_ids.port_name = wwn_to_u64(fcport->port_name); rport_ids.port_id = fcport->d_id.b.domain << 16 | @@ -5649,7 +5615,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_reg_remote_port(vha, fcport); break; case MODE_TARGET: - qla2x00_set_fcport_state(fcport, FCS_ONLINE); if (!vha->vha_tgt.qla_tgt->tgt_stop && !vha->vha_tgt.qla_tgt->tgt_stopped) qlt_fc_port_added(vha, fcport); @@ -5664,6 +5629,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { if (fcport->id_changed) { fcport->id_changed = 0; @@ -9160,7 +9127,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->rsp->req = qpair->req; qpair->rsp->qpair = qpair; /* init qpair to this cpu. Will adjust at run time. */ - qla_cpu_update(qpair, raw_smp_processor_id()); + qla_cpu_update(qpair, smp_processor_id()); if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index e54cc2a761dd4..c532c74ca1ab9 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2910,7 +2910,6 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - break; } fallthrough; default: @@ -2920,7 +2919,9 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); fcport->flags &= ~FCF_ASYNC_SENT; - qlt_schedule_sess_for_deletion(fcport); + qla2x00_set_fcport_disc_state(fcport, + DSC_LOGIN_FAILED); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } break; @@ -2932,7 +2933,8 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); sp->fcport->flags &= ~FCF_ASYNC_SENT; - qlt_schedule_sess_for_deletion(fcport); + qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_FAILED); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c5c7d60ab2524..5e040b6debc84 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2248,7 +2248,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) iocb->u.tmf.data = QLA_FUNCTION_FAILED; } else if ((le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID)) { - host_to_fcp_swap(sts->data, sizeof(sts->data)); if (le32_to_cpu(sts->rsp_data_len) < 4) { ql_log(ql_log_warn, fcport->vha, 0x503b, "Async-%s error - hdl=%x not enough response(%d).\n", diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bbb57edc1f662..734745f450211 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -9,12 +9,6 @@ #include #include -#ifdef CONFIG_PPC -#define IS_PPCARCH true -#else -#define IS_PPCARCH false -#endif - static struct mb_cmd_name { uint16_t cmd; const char *str; @@ -704,9 +698,6 @@ again: vha->min_supported_speed = nv->min_supported_speed; } - - if (IS_PPCARCH) - mcp->mb[11] |= BIT_4; } if (ha->flags.exlogins_enabled) @@ -2993,7 +2984,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha) ha->orig_fw_iocb_count = mcp->mb[10]; if (ha->flags.npiv_supported) ha->max_npiv_vports = mcp->mb[11]; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) ha->fw_max_fcf_count = mcp->mb[12]; } @@ -5554,7 +5546,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) - mcp->in_mb |= MBX_4|MBX_3; + mcp->in_mb |= MBX_3; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index ba1b1c7549d35..5acee3c798d42 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -35,11 +35,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; - if (atomic_read(&fcport->state) == FCS_ONLINE) - return 0; - - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - fcport->nvme_flag &= ~NVME_FLAG_RESETTING; memset(&req, 0, sizeof(struct nvme_fc_port_info)); @@ -170,18 +165,6 @@ out: qla2xxx_rel_qpair_sp(sp->qpair, sp); } -static void qla_nvme_ls_unmap(struct srb *sp, struct nvmefc_ls_req *fd) -{ - if (sp->flags & SRB_DMA_VALID) { - struct srb_iocb *nvme = &sp->u.iocb_cmd; - struct qla_hw_data *ha = sp->fcport->vha->hw; - - dma_unmap_single(&ha->pdev->dev, nvme->u.nvme.cmd_dma, - fd->rqstlen, DMA_TO_DEVICE); - sp->flags &= ~SRB_DMA_VALID; - } -} - static void qla_nvme_release_ls_cmd_kref(struct kref *kref) { struct srb *sp = container_of(kref, struct srb, cmd_kref); @@ -198,8 +181,6 @@ static void qla_nvme_release_ls_cmd_kref(struct kref *kref) spin_unlock_irqrestore(&priv->cmd_lock, flags); fd = priv->fd; - - qla_nvme_ls_unmap(sp, fd); fd->done(fd, priv->comp_status); out: qla2x00_rel_sp(sp); @@ -346,8 +327,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, fd->rqstlen, DMA_TO_DEVICE); - sp->flags |= SRB_DMA_VALID; - rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, @@ -355,7 +334,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, wake_up(&sp->nvme_ls_waitq); sp->priv = NULL; priv->sp = NULL; - qla_nvme_ls_unmap(sp, fd); qla2x00_rel_sp(sp); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 419156121cb59..e7f73a167fbd6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3673,7 +3673,8 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha) if (ha->mqiobase) iounmap(ha->mqiobase); - if (ha->msixbase) + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && + ha->msixbase) iounmap(ha->msixbase); } } @@ -5389,11 +5390,6 @@ void qla2x00_relogin(struct scsi_qla_host *vha) memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; qla24xx_handle_relogin_event(vha, &ea); - } else if (vha->hw->current_topology == - ISP_CFG_NL && - IS_QLA2XXX_MIDTYPE(vha->hw)) { - (void)qla24xx_fcport_handle_login(vha, - fcport); } else if (vha->hw->current_topology == ISP_CFG_NL) { fcport->login_retry--; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 0fa9c529fca11..0f92e9a044dcd 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -844,7 +844,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_nvram = start; break; case FLT_REG_IMG_PRI_27XX: - if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_img_status_pri = start; break; case FLT_REG_IMG_SEC_27XX: @@ -1356,7 +1356,7 @@ next: flash_data_addr(ha, faddr), le32_to_cpu(*dwptr)); if (ret) { ql_dbg(ql_dbg_user, vha, 0x7006, - "Failed slow write %x (%x)\n", faddr, *dwptr); + "Failed slopw write %x (%x)\n", faddr, *dwptr); break; } } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index cf9ae0ab489a0..ebed14bed7835 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3256,7 +3256,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), cmd->reset_count, qpair->chip_reset); - res = 0; goto out_unmap_unlock; } @@ -7077,7 +7076,8 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) if (!QLA_TGT_MODE_ENABLED()) return; - if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; } else { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f11f51e2465f5..cfa588e915619 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -448,8 +448,13 @@ static void scsi_report_sense(struct scsi_device *sdev, if (sshdr->asc == 0x29) { evt_type = SDEV_EVT_POWER_ON_RESET_OCCURRED; - sdev_printk(KERN_WARNING, sdev, - "Power-on or device reset occurred\n"); + /* + * Do not print message if it is an expected side-effect + * of runtime PM. + */ + if (!sdev->silence_suspend) + sdev_printk(KERN_WARNING, sdev, + "Power-on or device reset occurred\n"); } if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9de0bd97c556e..edb1e26c734b1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3663,7 +3663,8 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) return 0; if (sdkp->WCE && sdkp->media_present) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); ret = sd_sync_cache(sdkp, &sshdr); if (ret) { @@ -3685,7 +3686,8 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) } if (sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); /* an error is not worth aborting a system sleep */ ret = sd_start_stop_device(sdkp, 0); if (ignore_stop_errors) diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index fc5b214347b36..86a938075f308 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -557,7 +557,7 @@ static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba) struct ufs_mtk_host *host = ufshcd_get_variant(hba); host->reg_va09 = regulator_get(hba->dev, "va09"); - if (!host->reg_va09) + if (IS_ERR(host->reg_va09)) dev_info(hba->dev, "failed to get va09"); else host->caps |= UFS_MTK_CAP_VA09_PWR_CTRL; @@ -1189,6 +1189,7 @@ static int ufs_mtk_probe(struct platform_device *pdev) } link = device_link_add(dev, &reset_pdev->dev, DL_FLAG_AUTOPROBE_CONSUMER); + put_device(&reset_pdev->dev); if (!link) { dev_notice(dev, "add reset device_link fail\n"); goto skip_reset; diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index b3c792fc7bad6..280c56db3b126 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -44,6 +44,12 @@ /* WriteBooster buffer is available only for the logical unit from 0 to 7 */ #define UFS_UPIU_MAX_WB_LUN_ID 8 +/* + * WriteBooster buffer lifetime has a limit setted by vendor. + * If it is over the limit, WriteBooster feature will be disabled. + */ +#define UFS_WB_EXCEED_LIFETIME 0x0B + /* Well known logical unit id in LUN field of UPIU */ enum { UFS_UPIU_REPORT_LUNS_WLUN = 0x81, diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index a673eedb2f059..f76692053ca17 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -421,6 +421,13 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba) return err; } +static int ufs_intel_adl_init(struct ufs_hba *hba) +{ + hba->nop_out_timeout = 200; + hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; + return ufs_intel_common_init(hba); +} + static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = { .name = "intel-pci", .init = ufs_intel_common_init, @@ -449,6 +456,15 @@ static struct ufs_hba_variant_ops ufs_intel_lkf_hba_vops = { .device_reset = ufs_intel_device_reset, }; +static struct ufs_hba_variant_ops ufs_intel_adl_hba_vops = { + .name = "intel-pci", + .init = ufs_intel_adl_init, + .exit = ufs_intel_common_exit, + .link_startup_notify = ufs_intel_link_startup_notify, + .resume = ufs_intel_resume, + .device_reset = ufs_intel_device_reset, +}; + #ifdef CONFIG_PM_SLEEP static int ufshcd_pci_restore(struct device *dev) { @@ -561,6 +577,8 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, { PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops }, + { PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d892faaef7bf2..93046952cbb03 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -86,8 +86,6 @@ /* Polling time to wait for fDeviceInit */ #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */ -#define wlun_dev_to_hba(dv) shost_priv(to_scsi_device(dv)->host) - #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ int _ret; \ @@ -118,8 +116,13 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, if (!regs) return -ENOMEM; - for (pos = 0; pos < len; pos += 4) + for (pos = 0; pos < len; pos += 4) { + if (offset == 0 && + pos >= REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER && + pos <= REG_UIC_ERROR_CODE_DME) + continue; regs[pos / 4] = ufshcd_readl(hba, offset + pos); + } ufshcd_hex_dump(prefix, regs, len); kfree(regs); @@ -385,7 +388,7 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba, static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, enum ufs_trace_str_t str_t) { - u64 lba; + u64 lba = 0; u8 opcode = 0, group_id = 0; u32 intr, doorbell; struct ufshcd_lrb *lrbp = &hba->lrb[tag]; @@ -402,7 +405,6 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, return; opcode = cmd->cmnd[0]; - lba = scsi_get_lba(cmd); if (opcode == READ_10 || opcode == WRITE_10) { /* @@ -410,6 +412,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, */ transfer_len = be32_to_cpu(lrbp->ucd_req_ptr->sc.exp_data_transfer_len); + lba = scsi_get_lba(cmd); if (opcode == WRITE_10) group_id = lrbp->cmd->cmnd[6]; } else if (opcode == UNMAP) { @@ -417,6 +420,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, * The number of Bytes to be unmapped beginning with the lba. */ transfer_len = blk_rq_bytes(rq); + lba = scsi_get_lba(cmd); } intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); @@ -603,7 +607,12 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) "INVALID MODE", }; - dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by user space + * causing runtime resume, causing more messages and so on. + */ + dev_dbg(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", __func__, hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, @@ -1107,6 +1116,12 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) return pending; } +/* + * Wait until all pending SCSI commands and TMFs have finished or the timeout + * has expired. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) { @@ -1140,7 +1155,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, } spin_unlock_irqrestore(hba->host->host_lock, flags); - schedule(); + io_schedule_timeout(msecs_to_jiffies(20)); if (ktime_to_us(ktime_sub(ktime_get(), start)) > wait_timeout_us) { timeout = true; @@ -1211,9 +1226,14 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) return ret; } -static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) +/* + * Wait until all pending SCSI commands and TMFs have finished or the timeout + * has expired. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ +static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us) { - #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ int ret = 0; /* * make sure that there are no outstanding requests when @@ -1222,8 +1242,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) ufshcd_scsi_block_requests(hba); down_write(&hba->clk_scaling_lock); - if (!hba->clk_scaling.is_allowed || - ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) { + if (ufshcd_wait_for_doorbell_clr(hba, timeout_us)) { ret = -EBUSY; up_write(&hba->clk_scaling_lock); ufshcd_scsi_unblock_requests(hba); @@ -1261,10 +1280,18 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) int ret = 0; bool is_writelock = true; - ret = ufshcd_clock_scaling_prepare(hba); + if (!hba->clk_scaling.is_allowed) + return -EBUSY; + + ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC); if (ret) return ret; + if (!hba->clk_scaling.is_allowed) { + ret = -EBUSY; + goto out_unprepare; + } + /* scale down the gear before scaling down clocks */ if (!scale_up) { ret = ufshcd_scale_gear(hba, false); @@ -1678,6 +1705,26 @@ unblock_reqs: ufshcd_scsi_unblock_requests(hba); } +/* + * Block processing of new SCSI commands and wait until pending SCSI + * commands and TMFs have finished. ufshcd_exec_dev_cmd() and + * ufshcd_issue_devman_upiu_cmd() are not affected by this function. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ +int ufshcd_freeze_scsi_devs(struct ufs_hba *hba, u64 timeout_us) +{ + return ufshcd_clock_scaling_prepare(hba, timeout_us); +} +EXPORT_SYMBOL_GPL(ufshcd_freeze_scsi_devs); + +/* Resume processing of SCSI commands. */ +void ufshcd_unfreeze_scsi_devs(struct ufs_hba *hba) +{ + ufshcd_clock_scaling_unprepare(hba, true); +} +EXPORT_SYMBOL_GPL(ufshcd_unfreeze_scsi_devs); + /** * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release. * Also, exit from hibern8 mode and set the link as active. @@ -5065,6 +5112,12 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) pm_runtime_get_noresume(&sdev->sdev_gendev); else if (ufshcd_is_rpm_autosuspend_allowed(hba)) sdev->rpm_autosuspend = 1; + /* + * Do not print messages during runtime PM to avoid never-ending cycles + * of messages written back to storage by user space causing runtime + * resume, causing more messages and so on. + */ + sdev->silence_suspend = 1; ufshcd_crypto_setup_rq_keyslot_manager(hba, q); @@ -5825,6 +5878,47 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba, return false; } +static void ufshcd_wb_force_disable(struct ufs_hba *hba) +{ + if (!(hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL)) + ufshcd_wb_toggle_flush(hba, false); + + ufshcd_wb_toggle_flush_during_h8(hba, false); + ufshcd_wb_toggle(hba, false); + hba->caps &= ~UFSHCD_CAP_WB_EN; + + dev_info(hba->dev, "%s: WB force disabled\n", __func__); +} + +static bool ufshcd_is_wb_buf_lifetime_available(struct ufs_hba *hba) +{ + u32 lifetime; + int ret; + u8 index; + + index = ufshcd_wb_get_query_index(hba); + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + index, 0, &lifetime); + if (ret) { + dev_err(hba->dev, + "%s: bWriteBoosterBufferLifeTimeEst read failed %d\n", + __func__, ret); + return false; + } + + if (lifetime == UFS_WB_EXCEED_LIFETIME) { + dev_err(hba->dev, "%s: WB buf lifetime is exhausted 0x%02X\n", + __func__, lifetime); + return false; + } + + dev_dbg(hba->dev, "%s: WB buf lifetime is 0x%02X\n", + __func__, lifetime); + + return true; +} + static bool ufshcd_wb_need_flush(struct ufs_hba *hba) { int ret; @@ -5833,6 +5927,12 @@ static bool ufshcd_wb_need_flush(struct ufs_hba *hba) if (!ufshcd_is_wb_allowed(hba)) return false; + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) { + ufshcd_wb_force_disable(hba); + return false; + } + /* * The ufs device needs the vcc to be ON to flush. * With user-space reduction enabled, it's enough to enable flush @@ -7388,7 +7488,13 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, if (!hba->vreg_info.vcc || !hba->vreg_info.vccq || !hba->vreg_info.vccq2) { - dev_err(hba->dev, + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by + * user space causing runtime resume, causing more messages and + * so on. + */ + dev_dbg(hba->dev, "%s: Regulator capability was not set, actvIccLevel=%d", __func__, icc_level); goto out; @@ -7535,6 +7641,7 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!ufshcd_is_wb_allowed(hba)) return; + /* * Probe WB only for UFS-2.2 and UFS-3.1 (and later) devices or * UFS devices with quirk UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES @@ -7586,6 +7693,10 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!d_lu_wb_buf_alloc) goto wb_disabled; } + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) + goto wb_disabled; + return; wb_disabled: @@ -7864,7 +7975,7 @@ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) peer_pa_tactivate_us = peer_pa_tactivate * gran_to_us_table[peer_granularity - 1]; - if (pa_tactivate_us > peer_pa_tactivate_us) { + if (pa_tactivate_us >= peer_pa_tactivate_us) { u32 new_peer_pa_tactivate; new_peer_pa_tactivate = pa_tactivate_us / @@ -8664,7 +8775,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) * @pwr_mode: device power mode to set * * Returns 0 if requested power mode is set successfully - * Returns non-zero if failed to set the requested power mode + * Returns < 0 if failed to set the requested power mode */ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, enum ufs_dev_pwr_mode pwr_mode) @@ -8718,8 +8829,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", pwr_mode, ret); - if (ret > 0 && scsi_sense_valid(&sshdr)) - scsi_print_sense_hdr(sdp, NULL, &sshdr); + if (ret > 0) { + if (scsi_sense_valid(&sshdr)) + scsi_print_sense_hdr(sdp, NULL, &sshdr); + ret = -EIO; + } } if (!ret) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 88bc1b9c8768d..4fc5deaa99dd6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1219,11 +1219,11 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, u8 param_offset, u8 *param_read_buf, u8 param_size); +int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, + u32 *attr_val); int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val); -int ufshcd_query_attr_retry(struct ufs_hba *hba, - enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, - u32 *attr_val); int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res); int ufshcd_query_flag_retry(struct ufs_hba *hba, @@ -1241,6 +1241,9 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); +int ufshcd_freeze_scsi_devs(struct ufs_hba *hba, u64 timeout_us); +void ufshcd_unfreeze_scsi_devs(struct ufs_hba *hba); + void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, int *desc_length); diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 40c6c4515e6c6..63078ce2a70e5 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -320,7 +320,7 @@ ufshpb_set_hpb_read_to_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, cdb[0] = UFSHPB_READ; if (hba->dev_quirks & UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ) - ppn_tmp = swab64(ppn); + ppn_tmp = (__force __be64)swab64((__force u64)ppn); /* ppn value is stored as big-endian in the host memory */ memcpy(&cdb[6], &ppn_tmp, sizeof(__be64)); diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 85f82e195ef8b..f1875dc31ae2c 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -206,7 +206,6 @@ struct ocmem *of_get_ocmem(struct device *dev) ocmem = platform_get_drvdata(pdev); if (!ocmem) { dev_err(dev, "Cannot get ocmem\n"); - put_device(&pdev->dev); return ERR_PTR(-ENODEV); } return ocmem; diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 941499b117580..4fe88d4690e2b 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -548,7 +548,7 @@ static int qmp_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, irq, qmp_intr, 0, + ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT, "aoss-qmp", qmp); if (ret < 0) { dev_err(&pdev->dev, "failed to request interrupt\n"); diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index c6084c0d35302..f2168e4259b23 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -387,9 +387,6 @@ static int rpmpd_probe(struct platform_device *pdev) data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), GFP_KERNEL); - if (!data->domains) - return -ENOMEM; - data->num_domains = num; for (i = 0; i < num; i++) { diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index ef3f95fefab58..e9ece45d7a333 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -447,9 +447,9 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { + if (!irq) { dev_err(&pdev->dev, "no irq resource\n"); - return irq; + return -ENXIO; } ret = devm_request_irq(dev, irq, wkup_m3_txev_handler, diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 824d9f900aca7..dad4326a2a714 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -521,8 +521,8 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) /* Clear wake status */ wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); - wake_sts |= (SDW_SHIM_WAKESTS_STATUS << link_id); - intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts); + wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); } mutex_unlock(sdw->link_res->shim_lock); } diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 4fb19e6f94b05..96b418293bf2a 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -304,21 +304,25 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf, writel(data, mxic->regs + TXD(nbytes % 4)); - ret = readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_TX_EMPTY, 0, USEC_PER_SEC); - if (ret) - return ret; - - ret = readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_RX_NOT_EMPTY, 0, - USEC_PER_SEC); - if (ret) - return ret; - - data = readl(mxic->regs + RXD); if (rxbuf) { + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + data = readl(mxic->regs + RXD); data >>= (8 * (4 - nbytes)); memcpy(rxbuf + pos, &data, nbytes); + WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); + } else { + readl(mxic->regs + RXD); } WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 4eb979a096c78..aafac128bb5f1 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -74,23 +74,14 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param) return true; } -static void lpss_dma_put_device(void *dma_dev) -{ - pci_dev_put(dma_dev); -} - static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct pci_dev *dma_dev; - int ret; c->num_chipselect = 1; c->max_clk_rate = 50000000; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); - ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); - if (ret) - return ret; if (c->tx_param) { struct dw_dma_slave *slave = c->tx_param; @@ -114,9 +105,8 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); struct dw_dma_slave *tx, *rx; - struct pci_dev *dma_dev; - int ret; switch (PCI_FUNC(dev->devfn)) { case 0: @@ -141,11 +131,6 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } - dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); - ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); - if (ret) - return ret; - tx = c->tx_param; tx->dma_dev = &dma_dev->dev; diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index ed42665b12241..a2e5907276e7f 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1353,10 +1353,6 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->phys = r->start; spi_irq = platform_get_irq(pdev, 0); - if (spi_irq < 0) { - ret = spi_irq; - goto exit_free_master; - } tspi->irq = spi_irq; tspi->clk = devm_clk_get(&pdev->dev, "spi"); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 9e2b812b9025f..669fc4286231f 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1006,8 +1006,14 @@ static int tegra_slink_probe(struct platform_device *pdev) struct resource *r; int ret, spi_irq; const struct tegra_slink_chip_data *cdata = NULL; + const struct of_device_id *match; - cdata = of_device_get_match_data(&pdev->dev); + match = of_match_device(tegra_slink_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 3d3ac48243ebd..1dd2af9cc2374 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1165,10 +1165,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); - if (ret) - goto clk_dis_all; - + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops = &zynqmp_qspi_mem_ops; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2ff27f3321045..c640a9f4f1c8f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -881,10 +881,10 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev, int i, ret; if (vmalloced_buf || kmap_buf) { - desc_len = min_t(unsigned long, max_seg_size, PAGE_SIZE); + desc_len = min_t(int, max_seg_size, PAGE_SIZE); sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); } else if (virt_addr_valid(buf)) { - desc_len = min_t(size_t, max_seg_size, ctlr->max_dma_len); + desc_len = min_t(int, max_seg_size, ctlr->max_dma_len); sgs = DIV_ROUND_UP(len, desc_len); } else { return -EINVAL; diff --git a/drivers/staging/android/ion/ion_buffer.c b/drivers/staging/android/ion/ion_buffer.c index 9baca1a472b6a..9c7a353a42209 100644 --- a/drivers/staging/android/ion/ion_buffer.c +++ b/drivers/staging/android/ion/ion_buffer.c @@ -249,6 +249,9 @@ void *ion_buffer_kmap_get(struct ion_buffer *buffer) void *vaddr; if (buffer->kmap_cnt) { + if (buffer->kmap_cnt == INT_MAX) + return ERR_PTR(-EOVERFLOW); + buffer->kmap_cnt++; return buffer->vaddr; } diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c index 0a2dbed9ffc74..3a280cc1892ca 100644 --- a/drivers/staging/fbtft/fb_st7789v.c +++ b/drivers/staging/fbtft/fb_st7789v.c @@ -82,8 +82,6 @@ enum st7789v_command { */ static int init_display(struct fbtft_par *par) { - par->fbtftops.reset(par); - /* turn off sleep mode */ write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); mdelay(120); diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 20183b2ea1279..fef0055b89909 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -107,9 +107,9 @@ static unsigned int ad7280a_devaddr(unsigned int addr) { return ((addr & 0x1) << 4) | - ((addr & 0x2) << 2) | + ((addr & 0x2) << 3) | (addr & 0x4) | - ((addr & 0x8) >> 2) | + ((addr & 0x8) >> 3) | ((addr & 0x10) >> 4); } diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c index b1614cce2dfb0..f638d0bd09fe6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c @@ -439,18 +439,6 @@ int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd, return 0; } -static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd, - int i, - struct atomisp_acc_fw *acc_fw) -{ - while (--i >= 0) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } -} - /* * Appends the loaded acceleration binary extensions to the * current ISP mode. Must be called just before sh_css_start(). @@ -489,20 +477,16 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) acc_fw->fw, acc_flag_to_pipe[i].pipe_id, acc_fw->type); - if (ret) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); + if (ret) goto error; - } ext_loaded = true; } } ret = atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); + if (ret < 0) goto error; - } } if (!ext_loaded) @@ -511,7 +495,6 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) ret = atomisp_css_update_stream(asd); if (ret) { dev_err(isp->dev, "%s: update stream failed.\n", __func__); - atomisp_acc_unload_extensions(asd); goto error; } @@ -519,6 +502,13 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) return 0; error: + while (--i >= 0) { + if (acc_fw->flags & acc_flag_to_pipe[i].flag) { + atomisp_css_unload_acc_extension(asd, acc_fw->fw, + acc_flag_to_pipe[i].pipe_id); + } + } + list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) { if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index c9ee85037644f..34480ca164746 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -729,21 +729,6 @@ static int axp_regulator_set(struct device *dev, struct gmin_subdev *gs, return 0; } -/* - * Some boards contain a hw-bug where turning eldo2 back on after having turned - * it off causes the CPLM3218 ambient-light-sensor on the image-sensor's I2C bus - * to crash, hanging the bus. Do not turn eldo2 off on these systems. - */ -static const struct dmi_system_id axp_leave_eldo2_on_ids[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"), - }, - }, - { } -}; - static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) { int ret; @@ -778,9 +763,6 @@ static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) if (ret) return ret; - if (dmi_check_system(axp_leave_eldo2_on_ids)) - return 0; - ret = axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, ELDO_CTRL_REG, gs->eldo2_ctrl_shift, false); return ret; diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index c1cda16f2dc01..6a5ee46070898 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -39,7 +39,7 @@ struct hmm_bo_device bo_device; struct hmm_pool dynamic_pool; struct hmm_pool reserved_pool; -static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; +static ia_css_ptr dummy_ptr; static bool hmm_initialized; struct _hmm_mem_stat hmm_mem_stat; @@ -209,7 +209,7 @@ int hmm_init(void) void hmm_cleanup(void) { - if (dummy_ptr == mmgr_EXCEPTION) + if (!dummy_ptr) return; sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); @@ -288,8 +288,7 @@ void hmm_free(ia_css_ptr virt) dev_dbg(atomisp_dev, "%s: free 0x%08x\n", __func__, virt); - if (WARN_ON(virt == mmgr_EXCEPTION)) - return; + WARN_ON(!virt); bo = hmm_bo_device_search_start(&bo_device, (unsigned int)virt); diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index ed244aee196c3..b88dc4ed06db7 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -23,7 +23,7 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | H1_REG_IN_IMG_CTRL_OVRFLB(0) + | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h index 30e7e7b920b55..d6e9825bb5c7b 100644 --- a/drivers/staging/media/hantro/hantro_h1_regs.h +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -47,7 +47,7 @@ #define H1_REG_IN_IMG_CTRL 0x03c #define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) #define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define H1_REG_IN_IMG_CTRL_OVRFLB(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) #define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) #define H1_REG_ENC_CTRL0 0x040 #define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c index 86ccc8937afca..db7022707ff8d 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -328,12 +328,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) offset = esparser_get_offset(sess); - ret = amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); - if (ret) { - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - return ret; - } - + amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X flags = %08X\n", vb->timestamp, payload_size, offset, vbuf->flags); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c index db4a854e59a38..7f07a9175815f 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.c +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -227,16 +227,13 @@ int amvdec_set_canvases(struct amvdec_session *sess, } EXPORT_SYMBOL_GPL(amvdec_set_canvases); -int amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) +void amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) { struct amvdec_timestamp *new_ts; unsigned long flags; new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL); - if (!new_ts) - return -ENOMEM; - new_ts->ts = ts; new_ts->tc = tc; new_ts->offset = offset; @@ -245,7 +242,6 @@ int amvdec_add_ts(struct amvdec_session *sess, u64 ts, spin_lock_irqsave(&sess->ts_spinlock, flags); list_add_tail(&new_ts->list, &sess->timestamps); spin_unlock_irqrestore(&sess->ts_spinlock, flags); - return 0; } EXPORT_SYMBOL_GPL(amvdec_add_ts); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h index 798e5a8a9b3f1..cfaed52ab5265 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.h +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -55,8 +55,8 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess, * @offset: offset in the VIFIFO where the associated packet was written * @flags the vb2_v4l2_buffer flags */ -int amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 flags); +void amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 flags); void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); /** diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index d3e26bfe6c90b..de7442d4834dc 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -38,7 +38,7 @@ struct cedrus_h264_sram_ref_pic { #define CEDRUS_H264_FRAME_NUM 18 -#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (32 * SZ_1K) +#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) #define CEDRUS_MIN_PIC_INFO_BUF_SIZE (130 * SZ_1K) static void cedrus_h264_write_sram(struct cedrus_dev *dev, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 368439cf5e174..10744fab7ceaa 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -23,7 +23,7 @@ * Subsequent BSP implementations seem to double the neighbor info buffer size * for the H6 SoC, which may be related to 10 bit H265 support. */ -#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (794 * SZ_1K) +#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) #define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) #define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index 3f223e5b1872b..e7fe8da7732c7 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -314,6 +314,6 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) #endif -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq); void zoran_queue_exit(struct zoran *zr); int zr_set_buf(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index fe0cca12119c7..dfc60e2e9dd7a 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -802,52 +802,6 @@ int zoran_check_jpg_settings(struct zoran *zr, return 0; } -static int zoran_init_video_device(struct zoran *zr, struct video_device *video_dev, int dir) -{ - int err; - - /* Now add the template and register the device unit. */ - *video_dev = zoran_template; - video_dev->v4l2_dev = &zr->v4l2_dev; - video_dev->lock = &zr->lock; - video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | dir; - - strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); - /* - * It's not a mem2mem device, but you can both capture and output from one and the same - * device. This should really be split up into two device nodes, but that's a job for - * another day. - */ - video_dev->vfl_dir = VFL_DIR_M2M; - zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); - if (err < 0) - return err; - video_set_drvdata(video_dev, zr); - return 0; -} - -static void zoran_exit_video_devices(struct zoran *zr) -{ - video_unregister_device(zr->video_dev); - kfree(zr->video_dev); -} - -static int zoran_init_video_devices(struct zoran *zr) -{ - int err; - - zr->video_dev = video_device_alloc(); - if (!zr->video_dev) - return -ENOMEM; - - err = zoran_init_video_device(zr, zr->video_dev, V4L2_CAP_VIDEO_CAPTURE); - if (err) - kfree(zr->video_dev); - return err; -} - void zoran_open_init_params(struct zoran *zr) { int i; @@ -919,11 +873,17 @@ static int zr36057_init(struct zoran *zr) zoran_open_init_params(zr); /* allocate memory *before* doing anything to the hardware in case allocation fails */ + zr->video_dev = video_device_alloc(); + if (!zr->video_dev) { + err = -ENOMEM; + goto exit; + } zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), &zr->p_sc, GFP_KERNEL); if (!zr->stat_com) { - return -ENOMEM; + err = -ENOMEM; + goto exit_video; } for (j = 0; j < BUZ_NUM_STAT_COM; j++) zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ @@ -936,9 +896,26 @@ static int zr36057_init(struct zoran *zr) goto exit_statcom; } - err = zoran_init_video_devices(zr); - if (err) + /* Now add the template and register the device unit. */ + *zr->video_dev = zoran_template; + zr->video_dev->v4l2_dev = &zr->v4l2_dev; + zr->video_dev->lock = &zr->lock; + zr->video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + + strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name)); + /* + * It's not a mem2mem device, but you can both capture and output from one and the same + * device. This should really be split up into two device nodes, but that's a job for + * another day. + */ + zr->video_dev->vfl_dir = VFL_DIR_M2M; + + zoran_queue_init(zr, &zr->vq); + + err = video_register_device(zr->video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); + if (err < 0) goto exit_statcomb; + video_set_drvdata(zr->video_dev, zr); zoran_init_hardware(zr); if (!pass_through) { @@ -953,6 +930,9 @@ exit_statcomb: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); exit_statcom: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc); +exit_video: + kfree(zr->video_dev); +exit: return err; } @@ -984,7 +964,7 @@ static void zoran_remove(struct pci_dev *pdev) dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); pci_release_regions(pdev); pci_disable_device(zr->pci_dev); - zoran_exit_video_devices(zr); + video_unregister_device(zr->video_dev); exit_free: v4l2_ctrl_handler_free(&zr->hdl); v4l2_device_unregister(&zr->v4l2_dev); @@ -1088,10 +1068,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) - return err; - err = vb2_dma_contig_set_max_seg_size(&pdev->dev, U32_MAX); - if (err) - return err; + return -ENODEV; + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); nr = zoran_num++; if (nr >= BUZ_MAX) { diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c index 913f5a3c5bfce..e569a1341d010 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -879,7 +879,7 @@ static void zoran_reap_stat_com(struct zoran *zr) if (zr->jpg_settings.tmp_dcm == 1) i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; + i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2 + 1; stat_com = le32_to_cpu(zr->stat_com[i]); if ((stat_com & 1) == 0) { @@ -891,11 +891,6 @@ static void zoran_reap_stat_com(struct zoran *zr) size = (stat_com & GENMASK(22, 1)) >> 1; buf = zr->inuse[i]; - if (!buf) { - spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); - pci_err(zr->pci_dev, "No buffer at slot %d\n", i); - return; - } buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index ea04f6c732b21..808196ea5b81b 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -255,6 +255,8 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); strscpy(cap->driver, "zoran", sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev)); + cap->device_caps = zr->video_dev->device_caps; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -580,9 +582,6 @@ static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) struct zoran *zr = video_drvdata(file); int res = 0; - if (zr->norm == std) - return 0; - if (zr->running != ZORAN_MAP_MODE_NONE) return -EBUSY; @@ -738,7 +737,6 @@ static int zoran_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - parm->parm.capture.readbuffers = 9; return 0; } @@ -869,10 +867,6 @@ int zr_set_buf(struct zoran *zr) vbuf = &buf->vbuf; buf->vbuf.field = V4L2_FIELD_INTERLACED; - if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) - buf->vbuf.field = V4L2_FIELD_INTERLACED; - else - buf->vbuf.field = V4L2_FIELD_TOP; vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size); vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); zr->inuse[0] = NULL; @@ -932,7 +926,6 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) zr->stat_com[j] = cpu_to_le32(1); zr->inuse[j] = NULL; } - zr->vbseq = 0; if (zr->map_mode != ZORAN_MAP_MODE_RAW) { pci_info(zr->pci_dev, "START JPG\n"); @@ -1013,7 +1006,7 @@ static const struct vb2_ops zr_video_qops = { .wait_finish = vb2_ops_wait_finish, }; -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq) { int err; @@ -1021,9 +1014,8 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) INIT_LIST_HEAD(&zr->queued_bufs); vq->dev = &zr->pci_dev->dev; - vq->type = dir; - - vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes = VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; vq->drv_priv = zr; vq->buf_struct_size = sizeof(struct zr_buffer); vq->ops = &zr_video_qops; diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index d48ca5a25c2c4..a7c0d3115d726 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -11,8 +11,7 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x1c000000>, - <0x20000000 0x04000000>; + reg = <0x0 0x1c000000>, <0x20000000 0x4000000>; }; chosen { @@ -38,16 +37,24 @@ gpio-leds { compatible = "gpio-leds"; - power { - label = "green:power"; + system { + label = "gb-pc1:green:system"; gpios = <&gpio 6 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-on"; }; - system { - label = "green:system"; + status { + label = "gb-pc1:green:status"; gpios = <&gpio 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "disk-activity"; + }; + + lan1 { + label = "gb-pc1:green:lan1"; + gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "gb-pc1:green:lan2"; + gpios = <&gpio 25 GPIO_ACTIVE_LOW>; }; }; }; @@ -87,8 +94,9 @@ partition@50000 { label = "firmware"; - reg = <0x50000 0x1fb0000>; + reg = <0x50000 0x1FB0000>; }; + }; }; @@ -114,12 +122,9 @@ }; &pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - state_default: state-default { - gpio-pinmux { - groups = "rgmii2", "uart3", "wdt"; + state_default: pinctrl0 { + default_gpio: gpio { + groups = "wdt", "rgmii2", "uart3"; function = "gpio"; }; }; @@ -128,13 +133,12 @@ &switch0 { ports { port@0 { - status = "okay"; label = "ethblack"; + status = "ok"; }; - port@4 { - status = "okay"; label = "ethblue"; + status = "ok"; }; }; }; diff --git a/drivers/staging/mt7621-dts/gbpc2.dts b/drivers/staging/mt7621-dts/gbpc2.dts index 6f6fed071dda0..52760e7351f6c 100644 --- a/drivers/staging/mt7621-dts/gbpc2.dts +++ b/drivers/staging/mt7621-dts/gbpc2.dts @@ -1,121 +1,21 @@ /dts-v1/; -#include "mt7621.dtsi" - -#include -#include +#include "gbpc1.dts" / { compatible = "gnubee,gb-pc2", "mediatek,mt7621-soc"; model = "GB-PC2"; - - memory@0 { - device_type = "memory"; - reg = <0x00000000 0x1c000000>, - <0x20000000 0x04000000>; - }; - - chosen { - bootargs = "console=ttyS0,57600"; - }; - - palmbus: palmbus@1e000000 { - i2c@900 { - status = "okay"; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - - reset { - label = "reset"; - gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; - linux,code = ; - }; - }; -}; - -&sdhci { - status = "okay"; -}; - -&spi0 { - status = "okay"; - - m25p80@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - broken-flash-reset; - - partition@0 { - label = "u-boot"; - reg = <0x0 0x30000>; - read-only; - }; - - partition@30000 { - label = "u-boot-env"; - reg = <0x30000 0x10000>; - read-only; - }; - - factory: partition@40000 { - label = "factory"; - reg = <0x40000 0x10000>; - read-only; - }; - - partition@50000 { - label = "firmware"; - reg = <0x50000 0x1fb0000>; - }; - }; }; -&pcie { - status = "okay"; +&default_gpio { + groups = "wdt", "uart3"; + function = "gpio"; }; -&pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - state_default: state-default { - gpio-pinmux { - groups = "wdt"; - function = "gpio"; - }; - }; +&gmac1 { + status = "ok"; }; -ðernet { - gmac1: mac@1 { - status = "okay"; - phy-handle = <ðphy7>; - }; - - mdio-bus { - ethphy7: ethernet-phy@7 { - reg = <7>; - phy-mode = "rgmii-rxid"; - }; - }; -}; - -&switch0 { - ports { - port@0 { - status = "okay"; - label = "ethblack"; - }; - - port@4 { - status = "okay"; - label = "ethblue"; - }; - }; +&phy_external { + status = "ok"; }; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 91a7fa7482964..27222f7b246fd 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -56,9 +56,9 @@ regulator-max-microvolt = <3300000>; enable-active-high; regulator-always-on; - }; + }; - mmc_fixed_1v8_io: fixedregulator@1 { + mmc_fixed_1v8_io: fixedregulator@1 { compatible = "regulator-fixed"; regulator-name = "mmc_io"; regulator-min-microvolt = <1800000>; @@ -412,32 +412,37 @@ mediatek,ethsys = <ðsys>; - pinctrl-names = "default"; - pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>, <&rgmii2_pins>; gmac0: mac@0 { compatible = "mediatek,eth-mac"; reg = <0>; phy-mode = "rgmii"; - fixed-link { speed = <1000>; full-duplex; pause; }; }; - gmac1: mac@1 { compatible = "mediatek,eth-mac"; reg = <1>; status = "off"; phy-mode = "rgmii-rxid"; + phy-handle = <&phy_external>; }; - mdio-bus { #address-cells = <1>; #size-cells = <0>; + phy_external: ethernet-phy@5 { + status = "off"; + reg = <5>; + phy-mode = "rgmii-rxid"; + + pinctrl-names = "default"; + pinctrl-0 = <&rgmii2_pins>; + }; + switch0: switch0@0 { compatible = "mediatek,mt7621"; #address-cells = <1>; @@ -451,43 +456,36 @@ #address-cells = <1>; #size-cells = <0>; reg = <0>; - port@0 { status = "off"; reg = <0>; label = "lan0"; }; - port@1 { status = "off"; reg = <1>; label = "lan1"; }; - port@2 { status = "off"; reg = <2>; label = "lan2"; }; - port@3 { status = "off"; reg = <3>; label = "lan3"; }; - port@4 { status = "off"; reg = <4>; label = "lan4"; }; - port@6 { reg = <6>; label = "cpu"; ethernet = <&gmac0>; phy-mode = "trgmii"; - fixed-link { speed = <1000>; full-duplex; diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 56ae882fb7b39..1411f0cb40c51 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3652,6 +3652,7 @@ static void __exit target_core_exit_configfs(void) MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); module_init(target_core_init_configfs); module_exit(target_core_exit_configfs); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 7143d03f0e027..cfa1bbef32e2e 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -956,6 +956,7 @@ static void __exit fileio_module_exit(void) MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); module_init(fileio_module_init); module_exit(fileio_module_exit); diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 72a26867c2092..793d7b58fc650 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -53,7 +53,7 @@ struct int3400_thermal_priv { struct art *arts; int trt_count; struct trt *trts; - u32 uuid_bitmap; + u8 uuid_bitmap; int rel_misc_dev_res; int current_uuid_index; char *data_vault; @@ -466,11 +466,6 @@ static void int3400_setup_gddv(struct int3400_thermal_priv *priv) priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer, obj->package.elements[0].buffer.length, GFP_KERNEL); - if (!priv->data_vault) { - kfree(buffer.pointer); - return; - } - bin_attr_data_vault.private = priv->data_vault; bin_attr_data_vault.size = obj->package.elements[0].buffer.length; kfree(buffer.pointer); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 796fbff623f6e..2af1e5751bd63 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1470,9 +1470,7 @@ out_error: */ static int __init hvc_iucv_config(char *val) { - if (kstrtoul(val, 10, &hvc_iucv_devices)) - pr_warn("hvc_iucv= invalid parameter value '%s'\n", val); - return 1; + return kstrtoul(val, 10, &hvc_iucv_devices); } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8344265a1948b..3703987c46661 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -858,7 +858,6 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) struct mxser_port *info = container_of(port, struct mxser_port, port); unsigned long page; unsigned long flags; - int ret; page = __get_free_page(GFP_KERNEL); if (!page) @@ -868,9 +867,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (!info->ioaddr || !info->type) { set_bit(TTY_IO_ERROR, &tty->flags); + free_page(page); spin_unlock_irqrestore(&info->slock, flags); - ret = 0; - goto err_free_xmit; + return 0; } info->port.xmit_buf = (unsigned char *) page; @@ -896,10 +895,8 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } - - ret = -ENODEV; - goto err_free_xmit; + } else + return -ENODEV; } /* @@ -944,10 +941,6 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); return 0; -err_free_xmit: - free_page(page); - info->port.xmit_buf = NULL; - return ret; } /* diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index b3c3f7e5851ab..890fa7ddaa7f3 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -64,19 +64,10 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; - struct uart_port *up = &p->port; int ret; - if (dma->tx_running) { - if (up->x_char) { - dmaengine_pause(dma->txchan); - uart_xchar_out(up, UART_TX); - dmaengine_resume(dma->txchan); - } + if (dma->tx_running) return 0; - } else if (up->x_char) { - uart_xchar_out(up, UART_TX); - } if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { /* We have been called from __dma_tx_complete() */ diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index dfb730b7ea2ae..4dee8a9e0c951 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -121,7 +121,8 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct dw_dma_slave *param = &lpss->dma_param; struct pci_dev *pdev = to_pci_dev(port->dev); - struct pci_dev *dma_dev; + unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: @@ -140,8 +141,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return -EINVAL; } - dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); - param->dma_dev = &dma_dev->dev; param->m_master = 0; param->p_master = 1; @@ -157,26 +156,11 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return 0; } -static void byt_serial_exit(struct lpss8250 *lpss) -{ - struct dw_dma_slave *param = &lpss->dma_param; - - /* Paired with pci_get_slot() in the byt_serial_setup() above */ - put_device(param->dma_dev); -} - static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { return 0; } -static void ehl_serial_exit(struct lpss8250 *lpss) -{ - struct uart_8250_port *up = serial8250_get_port(lpss->data.line); - - up->dma = NULL; -} - #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, @@ -351,7 +335,8 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_exit: - lpss->board->exit(lpss); + if (lpss->board->exit) + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); return ret; } @@ -362,7 +347,8 @@ static void lpss8250_remove(struct pci_dev *pdev) serial8250_unregister_port(lpss->data.line); - lpss->board->exit(lpss); + if (lpss->board->exit) + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); } @@ -370,14 +356,12 @@ static const struct lpss8250_board byt_board = { .freq = 100000000, .base_baud = 2764800, .setup = byt_serial_setup, - .exit = byt_serial_exit, }; static const struct lpss8250_board ehl_board = { .freq = 200000000, .base_baud = 12500000, .setup = ehl_serial_setup, - .exit = ehl_serial_exit, }; static const struct lpss8250_board qrk_board = { diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index e6c1791609ddf..efa0515139f8e 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -73,11 +73,6 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p) return 0; } -static void pnw_exit(struct mid8250 *mid) -{ - pci_dev_put(mid->dma_dev); -} - static int tng_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -129,11 +124,6 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) return 0; } -static void tng_exit(struct mid8250 *mid) -{ - pci_dev_put(mid->dma_dev); -} - static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -340,9 +330,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, mid); return 0; - err: - mid->board->exit(mid); + if (mid->board->exit) + mid->board->exit(mid); return ret; } @@ -352,7 +342,8 @@ static void mid8250_remove(struct pci_dev *pdev) serial8250_unregister_port(mid->line); - mid->board->exit(mid); + if (mid->board->exit) + mid->board->exit(mid); } static const struct mid8250_board pnw_board = { @@ -360,7 +351,6 @@ static const struct mid8250_board pnw_board = { .freq = 50000000, .base_baud = 115200, .setup = pnw_setup, - .exit = pnw_exit, }; static const struct mid8250_board tng_board = { @@ -368,7 +358,6 @@ static const struct mid8250_board tng_board = { .freq = 38400000, .base_baud = 1843200, .setup = tng_setup, - .exit = tng_exit, }; static const struct mid8250_board dnv_board = { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3055353514e1d..7c07ebb37b1b9 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1620,18 +1620,6 @@ static inline void start_tx_rs485(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; - /* - * While serial8250_em485_handle_stop_tx() is a noop if - * em485->active_timer != &em485->stop_tx_timer, it might happen that - * the timer is still armed and triggers only after the current bunch of - * chars is send and em485->active_timer == &em485->stop_tx_timer again. - * So cancel the timer. There is still a theoretical race condition if - * the timer is already running and only comes around to check for - * em485->active_timer when &em485->stop_tx_timer is armed again. - */ - if (em485->active_timer == &em485->stop_tx_timer) - hrtimer_try_to_cancel(&em485->stop_tx_timer); - em485->active_timer = NULL; if (em485->tx_stopped) { @@ -1817,7 +1805,9 @@ void serial8250_tx_chars(struct uart_8250_port *up) int count; if (port->x_char) { - uart_xchar_out(port, UART_TX); + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; return; } if (uart_tx_stopped(port)) { diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 79b7db8580e05..49d0c7f2b29b8 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -403,16 +403,16 @@ static int kgdboc_option_setup(char *opt) { if (!opt) { pr_err("config string not provided\n"); - return 1; + return -EINVAL; } if (strlen(opt) >= MAX_CONFIG_LEN) { pr_err("config string too long\n"); - return 1; + return -ENOSPC; } strcpy(config, opt); - return 1; + return 0; } __setup("kgdboc=", kgdboc_option_setup); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 19f0c5db11e33..be0d9922e320e 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -676,20 +676,6 @@ static void uart_flush_buffer(struct tty_struct *tty) tty_port_tty_wakeup(&state->port); } -/* - * This function performs low-level write of high-priority XON/XOFF - * character and accounting for it. - * - * Requires uart_port to implement .serial_out(). - */ -void uart_xchar_out(struct uart_port *uport, int offset) -{ - serial_port_out(uport, offset, uport->x_char); - uport->icount.tx++; - uport->x_char = 0; -} -EXPORT_SYMBOL_GPL(uart_xchar_out); - /* * This function is used to send a high-priority XON/XOFF character to * the device diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 49f59d53b4b26..58274c5073531 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1889,7 +1889,6 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, struct usbtmc_ctrlrequest request; u8 *buffer = NULL; int rv; - unsigned int is_in, pipe; unsigned long res; res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); @@ -1899,14 +1898,12 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; - is_in = request.req.bRequestType & USB_DIR_IN; - if (request.req.wLength) { buffer = kmalloc(request.req.wLength, GFP_KERNEL); if (!buffer) return -ENOMEM; - if (!is_in) { + if ((request.req.bRequestType & USB_DIR_IN) == 0) { /* Send control data to device */ res = copy_from_user(buffer, request.data, request.req.wLength); @@ -1917,12 +1914,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, } } - if (is_in) - pipe = usb_rcvctrlpipe(data->usb_dev, 0); - else - pipe = usb_sndctrlpipe(data->usb_dev, 0); rv = usb_control_msg(data->usb_dev, - pipe, + usb_rcvctrlpipe(data->usb_dev, 0), request.req.bRequest, request.req.bRequestType, request.req.wValue, @@ -1934,7 +1927,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, goto exit; } - if (rv && is_in) { + if (rv && (request.req.bRequestType & USB_DIR_IN)) { /* Read control data from device */ res = copy_to_user(request.data, buffer, rv); if (res) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index be4690bcf1302..a448277e27f08 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1566,6 +1566,12 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_get_properties(dwc); + if (!dwc->sysdev_is_parent) { + ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); + if (ret) + return ret; + } + dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) return PTR_ERR(dwc->reset); @@ -1712,11 +1718,6 @@ static int dwc3_remove(struct platform_device *pdev) return 0; } -static void dwc3_shutdown(struct platform_device *pdev) -{ - dwc3_remove(pdev); -} - #ifdef CONFIG_PM static int dwc3_core_init_for_resume(struct dwc3 *dwc) { @@ -2034,7 +2035,6 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); static struct platform_driver dwc3_driver = { .probe = dwc3_probe, .remove = dwc3_remove, - .shutdown = dwc3_shutdown, .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 66a603f3327d6..3510f6d39f0c3 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -931,6 +931,7 @@ static const struct file_operations acc_fops = { .read = acc_read, .write = acc_write, .unlocked_ioctl = acc_ioctl, + .compat_ioctl = acc_ioctl, .open = acc_open, .release = acc_release, }; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 73a28f8a38a7e..03db2d6b2dbae 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3446,6 +3446,7 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Michal Nazarewicz"); /************************* Module parameters *************************/ diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c index e2d7f69128a0e..8ffd477e79e11 100644 --- a/drivers/usb/gadget/function/f_uac1_legacy.c +++ b/drivers/usb/gadget/function/f_uac1_legacy.c @@ -1015,4 +1015,5 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION_INIT(uac1_legacy, f_audio_alloc_inst, f_audio_alloc); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Bryan Wu"); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 4150de96b937a..0f14c5291af07 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -640,7 +640,6 @@ static int rndis_set_response(struct rndis_params *params, BufLength = le32_to_cpu(buf->InformationBufferLength); BufOffset = le32_to_cpu(buf->InformationBufferOffset); if ((BufLength > RNDIS_MAX_TOTAL_SIZE) || - (BufOffset > RNDIS_MAX_TOTAL_SIZE) || (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE)) return -EINVAL; diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index f7e6c42558eb7..2451e45ada6ed 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -520,3 +520,4 @@ ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, EXPORT_SYMBOL_GPL(fsg_store_inquiry_string); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e1e243e52a2d5..24d0ace3ed3c2 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1437,6 +1437,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) usb_gadget_udc_stop(udc); udc->driver = NULL; + udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; } @@ -1498,6 +1499,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri driver->function); udc->driver = driver; + udc->dev.driver = &driver->driver; udc->gadget->dev.driver = &driver->driver; usb_gadget_udc_set_speed(udc, driver->max_speed); @@ -1520,6 +1522,7 @@ err1: dev_err(&udc->dev, "failed to start %s: %d\n", udc->driver->function, ret); udc->driver = NULL; + udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; return ret; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7ec04d4e66464..e0cd2825fcdce 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -681,7 +681,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) } pm_runtime_allow(xhci_to_hcd(xhci)->self.controller); xhci->test_mode = 0; - return xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + return xhci_reset(xhci); } void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, @@ -1007,9 +1007,6 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status, if (link_state == XDEV_U2) *status |= USB_PORT_STAT_L1; if (link_state == XDEV_U0) { - if (bus_state->resume_done[portnum]) - usb_hcd_end_port_resume(&port->rhub->hcd->self, - portnum); bus_state->resume_done[portnum] = 0; clear_bit(portnum, &bus_state->resuming_ports); if (bus_state->suspended_ports & (1 << portnum)) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 644ddcb26e763..4324fd31b2c45 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2695,7 +2695,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) fail: xhci_halt(xhci); - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); xhci_mem_cleanup(xhci); return -ENOMEM; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dfb3ab2afbcee..f39db28ef040a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -65,7 +65,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; int ret; @@ -73,7 +73,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) ret = readl_poll_timeout_atomic(ptr, result, (result & mask) == done || result == U32_MAX, - 1, timeout_us); + 1, usec); if (result == U32_MAX) /* card removed */ return -ENODEV; @@ -162,7 +162,7 @@ int xhci_start(struct xhci_hcd *xhci) * Transactions will be terminated immediately, and operational registers * will be set to their defaults. */ -int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) +int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; @@ -195,7 +195,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) if (xhci->quirks & XHCI_INTEL_HOST) udelay(1000); - ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us); + ret = xhci_handshake(&xhci->op_regs->command, + CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; @@ -208,7 +209,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us); + ret = xhci_handshake(&xhci->op_regs->status, + STS_CNR, 0, 10 * 1000 * 1000); xhci->usb2_rhub.bus_state.port_c_suspend = 0; xhci->usb2_rhub.bus_state.suspended_ports = 0; @@ -729,7 +731,7 @@ static void xhci_stop(struct usb_hcd *hcd) xhci->xhc_state |= XHCI_STATE_HALTED; xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; xhci_halt(xhci); - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -782,7 +784,7 @@ void xhci_shutdown(struct usb_hcd *hcd) xhci_halt(xhci); /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -1167,7 +1169,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_zero_64b_regs(xhci); - retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); + retval = xhci_reset(xhci); spin_unlock_irq(&xhci->lock); if (retval) return retval; @@ -5278,7 +5280,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ - retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); + retval = xhci_reset(xhci); if (retval) return retval; xhci_dbg(xhci, "Reset complete\n"); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 111dc5ff3f0df..2bba700a78059 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -230,9 +230,6 @@ struct xhci_op_regs { #define CMD_ETE (1 << 14) /* bits 15:31 are reserved (and should be preserved on writes). */ -#define XHCI_RESET_LONG_USEC (10 * 1000 * 1000) -#define XHCI_RESET_SHORT_USEC (250 * 1000) - /* IMAN - Interrupt Management Register */ #define IMAN_IE (1 << 1) #define IMAN_IP (1 << 0) @@ -2100,11 +2097,11 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci, /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us); +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_start(struct xhci_hcd *xhci); -int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); +int xhci_reset(struct xhci_hcd *xhci); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); @@ -2532,8 +2529,6 @@ static inline const char *xhci_decode_ctrl_ctx(char *str, unsigned int bit; int ret = 0; - str[0] = '\0'; - if (drop) { ret = sprintf(str, "Drop:"); for_each_set_bit(bit, &drop, 32) @@ -2691,11 +2686,8 @@ static inline const char *xhci_decode_usbsts(char *str, u32 usbsts) { int ret = 0; - ret = sprintf(str, " 0x%08x", usbsts); - if (usbsts == ~(u32)0) - return str; - + return " 0xffffffff"; if (usbsts & STS_HALT) ret += sprintf(str + ret, " HCHalted"); if (usbsts & STS_FATAL) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 169251ec8353e..4007fa25a8ffa 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -66,7 +66,6 @@ config USB_SERIAL_SIMPLE - Libtransistor USB console - a number of Motorola phones - Motorola Tetra devices - - Nokia mobile phones - Novatel Wireless GPS receivers - Siemens USB/MPI adapter. - ViVOtech ViVOpay USB device. diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index d736822e95e18..1bbe18f3f9f11 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -116,7 +116,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530GC_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index c5406452b774e..6097ee8fccb25 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -35,9 +35,6 @@ #define ATEN_PRODUCT_UC232B 0x2022 #define ATEN_PRODUCT_ID2 0x2118 -#define IBM_VENDOR_ID 0x04b3 -#define IBM_PRODUCT_ID 0x4016 - #define IODATA_VENDOR_ID 0x04bb #define IODATA_PRODUCT_ID 0x0a03 #define IODATA_PRODUCT_ID_RSAQ5 0x0a0e diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4c6747889a194..bd23a7cb1be2b 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -91,11 +91,6 @@ DEVICE(moto_modem, MOTO_IDS); { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); -/* Nokia mobile phone driver */ -#define NOKIA_IDS() \ - { USB_DEVICE(0x0421, 0x069a) } /* Nokia 130 (RM-1035) */ -DEVICE(nokia, NOKIA_IDS); - /* Novatel Wireless GPS driver */ #define NOVATEL_IDS() \ { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ @@ -128,7 +123,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &vivopay_device, &moto_modem_device, &motorola_tetra_device, - &nokia_device, &novatel_gps_device, &hp4x_device, &suunto_device, @@ -146,7 +140,6 @@ static const struct usb_device_id id_table[] = { VIVOPAY_IDS(), MOTO_IDS(), MOTOROLA_TETRA_IDS(), - NOKIA_IDS(), NOVATEL_IDS(), HP4X_IDS(), SUUNTO_IDS(), diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index c9ce1c25c80cc..98c1aa594e6c4 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -237,33 +237,36 @@ static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0)) -/* SD_STATUS bits */ -#define SD_Insert BIT(0) -#define SD_Ready BIT(1) -#define SD_MediaChange BIT(2) -#define SD_IsMMC BIT(3) -#define SD_HiCapacity BIT(4) -#define SD_HiSpeed BIT(5) -#define SD_WtP BIT(6) - /* Bit 7 reserved */ - -/* MS_STATUS bits */ -#define MS_Insert BIT(0) -#define MS_Ready BIT(1) -#define MS_MediaChange BIT(2) -#define MS_IsMSPro BIT(3) -#define MS_IsMSPHG BIT(4) - /* Bit 5 reserved */ -#define MS_WtP BIT(6) - /* Bit 7 reserved */ - -/* SM_STATUS bits */ -#define SM_Insert BIT(0) -#define SM_Ready BIT(1) -#define SM_MediaChange BIT(2) - /* Bits 3-5 reserved */ -#define SM_WtP BIT(6) -#define SM_IsMS BIT(7) +struct SD_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 IsMMC:1; + u8 HiCapacity:1; + u8 HiSpeed:1; + u8 WtP:1; + u8 Reserved:1; +}; + +struct MS_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 IsMSPro:1; + u8 IsMSPHG:1; + u8 Reserved1:1; + u8 WtP:1; + u8 Reserved2:1; +}; + +struct SM_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 Reserved:3; + u8 WtP:1; + u8 IsMS:1; +}; struct ms_bootblock_cis { u8 bCistplDEVICE[6]; /* 0 */ @@ -434,9 +437,9 @@ struct ene_ub6250_info { u8 *bbuf; /* for 6250 code */ - u8 SD_Status; - u8 MS_Status; - u8 SM_Status; + struct SD_STATUS SD_Status; + struct MS_STATUS MS_Status; + struct SM_STATUS SM_Status; /* ----- SD Control Data ---------------- */ /*SD_REGISTER SD_Regs; */ @@ -599,7 +602,7 @@ static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) { struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) + if (info->SD_Status.Insert && info->SD_Status.Ready) return USB_STOR_TRANSPORT_GOOD; else { ene_sd_init(us); @@ -619,7 +622,7 @@ static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - if (info->SD_Status & SD_WtP) + if (info->SD_Status.WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -638,9 +641,9 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; usb_stor_dbg(us, "sd_scsi_read_capacity\n"); - if (info->SD_Status & SD_HiCapacity) { + if (info->SD_Status.HiCapacity) { bl_len = 0x200; - if (info->SD_Status & SD_IsMMC) + if (info->SD_Status.IsMMC) bl_num = info->HC_C_SIZE-1; else bl_num = (info->HC_C_SIZE + 1) * 1024 - 1; @@ -690,7 +693,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } - if (info->SD_Status & SD_HiCapacity) + if (info->SD_Status.HiCapacity) bnByte = bn; /* set up the command wrapper */ @@ -730,7 +733,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } - if (info->SD_Status & SD_HiCapacity) + if (info->SD_Status.HiCapacity) bnByte = bn; /* set up the command wrapper */ @@ -1452,7 +1455,7 @@ static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */ - if ((info->MS_Status & MS_Insert) && (info->MS_Status & MS_Ready)) { + if (info->MS_Status.Insert && info->MS_Status.Ready) { return USB_STOR_TRANSPORT_GOOD; } else { ene_ms_init(us); @@ -1472,7 +1475,7 @@ static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - if (info->MS_Status & MS_WtP) + if (info->MS_Status.WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -1491,7 +1494,7 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) usb_stor_dbg(us, "ms_scsi_read_capacity\n"); bl_len = 0x200; - if (info->MS_Status & MS_IsMSPro) + if (info->MS_Status.IsMSPro) bl_num = info->MSP_TotalBlock - 1; else bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1; @@ -1646,7 +1649,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; - if (info->MS_Status & MS_IsMSPro) { + if (info->MS_Status.IsMSPro) { result = ene_load_bincode(us, MSP_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n"); @@ -1747,7 +1750,7 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; - if (info->MS_Status & MS_IsMSPro) { + if (info->MS_Status.IsMSPro) { result = ene_load_bincode(us, MSP_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { pr_info("Load MSP RW pattern Fail !!\n"); @@ -1855,12 +1858,12 @@ static int ene_get_card_status(struct us_data *us, u8 *buf) tmpreg = (u16) reg4b; reg4b = *(u32 *)(&buf[0x14]); - if ((info->SD_Status & SD_HiCapacity) && !(info->SD_Status & SD_IsMMC)) + if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff; info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07; - if ((info->SD_Status & SD_HiCapacity) && (info->SD_Status & SD_IsMMC)) + if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) info->HC_C_SIZE = *(u32 *)(&buf[0x100]); if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { @@ -2072,7 +2075,6 @@ static int ene_ms_init(struct us_data *us) u16 MSP_BlockSize, MSP_UserAreaBlocks; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; u8 *bbuf = info->bbuf; - unsigned int s; printk(KERN_INFO "transport --- ENE_MSInit\n"); @@ -2097,16 +2099,15 @@ static int ene_ms_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } /* the same part to test ENE */ - info->MS_Status = bbuf[0]; - - s = info->MS_Status; - if ((s & MS_Insert) && (s & MS_Ready)) { - printk(KERN_INFO "Insert = %x\n", !!(s & MS_Insert)); - printk(KERN_INFO "Ready = %x\n", !!(s & MS_Ready)); - printk(KERN_INFO "IsMSPro = %x\n", !!(s & MS_IsMSPro)); - printk(KERN_INFO "IsMSPHG = %x\n", !!(s & MS_IsMSPHG)); - printk(KERN_INFO "WtP= %x\n", !!(s & MS_WtP)); - if (s & MS_IsMSPro) { + info->MS_Status = *(struct MS_STATUS *) bbuf; + + if (info->MS_Status.Insert && info->MS_Status.Ready) { + printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); + printk(KERN_INFO "Ready = %x\n", info->MS_Status.Ready); + printk(KERN_INFO "IsMSPro = %x\n", info->MS_Status.IsMSPro); + printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); + printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); + if (info->MS_Status.IsMSPro) { MSP_BlockSize = (bbuf[6] << 8) | bbuf[7]; MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11]; info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; @@ -2167,17 +2168,17 @@ static int ene_sd_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } - info->SD_Status = bbuf[0]; - if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) { - unsigned int s = info->SD_Status; + info->SD_Status = *(struct SD_STATUS *) bbuf; + if (info->SD_Status.Insert && info->SD_Status.Ready) { + struct SD_STATUS *s = &info->SD_Status; ene_get_card_status(us, bbuf); - usb_stor_dbg(us, "Insert = %x\n", !!(s & SD_Insert)); - usb_stor_dbg(us, "Ready = %x\n", !!(s & SD_Ready)); - usb_stor_dbg(us, "IsMMC = %x\n", !!(s & SD_IsMMC)); - usb_stor_dbg(us, "HiCapacity = %x\n", !!(s & SD_HiCapacity)); - usb_stor_dbg(us, "HiSpeed = %x\n", !!(s & SD_HiSpeed)); - usb_stor_dbg(us, "WtP = %x\n", !!(s & SD_WtP)); + usb_stor_dbg(us, "Insert = %x\n", s->Insert); + usb_stor_dbg(us, "Ready = %x\n", s->Ready); + usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); + usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity); + usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); + usb_stor_dbg(us, "WtP = %x\n", s->WtP); } else { usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]); return USB_STOR_TRANSPORT_ERROR; @@ -2199,14 +2200,14 @@ static int ene_init(struct us_data *us) misc_reg03 = bbuf[0]; if (misc_reg03 & 0x01) { - if (!(info->SD_Status & SD_Ready)) { + if (!info->SD_Status.Ready) { result = ene_sd_init(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } } if (misc_reg03 & 0x02) { - if (!(info->MS_Status & MS_Ready)) { + if (!info->MS_Status.Ready) { result = ene_ms_init(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -2305,14 +2306,14 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) /*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid(srb, 0); - if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready))) + if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) result = ene_init(us); if (result == USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; - if (info->SD_Status & SD_Ready) + if (info->SD_Status.Ready) result = sd_scsi_irp(us, srb); - if (info->MS_Status & MS_Ready) + if (info->MS_Status.Ready) result = ms_scsi_irp(us, srb); } return result; @@ -2376,6 +2377,7 @@ static int ene_ub6250_probe(struct usb_interface *intf, static int ene_ub6250_resume(struct usb_interface *iface) { + u8 tmp = 0; struct us_data *us = usb_get_intfdata(iface); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); @@ -2387,16 +2389,17 @@ static int ene_ub6250_resume(struct usb_interface *iface) mutex_unlock(&us->dev_mutex); info->Power_IsResum = true; - /* info->SD_Status &= ~SD_Ready; */ - info->SD_Status = 0; - info->MS_Status = 0; - info->SM_Status = 0; + /*info->SD_Status.Ready = 0; */ + info->SD_Status = *(struct SD_STATUS *)&tmp; + info->MS_Status = *(struct MS_STATUS *)&tmp; + info->SM_Status = *(struct SM_STATUS *)&tmp; return 0; } static int ene_ub6250_reset_resume(struct usb_interface *iface) { + u8 tmp = 0; struct us_data *us = usb_get_intfdata(iface); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); @@ -2408,10 +2411,10 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface) * the device */ info->Power_IsResum = true; - /* info->SD_Status &= ~SD_Ready; */ - info->SD_Status = 0; - info->MS_Status = 0; - info->SM_Status = 0; + /*info->SD_Status.Ready = 0; */ + info->SD_Status = *(struct SD_STATUS *)&tmp; + info->MS_Status = *(struct MS_STATUS *)&tmp; + info->SM_Status = *(struct SM_STATUS *)&tmp; return 0; } diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 0c423916d7bfa..3789698d9d3c6 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -365,7 +365,7 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len) buf = kmalloc(len, GFP_NOIO); if (buf == NULL) - return -ENOMEM; + return USB_STOR_TRANSPORT_ERROR; usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len); diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 577ff786f11b1..65d6f8fd81e70 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1482,25 +1482,11 @@ static u64 mlx5_vdpa_get_features(struct vdpa_device *vdev) return ndev->mvdev.mlx_features; } -static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) +static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features) { - /* Minimum features to expect */ if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) return -EOPNOTSUPP; - /* Double check features combination sent down by the driver. - * Fail invalid features due to absence of the depended feature. - * - * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit - * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". - * By failing the invalid features sent down by untrusted drivers, - * we're assured the assumption made upon is_index_valid() and - * is_ctrl_vq_idx() will not be compromised. - */ - if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) == - BIT_ULL(VIRTIO_NET_F_MQ)) - return -EINVAL; - return 0; } @@ -1558,7 +1544,7 @@ static int mlx5_vdpa_set_features(struct vdpa_device *vdev, u64 features) print_features(mvdev, features, true); - err = verify_driver_features(mvdev, features); + err = verify_min_features(mvdev, features); if (err) return err; diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c index 3626c21501017..62c97aa21a79b 100644 --- a/drivers/vfio/platform/vfio_amba.c +++ b/drivers/vfio/platform/vfio_amba.c @@ -73,11 +73,13 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id) static void vfio_amba_remove(struct amba_device *adev) { - struct vfio_platform_device *vdev = - vfio_platform_remove_common(&adev->dev); + struct vfio_platform_device *vdev; - kfree(vdev->name); - kfree(vdev); + vdev = vfio_platform_remove_common(&adev->dev); + if (vdev) { + kfree(vdev->name); + kfree(vdev); + } } static const struct amba_id pl330_ids[] = { diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 5d2d6ce7ff413..c282fc0d04bd1 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -697,8 +697,7 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file) /* Iterating over all connections for all CIDs to find orphans is * inefficient. Room for improvement here. */ - vsock_for_each_connected_socket(&vhost_transport.transport, - vhost_vsock_reset_orphans); + vsock_for_each_connected_socket(vhost_vsock_reset_orphans); /* Don't check the owner, because we are in the release path, so we * need to stop the vsock device in any case. diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index a7a1739cff1bd..f253daa05d9d3 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -1691,9 +1691,9 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red, ((blue & 0xfc00) >> 8)); if (regno < 16) { shifter_tt.color_reg[regno] = - ((((red & 0xe000) >> 13) | ((red & 0x1000) >> 12)) << 8) | - ((((green & 0xe000) >> 13) | ((green & 0x1000) >> 12)) << 4) | - ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); + (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | + (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | + ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11)); @@ -1979,9 +1979,9 @@ static int stste_setcolreg(unsigned int regno, unsigned int red, green >>= 12; if (ATARIHW_PRESENT(EXTD_SHIFTER)) shifter_tt.color_reg[regno] = - ((((red & 0xe) >> 1) | ((red & 1) << 3)) << 8) | - ((((green & 0xe) >> 1) | ((green & 1) << 3)) << 4) | - ((blue & 0xe) >> 1) | ((blue & 1) << 3); + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); else shifter_tt.color_reg[regno] = ((red & 0xe) << 7) | diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 1fc8de4ecbebf..355b6120dc4f0 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1062,16 +1062,15 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&info->modelist); - if (!pdev->dev.of_node) { + if (pdev->dev.of_node) { + ret = atmel_lcdfb_of_init(sinfo); + if (ret) + goto free_info; + } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; } - ret = atmel_lcdfb_of_init(sinfo); - if (ret) - goto free_info; - - ret = -ENODEV; if (!sinfo->config) goto free_info; diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index b4980bc2985e3..15a9ee7cd734d 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -469,7 +469,7 @@ static int cirrusfb_check_mclk(struct fb_info *info, long freq) return 0; } -static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, +static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, struct fb_info *info) { long freq; @@ -478,7 +478,9 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, unsigned maxclockidx = var->bits_per_pixel >> 3; /* convert from ps to kHz */ - freq = PICOS2KHZ(var->pixclock ? : 1); + freq = PICOS2KHZ(var->pixclock); + + dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; cinfo->multiplexing = 0; @@ -486,13 +488,11 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, /* If the frequency is greater than we can support, we might be able * to use multiplexing for the video mode */ if (freq > maxclock) { - var->pixclock = KHZ2PICOS(maxclock); - - while ((freq = PICOS2KHZ(var->pixclock)) > maxclock) - var->pixclock++; + dev_err(info->device, + "Frequency greater than maxclock (%ld kHz)\n", + maxclock); + return -EINVAL; } - dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); - /* * Additional constraint: 8bpp uses DAC clock doubling to allow maximum * pixel clock diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c index bd59e7b11ed53..2df56bd303d25 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -64,12 +64,10 @@ #undef in_le32 #undef out_le32 #define in_8(addr) 0 -#define out_8(addr, val) (void)(val) +#define out_8(addr, val) #define in_le32(addr) 0 -#define out_le32(addr, val) (void)(val) -#ifndef pgprot_cached_wthru +#define out_le32(addr, val) #define pgprot_cached_wthru(prot) (prot) -#endif #else static void invalid_vram_cache(void __force *addr) { diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c index 64843464c6613..55d2bd0ce5c02 100644 --- a/drivers/video/fbdev/core/fbcvt.c +++ b/drivers/video/fbdev/core/fbcvt.c @@ -214,11 +214,9 @@ static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt) static void fb_cvt_print_name(struct fb_cvt_data *cvt) { u32 pixcount, pixcount_mod; - int size = 256; - int off = 0; - u8 *buf; + int cnt = 255, offset = 0, read = 0; + u8 *buf = kzalloc(256, GFP_KERNEL); - buf = kzalloc(size, GFP_KERNEL); if (!buf) return; @@ -226,30 +224,43 @@ static void fb_cvt_print_name(struct fb_cvt_data *cvt) pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000; pixcount_mod /= 1000; - off += scnprintf(buf + off, size - off, "fbcvt: %dx%d@%d: CVT Name - ", - cvt->xres, cvt->yres, cvt->refresh); + read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ", + cvt->xres, cvt->yres, cvt->refresh); + offset += read; + cnt -= read; - if (cvt->status) { - off += scnprintf(buf + off, size - off, - "Not a CVT standard - %d.%03d Mega Pixel Image\n", - pixcount, pixcount_mod); - } else { - if (pixcount) - off += scnprintf(buf + off, size - off, "%d", pixcount); + if (cvt->status) + snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega " + "Pixel Image\n", pixcount, pixcount_mod); + else { + if (pixcount) { + read = snprintf(buf+offset, cnt, "%d", pixcount); + cnt -= read; + offset += read; + } - off += scnprintf(buf + off, size - off, ".%03dM", pixcount_mod); + read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod); + cnt -= read; + offset += read; if (cvt->aspect_ratio == 0) - off += scnprintf(buf + off, size - off, "3"); + read = snprintf(buf+offset, cnt, "3"); else if (cvt->aspect_ratio == 3) - off += scnprintf(buf + off, size - off, "4"); + read = snprintf(buf+offset, cnt, "4"); else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4) - off += scnprintf(buf + off, size - off, "9"); + read = snprintf(buf+offset, cnt, "9"); else if (cvt->aspect_ratio == 2) - off += scnprintf(buf + off, size - off, "A"); - - if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) - off += scnprintf(buf + off, size - off, "-R"); + read = snprintf(buf+offset, cnt, "A"); + else + read = 0; + cnt -= read; + offset += read; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + read = snprintf(buf+offset, cnt, "-R"); + cnt -= read; + offset += read; + } } printk(KERN_INFO "%s\n", buf); diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index daaa99818d3b7..570439b326552 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1377,7 +1377,7 @@ static struct video_board vbG200 = { .lowlevel = &matrox_G100 }; static struct video_board vbG200eW = { - .maxvram = 0x100000, + .maxvram = 0x800000, .maxdisplayable = 0x800000, .accelID = FB_ACCEL_MATROX_MGAG200, .lowlevel = &matrox_G100 diff --git a/drivers/video/fbdev/nvidia/nv_i2c.c b/drivers/video/fbdev/nvidia/nv_i2c.c index 0b48965a6420c..d7994a1732459 100644 --- a/drivers/video/fbdev/nvidia/nv_i2c.c +++ b/drivers/video/fbdev/nvidia/nv_i2c.c @@ -86,7 +86,7 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name, { int rc; - strscpy(chan->adapter.name, name, sizeof(chan->adapter.name)); + strcpy(chan->adapter.name, name); chan->adapter.owner = THIS_MODULE; chan->adapter.class = i2c_class; chan->adapter.algo_data = &chan->algo; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c index 777f6d66c28c3..b4a1aefff7661 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c @@ -251,7 +251,6 @@ static int dvic_probe_of(struct platform_device *pdev) adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { adapter = of_get_i2c_adapter_by_node(adapter_node); - of_node_put(adapter_node); if (adapter == NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); omap_dss_put_device(ddata->in); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index a2c7c5cb15234..4b0793abdd84b 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -409,7 +409,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev, if (r) return r; - return sysfs_emit(buf, "%d\n", errors); + return snprintf(buf, PAGE_SIZE, "%d\n", errors); } static ssize_t dsicm_hw_revision_show(struct device *dev, @@ -439,7 +439,7 @@ static ssize_t dsicm_hw_revision_show(struct device *dev, if (r) return r; - return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3); + return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); } static ssize_t dsicm_store_ulps(struct device *dev, @@ -487,7 +487,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, t = ddata->ulps_enabled; mutex_unlock(&ddata->lock); - return sysfs_emit(buf, "%u\n", t); + return snprintf(buf, PAGE_SIZE, "%u\n", t); } static ssize_t dsicm_store_ulps_timeout(struct device *dev, @@ -532,7 +532,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, t = ddata->ulps_timeout; mutex_unlock(&ddata->lock); - return sysfs_emit(buf, "%u\n", t); + return snprintf(buf, PAGE_SIZE, "%u\n", t); } static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 0cbc5b9183f89..1293515e4b169 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -476,7 +476,7 @@ static ssize_t show_cabc_available_modes(struct device *dev, int i; if (!ddata->has_cabc) - return sysfs_emit(buf, "%s\n", cabc_modes[0]); + return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); for (i = 0, len = 0; len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c index 9f6ef9e04d9ce..bb85b21f07248 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c @@ -169,7 +169,7 @@ static ssize_t tpo_td043_vmirror_show(struct device *dev, { struct panel_drv_data *ddata = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", ddata->vmirror); + return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror); } static ssize_t tpo_td043_vmirror_store(struct device *dev, @@ -199,7 +199,7 @@ static ssize_t tpo_td043_mode_show(struct device *dev, { struct panel_drv_data *ddata = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", ddata->mode); + return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode); } static ssize_t tpo_td043_mode_store(struct device *dev, diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 092a1caa1208e..0dbc6bf8268ac 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1047,7 +1047,7 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, if (count + p > total_size) count = total_size - p; - buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1059,14 +1059,25 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; - for (i = (c + 3) >> 2; i--;) { - u32 val; - - val = fb_readl(src); - *dst = big_swap(val); - src++; + for (i = c >> 2; i--;) { + *dst = fb_readl(src++); + *dst = big_swap(*dst); dst++; } + if (c & 3) { + u8 *dst8 = (u8 *)dst; + u8 __iomem *src8 = (u8 __iomem *)src; + + for (i = c & 3; i--;) { + if (i & 1) { + *dst8++ = fb_readb(++src8); + } else { + *dst8++ = fb_readb(--src8); + src8 += 2; + } + } + src = (u32 __iomem *)src8; + } if (copy_to_user(buf, buffer, c)) { err = -EFAULT; @@ -1119,7 +1130,7 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, count = total_size - p; } - buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1137,11 +1148,24 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, break; } - for (i = (c + 3) >> 2; i--;) { - fb_writel(big_swap(*src), dst); - dst++; + for (i = c >> 2; i--;) { + fb_writel(big_swap(*src), dst++); src++; } + if (c & 3) { + u8 *src8 = (u8 *)src; + u8 __iomem *dst8 = (u8 __iomem *)dst; + + for (i = c & 3; i--;) { + if (i & 1) { + fb_writeb(*src8++, ++dst8); + } else { + fb_writeb(*src8++, --dst8); + dst8 += 2; + } + } + dst = (u32 __iomem *)dst8; + } *ppos += c; buf += c; diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 28768c272b73d..bfac3ee4a6422 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1656,7 +1656,6 @@ static int ufx_usb_probe(struct usb_interface *interface, info->par = dev; info->pseudo_palette = dev->pseudo_palette; info->fbops = &ufx_ops; - INIT_LIST_HEAD(&info->modelist); retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) { @@ -1667,6 +1666,8 @@ static int ufx_usb_probe(struct usb_interface *interface, INIT_DELAYED_WORK(&dev->free_framebuffer_work, ufx_free_framebuffer_work); + INIT_LIST_HEAD(&info->modelist); + retval = ufx_reg_read(dev, 0x3000, &id_rev); check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval); dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 90f48b71fd8f7..b9cdd02c10009 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1426,7 +1426,7 @@ static ssize_t metrics_bytes_rendered_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_rendered)); } @@ -1434,7 +1434,7 @@ static ssize_t metrics_bytes_identical_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_identical)); } @@ -1442,7 +1442,7 @@ static ssize_t metrics_bytes_sent_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_sent)); } @@ -1450,7 +1450,7 @@ static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->cpu_kcycles_used)); } diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index 4e641a780726e..d96ab28f8ce4a 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -770,18 +770,12 @@ out: fb_dealloc_cmap(&info->cmap); kfree(info->pseudo_palette); } - if (remapped_fbuf != NULL) { + if (remapped_fbuf != NULL) iounmap(remapped_fbuf); - remapped_fbuf = NULL; - } - if (remapped_regs != NULL) { + if (remapped_regs != NULL) iounmap(remapped_regs); - remapped_regs = NULL; - } - if (remapped_base != NULL) { + if (remapped_base != NULL) iounmap(remapped_base); - remapped_base = NULL; - } if (info) framebuffer_release(info); return err; @@ -801,11 +795,8 @@ static int w100fb_remove(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); iounmap(remapped_base); - remapped_base = NULL; iounmap(remapped_regs); - remapped_regs = NULL; iounmap(remapped_fbuf); - remapped_fbuf = NULL; framebuffer_release(info); diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 1bce254a462a9..b35bb2d57f62c 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -24,46 +24,17 @@ MODULE_PARM_DESC(force_legacy, "Force legacy mode for transitional virtio 1 devices"); #endif -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev) +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); int i; - if (vp_dev->intx_enabled) { - /* - * The below synchronize() guarantees that any - * interrupt for this line arriving after - * synchronize_irq() has completed is guaranteed to see - * intx_soft_enabled == false. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, false); + if (vp_dev->intx_enabled) synchronize_irq(vp_dev->pci_dev->irq); - } - - for (i = 0; i < vp_dev->msix_vectors; ++i) - disable_irq(pci_irq_vector(vp_dev->pci_dev, i)); -} - -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev) -{ - struct virtio_pci_device *vp_dev = to_vp_device(vdev); - int i; - - if (vp_dev->intx_enabled) { - disable_irq(vp_dev->pci_dev->irq); - /* - * The above disable_irq() provides TSO ordering and - * as such promotes the below store to store-release. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, true); - enable_irq(vp_dev->pci_dev->irq); - return; - } for (i = 0; i < vp_dev->msix_vectors; ++i) - enable_irq(pci_irq_vector(vp_dev->pci_dev, i)); + synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); } /* the notify function used when creating a virt queue */ @@ -113,9 +84,6 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) struct virtio_pci_device *vp_dev = opaque; u8 isr; - if (!READ_ONCE(vp_dev->intx_soft_enabled)) - return IRQ_NONE; - /* reading the ISR has the effect of also clearing it so it's very * important to save off the value. */ isr = ioread8(vp_dev->isr); @@ -173,8 +141,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-config", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_config_changed, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_config_changed, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -193,8 +160,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-virtqueues", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_vring_interrupt, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_vring_interrupt, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -371,7 +337,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, "%s-%s", dev_name(&vp_dev->vdev.dev), names[i]); err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), - vring_interrupt, IRQF_NO_AUTOEN, + vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); if (err) diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 94cc3cb0f18f1..b2f0eb4067cbf 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -82,7 +82,6 @@ struct virtio_pci_device { /* MSI-X support */ int msix_enabled; int intx_enabled; - bool intx_soft_enabled; cpumask_var_t *msix_affinity_masks; /* Name strings for interrupts. This size should be enough, * and I'm too lazy to allocate each name separately. */ @@ -121,10 +120,8 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) return container_of(vdev, struct virtio_pci_device, vdev); } -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev); -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev); +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev); /* the notify function used when creating a virt queue */ bool vp_notify(struct virtqueue *vq); /* the config->del_vqs() implementation */ diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index d9c95d89cdd08..d62e9835aeeca 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -97,8 +97,8 @@ static void vp_reset(struct virtio_device *vdev) /* Flush out the status write, and flush in device writes, * including MSi-X interrupts, if any. */ ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -194,7 +194,6 @@ static void del_vq(struct virtio_pci_vq_info *info) } static const struct virtio_config_ops virtio_pci_config_ops = { - .enable_cbs = vp_enable_cbs, .get = vp_get, .set = vp_set, .get_status = vp_get_status, diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index d30e00852318e..2158e16251334 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -63,12 +63,13 @@ static void vp_iowrite64_twopart(u64 val, vp_iowrite32(val >> 32, hi); } -static void __iomem *map_capability(struct pci_dev *dev, int off, +static void __iomem *map_capability(struct virtio_pci_device *vp_dev, int off, size_t minlen, u32 align, u32 start, u32 size, size_t *len) { + struct pci_dev *dev = vp_dev->pci_dev; u8 bar; u32 offset, length; void __iomem *p; @@ -81,6 +82,13 @@ static void __iomem *map_capability(struct pci_dev *dev, int off, pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length), &length); + /* Check if the BAR may have changed since we requested the region. */ + if (bar >= PCI_STD_NUM_BARS || !(vp_dev->modern_bars & (1 << bar))) { + dev_err(&dev->dev, + "virtio_pci: bar unexpectedly changed to %u\n", bar); + return NULL; + } + if (length <= start) { dev_err(&dev->dev, "virtio_pci: bad capability len %u (>%u expected)\n", @@ -291,8 +299,8 @@ static void vp_reset(struct virtio_device *vdev) */ while (vp_ioread8(&vp_dev->common->device_status)) msleep(1); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -370,7 +378,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, vq->priv = (void __force *)vp_dev->notify_base + off * vp_dev->notify_offset_multiplier; } else { - vq->priv = (void __force *)map_capability(vp_dev->pci_dev, + vq->priv = (void __force *)map_capability(vp_dev, vp_dev->notify_map_cap, 2, 2, off * vp_dev->notify_offset_multiplier, 2, NULL); @@ -451,7 +459,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); pos > 0; pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) { - u8 type, cap_len, id; + u8 type, cap_len, id, res_bar; u32 tmp32; u64 res_offset, res_length; @@ -473,9 +481,14 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, if (id != required_id) continue; - /* Type, and ID match, looks good */ pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap, - bar), bar); + bar), &res_bar); + if (res_bar >= PCI_STD_NUM_BARS) + continue; + + /* Type and ID match, and the BAR value isn't reserved. + * Looks good. + */ /* Read the lower 32bit of length and offset */ pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap, @@ -495,6 +508,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, length_hi), &tmp32); res_length |= ((u64)tmp32) << 32; + *bar = res_bar; *offset = res_offset; *len = res_length; @@ -538,7 +552,6 @@ static bool vp_get_shm_region(struct virtio_device *vdev, } static const struct virtio_config_ops virtio_pci_config_nodev_ops = { - .enable_cbs = vp_enable_cbs, .get = NULL, .set = NULL, .generation = vp_generation, @@ -556,7 +569,6 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = { }; static const struct virtio_config_ops virtio_pci_config_ops = { - .enable_cbs = vp_enable_cbs, .get = vp_get, .set = vp_set, .generation = vp_generation, @@ -599,7 +611,7 @@ static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type, &bar); /* Ignore structures with reserved BAR values */ - if (bar > 0x5) + if (bar >= PCI_STD_NUM_BARS) continue; if (type == cfg_type) { @@ -745,13 +757,13 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) return err; err = -EINVAL; - vp_dev->common = map_capability(pci_dev, common, + vp_dev->common = map_capability(vp_dev, common, sizeof(struct virtio_pci_common_cfg), 4, 0, sizeof(struct virtio_pci_common_cfg), NULL); if (!vp_dev->common) goto err_map_common; - vp_dev->isr = map_capability(pci_dev, isr, sizeof(u8), 1, + vp_dev->isr = map_capability(vp_dev, isr, sizeof(u8), 1, 0, 1, NULL); if (!vp_dev->isr) @@ -778,7 +790,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) * Otherwise, map each VQ individually later. */ if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) { - vp_dev->notify_base = map_capability(pci_dev, notify, 2, 2, + vp_dev->notify_base = map_capability(vp_dev, notify, 2, 2, 0, notify_length, &vp_dev->notify_len); if (!vp_dev->notify_base) @@ -791,7 +803,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) * is more than enough for all existing devices. */ if (device) { - vp_dev->device = map_capability(pci_dev, device, 0, 4, + vp_dev->device = map_capability(vp_dev, device, 0, 4, 0, PAGE_SIZE, &vp_dev->device_len); if (!vp_dev->device) diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index ae7f9357bb871..359302f71f7ef 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -229,7 +229,6 @@ static int rti_wdt_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(dev); if (ret) { pm_runtime_put_noidle(dev); - pm_runtime_disable(&pdev->dev); return dev_err_probe(dev, ret, "runtime pm failed\n"); } diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 39def020a074b..6e3e65deb0b93 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -738,3 +738,4 @@ MODULE_AUTHOR("Latchesar Ionkov "); MODULE_AUTHOR("Eric Van Hensbergen "); MODULE_AUTHOR("Ron Minnich "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/Makefile b/fs/Makefile index 5dca3480ee83b..359c63fefa1b8 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -6,6 +6,8 @@ # Rewritten to use lists instead of if-statements. # +subdir-ccflags-y += -DANDROID_GKI_VFS_EXPORT_ONLY=VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver + obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o dcache.o inode.o \ diff --git a/fs/adfs/super.c b/fs/adfs/super.c index bdbd26e571ed3..57044e5372906 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -492,3 +492,4 @@ static void __exit exit_adfs_fs(void) module_init(init_adfs_fs) module_exit(exit_adfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/affs/super.c b/fs/affs/super.c index c6c2a513ec92d..2d2797ef7cfaf 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -676,6 +676,7 @@ static void __exit exit_affs_fs(void) MODULE_DESCRIPTION("Amiga filesystem support for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_affs_fs) module_exit(exit_affs_fs) diff --git a/fs/afs/main.c b/fs/afs/main.c index 179004b15566d..c6bd956454995 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -18,6 +18,7 @@ MODULE_DESCRIPTION("AFS Client File System"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); unsigned afs_debug; module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); diff --git a/fs/attr.c b/fs/attr.c index b4bbdbd4c8ca0..d8c1f796d0e91 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -114,7 +114,7 @@ kill_priv: return 0; } -EXPORT_SYMBOL(setattr_prepare); +EXPORT_SYMBOL_NS(setattr_prepare, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_newsize_ok - may this inode be truncated to a given size @@ -158,7 +158,7 @@ out_sig: out_big: return -EFBIG; } -EXPORT_SYMBOL(inode_newsize_ok); +EXPORT_SYMBOL_NS(inode_newsize_ok, ANDROID_GKI_VFS_EXPORT_ONLY); /** * setattr_copy - copy simple metadata updates into the generic inode @@ -345,4 +345,4 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de return error; } -EXPORT_SYMBOL(notify_change); +EXPORT_SYMBOL_NS(notify_change, ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/autofs/init.c b/fs/autofs/init.c index d3f55e8743389..ba08261f4faa7 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -44,3 +44,4 @@ static void __exit exit_autofs_fs(void) module_init(init_autofs_fs) module_exit(exit_autofs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 54f0ce4442720..b292859f5f85a 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -207,7 +207,7 @@ void make_bad_inode(struct inode *inode) inode->i_opflags &= ~IOP_XATTR; inode->i_fop = &bad_file_ops; } -EXPORT_SYMBOL(make_bad_inode); +EXPORT_SYMBOL_NS(make_bad_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This tests whether an inode has been flagged as bad. The test uses @@ -227,7 +227,7 @@ bool is_bad_inode(struct inode *inode) return (inode->i_op == &bad_inode_ops); } -EXPORT_SYMBOL(is_bad_inode); +EXPORT_SYMBOL_NS(is_bad_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /** * iget_failed - Mark an under-construction inode as dead and release it diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index c1ba13d19024e..abb8f6bb7e395 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -34,6 +34,7 @@ MODULE_DESCRIPTION("BeOS File System (BeFS) driver"); MODULE_AUTHOR("Will Dyson"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); /* The units the vfs expects inode->i_blocks to be in */ #define VFS_BLOCK_SIZE 512 diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index fd691e4815c56..293223cd4b375 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -22,6 +22,7 @@ MODULE_AUTHOR("Tigran Aivazian "); MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); #undef DEBUG diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 213864bc7e8c0..04c4aa7a1df2c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss) static int create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, - unsigned long interp_load_addr, - unsigned long e_entry, unsigned long phdr_addr) + unsigned long load_addr, unsigned long interp_load_addr, + unsigned long e_entry) { struct mm_struct *mm = current->mm; unsigned long p = bprm->p; @@ -256,7 +256,7 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); - NEW_AUX_ENT(AT_PHDR, phdr_addr); + NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); @@ -820,7 +820,7 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, static int load_elf_binary(struct linux_binprm *bprm) { struct file *interpreter = NULL; /* to shut gcc up */ - unsigned long load_addr, load_bias = 0, phdr_addr = 0; + unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; @@ -1153,17 +1153,6 @@ out_free_interp: reloc_func_desc = load_bias; } } - - /* - * Figure out which segment in the file contains the Program - * Header table, and map to the associated memory address. - */ - if (elf_ppnt->p_offset <= elf_ex->e_phoff && - elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { - phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + - elf_ppnt->p_vaddr; - } - k = elf_ppnt->p_vaddr; if ((elf_ppnt->p_flags & PF_X) && k < start_code) start_code = k; @@ -1199,7 +1188,6 @@ out_free_interp: } e_entry = elf_ex->e_entry + load_bias; - phdr_addr += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; @@ -1263,8 +1251,8 @@ out_free_interp: goto out; #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ - retval = create_elf_tables(bprm, elf_ex, interp_load_addr, - e_entry, phdr_addr); + retval = create_elf_tables(bprm, elf_ex, + load_addr, interp_load_addr, e_entry); if (retval < 0) goto out; @@ -1613,16 +1601,17 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, * long file_ofs * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... */ -static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm) +static int fill_files_note(struct memelfnote *note) { + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; unsigned count, size, names_ofs, remaining, n; user_long_t *data; user_long_t *start_end_ofs; char *name_base, *name_curpos; - int i; /* *Estimated* file count and total data size needed */ - count = cprm->vma_count; + count = mm->map_count; if (count > UINT_MAX / 64) return -EINVAL; size = count * 64; @@ -1644,12 +1633,11 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm name_base = name_curpos = ((char *)data) + names_ofs; remaining = size - names_ofs; count = 0; - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *m = &cprm->vma_meta[i]; + for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { struct file *file; const char *filename; - file = m->file; + file = vma->vm_file; if (!file) continue; filename = file_path(file, name_curpos, remaining); @@ -1669,9 +1657,9 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm memmove(name_curpos, filename, n); name_curpos += n; - *start_end_ofs++ = m->start; - *start_end_ofs++ = m->end; - *start_end_ofs++ = m->pgoff; + *start_end_ofs++ = vma->vm_start; + *start_end_ofs++ = vma->vm_end; + *start_end_ofs++ = vma->vm_pgoff; count++; } @@ -1682,7 +1670,7 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm * Count usually is less than mm->map_count, * we need to move filenames down. */ - n = cprm->vma_count - count; + n = mm->map_count - count; if (n != 0) { unsigned shift_bytes = n * 3 * sizeof(data[0]); memmove(name_base - shift_bytes, name_base, @@ -1797,7 +1785,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - struct coredump_params *cprm) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct task_struct *dump_task = current; const struct user_regset_view *view = task_user_regset_view(dump_task); @@ -1869,7 +1857,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, * Now fill in each thread's information. */ for (t = info->thread; t != NULL; t = t->next) - if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size)) + if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) return 0; /* @@ -1878,13 +1866,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); info->size += notesize(&info->psinfo); - fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); + fill_siginfo_note(&info->signote, &info->csigdata, siginfo); info->size += notesize(&info->signote); fill_auxv_note(&info->auxv, current->mm); info->size += notesize(&info->auxv); - if (fill_files_note(&info->files, cprm) == 0) + if (fill_files_note(&info->files) == 0) info->size += notesize(&info->files); return 1; @@ -2026,7 +2014,7 @@ static int elf_note_info_init(struct elf_note_info *info) static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - struct coredump_params *cprm) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct core_thread *ct; struct elf_thread_status *ets; @@ -2047,13 +2035,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, list_for_each_entry(ets, &info->thread_list, list) { int sz; - sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets); + sz = elf_dump_thread_status(siginfo->si_signo, ets); info->thread_status_size += sz; } /* now collect the dump for the current */ memset(info->prstatus, 0, sizeof(*info->prstatus)); - fill_prstatus(info->prstatus, current, cprm->siginfo->si_signo); - elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs); + fill_prstatus(info->prstatus, current, siginfo->si_signo); + elf_core_copy_regs(&info->prstatus->pr_reg, regs); /* Set up header */ fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); @@ -2069,18 +2057,18 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_note(info->notes + 1, "CORE", NT_PRPSINFO, sizeof(*info->psinfo), info->psinfo); - fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo); + fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); fill_auxv_note(info->notes + 3, current->mm); info->numnote = 4; - if (fill_files_note(info->notes + info->numnote, cprm) == 0) { + if (fill_files_note(info->notes + info->numnote) == 0) { info->notes_files = info->notes + info->numnote; info->numnote++; } /* Try to dump the FPU. */ - info->prstatus->pr_fpvalid = - elf_core_copy_task_fpregs(current, cprm->regs, info->fpu); + info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, + info->fpu); if (info->prstatus->pr_fpvalid) fill_note(info->notes + info->numnote++, "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); @@ -2166,7 +2154,8 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, static int elf_core_dump(struct coredump_params *cprm) { int has_dumped = 0; - int segs, i; + int vma_count, segs, i; + size_t vma_data_size; struct elfhdr elf; loff_t offset = 0, dataoff; struct elf_note_info info = { }; @@ -2174,12 +2163,16 @@ static int elf_core_dump(struct coredump_params *cprm) struct elf_shdr *shdr4extnum = NULL; Elf_Half e_phnum; elf_addr_t e_shoff; + struct core_vma_metadata *vma_meta; + + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) + return 0; /* * The number of segs are recored into ELF header as 16bit value. * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. */ - segs = cprm->vma_count + elf_core_extra_phdrs(); + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -2193,7 +2186,7 @@ static int elf_core_dump(struct coredump_params *cprm) * Collect all the non-memory information about the process for the * notes. This also sets up the file header. */ - if (!fill_note_info(&elf, e_phnum, &info, cprm)) + if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs)) goto end_coredump; has_dumped = 1; @@ -2217,7 +2210,7 @@ static int elf_core_dump(struct coredump_params *cprm) dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - offset += cprm->vma_data_size; + offset += vma_data_size; offset += elf_core_extra_data_size(); e_shoff = offset; @@ -2237,8 +2230,8 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; /* Write program headers for segments dump */ - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; phdr.p_type = PT_LOAD; @@ -2275,8 +2268,8 @@ static int elf_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto end_coredump; - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; if (!dump_user_range(cprm, meta->start, meta->dump_size)) goto end_coredump; @@ -2294,6 +2287,7 @@ static int elf_core_dump(struct coredump_params *cprm) end_coredump: free_note_info(&info); kfree(shdr4extnum); + kvfree(vma_meta); kfree(phdr4note); return has_dumped; } diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 5764295a3f0ff..be4062b8ba75e 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1479,7 +1479,7 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm, static int elf_fdpic_core_dump(struct coredump_params *cprm) { int has_dumped = 0; - int segs; + int vma_count, segs; int i; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; @@ -1494,6 +1494,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf_addr_t e_shoff; struct core_thread *ct; struct elf_thread_status *tmp; + struct core_vma_metadata *vma_meta = NULL; + size_t vma_data_size; /* alloc memory for large data structures: too large to be on stack */ elf = kmalloc(sizeof(*elf), GFP_KERNEL); @@ -1503,6 +1505,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) if (!psinfo) goto end_coredump; + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) + goto end_coredump; + for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { tmp = elf_dump_thread_status(cprm->siginfo->si_signo, @@ -1522,7 +1527,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) tmp->next = thread_list; thread_list = tmp; - segs = cprm->vma_count + elf_core_extra_phdrs(); + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -1567,7 +1572,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - offset += cprm->vma_data_size; + offset += vma_data_size; offset += elf_core_extra_data_size(); e_shoff = offset; @@ -1587,8 +1592,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; /* write program headers for segments dump */ - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; size_t sz; @@ -1638,7 +1643,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto end_coredump; - if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count)) + if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) goto end_coredump; if (!elf_core_write_extra_data(cprm)) @@ -1662,6 +1667,7 @@ end_coredump: thread_list = thread_list->next; kfree(tmp); } + kvfree(vma_meta); kfree(phdr4note); kfree(elf); kfree(psinfo); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 11b5bf2419555..3e4791efdf77b 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -832,3 +832,4 @@ static void __exit exit_misc_binfmt(void) core_initcall(init_misc_binfmt); module_exit(exit_misc_binfmt); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/block_dev.c b/fs/block_dev.c index 600ce43c1843e..aa0766b7be4f3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -186,7 +186,7 @@ int sb_set_blocksize(struct super_block *sb, int size) return sb->s_blocksize; } -EXPORT_SYMBOL(sb_set_blocksize); +EXPORT_SYMBOL_NS(sb_set_blocksize, ANDROID_GKI_VFS_EXPORT_ONLY); int sb_min_blocksize(struct super_block *sb, int size) { @@ -196,7 +196,7 @@ int sb_min_blocksize(struct super_block *sb, int size) return sb_set_blocksize(sb, size); } -EXPORT_SYMBOL(sb_min_blocksize); +EXPORT_SYMBOL_NS(sb_min_blocksize, ANDROID_GKI_VFS_EXPORT_ONLY); static int blkdev_get_block(struct inode *inode, sector_t iblock, diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 4b3ae0faf548e..3a3102bc15a05 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -503,11 +503,8 @@ process_slot: */ ASSERT(key.offset == 0); ASSERT(datal <= fs_info->sectorsize); - if (WARN_ON(key.offset != 0) || - WARN_ON(datal > fs_info->sectorsize)) { - ret = -EUCLEAN; - goto out; - } + if (key.offset != 0 || datal > fs_info->sectorsize) + return -EUCLEAN; ret = clone_copy_inline_extent(inode, path, &new_key, drop_start, datal, size, diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2663485c17cb8..b5d2005d3415d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2597,6 +2597,7 @@ late_initcall(init_btrfs_fs); module_exit(exit_btrfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32c"); MODULE_SOFTDEP("pre: xxhash64"); MODULE_SOFTDEP("pre: sha256"); diff --git a/fs/buffer.c b/fs/buffer.c index 63afd6ddb85f7..13dd0f71f7623 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -173,7 +173,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate) unlock_buffer(bh); put_bh(bh); } -EXPORT_SYMBOL(end_buffer_write_sync); +EXPORT_SYMBOL_NS(end_buffer_write_sync, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Various filesystems appear to want __find_get_block to be non-blocking. @@ -419,7 +419,7 @@ void mark_buffer_async_write(struct buffer_head *bh) { mark_buffer_async_write_endio(bh, end_buffer_async_write); } -EXPORT_SYMBOL(mark_buffer_async_write); +EXPORT_SYMBOL_NS(mark_buffer_async_write, ANDROID_GKI_VFS_EXPORT_ONLY); /* @@ -674,7 +674,7 @@ int __set_page_dirty_buffers(struct page *page) return newly_dirty; } -EXPORT_SYMBOL(__set_page_dirty_buffers); +EXPORT_SYMBOL_NS(__set_page_dirty_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Write out and wait upon a list of buffers. @@ -1141,7 +1141,7 @@ void mark_buffer_dirty(struct buffer_head *bh) __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } } -EXPORT_SYMBOL(mark_buffer_dirty); +EXPORT_SYMBOL_NS(mark_buffer_dirty, ANDROID_GKI_VFS_EXPORT_ONLY); void mark_buffer_write_io_error(struct buffer_head *bh) { @@ -1159,7 +1159,7 @@ void mark_buffer_write_io_error(struct buffer_head *bh) errseq_set(&sb->s_wb_err, -EIO); rcu_read_unlock(); } -EXPORT_SYMBOL(mark_buffer_write_io_error); +EXPORT_SYMBOL_NS(mark_buffer_write_io_error, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Decrement a buffer_head's reference count. If all buffers against a page @@ -1176,7 +1176,7 @@ void __brelse(struct buffer_head * buf) } WARN(1, KERN_ERR "VFS: brelse: Trying to free free buffer\n"); } -EXPORT_SYMBOL(__brelse); +EXPORT_SYMBOL_NS(__brelse, ANDROID_GKI_VFS_EXPORT_ONLY); /* * bforget() is like brelse(), except it discards any @@ -1195,7 +1195,7 @@ void __bforget(struct buffer_head *bh) } __brelse(bh); } -EXPORT_SYMBOL(__bforget); +EXPORT_SYMBOL_NS(__bforget, ANDROID_GKI_VFS_EXPORT_ONLY); static struct buffer_head *__bread_slow(struct buffer_head *bh) { @@ -1376,7 +1376,7 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size) brelse(bh); } } -EXPORT_SYMBOL(__breadahead); +EXPORT_SYMBOL_NS(__breadahead, ANDROID_GKI_VFS_EXPORT_ONLY); void __breadahead_gfp(struct block_device *bdev, sector_t block, unsigned size, gfp_t gfp) @@ -1411,7 +1411,7 @@ __bread_gfp(struct block_device *bdev, sector_t block, bh = __bread_slow(bh); return bh; } -EXPORT_SYMBOL(__bread_gfp); +EXPORT_SYMBOL_NS(__bread_gfp, ANDROID_GKI_VFS_EXPORT_ONLY); static void __invalidate_bh_lrus(struct bh_lru *b) { @@ -1569,7 +1569,7 @@ void block_invalidatepage(struct page *page, unsigned int offset, out: return; } -EXPORT_SYMBOL(block_invalidatepage); +EXPORT_SYMBOL_NS(block_invalidatepage, ANDROID_GKI_VFS_EXPORT_ONLY); /* @@ -1605,7 +1605,7 @@ void create_empty_buffers(struct page *page, attach_page_private(page, head); spin_unlock(&page->mapping->private_lock); } -EXPORT_SYMBOL(create_empty_buffers); +EXPORT_SYMBOL_NS(create_empty_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); /** * clean_bdev_aliases: clean a range of buffers in block device @@ -1679,7 +1679,7 @@ unlock_page: break; } } -EXPORT_SYMBOL(clean_bdev_aliases); +EXPORT_SYMBOL_NS(clean_bdev_aliases, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Size is a power-of-two in the range 512..PAGE_SIZE, @@ -1937,7 +1937,7 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) bh = bh->b_this_page; } while (bh != head); } -EXPORT_SYMBOL(page_zero_new_buffers); +EXPORT_SYMBOL_NS(page_zero_new_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); static void iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, @@ -2271,7 +2271,7 @@ int block_is_partially_uptodate(struct page *page, unsigned long from, return ret; } -EXPORT_SYMBOL(block_is_partially_uptodate); +EXPORT_SYMBOL_NS(block_is_partially_uptodate, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Generic "read page" function for block devices that have the normal @@ -3138,7 +3138,7 @@ void ll_rw_block(int op, int op_flags, int nr, struct buffer_head *bhs[]) unlock_buffer(bh); } } -EXPORT_SYMBOL(ll_rw_block); +EXPORT_SYMBOL_NS(ll_rw_block, ANDROID_GKI_VFS_EXPORT_ONLY); void write_dirty_buffer(struct buffer_head *bh, int op_flags) { @@ -3185,13 +3185,13 @@ int __sync_dirty_buffer(struct buffer_head *bh, int op_flags) } return ret; } -EXPORT_SYMBOL(__sync_dirty_buffer); +EXPORT_SYMBOL_NS(__sync_dirty_buffer, ANDROID_GKI_VFS_EXPORT_ONLY); int sync_dirty_buffer(struct buffer_head *bh) { return __sync_dirty_buffer(bh, REQ_SYNC); } -EXPORT_SYMBOL(sync_dirty_buffer); +EXPORT_SYMBOL_NS(sync_dirty_buffer, ANDROID_GKI_VFS_EXPORT_ONLY); /* * try_to_free_buffers() checks if all the buffers on this particular page diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index ddf0cd58d60cc..0649e7e601341 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -28,6 +28,7 @@ MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask"); MODULE_DESCRIPTION("Mounted-filesystem based cache"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct kmem_cache *cachefiles_object_jar; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 08c8d34c98091..e0562c55384f6 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -1335,3 +1335,4 @@ MODULE_AUTHOR("Yehuda Sadeh "); MODULE_AUTHOR("Patience Warnick "); MODULE_DESCRIPTION("Ceph filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index aa5a4d759ca23..8563e7b78c02d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1693,6 +1693,7 @@ exit_cifs(void) MODULE_AUTHOR("Steve French"); MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and " "also older servers complying with the SNIA CIFS Specification)"); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 0e8f484031da9..fdb1d660bd136 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1526,7 +1526,6 @@ smb2_ioctl_query_info(const unsigned int xid, unsigned int size[2]; void *data[2]; int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; - void (*free_req1_func)(struct smb_rqst *r); vars = kzalloc(sizeof(*vars), GFP_ATOMIC); if (vars == NULL) @@ -1536,29 +1535,27 @@ smb2_ioctl_query_info(const unsigned int xid, resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; - if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) { - rc = -EFAULT; - goto free_vars; - } + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) + goto e_fault; + if (qi.output_buffer_length > 1024) { - rc = -EINVAL; - goto free_vars; + kfree(vars); + return -EINVAL; } if (!ses || !server) { - rc = -EIO; - goto free_vars; + kfree(vars); + return -EIO; } if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - if (qi.output_buffer_length) { - buffer = memdup_user(arg + sizeof(struct smb_query_info), qi.output_buffer_length); - if (IS_ERR(buffer)) { - rc = PTR_ERR(buffer); - goto free_vars; - } + buffer = memdup_user(arg + sizeof(struct smb_query_info), + qi.output_buffer_length); + if (IS_ERR(buffer)) { + kfree(vars); + return PTR_ERR(buffer); } /* Open */ @@ -1596,45 +1593,45 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_open_init(tcon, server, &rqst[0], &oplock, &oparms, path); if (rc) - goto free_output_buffer; + goto iqinf_exit; smb2_set_next_command(tcon, &rqst[0]); /* Query */ if (qi.flags & PASSTHRU_FSCTL) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) rc = -EPERM; - goto free_open_req; + else { + rqst[1].rq_iov = &vars->io_iov[0]; + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; + + rc = SMB2_ioctl_init(tcon, server, + &rqst[1], + COMPOUND_FID, COMPOUND_FID, + qi.info_type, true, buffer, + qi.output_buffer_length, + CIFSMaxBufSize - + MAX_SMB2_CREATE_RESPONSE_SIZE - + MAX_SMB2_CLOSE_RESPONSE_SIZE); } - rqst[1].rq_iov = &vars->io_iov[0]; - rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; - - rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, - qi.info_type, true, buffer, qi.output_buffer_length, - CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - - MAX_SMB2_CLOSE_RESPONSE_SIZE); - free_req1_func = SMB2_ioctl_free; } else if (qi.flags == PASSTHRU_SET_INFO) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) rc = -EPERM; - goto free_open_req; - } - if (qi.output_buffer_length < 8) { - rc = -EINVAL; - goto free_open_req; - } - rqst[1].rq_iov = &vars->si_iov[0]; - rqst[1].rq_nvec = 1; - - /* MS-FSCC 2.4.13 FileEndOfFileInformation */ - size[0] = 8; - data[0] = buffer; - - rc = SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, - current->tgid, FILE_END_OF_FILE_INFORMATION, + else { + rqst[1].rq_iov = &vars->si_iov[0]; + rqst[1].rq_nvec = 1; + + size[0] = 8; + data[0] = buffer; + + rc = SMB2_set_info_init(tcon, server, + &rqst[1], + COMPOUND_FID, COMPOUND_FID, + current->tgid, + FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE, 0, data, size); - free_req1_func = SMB2_set_info_free; + } } else if (qi.flags == PASSTHRU_QUERY_INFO) { rqst[1].rq_iov = &vars->qi_iov[0]; rqst[1].rq_nvec = 1; @@ -1645,7 +1642,6 @@ smb2_ioctl_query_info(const unsigned int xid, qi.info_type, qi.additional_information, qi.input_buffer_length, qi.output_buffer_length, buffer); - free_req1_func = SMB2_query_info_free; } else { /* unknown flags */ cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n", qi.flags); @@ -1653,7 +1649,7 @@ smb2_ioctl_query_info(const unsigned int xid, } if (rc) - goto free_open_req; + goto iqinf_exit; smb2_set_next_command(tcon, &rqst[1]); smb2_set_related(&rqst[1]); @@ -1664,14 +1660,14 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_close_init(tcon, server, &rqst[2], COMPOUND_FID, COMPOUND_FID, false); if (rc) - goto free_req_1; + goto iqinf_exit; smb2_set_related(&rqst[2]); rc = compound_send_recv(xid, ses, server, flags, 3, rqst, resp_buftype, rsp_iov); if (rc) - goto out; + goto iqinf_exit; /* No need to bump num_remote_opens since handle immediately closed */ if (qi.flags & PASSTHRU_FSCTL) { @@ -1681,22 +1677,18 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount); if (qi.input_buffer_length > 0 && le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length - > rsp_iov[1].iov_len) { - rc = -EFAULT; - goto out; - } + > rsp_iov[1].iov_len) + goto e_fault; if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) { - rc = -EFAULT; - goto out; - } + sizeof(qi.input_buffer_length))) + goto e_fault; if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info), (const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset), qi.input_buffer_length)) - rc = -EFAULT; + goto e_fault; } else { pqi = (struct smb_query_info __user *)arg; qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; @@ -1704,30 +1696,28 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) { - rc = -EFAULT; - goto out; - } + sizeof(qi.input_buffer_length))) + goto e_fault; if (copy_to_user(pqi + 1, qi_rsp->Buffer, qi.input_buffer_length)) - rc = -EFAULT; + goto e_fault; } -out: + iqinf_exit: + cifs_small_buf_release(rqst[0].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[1].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[2].rq_iov[0].iov_base); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); - SMB2_close_free(&rqst[2]); -free_req_1: - free_req1_func(&rqst[1]); -free_open_req: - SMB2_open_free(&rqst[0]); -free_output_buffer: - kfree(buffer); -free_vars: kfree(vars); + kfree(buffer); return rc; + +e_fault: + rc = -EFAULT; + goto iqinf_exit; } static ssize_t diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 240669f51eac3..897c7cb93f47c 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -388,6 +388,7 @@ MODULE_AUTHOR("Jan Harkes, Peter J. Braam"); MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_VERSION("7.0"); static int __init init_coda(void) diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 0c6e8cf619530..c01eb7264b4d1 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -175,6 +175,7 @@ MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); core_initcall(configfs_init); module_exit(configfs_exit); diff --git a/fs/coredump.c b/fs/coredump.c index b08f8fcb57124..c56a3bdce7cd4 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -53,9 +52,6 @@ #include -static bool dump_vma_snapshot(struct coredump_params *cprm); -static void free_vma_snapshot(struct coredump_params *cprm); - int core_uses_pid; unsigned int core_pipe_limit; char core_pattern[CORENAME_MAX_SIZE] = "core"; @@ -605,7 +601,6 @@ void do_coredump(const kernel_siginfo_t *siginfo) * by any locks. */ .mm_flags = mm->flags, - .vma_meta = NULL, }; audit_core_dumps(siginfo->si_signo); @@ -811,13 +806,9 @@ void do_coredump(const kernel_siginfo_t *siginfo) pr_info("Core dump to |%s disabled\n", cn.corename); goto close_fail; } - if (!dump_vma_snapshot(&cprm)) - goto close_fail; - file_start_write(cprm.file); core_dumped = binfmt->core_dump(&cprm); file_end_write(cprm.file); - free_vma_snapshot(&cprm); } if (ispipe && core_pipe_limit) wait_for_dump_helpers(cprm.file); @@ -909,7 +900,7 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start, stop = !dump_emit(cprm, kaddr, PAGE_SIZE); kunmap(page); - put_user_page(page); + put_page(page); } else { stop = !dump_skip(cprm, PAGE_SIZE); } @@ -978,8 +969,6 @@ static bool always_dump_vma(struct vm_area_struct *vma) return false; } -#define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1 - /* * Decide how much of @vma's contents should be included in a core dump. */ @@ -1039,20 +1028,9 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, * dump the first page to aid in determining what was mapped here. */ if (FILTER(ELF_HEADERS) && - vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { - if ((READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0) - return PAGE_SIZE; - - /* - * ELF libraries aren't always executable. - * We'll want to check whether the mapping starts with the ELF - * magic, but not now - we're holding the mmap lock, - * so copy_from_user() doesn't work here. - * Use a placeholder instead, and fix it up later in - * dump_vma_snapshot(). - */ - return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER; - } + vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ) && + (READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0) + return PAGE_SIZE; #undef FILTER @@ -1089,29 +1067,18 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, return gate_vma; } -static void free_vma_snapshot(struct coredump_params *cprm) -{ - if (cprm->vma_meta) { - int i; - for (i = 0; i < cprm->vma_count; i++) { - struct file *file = cprm->vma_meta[i].file; - if (file) - fput(file); - } - kvfree(cprm->vma_meta); - cprm->vma_meta = NULL; - } -} - /* * Under the mmap_lock, take a snapshot of relevant information about the task's * VMAs. */ -static bool dump_vma_snapshot(struct coredump_params *cprm) +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + size_t *vma_data_size_ptr) { struct vm_area_struct *vma, *gate_vma; struct mm_struct *mm = current->mm; int i; + size_t vma_data_size = 0; /* * Once the stack expansion code is fixed to not change VMA bounds @@ -1119,51 +1086,36 @@ static bool dump_vma_snapshot(struct coredump_params *cprm) * mmap_lock in read mode. */ if (mmap_write_lock_killable(mm)) - return false; + return -EINTR; - cprm->vma_data_size = 0; gate_vma = get_gate_vma(mm); - cprm->vma_count = mm->map_count + (gate_vma ? 1 : 0); + *vma_count = mm->map_count + (gate_vma ? 1 : 0); - cprm->vma_meta = kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta), GFP_KERNEL); - if (!cprm->vma_meta) { + *vma_meta = kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL); + if (!*vma_meta) { mmap_write_unlock(mm); - return false; + return -ENOMEM; } for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; vma = next_vma(vma, gate_vma), i++) { - struct core_vma_metadata *m = cprm->vma_meta + i; + struct core_vma_metadata *m = (*vma_meta) + i; m->start = vma->vm_start; m->end = vma->vm_end; m->flags = vma->vm_flags; m->dump_size = vma_dump_size(vma, cprm->mm_flags); - m->pgoff = vma->vm_pgoff; - m->file = vma->vm_file; - if (m->file) - get_file(m->file); + vma_data_size += m->dump_size; } mmap_write_unlock(mm); - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *m = cprm->vma_meta + i; - - if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) { - char elfmag[SELFMAG]; - - if (copy_from_user(elfmag, (void __user *)m->start, SELFMAG) || - memcmp(elfmag, ELFMAG, SELFMAG) != 0) { - m->dump_size = 0; - } else { - m->dump_size = PAGE_SIZE; - } - } - - cprm->vma_data_size += m->dump_size; + if (WARN_ON(i != *vma_count)) { + kvfree(*vma_meta); + return -EFAULT; } - return true; + *vma_data_size_ptr = vma_data_size; + return 0; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 4b90cfd1ec360..6245470112a1d 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -1010,3 +1010,4 @@ static void __exit exit_cramfs_fs(void) module_init(init_cramfs_fs) module_exit(exit_cramfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index 652c7180ec6de..d39077502e062 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + fscrypto-y := crypto.o \ fname.o \ hkdf.o \ diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 7df5877fac9a9..68ab6830767a4 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -345,6 +345,10 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); * * fscrypt_set_bio_crypt_ctx() must have already been called on the bio. * + * This function isn't required in cases where crypto-mergeability is ensured in + * another way, such as I/O targeting only a single file (and thus a single key) + * combined with fscrypt_limit_io_blocks() to ensure DUN contiguity. + * * This function also returns false if the next part of the I/O would need to * have a different value for the bi_skip_dm_default_key flag. * @@ -402,12 +406,15 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio, EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); /** - * fscrypt_dio_supported() - check whether a direct I/O request is unsupported - * due to encryption constraints + * fscrypt_dio_supported() - check whether a DIO (direct I/O) request is + * supported as far as encryption is concerned * @iocb: the file and position the I/O is targeting * @iter: the I/O data segment(s) * - * Return: true if direct I/O is supported + * Return: %true if there are no encryption constraints that prevent DIO from + * being supported; %false if DIO is unsupported. (Note that in the + * %true case, the filesystem might have other, non-encryption-related + * constraints that prevent DIO from actually being supported.) */ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) { @@ -418,13 +425,22 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) if (!fscrypt_needs_contents_encryption(inode)) return true; - /* We only support direct I/O with inline crypto, not fs-layer crypto */ + /* We only support DIO with inline crypto, not fs-layer crypto. */ if (!fscrypt_inode_uses_inline_crypto(inode)) return false; /* - * Since the granularity of encryption is filesystem blocks, the I/O - * must be block aligned -- not just disk sector aligned. + * Since the granularity of encryption is filesystem blocks, the file + * position and total I/O length must be aligned to the filesystem block + * size -- not just to the block device's logical block size as is + * traditionally the case for DIO on many filesystems. + * + * We require that the user-provided memory buffers be filesystem block + * aligned too. It is simpler to have a single alignment value required + * for all properties of the I/O, as is normally the case for DIO. + * Also, allowing less aligned buffers would imply that data units could + * cross bvecs, which would greatly complicate the I/O stack, which + * assumes that bios can be split at any bvec boundary. */ if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize)) return false; @@ -437,24 +453,25 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported); * fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs * @inode: the file on which I/O is being done * @lblk: the block at which the I/O is being started from - * @nr_blocks: the number of blocks we want to submit starting at @pos + * @nr_blocks: the number of blocks we want to submit starting at @lblk * - * Determine the limit to the number of blocks that can be submitted in the bio - * targeting @pos without causing a data unit number (DUN) discontinuity. + * Determine the limit to the number of blocks that can be submitted in a bio + * targeting @lblk without causing a data unit number (DUN) discontiguity. * * This is normally just @nr_blocks, as normally the DUNs just increment along * with the logical blocks. (Or the file is not encrypted.) * * In rare cases, fscrypt can be using an IV generation method that allows the - * DUN to wrap around within logically continuous blocks, and that wraparound + * DUN to wrap around within logically contiguous blocks, and that wraparound * will occur. If this happens, a value less than @nr_blocks will be returned - * so that the wraparound doesn't occur in the middle of the bio. + * so that the wraparound doesn't occur in the middle of a bio, which would + * cause encryption/decryption to produce wrong results. * * Return: the actual number of blocks that can be submitted */ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) { - const struct fscrypt_info *ci = inode->i_crypt_info; + const struct fscrypt_info *ci; u32 dun; if (!fscrypt_inode_uses_inline_crypto(inode)) @@ -463,6 +480,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; + ci = inode->i_crypt_info; if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; diff --git a/fs/dcache.c b/fs/dcache.c index ea0485861d937..cb588cee9669a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2110,7 +2110,7 @@ struct dentry *d_obtain_alias(struct inode *inode) { return __d_obtain_alias(inode, true); } -EXPORT_SYMBOL(d_obtain_alias); +EXPORT_SYMBOL_NS(d_obtain_alias, ANDROID_GKI_VFS_EXPORT_ONLY); /** * d_obtain_root - find or allocate a dentry for a given inode @@ -2184,7 +2184,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, } return found; } -EXPORT_SYMBOL(d_add_ci); +EXPORT_SYMBOL_NS(d_add_ci, ANDROID_GKI_VFS_EXPORT_ONLY); static inline bool d_same_name(const struct dentry *dentry, @@ -3065,7 +3065,7 @@ out: __d_add(dentry, inode); return NULL; } -EXPORT_SYMBOL(d_splice_alias); +EXPORT_SYMBOL_NS(d_splice_alias, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Test whether new_dentry is a subdirectory of old_dentry. diff --git a/fs/direct-io.c b/fs/direct-io.c index 4e9b306ca6bea..771017cf8fcc9 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1367,7 +1367,7 @@ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, end_io, submit_io, flags); } -EXPORT_SYMBOL(__blockdev_direct_IO); +EXPORT_SYMBOL_NS(__blockdev_direct_IO, ANDROID_GKI_VFS_EXPORT_ONLY); static __init int dio_init(void) { diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index b2f6a1937d239..eb12d38d000df 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -891,6 +891,7 @@ MODULE_AUTHOR("Michael A. Halcrow "); MODULE_DESCRIPTION("eCryptfs"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(ecryptfs_init) module_exit(ecryptfs_exit) diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 15880a68faadc..b62aefe3b4b82 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -272,6 +272,7 @@ static __exit void efivarfs_exit(void) MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr"); MODULE_DESCRIPTION("EFI Variable Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_ALIAS_FS("efivarfs"); module_init(efivarfs_init); diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 89e73a6f0d361..8c0ecaa62de2b 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -311,3 +311,4 @@ efs_block_t efs_map_block(struct inode *inode, efs_block_t block) { } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 756fe2d652725..8a3317e38e5a8 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_EROFS_FS) += erofs.o -erofs-objs := super.o inode.o data.o namei.o dir.o utils.o pcpubuf.o +erofs-objs := super.o inode.o data.o namei.o dir.o utils.o pcpubuf.o sysfs.o erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o erofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index d5046bbbcaf1e..d75a45c691346 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -134,6 +134,10 @@ struct erofs_sb_info { u8 volume_name[16]; /* volume name */ u32 feature_compat; u32 feature_incompat; + + /* sysfs support */ + struct kobject s_kobj; /* /sys/fs/erofs/ */ + struct completion s_kobj_unregister; }; #define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info) @@ -261,7 +265,9 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) +EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE) EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) +EROFS_FEATURE_FUNCS(compr_head2, incompat, INCOMPAT_COMPR_HEAD2) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) /* atomic flag definitions */ @@ -484,6 +490,12 @@ int erofs_pcpubuf_growsize(unsigned int nrpages); void erofs_pcpubuf_init(void); void erofs_pcpubuf_exit(void); +/* sysfs.c */ +int erofs_register_sysfs(struct super_block *sb); +void erofs_unregister_sysfs(struct super_block *sb); +int __init erofs_init_sysfs(void); +void erofs_exit_sysfs(void); + /* utils.c / zdata.c */ struct page *erofs_allocpage(struct page **pagepool, gfp_t gfp); static inline void erofs_pagepool_add(struct page **pagepool, diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 9862457b421a1..46c80eab75274 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -695,6 +695,10 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) if (err) return err; + err = erofs_register_sysfs(sb); + if (err) + return err; + erofs_info(sb, "mounted with root inode @ nid %llu.", ROOT_NID(sbi)); return 0; } @@ -808,6 +812,7 @@ static void erofs_put_super(struct super_block *sb) DBG_BUGON(!sbi); + erofs_unregister_sysfs(sb); erofs_shrinker_unregister(sb); #ifdef CONFIG_EROFS_FS_ZIP iput(sbi->managed_cache); @@ -852,6 +857,10 @@ static int __init erofs_module_init(void) if (err) goto zip_err; + err = erofs_init_sysfs(); + if (err) + goto sysfs_err; + err = register_filesystem(&erofs_fs_type); if (err) goto fs_err; @@ -859,6 +868,8 @@ static int __init erofs_module_init(void) return 0; fs_err: + erofs_exit_sysfs(); +sysfs_err: z_erofs_exit_zip_subsystem(); zip_err: z_erofs_lzma_exit(); @@ -877,6 +888,7 @@ static void __exit erofs_module_exit(void) /* Ensure all RCU free inodes / pclusters are safe to be destroyed. */ rcu_barrier(); + erofs_exit_sysfs(); z_erofs_exit_zip_subsystem(); z_erofs_lzma_exit(); erofs_exit_shrinker(); @@ -951,3 +963,4 @@ module_exit(erofs_module_exit); MODULE_DESCRIPTION("Enhanced ROM File System"); MODULE_AUTHOR("Gao Xiang, Chao Yu, Miao Xie, CONSUMER BG, HUAWEI Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c new file mode 100644 index 0000000000000..33e15fa63c82d --- /dev/null +++ b/fs/erofs/sysfs.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C), 2008-2021, OPPO Mobile Comm Corp., Ltd. + * https://www.oppo.com/ + */ +#include +#include + +#include "internal.h" + +enum { + attr_feature, + attr_pointer_ui, + attr_pointer_bool, +}; + +enum { + struct_erofs_sb_info, +}; + +struct erofs_attr { + struct attribute attr; + short attr_id; + int struct_type, offset; +}; + +#define EROFS_ATTR(_name, _mode, _id) \ +static struct erofs_attr erofs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_id, \ +} +#define EROFS_ATTR_FUNC(_name, _mode) EROFS_ATTR(_name, _mode, _name) +#define EROFS_ATTR_FEATURE(_name) EROFS_ATTR(_name, 0444, feature) + +#define EROFS_ATTR_OFFSET(_name, _mode, _id, _struct) \ +static struct erofs_attr erofs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_id, \ + .struct_type = struct_##_struct, \ + .offset = offsetof(struct _struct, _name),\ +} + +#define EROFS_ATTR_RW(_name, _id, _struct) \ + EROFS_ATTR_OFFSET(_name, 0644, _id, _struct) + +#define EROFS_RO_ATTR(_name, _id, _struct) \ + EROFS_ATTR_OFFSET(_name, 0444, _id, _struct) + +#define EROFS_ATTR_RW_UI(_name, _struct) \ + EROFS_ATTR_RW(_name, pointer_ui, _struct) + +#define EROFS_ATTR_RW_BOOL(_name, _struct) \ + EROFS_ATTR_RW(_name, pointer_bool, _struct) + +#define ATTR_LIST(name) (&erofs_attr_##name.attr) + +static struct attribute *erofs_attrs[] = { + NULL, +}; +ATTRIBUTE_GROUPS(erofs); + +/* Features this copy of erofs supports */ +EROFS_ATTR_FEATURE(zero_padding); +EROFS_ATTR_FEATURE(compr_cfgs); +EROFS_ATTR_FEATURE(big_pcluster); +EROFS_ATTR_FEATURE(chunked_file); +EROFS_ATTR_FEATURE(device_table); +EROFS_ATTR_FEATURE(compr_head2); +EROFS_ATTR_FEATURE(sb_chksum); + +static struct attribute *erofs_feat_attrs[] = { + ATTR_LIST(zero_padding), + ATTR_LIST(compr_cfgs), + ATTR_LIST(big_pcluster), + ATTR_LIST(chunked_file), + ATTR_LIST(device_table), + ATTR_LIST(compr_head2), + ATTR_LIST(sb_chksum), + NULL, +}; +ATTRIBUTE_GROUPS(erofs_feat); + +static unsigned char *__struct_ptr(struct erofs_sb_info *sbi, + int struct_type, int offset) +{ + if (struct_type == struct_erofs_sb_info) + return (unsigned char *)sbi + offset; + return NULL; +} + +static ssize_t erofs_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + struct erofs_attr *a = container_of(attr, struct erofs_attr, attr); + unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset); + + switch (a->attr_id) { + case attr_feature: + return sysfs_emit(buf, "supported\n"); + case attr_pointer_ui: + if (!ptr) + return 0; + return sysfs_emit(buf, "%u\n", *(unsigned int *)ptr); + case attr_pointer_bool: + if (!ptr) + return 0; + return sysfs_emit(buf, "%d\n", *(bool *)ptr); + } + return 0; +} + +static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + struct erofs_attr *a = container_of(attr, struct erofs_attr, attr); + unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset); + unsigned long t; + int ret; + + switch (a->attr_id) { + case attr_pointer_ui: + if (!ptr) + return 0; + ret = kstrtoul(skip_spaces(buf), 0, &t); + if (ret) + return ret; + if (t != (unsigned int)t) + return -ERANGE; + *(unsigned int *)ptr = t; + return len; + case attr_pointer_bool: + if (!ptr) + return 0; + ret = kstrtoul(skip_spaces(buf), 0, &t); + if (ret) + return ret; + if (t != 0 && t != 1) + return -EINVAL; + *(bool *)ptr = !!t; + return len; + } + return 0; +} + +static void erofs_sb_release(struct kobject *kobj) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + complete(&sbi->s_kobj_unregister); +} + +static const struct sysfs_ops erofs_attr_ops = { + .show = erofs_attr_show, + .store = erofs_attr_store, +}; + +static struct kobj_type erofs_sb_ktype = { + .default_groups = erofs_groups, + .sysfs_ops = &erofs_attr_ops, + .release = erofs_sb_release, +}; + +static struct kobj_type erofs_ktype = { + .sysfs_ops = &erofs_attr_ops, +}; + +static struct kset erofs_root = { + .kobj = {.ktype = &erofs_ktype}, +}; + +static struct kobj_type erofs_feat_ktype = { + .default_groups = erofs_feat_groups, + .sysfs_ops = &erofs_attr_ops, +}; + +static struct kobject erofs_feat = { + .kset = &erofs_root, +}; + +int erofs_register_sysfs(struct super_block *sb) +{ + struct erofs_sb_info *sbi = EROFS_SB(sb); + int err; + + sbi->s_kobj.kset = &erofs_root; + init_completion(&sbi->s_kobj_unregister); + err = kobject_init_and_add(&sbi->s_kobj, &erofs_sb_ktype, NULL, + "%s", sb->s_id); + if (err) + goto put_sb_kobj; + return 0; + +put_sb_kobj: + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); + return err; +} + +void erofs_unregister_sysfs(struct super_block *sb) +{ + struct erofs_sb_info *sbi = EROFS_SB(sb); + + kobject_del(&sbi->s_kobj); + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); +} + +int __init erofs_init_sysfs(void) +{ + int ret; + + kobject_set_name(&erofs_root.kobj, "erofs"); + erofs_root.kobj.parent = fs_kobj; + ret = kset_register(&erofs_root); + if (ret) + goto root_err; + + ret = kobject_init_and_add(&erofs_feat, &erofs_feat_ktype, + NULL, "features"); + if (ret) + goto feat_err; + return ret; + +feat_err: + kobject_put(&erofs_feat); + kset_unregister(&erofs_root); +root_err: + return ret; +} + +void erofs_exit_sysfs(void) +{ + kobject_put(&erofs_feat); + kset_unregister(&erofs_root); +} diff --git a/fs/exec.c b/fs/exec.c index 43e7883c8606a..5b45f14f67f9f 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -235,7 +235,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, static void put_arg_page(struct page *page) { - put_user_page(page); + put_page(page); } static void free_arg_pages(struct linux_binprm *bprm) @@ -497,14 +497,8 @@ static int bprm_stack_limits(struct linux_binprm *bprm) * the stack. They aren't stored until much later when we can't * signal to the parent that the child has run out of stack space. * Instead, calculate it here so it's possible to fail gracefully. - * - * In the case of argc = 0, make sure there is space for adding a - * empty string (which will bump argc to 1), to ensure confused - * userspace programs don't start processing from argv[1], thinking - * argc can never be 0, to keep them from walking envp by accident. - * See do_execveat_common(). */ - ptr_size = (max(bprm->argc, 1) + bprm->envc) * sizeof(void *); + ptr_size = (bprm->argc + bprm->envc) * sizeof(void *); if (limit <= ptr_size) return -E2BIG; limit -= ptr_size; @@ -1016,6 +1010,7 @@ static int exec_mmap(struct mm_struct *mm) active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; + lru_gen_add_mm(mm); /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for @@ -1028,6 +1023,7 @@ static int exec_mmap(struct mm_struct *mm) activate_mm(active_mm, mm); if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) local_irq_enable(); + lru_gen_use_mm(mm); tsk->mm->vmacache_seqnum = 0; vmacache_flush(tsk); task_unlock(tsk); @@ -1896,9 +1892,6 @@ static int do_execveat_common(int fd, struct filename *filename, } retval = count(argv, MAX_ARG_STRINGS); - if (retval == 0) - pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n", - current->comm, bprm->filename); if (retval < 0) goto out_free; bprm->argc = retval; @@ -1925,19 +1918,6 @@ static int do_execveat_common(int fd, struct filename *filename, if (retval < 0) goto out_free; - /* - * When argv is empty, add an empty string ("") as argv[0] to - * ensure confused userspace programs that start processing - * from argv[1] won't end up walking envp. See also - * bprm_stack_limits(). - */ - if (bprm->argc == 0) { - retval = copy_string_kernel("", bprm); - if (retval < 0) - goto out_free; - bprm->argc = 1; - } - retval = bprm_execve(bprm, fd, filename, flags); out_free: free_bprm(bprm); @@ -1966,8 +1946,6 @@ int kernel_execve(const char *kernel_filename, } retval = count_strings_kernel(argv); - if (WARN_ON_ONCE(retval == 0)) - retval = -EINVAL; if (retval < 0) goto out_free; bprm->argc = retval; diff --git a/fs/exfat/super.c b/fs/exfat/super.c index ba70ed1c98049..d3bf120e31e1d 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -690,7 +690,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) if (!sb->s_root) { exfat_err(sb, "failed to get the root dentry"); err = -ENOMEM; - goto free_table; + goto put_inode; } return 0; @@ -836,5 +836,6 @@ module_exit(exit_exfat_fs); MODULE_ALIAS_FS("exfat"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("exFAT filesystem support"); MODULE_AUTHOR("Samsung Electronics Co., Ltd."); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index b6314d3c6a87d..3b772568cccc7 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -756,12 +756,8 @@ static loff_t ext2_max_size(int bits) res += 1LL << (bits-2); res += 1LL << (2*(bits-2)); res += 1LL << (3*(bits-2)); - /* Compute how many metadata blocks are needed */ - meta_blocks = 1; - meta_blocks += 1 + ppb; - meta_blocks += 1 + ppb + ppb * ppb; /* Does block tree limit file size? */ - if (res + meta_blocks <= upper_limit) + if (res < upper_limit) goto check_lfs; res = upper_limit; @@ -1654,5 +1650,6 @@ static void __exit exit_ext2_fs(void) MODULE_AUTHOR("Remy Card and others"); MODULE_DESCRIPTION("Second Extended Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_ext2_fs) module_exit(exit_ext2_fs) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index ff9d356932a66..afc5f656c3e76 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1787,20 +1787,19 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) void *inline_pos; unsigned int offset; struct ext4_dir_entry_2 *de; - bool ret = false; + bool ret = true; err = ext4_get_inode_loc(dir, &iloc); if (err) { EXT4_ERROR_INODE_ERR(dir, -err, "error %d getting inode %lu block", err, dir->i_ino); - return false; + return true; } down_read(&EXT4_I(dir)->xattr_sem); if (!ext4_has_inline_data(dir)) { *has_inline_data = 0; - ret = true; goto out; } @@ -1809,6 +1808,7 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) ext4_warning(dir->i_sb, "bad inline directory (dir #%lu) - no `..'", dir->i_ino); + ret = true; goto out; } @@ -1827,15 +1827,16 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) dir->i_ino, le32_to_cpu(de->inode), le16_to_cpu(de->rec_len), de->name_len, inline_size); + ret = true; goto out; } if (le32_to_cpu(de->inode)) { + ret = false; goto out; } offset += ext4_rec_len_from_disk(de->rec_len, inline_size); } - ret = true; out: up_read(&EXT4_I(dir)->xattr_sem); brelse(iloc.bh); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a6b3a5553fded..04c51065c1c99 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3542,10 +3542,9 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (ret < 0) return ret; out: - /* * When inline encryption is enabled, sometimes I/O to an encrypted file - * has to be broken up to guarantee DUN contiguity. Handle this by + * has to be broken up to guarantee DUN contiguity. Handle this by * limiting the length of the mapping returned. */ map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 15223b5a3af97..110c25824a67f 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3320,95 +3320,69 @@ void ext4_mb_mark_bb(struct super_block *sb, ext4_fsblk_t block, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_group_t group; ext4_grpblk_t blkoff; - int i, err; + int i, clen, err; int already; - unsigned int clen, clen_changed, thisgrp_len; - while (len > 0) { - ext4_get_group_no_and_offset(sb, block, &group, &blkoff); - - /* - * Check to see if we are freeing blocks across a group - * boundary. - * In case of flex_bg, this can happen that (block, len) may - * span across more than one group. In that case we need to - * get the corresponding group metadata to work with. - * For this we have goto again loop. - */ - thisgrp_len = min_t(unsigned int, (unsigned int)len, - EXT4_BLOCKS_PER_GROUP(sb) - EXT4_C2B(sbi, blkoff)); - clen = EXT4_NUM_B2C(sbi, thisgrp_len); + clen = EXT4_B2C(sbi, len); - bitmap_bh = ext4_read_block_bitmap(sb, group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - break; - } - - err = -EIO; - gdp = ext4_get_group_desc(sb, group, &gdp_bh); - if (!gdp) - break; - - ext4_lock_group(sb, group); - already = 0; - for (i = 0; i < clen; i++) - if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) == - !state) - already++; - - clen_changed = clen - already; - if (state) - ext4_set_bits(bitmap_bh->b_data, blkoff, clen); - else - mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); - if (ext4_has_group_desc_csum(sb) && - (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { - gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - ext4_free_group_clusters_set(sb, gdp, - ext4_free_clusters_after_init(sb, group, gdp)); - } - if (state) - clen = ext4_free_group_clusters(sb, gdp) - clen_changed; - else - clen = ext4_free_group_clusters(sb, gdp) + clen_changed; + ext4_get_group_no_and_offset(sb, block, &group, &blkoff); + bitmap_bh = ext4_read_block_bitmap(sb, group); + if (IS_ERR(bitmap_bh)) { + err = PTR_ERR(bitmap_bh); + bitmap_bh = NULL; + goto out_err; + } - ext4_free_group_clusters_set(sb, gdp, clen); - ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); - ext4_group_desc_csum_set(sb, group, gdp); + err = -EIO; + gdp = ext4_get_group_desc(sb, group, &gdp_bh); + if (!gdp) + goto out_err; - ext4_unlock_group(sb, group); + ext4_lock_group(sb, group); + already = 0; + for (i = 0; i < clen; i++) + if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) == !state) + already++; - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group = ext4_flex_group(sbi, group); - struct flex_groups *fg = sbi_array_rcu_deref(sbi, - s_flex_groups, flex_group); + if (state) + ext4_set_bits(bitmap_bh->b_data, blkoff, clen); + else + mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + ext4_free_group_clusters_set(sb, gdp, + ext4_free_clusters_after_init(sb, + group, gdp)); + } + if (state) + clen = ext4_free_group_clusters(sb, gdp) - clen + already; + else + clen = ext4_free_group_clusters(sb, gdp) + clen - already; - if (state) - atomic64_sub(clen_changed, &fg->free_clusters); - else - atomic64_add(clen_changed, &fg->free_clusters); + ext4_free_group_clusters_set(sb, gdp, clen); + ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); + ext4_group_desc_csum_set(sb, group, gdp); - } + ext4_unlock_group(sb, group); - err = ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); - if (err) - break; - sync_dirty_buffer(bitmap_bh); - err = ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); - sync_dirty_buffer(gdp_bh); - if (err) - break; + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group = ext4_flex_group(sbi, group); - block += thisgrp_len; - len -= thisgrp_len; - brelse(bitmap_bh); - BUG_ON(len < 0); + atomic64_sub(len, + &sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_clusters); } + err = ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); if (err) - brelse(bitmap_bh); + goto out_err; + sync_dirty_buffer(bitmap_bh); + err = ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); + sync_dirty_buffer(gdp_bh); + +out_err: + brelse(bitmap_bh); } /* diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1d508db10a687..bcc72cf65ed9f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2962,14 +2962,14 @@ bool ext4_empty_dir(struct inode *inode) if (inode->i_size < ext4_dir_rec_len(1, NULL) + ext4_dir_rec_len(2, NULL)) { EXT4_ERROR_INODE(inode, "invalid size"); - return false; + return true; } /* The first directory block must not be a hole, * so treat it as DIRENT_HTREE */ bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE); if (IS_ERR(bh)) - return false; + return true; de = (struct ext4_dir_entry_2 *) bh->b_data; if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, @@ -2977,7 +2977,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) { ext4_warning_inode(inode, "directory missing '.'"); brelse(bh); - return false; + return true; } offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); de = ext4_next_entry(de, sb->s_blocksize); @@ -2986,7 +2986,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { ext4_warning_inode(inode, "directory missing '..'"); brelse(bh); - return false; + return true; } offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); while (offset < inode->i_size) { @@ -3000,7 +3000,7 @@ bool ext4_empty_dir(struct inode *inode) continue; } if (IS_ERR(bh)) - return false; + return true; } de = (struct ext4_dir_entry_2 *) (bh->b_data + (offset & (sb->s_blocksize - 1))); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c3cdfec63fdf7..bccf4f403bf8b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -6758,6 +6758,7 @@ static void __exit ext4_exit_fs(void) MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); MODULE_DESCRIPTION("Fourth Extended Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32c"); module_init(ext4_init_fs) module_exit(ext4_exit_fs) diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index f46a7339d6cf7..03ef087537c7c 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -143,3 +143,10 @@ config F2FS_IOSTAT Support getting IO statistics through sysfs and printing out periodic IO statistics tracepoint events. You have to turn on "iostat_enable" sysfs node to enable this feature. + +config F2FS_UNFAIR_RWSEM + bool "F2FS unfair rw_semaphore" + depends on F2FS_FS && BLK_CGROUP + help + Use unfair rw_semaphore, if system configured IO priority by block + cgroup. diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 727eb49491eed..bd2a0f5854aaa 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -98,6 +98,13 @@ repeat: } if (unlikely(!PageUptodate(page))) { + if (page->index == sbi->metapage_eio_ofs && + sbi->metapage_eio_cnt++ == MAX_RETRY_META_PAGE_EIO) { + set_ckpt_flags(sbi, CP_ERROR_FLAG); + } else { + sbi->metapage_eio_ofs = page->index; + sbi->metapage_eio_cnt = 0; + } f2fs_put_page(page, 1); return ERR_PTR(-EIO); } @@ -282,18 +289,22 @@ out: return blkno - start; } -void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) +void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index, + unsigned int ra_blocks) { struct page *page; bool readahead = false; + if (ra_blocks == RECOVERY_MIN_RA_BLOCKS) + return; + page = find_get_page(META_MAPPING(sbi), index); if (!page || !PageUptodate(page)) readahead = true; f2fs_put_page(page, 0); if (readahead) - f2fs_ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); + f2fs_ra_meta_pages(sbi, index, ra_blocks, META_POR, true); } static int __f2fs_write_meta_page(struct page *page, @@ -1545,6 +1556,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* update user_block_counts */ sbi->last_valid_block_count = sbi->total_valid_block_count; percpu_counter_set(&sbi->alloc_valid_block_count, 0); + percpu_counter_set(&sbi->rf_node_block_count, 0); /* Here, we have one bio having CP pack except cp pack 2 page */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index cd5369de261d3..5c49817dbcc97 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2488,6 +2488,9 @@ static inline bool check_inplace_update_policy(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); unsigned int policy = SM_I(sbi)->ipu_policy; + if (policy & (0x1 << F2FS_IPU_HONOR_OPU_WRITE) && + is_inode_flag_set(inode, FI_OPU_WRITE)) + return false; if (policy & (0x1 << F2FS_IPU_FORCE)) return true; if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi)) @@ -2558,6 +2561,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) if (is_inode_flag_set(inode, FI_ALIGNED_WRITE)) return true; + if (is_inode_flag_set(inode, FI_OPU_WRITE)) + return true; + if (fio) { if (page_private_gcing(fio->page)) return true; @@ -3182,8 +3188,8 @@ static int __f2fs_write_data_pages(struct address_space *mapping, f2fs_available_free_memory(sbi, DIRTY_DENTS)) goto skip_write; - /* skip writing during file defragment */ - if (is_inode_flag_set(inode, FI_DO_DEFRAG)) + /* skip writing in file defragment preparing stage */ + if (is_inode_flag_set(inode, FI_SKIP_WRITES)) goto skip_write; trace_f2fs_writepages(mapping->host, wbc, DATA); @@ -3401,7 +3407,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, *fsdata = NULL; - if (len == PAGE_SIZE) + if (len == PAGE_SIZE && !(f2fs_is_atomic_file(inode))) goto repeat; ret = f2fs_prepare_compress_overwrite(inode, pagep, @@ -3774,6 +3780,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_down_write(&F2FS_I(inode)->i_mmap_sem); set_inode_flag(inode, FI_ALIGNED_WRITE); + set_inode_flag(inode, FI_OPU_WRITE); for (; secidx < end_sec; secidx++) { f2fs_down_write(&sbi->pin_sem); @@ -3782,7 +3789,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); f2fs_unlock_op(sbi); - set_inode_flag(inode, FI_DO_DEFRAG); + set_inode_flag(inode, FI_SKIP_WRITES); for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { struct page *page; @@ -3799,7 +3806,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_put_page(page, 1); } - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); ret = filemap_fdatawrite(inode->i_mapping); @@ -3810,7 +3817,8 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, } done: - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); + clear_inode_flag(inode, FI_OPU_WRITE); clear_inode_flag(inode, FI_ALIGNED_WRITE); f2fs_up_write(&F2FS_I(inode)->i_mmap_sem); diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 8c50518475a99..fcdf253cd211e 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -21,7 +21,7 @@ #include "gc.h" static LIST_HEAD(f2fs_stat_list); -static DEFINE_MUTEX(f2fs_stat_mutex); +static DEFINE_RAW_SPINLOCK(f2fs_stat_lock); #ifdef CONFIG_DEBUG_FS static struct dentry *f2fs_debugfs_root; #endif @@ -338,14 +338,16 @@ static char *s_flag[] = { [SBI_QUOTA_SKIP_FLUSH] = " quota_skip_flush", [SBI_QUOTA_NEED_REPAIR] = " quota_need_repair", [SBI_IS_RESIZEFS] = " resizefs", + [SBI_IS_FREEZING] = " freezefs", }; static int stat_show(struct seq_file *s, void *v) { struct f2fs_stat_info *si; int i = 0, j = 0; + unsigned long flags; - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_for_each_entry(si, &f2fs_stat_list, stat_list) { update_general_status(si->sbi); @@ -474,12 +476,14 @@ static int stat_show(struct seq_file *s, void *v) si->node_segs, si->bg_node_segs); seq_printf(s, " - Reclaimed segs : Normal (%d), Idle CB (%d), " "Idle Greedy (%d), Idle AT (%d), " - "Urgent High (%d), Urgent Low (%d)\n", + "Urgent High (%d), Urgent Mid (%d), " + "Urgent Low (%d)\n", si->sbi->gc_reclaimed_segs[GC_NORMAL], si->sbi->gc_reclaimed_segs[GC_IDLE_CB], si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY], si->sbi->gc_reclaimed_segs[GC_IDLE_AT], si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH], + si->sbi->gc_reclaimed_segs[GC_URGENT_MID], si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]); seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks, si->bg_data_blks + si->bg_node_blks); @@ -532,6 +536,9 @@ static int stat_show(struct seq_file *s, void *v) si->ndirty_meta, si->meta_pages); seq_printf(s, " - imeta: %4d\n", si->ndirty_imeta); + seq_printf(s, " - fsync mark: %4lld\n", + percpu_counter_sum_positive( + &si->sbi->rf_node_block_count)); seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", si->dirty_nats, si->nats, si->dirty_sits, si->sits); seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n", @@ -573,7 +580,7 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - paged : %llu KB\n", si->page_mem >> 10); } - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); return 0; } @@ -584,6 +591,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_stat_info *si; + unsigned long flags; int i; si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL); @@ -619,9 +627,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->max_aw_cnt, 0); atomic_set(&sbi->max_vw_cnt, 0); - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_add_tail(&si->stat_list, &f2fs_stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); return 0; } @@ -629,10 +637,11 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si = F2FS_STAT(sbi); + unsigned long flags; - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_del(&si->stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); kfree(si); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c92962e8c0f1e..6b5b3e293ae1f 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -130,7 +130,9 @@ typedef u32 nid_t; struct f2fs_rwsem { struct rw_semaphore internal_rwsem; +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wait_queue_head_t read_waiters; +#endif }; struct f2fs_mount_info { @@ -396,6 +398,10 @@ struct discard_cmd_control { struct mutex cmd_lock; unsigned int nr_discards; /* # of discards in the list */ unsigned int max_discards; /* max. discards to be issued */ + unsigned int max_discard_request; /* max. discard request per round */ + unsigned int min_discard_issue_time; /* min. interval between discard issue */ + unsigned int mid_discard_issue_time; /* mid. interval between discard issue */ + unsigned int max_discard_issue_time; /* max. interval between discard issue */ unsigned int discard_granularity; /* discard granularity */ unsigned int undiscard_blks; /* # of undiscard blocks */ unsigned int next_pos; /* next discard position */ @@ -571,6 +577,9 @@ enum { /* maximum retry quota flush count */ #define DEFAULT_RETRY_QUOTA_FLUSH_COUNT 8 +/* maximum retry of EIO'ed meta page */ +#define MAX_RETRY_META_PAGE_EIO 100 + #define F2FS_LINK_MAX 0xffffffff /* maximum link count per file */ #define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ @@ -584,6 +593,9 @@ enum { /* number of extent info in extent cache we try to shrink */ #define EXTENT_CACHE_SHRINK_NUMBER 128 +#define RECOVERY_MAX_RA_BLOCKS BIO_MAX_PAGES +#define RECOVERY_MIN_RA_BLOCKS 1 + struct rb_entry { struct rb_node rb_node; /* rb node located in rb-tree */ union { @@ -731,7 +743,8 @@ enum { FI_DROP_CACHE, /* drop dirty page cache */ FI_DATA_EXIST, /* indicate data exists */ FI_INLINE_DOTS, /* indicate inline dot dentries */ - FI_DO_DEFRAG, /* indicate defragment is running */ + FI_SKIP_WRITES, /* should skip data page writeback */ + FI_OPU_WRITE, /* used for opu per file */ FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ FI_PREALLOCATED_ALL, /* all blocks for write were preallocated */ FI_HOT_DATA, /* indicate file is hot */ @@ -908,6 +921,7 @@ struct f2fs_nm_info { nid_t max_nid; /* maximum possible node ids */ nid_t available_nids; /* # of available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ + nid_t max_rf_node_blocks; /* max # of nodes for recovery */ unsigned int ram_thresh; /* control the memory footprint */ unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */ unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */ @@ -1278,6 +1292,7 @@ enum { SBI_QUOTA_SKIP_FLUSH, /* skip flushing quota in current CP */ SBI_QUOTA_NEED_REPAIR, /* quota file may be corrupted */ SBI_IS_RESIZEFS, /* resizefs is in process */ + SBI_IS_FREEZING, /* freezefs is in process */ }; enum { @@ -1297,6 +1312,7 @@ enum { GC_IDLE_AT, GC_URGENT_HIGH, GC_URGENT_LOW, + GC_URGENT_MID, MAX_GC_MODE, }; @@ -1604,6 +1620,8 @@ struct f2fs_sb_info { /* keep migration IO order for LFS mode */ struct f2fs_rwsem io_order_lock; mempool_t *write_io_dummy; /* Dummy pages */ + pgoff_t metapage_eio_ofs; /* EIO page offset */ + int metapage_eio_cnt; /* EIO count */ /* for checkpoint */ struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ @@ -1679,6 +1697,8 @@ struct f2fs_sb_info { atomic_t nr_pages[NR_COUNT_TYPE]; /* # of allocated blocks */ struct percpu_counter alloc_valid_block_count; + /* # of node block writes as roll forward recovery */ + struct percpu_counter rf_node_block_count; /* writeback control */ atomic_t wb_sync_req[META]; /* count # of WB_SYNC threads */ @@ -2103,10 +2123,20 @@ static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f) spin_unlock_irqrestore(&sbi->cp_lock, flags); } -static inline void init_f2fs_rwsem(struct f2fs_rwsem *sem) +#define init_f2fs_rwsem(sem) \ +do { \ + static struct lock_class_key __key; \ + \ + __init_f2fs_rwsem((sem), #sem, &__key); \ +} while (0) + +static inline void __init_f2fs_rwsem(struct f2fs_rwsem *sem, + const char *sem_name, struct lock_class_key *key) { - init_rwsem(&sem->internal_rwsem); + __init_rwsem(&sem->internal_rwsem, sem_name, key); +#ifdef CONFIG_F2FS_UNFAIR_RWSEM init_waitqueue_head(&sem->read_waiters); +#endif } static inline int f2fs_rwsem_is_locked(struct f2fs_rwsem *sem) @@ -2121,7 +2151,11 @@ static inline int f2fs_rwsem_is_contended(struct f2fs_rwsem *sem) static inline void f2fs_down_read(struct f2fs_rwsem *sem) { +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wait_event(sem->read_waiters, down_read_trylock(&sem->internal_rwsem)); +#else + down_read(&sem->internal_rwsem); +#endif } static inline int f2fs_down_read_trylock(struct f2fs_rwsem *sem) @@ -2156,7 +2190,9 @@ static inline int f2fs_down_write_trylock(struct f2fs_rwsem *sem) static inline void f2fs_up_write(struct f2fs_rwsem *sem) { up_write(&sem->internal_rwsem); +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wake_up_all(&sem->read_waiters); +#endif } static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) @@ -2748,6 +2784,9 @@ static inline bool is_idle(struct f2fs_sb_info *sbi, int type) if (is_inflight_io(sbi, type)) return false; + if (sbi->gc_mode == GC_URGENT_MID) + return true; + if (sbi->gc_mode == GC_URGENT_LOW && (type == DISCARD_TIME || type == GC_TIME)) return true; @@ -3642,7 +3681,8 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type); int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type, bool sync); -void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index); +void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index, + unsigned int ra_blocks); long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write, enum iostat_type io_type); void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 144e1d9d2b201..387b653e1ad21 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -818,7 +818,7 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, { struct inode *inode = d_inode(path->dentry); struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_inode *ri; + struct f2fs_inode *ri = NULL; unsigned int flags; if (f2fs_has_extra_attr(inode) && @@ -2621,10 +2621,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, bool fragmented = false; int err; - /* if in-place-update policy is enabled, don't waste time here */ - if (f2fs_should_update_inplace(inode, NULL)) - return -EINVAL; - pg_start = range->start >> PAGE_SHIFT; pg_end = (range->start + range->len) >> PAGE_SHIFT; @@ -2632,6 +2628,13 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, inode_lock(inode); + /* if in-place-update policy is enabled, don't waste time here */ + set_inode_flag(inode, FI_OPU_WRITE); + if (f2fs_should_update_inplace(inode, NULL)) { + err = -EINVAL; + goto out; + } + /* writeback all dirty pages in the range */ err = filemap_write_and_wait_range(inode->i_mapping, range->start, range->start + range->len - 1); @@ -2713,7 +2716,7 @@ do_map: goto check; } - set_inode_flag(inode, FI_DO_DEFRAG); + set_inode_flag(inode, FI_SKIP_WRITES); idx = map.m_lblk; while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { @@ -2738,15 +2741,16 @@ check: if (map.m_lblk < pg_end && cnt < blk_per_seg) goto do_map; - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); err = filemap_fdatawrite(inode->i_mapping); if (err) goto out; } clear_out: - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); out: + clear_inode_flag(inode, FI_OPU_WRITE); inode_unlock(inode); if (!err) range->len = (u64)total << PAGE_SHIFT; @@ -3053,7 +3057,7 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) struct inode *inode = file_inode(filp); struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct page *ipage; + struct f2fs_inode *ri = NULL; kprojid_t kprojid; int err; @@ -3077,17 +3081,8 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) if (IS_NOQUOTA(inode)) return err; - ipage = f2fs_get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) - return PTR_ERR(ipage); - - if (!F2FS_FITS_IN_INODE(F2FS_INODE(ipage), fi->i_extra_isize, - i_projid)) { - err = -EOVERFLOW; - f2fs_put_page(ipage, 1); - return err; - } - f2fs_put_page(ipage, 1); + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid)) + return -EOVERFLOW; err = f2fs_dquot_initialize(inode); if (err) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 8ab4b40c12c57..79dc38eacb193 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -103,7 +103,10 @@ static int gc_thread_func(void *data) sbi->gc_urgent_high_remaining--; } spin_unlock(&sbi->gc_urgent_high_lock); + } + if (sbi->gc_mode == GC_URGENT_HIGH || + sbi->gc_mode == GC_URGENT_MID) { wait_ms = gc_th->urgent_sleep_time; f2fs_down_write(&sbi->gc_lock); goto do_gc; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 8507e92b95d9c..5fffc22689645 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -550,7 +550,8 @@ make_now: } f2fs_set_inode_flags(inode); - if (file_should_truncate(inode)) { + if (file_should_truncate(inode) && + !is_sbi_flag_set(sbi, SBI_POR_DOING)) { ret = f2fs_truncate(inode); if (ret) goto bad_inode; @@ -778,7 +779,8 @@ void f2fs_evict_inode(struct inode *inode) f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO); - sb_start_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_start_intwrite(inode->i_sb); set_inode_flag(inode, FI_NO_ALLOC); i_size_write(inode, 0); retry: @@ -809,7 +811,8 @@ retry: if (dquot_initialize_needed(inode)) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); } - sb_end_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_end_intwrite(inode->i_sb); no_delete: dquot_drop(inode); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index f978c0f91558d..0de98abd72829 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1106,8 +1106,7 @@ out_dir: out_old: f2fs_put_page(old_page, 0); out: - if (whiteout) - iput(whiteout); + iput(whiteout); return err; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 56d310c1f15ec..ba0766a56dfaa 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1782,6 +1782,7 @@ continue_unlock: if (!atomic || page == last_page) { set_fsync_mark(page, 1); + percpu_counter_inc(&sbi->rf_node_block_count); if (IS_INODE(page)) { if (is_inode_flag_set(inode, FI_DIRTY_INODE)) @@ -3222,6 +3223,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi) nm_i->ram_thresh = DEF_RAM_THRESHOLD; nm_i->ra_nid_pages = DEF_RA_NID_PAGES; nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD; + nm_i->max_rf_node_blocks = DEF_RF_NODE_BLOCKS; INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC); INIT_LIST_HEAD(&nm_i->free_nid_list); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 18b98cf0465b8..4c1d34bfea781 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -31,6 +31,9 @@ /* control total # of nats */ #define DEF_NAT_CACHE_THRESHOLD 100000 +/* control total # of node writes used for roll-fowrad recovery */ +#define DEF_RF_NODE_BLOCKS 0 + /* vector size for gang look-up from nat cache that consists of radix tree */ #define NATVEC_SIZE 64 #define SETVEC_SIZE 32 diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index be784f983b4a9..329ae992ee0eb 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -55,6 +55,10 @@ bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi) if (sbi->last_valid_block_count + nalloc > sbi->user_block_count) return false; + if (NM_I(sbi)->max_rf_node_blocks && + percpu_counter_sum_positive(&sbi->rf_node_block_count) >= + NM_I(sbi)->max_rf_node_blocks) + return false; return true; } @@ -342,6 +346,19 @@ static int recover_inode(struct inode *inode, struct page *page) return 0; } +static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi, + unsigned int ra_blocks, unsigned int blkaddr, + unsigned int next_blkaddr) +{ + if (blkaddr + 1 == next_blkaddr) + ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS, + ra_blocks * 2); + else if (next_blkaddr % sbi->blocks_per_seg) + ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS, + ra_blocks / 2); + return ra_blocks; +} + static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, bool check_only) { @@ -349,6 +366,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, struct page *page = NULL; block_t blkaddr; unsigned int loop_cnt = 0; + unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS; unsigned int free_blocks = MAIN_SEGS(sbi) * sbi->blocks_per_seg - valid_user_blocks(sbi); int err = 0; @@ -423,11 +441,14 @@ next: break; } + ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr, + next_blkaddr_of_node(page)); + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); - f2fs_ra_meta_pages_cond(sbi, blkaddr); + f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks); } return err; } @@ -704,6 +725,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, struct page *page = NULL; int err = 0; block_t blkaddr; + unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS; /* get node pages in the current segment */ curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); @@ -715,8 +737,6 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) break; - f2fs_ra_meta_pages_cond(sbi, blkaddr); - page = f2fs_get_tmp_page(sbi, blkaddr); if (IS_ERR(page)) { err = PTR_ERR(page); @@ -759,9 +779,14 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, if (entry->blkaddr == blkaddr) list_move_tail(&entry->list, tmp_inode_list); next: + ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr, + next_blkaddr_of_node(page)); + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); + + f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks); } if (!err) f2fs_allocate_new_segments(sbi); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c11d39965cae6..e5e4956ead314 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1159,14 +1159,14 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->ordered = false; dpolicy->granularity = granularity; - dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; + dpolicy->max_requests = dcc->max_discard_request; dpolicy->io_aware_gran = MAX_PLIST_NUM; dpolicy->timeout = false; if (discard_type == DPOLICY_BG) { - dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; - dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; - dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; + dpolicy->min_interval = dcc->min_discard_issue_time; + dpolicy->mid_interval = dcc->mid_discard_issue_time; + dpolicy->max_interval = dcc->max_discard_issue_time; dpolicy->io_aware = true; dpolicy->sync = false; dpolicy->ordered = true; @@ -1174,12 +1174,12 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->granularity = 1; if (atomic_read(&dcc->discard_cmd_cnt)) dpolicy->max_interval = - DEF_MIN_DISCARD_ISSUE_TIME; + dcc->min_discard_issue_time; } } else if (discard_type == DPOLICY_FORCE) { - dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; - dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; - dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; + dpolicy->min_interval = dcc->min_discard_issue_time; + dpolicy->mid_interval = dcc->mid_discard_issue_time; + dpolicy->max_interval = dcc->max_discard_issue_time; dpolicy->io_aware = false; } else if (discard_type == DPOLICY_FSTRIM) { dpolicy->io_aware = false; @@ -1784,7 +1784,7 @@ static int issue_discard_thread(void *data) struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; wait_queue_head_t *q = &dcc->discard_wait_queue; struct discard_policy dpolicy; - unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; + unsigned int wait_ms = dcc->min_discard_issue_time; int issued; set_freezable(); @@ -2183,6 +2183,10 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) atomic_set(&dcc->discard_cmd_cnt, 0); dcc->nr_discards = 0; dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; + dcc->max_discard_request = DEF_MAX_DISCARD_REQUEST; + dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME; + dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME; + dcc->max_discard_issue_time = DEF_MAX_DISCARD_ISSUE_TIME; dcc->undiscard_blks = 0; dcc->next_pos = 0; dcc->root = RB_ROOT_CACHED; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 3c01315931f61..aeb008f2377be 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -651,7 +651,9 @@ static inline int utilization(struct f2fs_sb_info *sbi) * pages over min_fsync_blocks. (=default option) * F2FS_IPU_ASYNC - do IPU given by asynchronous write requests. * F2FS_IPU_NOCACHE - disable IPU bio cache. - * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) + * F2FS_IPU_HONOR_OPU_WRITE - use OPU write prior to IPU write if inode has + * FI_OPU_WRITE flag. + * F2FS_IPU_DISABLE - disable IPU. (=default option in LFS mode) */ #define DEF_MIN_IPU_UTIL 70 #define DEF_MIN_FSYNC_BLOCKS 8 @@ -667,6 +669,7 @@ enum { F2FS_IPU_FSYNC, F2FS_IPU_ASYNC, F2FS_IPU_NOCACHE, + F2FS_IPU_HONOR_OPU_WRITE, }; static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ff6daa5838734..3d13fe053b308 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1512,8 +1512,9 @@ static void f2fs_free_inode(struct inode *inode) static void destroy_percpu_info(struct f2fs_sb_info *sbi) { - percpu_counter_destroy(&sbi->alloc_valid_block_count); percpu_counter_destroy(&sbi->total_valid_inode_count); + percpu_counter_destroy(&sbi->rf_node_block_count); + percpu_counter_destroy(&sbi->alloc_valid_block_count); } static void destroy_device_list(struct f2fs_sb_info *sbi) @@ -1673,11 +1674,15 @@ static int f2fs_freeze(struct super_block *sb) /* ensure no checkpoint required */ if (!llist_empty(&F2FS_SB(sb)->cprc_info.issue_list)) return -EINVAL; + + /* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */ + set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } static int f2fs_unfreeze(struct super_block *sb) { + clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } @@ -2086,6 +2091,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) { unsigned int s_flags = sbi->sb->s_flags; struct cp_control cpc; + unsigned int gc_mode; int err = 0; int ret; block_t unusable; @@ -2098,6 +2104,9 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) f2fs_update_time(sbi, DISABLE_TIME); + gc_mode = sbi->gc_mode; + sbi->gc_mode = GC_URGENT_HIGH; + while (!f2fs_time_over(sbi, DISABLE_TIME)) { f2fs_down_write(&sbi->gc_lock); err = f2fs_gc(sbi, true, false, false, NULL_SEGNO); @@ -2135,6 +2144,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) out_unlock: f2fs_up_write(&sbi->gc_lock); restore_flag: + sbi->gc_mode = gc_mode; sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */ return err; } @@ -3586,6 +3596,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino); F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino); sbi->cur_victim_sec = NULL_SECNO; + sbi->gc_mode = GC_NORMAL; sbi->next_victim_seg[BG_GC] = NULL_SEGNO; sbi->next_victim_seg[FG_GC] = NULL_SEGNO; sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; @@ -3631,11 +3642,20 @@ static int init_percpu_info(struct f2fs_sb_info *sbi) if (err) return err; + err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL); + if (err) + goto err_valid_block; + err = percpu_counter_init(&sbi->total_valid_inode_count, 0, GFP_KERNEL); if (err) - percpu_counter_destroy(&sbi->alloc_valid_block_count); + goto err_node_block; + return 0; +err_node_block: + percpu_counter_destroy(&sbi->rf_node_block_count); +err_valid_block: + percpu_counter_destroy(&sbi->alloc_valid_block_count); return err; } @@ -3962,7 +3982,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; if (f2fs_block_unit_discard(sbi)) sm_i->dcc_info->discard_granularity = 1; - sm_i->ipu_policy = 1 << F2FS_IPU_FORCE; + sm_i->ipu_policy = 1 << F2FS_IPU_FORCE | + 1 << F2FS_IPU_HONOR_OPU_WRITE; } sbi->readdir_ra = 1; @@ -4685,5 +4706,6 @@ module_exit(exit_f2fs_fs) MODULE_AUTHOR("Samsung Electronics's Praesto Team"); MODULE_DESCRIPTION("Flash Friendly File System"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32"); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 5a381d0fe4a47..f240f55933940 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -41,6 +41,16 @@ enum { ATGC_INFO, /* struct atgc_management */ }; +static const char *gc_mode_names[MAX_GC_MODE] = { + "GC_NORMAL", + "GC_IDLE_CB", + "GC_IDLE_GREEDY", + "GC_IDLE_AT", + "GC_URGENT_HIGH", + "GC_URGENT_LOW", + "GC_URGENT_MID" +}; + struct f2fs_attr { struct attribute attr; ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); @@ -317,8 +327,13 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, return sysfs_emit(buf, "%u\n", sbi->compr_new_inode); #endif + if (!strcmp(a->attr.name, "gc_urgent")) + return sysfs_emit(buf, "%s\n", + gc_mode_names[sbi->gc_mode]); + if (!strcmp(a->attr.name, "gc_segment_mode")) - return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode); + return sysfs_emit(buf, "%s\n", + gc_mode_names[sbi->gc_segment_mode]); if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { return sysfs_emit(buf, "%u\n", @@ -469,6 +484,13 @@ out: } } else if (t == 2) { sbi->gc_mode = GC_URGENT_LOW; + } else if (t == 3) { + sbi->gc_mode = GC_URGENT_MID; + if (sbi->gc_thread) { + sbi->gc_thread->gc_wake = 1; + wake_up_interruptible_all( + &sbi->gc_thread->gc_wait_queue_head); + } } else { return -EINVAL; } @@ -717,6 +739,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_request, max_discard_request); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_issue_time); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, mid_discard_issue_time, mid_discard_issue_time); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_issue_time, max_discard_issue_time); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); @@ -729,6 +755,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); +F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, max_roll_forward_node_blocks, max_rf_node_blocks); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, migration_granularity, migration_granularity); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); @@ -833,6 +860,10 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(reclaim_segments), ATTR_LIST(main_blkaddr), ATTR_LIST(max_small_discards), + ATTR_LIST(max_discard_request), + ATTR_LIST(min_discard_issue_time), + ATTR_LIST(mid_discard_issue_time), + ATTR_LIST(max_discard_issue_time), ATTR_LIST(discard_granularity), ATTR_LIST(pending_discard), ATTR_LIST(batched_trim_sections), @@ -848,6 +879,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(ram_thresh), ATTR_LIST(ra_nid_pages), ATTR_LIST(dirty_nats_ratio), + ATTR_LIST(max_roll_forward_node_blocks), ATTR_LIST(cp_interval), ATTR_LIST(idle_interval), ATTR_LIST(discard_idle_interval), diff --git a/fs/fat/inode.c b/fs/fat/inode.c index bab9b202b4966..577c73a55c68d 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1979,3 +1979,4 @@ module_init(init_fat_fs) module_exit(exit_fat_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 9d062886fbc19..8376577ba0149 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -680,6 +680,7 @@ static void __exit exit_msdos_fs(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("Werner Almesberger"); MODULE_DESCRIPTION("MS-DOS filesystem support"); diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 0cdd0fb9f742a..01fab05dc7a16 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1077,6 +1077,7 @@ static void __exit exit_vfat_fs(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("VFAT filesystem support"); MODULE_AUTHOR("Gordon Chaffee"); diff --git a/fs/file.c b/fs/file.c index 1f23ec78e722f..dcb7918b13742 100644 --- a/fs/file.c +++ b/fs/file.c @@ -85,21 +85,6 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds); } -/* - * Note how the fdtable bitmap allocations very much have to be a multiple of - * BITS_PER_LONG. This is not only because we walk those things in chunks of - * 'unsigned long' in some places, but simply because that is how the Linux - * kernel bitmaps are defined to work: they are not "bits in an array of bytes", - * they are very much "bits in an array of unsigned long". - * - * The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multiplied - * by that "1024/sizeof(ptr)" before, we already know there are sufficient - * clear low bits. Clang seems to realize that, gcc ends up being confused. - * - * On a 128-bit machine, the ALIGN() would actually matter. In the meantime, - * let's consider it documentation (and maybe a test-case for gcc to improve - * its code generation ;) - */ static struct fdtable * alloc_fdtable(unsigned int nr) { struct fdtable *fdt; @@ -115,7 +100,6 @@ static struct fdtable * alloc_fdtable(unsigned int nr) nr /= (1024 / sizeof(struct file *)); nr = roundup_pow_of_two(nr + 1); nr *= (1024 / sizeof(struct file *)); - nr = ALIGN(nr, BITS_PER_LONG); /* * Note that this can drive nr *below* what we had passed if sysctl_nr_open * had been set lower between the check in expand_files() and here. Deal @@ -283,19 +267,6 @@ static unsigned int count_open_files(struct fdtable *fdt) return i; } -/* - * Note that a sane fdtable size always has to be a multiple of - * BITS_PER_LONG, since we have bitmaps that are sized by this. - * - * 'max_fds' will normally already be properly aligned, but it - * turns out that in the close_range() -> __close_range() -> - * unshare_fd() -> dup_fd() -> sane_fdtable_size() we can end - * up having a 'max_fds' value that isn't already aligned. - * - * Rather than make close_range() have to worry about this, - * just make that BITS_PER_LONG alignment be part of a sane - * fdtable size. Becuase that's really what it is. - */ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int max_fds) { unsigned int count; @@ -303,7 +274,7 @@ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int max_fds) count = count_open_files(fdt); if (max_fds < NR_OPEN_DEFAULT) max_fds = NR_OPEN_DEFAULT; - return ALIGN(min(count, max_fds), BITS_PER_LONG); + return min(count, max_fds); } /* @@ -699,7 +670,7 @@ int __close_fd(struct files_struct *files, unsigned fd) return filp_close(file, files); } -EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ +EXPORT_SYMBOL_NS(__close_fd, ANDROID_GKI_VFS_EXPORT_ONLY); /* for ksys_close() */ /** * last_fd - return last valid index into fd table diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 578a5062706ee..88fe3f4704097 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -52,6 +52,7 @@ MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski"); MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver"); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *vxfs_inode_cachep; diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index a0869194ab739..d51354221fe77 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2338,7 +2338,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) out_unlock_inode: spin_unlock(&inode->i_lock); } -EXPORT_SYMBOL(__mark_inode_dirty); +EXPORT_SYMBOL_NS(__mark_inode_dirty, ANDROID_GKI_VFS_EXPORT_ONLY); /* * The @s_sync_lock is used to serialise concurrent sync operations @@ -2504,7 +2504,7 @@ void try_to_writeback_inodes_sb(struct super_block *sb, enum wb_reason reason) __writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason, true); up_read(&sb->s_umount); } -EXPORT_SYMBOL(try_to_writeback_inodes_sb); +EXPORT_SYMBOL_NS(try_to_writeback_inodes_sb, ANDROID_GKI_VFS_EXPORT_ONLY); /** * sync_inodes_sb - sync sb inode pages @@ -2571,7 +2571,7 @@ int write_inode_now(struct inode *inode, int sync) might_sleep(); return writeback_single_inode(inode, &wbc); } -EXPORT_SYMBOL(write_inode_now); +EXPORT_SYMBOL_NS(write_inode_now, ANDROID_GKI_VFS_EXPORT_ONLY); /** * sync_inode - write an inode and its pages to disk. @@ -2608,4 +2608,4 @@ int sync_inode_metadata(struct inode *inode, int wait) return sync_inode(inode, &wbc); } -EXPORT_SYMBOL(sync_inode_metadata); +EXPORT_SYMBOL_NS(sync_inode_metadata, ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/fs_types.c b/fs/fs_types.c index 78365e5dc08ca..a11a1d8c7811f 100644 --- a/fs/fs_types.c +++ b/fs/fs_types.c @@ -41,7 +41,7 @@ unsigned char fs_ftype_to_dtype(unsigned int filetype) return fs_dtype_by_ftype[filetype]; } -EXPORT_SYMBOL_GPL(fs_ftype_to_dtype); +EXPORT_SYMBOL_NS_GPL(fs_ftype_to_dtype, ANDROID_GKI_VFS_EXPORT_ONLY); /* * dirent file type to fs on-disk file type conversion diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile index 79e08e05ef848..9121382cf16da 100644 --- a/fs/fscache/Makefile +++ b/fs/fscache/Makefile @@ -3,6 +3,8 @@ # Makefile for general filesystem caching code # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + fscache-y := \ cache.o \ cookie.o \ diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 118bd9d12945f..b68f4f5349743 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -17,9 +17,12 @@ struct fuse_bpf_aio_req { struct kiocb iocb; - struct kiocb *iocb_fuse; + refcount_t ref; + struct kiocb *iocb_orig; }; +static struct kmem_cache *fuse_bpf_aio_request_cachep; + static void fuse_file_accessed(struct file *dst_file, struct file *src_file) { struct inode *dst_inode; @@ -94,7 +97,7 @@ out: return bpf_prog; } -int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, +int fuse_open_initialize(struct fuse_bpf_args *fa, struct fuse_open_io *foio, struct inode *inode, struct file *file, bool isdir) { foio->foi = (struct fuse_open_in) { @@ -103,16 +106,16 @@ int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, foio->foo = (struct fuse_open_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN, .in_numargs = 1, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(foio->foi), .value = &foio->foi, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(foio->foo), .value = &foio->foo, }, @@ -121,7 +124,7 @@ int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, return 0; } -int fuse_open_backing(struct fuse_args *fa, +int fuse_open_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir) { struct fuse_mount *fm = get_fuse_mount(inode); @@ -172,7 +175,7 @@ int fuse_open_backing(struct fuse_args *fa, return 0; } -void *fuse_open_finalize(struct fuse_args *fa, +void *fuse_open_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir) { struct fuse_file *ff = file->private_data; @@ -184,7 +187,7 @@ void *fuse_open_finalize(struct fuse_args *fa, } int fuse_create_open_initialize( - struct fuse_args *fa, struct fuse_create_open_io *fcoio, + struct fuse_bpf_args *fa, struct fuse_create_open_io *fcoio, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -196,24 +199,24 @@ int fuse_create_open_initialize( fcoio->feo = (struct fuse_entry_out) {0}; fcoio->foo = (struct fuse_open_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_CREATE, .in_numargs = 2, .out_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fcoio->fci), .value = &fcoio->fci, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fcoio->feo), .value = &fcoio->feo, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = sizeof(fcoio->foo), .value = &fcoio->foo, }, @@ -248,7 +251,7 @@ static int fuse_open_file_backing(struct inode *inode, struct file *file) } int fuse_create_open_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -318,7 +321,7 @@ out: } void *fuse_create_open_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -334,7 +337,7 @@ void *fuse_create_open_finalize( return 0; } -int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, +int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file) { struct fuse_file *fuse_file = file->private_data; @@ -346,7 +349,7 @@ int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, .fh = ((struct fuse_file *)(file->private_data))->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = FUSE_RELEASE, .in_numargs = 1, @@ -357,7 +360,7 @@ int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, return 0; } -int fuse_releasedir_initialize(struct fuse_args *fa, +int fuse_releasedir_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file) { @@ -370,7 +373,7 @@ int fuse_releasedir_initialize(struct fuse_args *fa, .fh = ((struct fuse_file *)(file->private_data))->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = FUSE_RELEASEDIR, .in_numargs = 1, @@ -381,20 +384,20 @@ int fuse_releasedir_initialize(struct fuse_args *fa, return 0; } -int fuse_release_backing(struct fuse_args *fa, +int fuse_release_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file) { return 0; } -void *fuse_release_finalize(struct fuse_args *fa, +void *fuse_release_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file) { fuse_file_free(file->private_data); return NULL; } -int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, +int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi, struct file *file, fl_owner_t id) { struct fuse_file *fuse_file = file->private_data; @@ -403,19 +406,19 @@ int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, .fh = fuse_file->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file->f_inode), .opcode = FUSE_FLUSH, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id) +int fuse_flush_backing(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id) { struct fuse_file *fuse_file = file->private_data; struct file *backing_file = fuse_file->backing_file; @@ -425,12 +428,12 @@ int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id) return 0; } -void *fuse_flush_finalize(struct fuse_args *fa, struct file *file, fl_owner_t id) +void *fuse_flush_finalize(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id) { return NULL; } -int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, +int fuse_lseek_initialize(struct fuse_bpf_args *fa, struct fuse_lseek_io *flio, struct file *file, loff_t offset, int whence) { struct fuse_file *fuse_file = file->private_data; @@ -441,7 +444,7 @@ int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, .whence = whence, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file->f_inode), .opcode = FUSE_LSEEK, .in_numargs = 1, @@ -455,7 +458,7 @@ int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, return 0; } -int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence) +int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence) { const struct fuse_lseek_in *fli = fa->in_args[0].value; struct fuse_lseek_out *flo = fa->out_args[0].value; @@ -465,11 +468,15 @@ int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, i /* TODO: Handle changing of the file handle */ if (offset == 0) { - if (whence == SEEK_CUR) - return file->f_pos; + if (whence == SEEK_CUR) { + flo->offset = file->f_pos; + return flo->offset; + } - if (whence == SEEK_SET) - return vfs_setpos(file, 0, 0); + if (whence == SEEK_SET) { + flo->offset = vfs_setpos(file, 0, 0); + return flo->offset; + } } inode_lock(file->f_inode); @@ -480,7 +487,7 @@ int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, i return ret; } -void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence) +void *fuse_lseek_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence) { struct fuse_lseek_out *flo = fa->out_args[0].value; @@ -489,7 +496,7 @@ void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset return ERR_PTR(flo->offset); } -int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_range_io *fcf, +int fuse_copy_file_range_initialize(struct fuse_bpf_args *fa, struct fuse_copy_file_range_io *fcf, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { @@ -507,7 +514,7 @@ int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_ .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file_in->f_inode), .opcode = FUSE_COPY_FILE_RANGE, .in_numargs = 1, @@ -521,7 +528,7 @@ int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_ return 0; } -int fuse_copy_file_range_backing(struct fuse_args *fa, struct file *file_in, loff_t pos_in, +int fuse_copy_file_range_backing(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { @@ -540,14 +547,14 @@ int fuse_copy_file_range_backing(struct fuse_args *fa, struct file *file_in, lof flags); } -void *fuse_copy_file_range_finalize(struct fuse_args *fa, struct file *file_in, loff_t pos_in, +void *fuse_copy_file_range_finalize(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { return NULL; } -int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -557,19 +564,19 @@ int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(file->f_inode)->nodeid, .opcode = FUSE_FSYNC, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_fsync_backing(struct fuse_args *fa, +int fuse_fsync_backing(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -580,13 +587,13 @@ int fuse_fsync_backing(struct fuse_args *fa, return vfs_fsync(backing_file, new_datasync); } -void *fuse_fsync_finalize(struct fuse_args *fa, +void *fuse_fsync_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync) { return NULL; } -int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_dir_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -596,19 +603,19 @@ int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(file->f_inode)->nodeid, .opcode = FUSE_FSYNCDIR, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_getxattr_initialize(struct fuse_args *fa, +int fuse_getxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, const char *name, void *value, size_t size) @@ -617,35 +624,34 @@ int fuse_getxattr_initialize(struct fuse_args *fa, .fgi.size = size, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_GETXATTR, .in_numargs = 2, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, - .out_argvar = size ? true : false, + .flags = size ? FUSE_BPF_OUT_ARGVAR : 0, .out_args[0].size = size ? size : sizeof(fgio->fgo), .out_args[0].value = size ? value : &fgio->fgo, }; - return 0; } -int fuse_getxattr_backing(struct fuse_args *fa, +int fuse_getxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size) { ssize_t ret = vfs_getxattr(get_fuse_dentry(dentry)->backing_path.dentry, fa->in_args[1].value, value, size); - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) fa->out_args[0].size = ret; else ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret; @@ -653,13 +659,13 @@ int fuse_getxattr_backing(struct fuse_args *fa, return 0; } -void *fuse_getxattr_finalize(struct fuse_args *fa, +void *fuse_getxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size) { struct fuse_getxattr_out *fgo; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) return ERR_PTR(fa->out_args[0].size); fgo = fa->out_args[0].value; @@ -668,7 +674,7 @@ void *fuse_getxattr_finalize(struct fuse_args *fa, } -int fuse_listxattr_initialize(struct fuse_args *fa, +int fuse_listxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, char *list, size_t size) { @@ -676,17 +682,17 @@ int fuse_listxattr_initialize(struct fuse_args *fa, .fgi.size = size, }; - *fa = (struct fuse_args){ + *fa = (struct fuse_bpf_args){ .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_LISTXATTR, .in_numargs = 1, .out_numargs = 1, .in_args[0] = - (struct fuse_in_arg){ + (struct fuse_bpf_in_arg){ .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .out_argvar = size ? true : false, + .flags = size ? FUSE_BPF_OUT_ARGVAR : 0, .out_args[0].size = size ? size : sizeof(fgio->fgo), .out_args[0].value = size ? (void *)list : &fgio->fgo, }; @@ -694,7 +700,7 @@ int fuse_listxattr_initialize(struct fuse_args *fa, return 0; } -int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_listxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size) { ssize_t ret = @@ -704,7 +710,7 @@ int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, if (ret < 0) return ret; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) fa->out_args[0].size = ret; else ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret; @@ -712,7 +718,7 @@ int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, return ret; } -void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_listxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size) { struct fuse_getxattr_out *fgo; @@ -720,14 +726,14 @@ void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, if (fa->error_in) return NULL; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) return ERR_PTR(fa->out_args[0].size); fgo = fa->out_args[0].value; return ERR_PTR(fgo->size); } -int fuse_setxattr_initialize(struct fuse_args *fa, +int fuse_setxattr_initialize(struct fuse_bpf_args *fa, struct fuse_setxattr_in *fsxi, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) @@ -737,19 +743,19 @@ int fuse_setxattr_initialize(struct fuse_args *fa, .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_SETXATTR, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fsxi), .value = fsxi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = size, .value = value, }, @@ -758,7 +764,7 @@ int fuse_setxattr_initialize(struct fuse_args *fa, return 0; } -int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_setxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { @@ -766,22 +772,22 @@ int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, value, size, flags); } -void *fuse_setxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_setxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { return NULL; } -int fuse_removexattr_initialize(struct fuse_args *fa, +int fuse_removexattr_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct dentry *dentry, const char *name) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_REMOVEXATTR, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, @@ -790,7 +796,7 @@ int fuse_removexattr_initialize(struct fuse_args *fa, return 0; } -int fuse_removexattr_backing(struct fuse_args *fa, +int fuse_removexattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name) { struct path *backing_path = @@ -800,63 +806,72 @@ int fuse_removexattr_backing(struct fuse_args *fa, return vfs_removexattr(backing_path->dentry, name); } -void *fuse_removexattr_finalize(struct fuse_args *fa, +void *fuse_removexattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name) { return NULL; } +static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) +{ + if (refcount_dec_and_test(&aio_req->ref)) + kmem_cache_free(fuse_bpf_aio_request_cachep, aio_req); +} + static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req) { struct kiocb *iocb = &aio_req->iocb; - struct kiocb *iocb_fuse = aio_req->iocb_fuse; + struct kiocb *iocb_orig = aio_req->iocb_orig; if (iocb->ki_flags & IOCB_WRITE) { __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, SB_FREEZE_WRITE); file_end_write(iocb->ki_filp); - fuse_copyattr(iocb_fuse->ki_filp, iocb->ki_filp); + fuse_copyattr(iocb_orig->ki_filp, iocb->ki_filp); } - - iocb_fuse->ki_pos = iocb->ki_pos; - kfree(aio_req); + iocb_orig->ki_pos = iocb->ki_pos; + fuse_bpf_aio_put(aio_req); } static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res, long res2) { struct fuse_bpf_aio_req *aio_req = container_of(iocb, struct fuse_bpf_aio_req, iocb); - struct kiocb *iocb_fuse = aio_req->iocb_fuse; + struct kiocb *iocb_orig = aio_req->iocb_orig; fuse_bpf_aio_cleanup_handler(aio_req); - iocb_fuse->ki_complete(iocb_fuse, res, res2); + iocb_orig->ki_complete(iocb_orig, res, res2); } int fuse_file_read_iter_initialize( - struct fuse_args *fa, struct fuse_read_in *fri, + struct fuse_bpf_args *fa, struct fuse_file_read_iter_io *fri, struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; - *fri = (struct fuse_read_in) { + fri->fri = (struct fuse_read_in) { .fh = ff->fh, .offset = iocb->ki_pos, .size = to->count, }; + fri->frio = (struct fuse_read_iter_out) { + .ret = fri->fri.size, + }; + /* TODO we can't assume 'to' is a kvec */ /* TODO we also can't assume the vector has only one component */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_READ, .nodeid = ff->nodeid, .in_numargs = 1, - .in_args[0].size = sizeof(*fri), - .in_args[0].value = fri, + .in_args[0].size = sizeof(fri->fri), + .in_args[0].value = &fri->fri, .out_numargs = 1, - .out_args[0].size = fri->size, - .out_args[0].value = to->kvec->iov_base, + .out_args[0].size = sizeof(fri->frio), + .out_args[0].value = &fri->frio, /* * TODO Design this properly. * Possible approach: do not pass buf to bpf @@ -869,9 +884,10 @@ int fuse_file_read_iter_initialize( return 0; } -int fuse_file_read_iter_backing(struct fuse_args *fa, +int fuse_file_read_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to) { + struct fuse_read_iter_out *frio = fa->out_args[0].value; struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; ssize_t ret; @@ -892,19 +908,21 @@ int fuse_file_read_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; - aio_req->iocb_fuse = iocb; + + aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_read(ff->backing_file, &aio_req->iocb, to); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } - if (ret >= 0) - fa->out_args[0].size = ret; + frio->ret = ret; /* TODO Need to point value at the buffer for post-modification */ @@ -914,14 +932,16 @@ out: return ret; } -void *fuse_file_read_iter_finalize(struct fuse_args *fa, +void *fuse_file_read_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to) { - return ERR_PTR(fa->out_args[0].size); + struct fuse_read_iter_out *frio = fa->out_args[0].value; + + return ERR_PTR(frio->ret); } int fuse_file_write_iter_initialize( - struct fuse_args *fa, struct fuse_file_write_iter_io *fwio, + struct fuse_bpf_args *fa, struct fuse_file_write_iter_io *fwio, struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -934,7 +954,7 @@ int fuse_file_write_iter_initialize( }; /* TODO we can't assume 'from' is a kvec */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_WRITE, .nodeid = ff->nodeid, .in_numargs = 2, @@ -950,7 +970,7 @@ int fuse_file_write_iter_initialize( return 0; } -int fuse_file_write_iter_backing(struct fuse_args *fa, +int fuse_file_write_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -980,17 +1000,18 @@ int fuse_file_write_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - /* TODO get this from a cache? */ - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; file_start_write(ff->backing_file); __sb_writers_release(file_inode(ff->backing_file)->i_sb, SB_FREEZE_WRITE); - aio_req->iocb_fuse = iocb; + aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } @@ -1003,7 +1024,7 @@ out: return 0; } -void *fuse_file_write_iter_finalize(struct fuse_args *fa, +void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from) { struct fuse_write_iter_out *fwio = fa->out_args[0].value; @@ -1049,7 +1070,7 @@ ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) return ret; } -int fuse_file_fallocate_initialize(struct fuse_args *fa, +int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa, struct fuse_fallocate_in *ffi, struct file *file, int mode, loff_t offset, loff_t length) { @@ -1062,7 +1083,7 @@ int fuse_file_fallocate_initialize(struct fuse_args *fa, .mode = mode }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_FALLOCATE, .nodeid = ff->nodeid, .in_numargs = 1, @@ -1073,7 +1094,7 @@ int fuse_file_fallocate_initialize(struct fuse_args *fa, return 0; } -int fuse_file_fallocate_backing(struct fuse_args *fa, +int fuse_file_fallocate_backing(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length) { const struct fuse_fallocate_in *ffi = fa->in_args[0].value; @@ -1083,7 +1104,7 @@ int fuse_file_fallocate_backing(struct fuse_args *fa, ffi->length); } -void *fuse_file_fallocate_finalize(struct fuse_args *fa, +void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length) { return NULL; @@ -1093,24 +1114,24 @@ void *fuse_file_fallocate_finalize(struct fuse_args *fa, * Directory operations after here * ******************************************************************************/ -int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *fli, +int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *fli, struct inode *dir, struct dentry *entry, unsigned int flags) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dir)->nodeid, .opcode = FUSE_LOOKUP, .in_numargs = 1, .out_numargs = 2, - .out_argvar = 1, - .in_args[0] = (struct fuse_in_arg) { + .flags = FUSE_BPF_OUT_ARGVAR, + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fli->feo), .value = &fli->feo, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = sizeof(fli->feb.out), .value = &fli->feb.out, }, @@ -1119,7 +1140,7 @@ int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *fli, return 0; } -int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, +int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fuse_entry = get_fuse_dentry(entry); @@ -1146,7 +1167,7 @@ int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, return 0; } -struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, +struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fd; @@ -1249,7 +1270,7 @@ struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, return d_splice_alias(inode, entry); } -int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, +int fuse_revalidate_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry); @@ -1267,13 +1288,13 @@ int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, return 1; } -void *fuse_revalidate_finalize(struct fuse_args *fa, struct inode *dir, +void *fuse_revalidate_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { return 0; } -int fuse_canonical_path_initialize(struct fuse_args *fa, +int fuse_canonical_path_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *fdi, const struct path *path, struct path *canonical_path) @@ -1282,14 +1303,14 @@ int fuse_canonical_path_initialize(struct fuse_args *fa, return 0; } -int fuse_canonical_path_backing(struct fuse_args *fa, const struct path *path, +int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path) { get_fuse_backing_path(path->dentry, canonical_path); return 0; } -void *fuse_canonical_path_finalize(struct fuse_args *fa, +void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path) { @@ -1297,7 +1318,7 @@ void *fuse_canonical_path_finalize(struct fuse_args *fa, } int fuse_mknod_initialize( - struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { *fmi = (struct fuse_mknod_in) { @@ -1305,15 +1326,15 @@ int fuse_mknod_initialize( .rdev = new_encode_dev(rdev), .umask = current_umask(), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_MKNOD, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fmi), .value = fmi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1323,7 +1344,7 @@ int fuse_mknod_initialize( } int fuse_mknod_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { int err = 0; @@ -1367,29 +1388,29 @@ out: } void *fuse_mknod_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { return NULL; } int fuse_mkdir_initialize( - struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode) { *fmi = (struct fuse_mkdir_in) { .mode = mode, .umask = current_umask(), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_MKDIR, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fmi), .value = fmi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1399,7 +1420,7 @@ int fuse_mkdir_initialize( } int fuse_mkdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode) { int err = 0; @@ -1445,21 +1466,21 @@ out: } void *fuse_mkdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode) { return NULL; } int fuse_rmdir_initialize( - struct fuse_args *fa, struct fuse_dummy_io *dummy, + struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *dir, struct dentry *entry) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_RMDIR, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1469,7 +1490,7 @@ int fuse_rmdir_initialize( } int fuse_rmdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { int err = 0; @@ -1498,7 +1519,7 @@ int fuse_rmdir_backing( } void *fuse_rmdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { return NULL; @@ -1561,7 +1582,7 @@ static int fuse_rename_backing_common( if (target_inode) fsstack_copy_attr_all(target_inode, get_fuse_inode(target_inode)->backing_inode); - fsstack_copy_attr_all(newdir, d_inode(new_backing_dir_dentry)); + fsstack_copy_attr_all(d_inode(oldent), d_inode(old_backing_dentry)); unlock: unlock_rename(old_backing_dir_dentry, new_backing_dir_dentry); put_parents: @@ -1574,7 +1595,7 @@ put_old_path: return err; } -int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, +int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1583,19 +1604,19 @@ int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, .newdir = get_node_id(newdir), .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(olddir), .opcode = FUSE_RENAME2, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fri), .value = fri, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = oldent->d_name.len + 1, .value = oldent->d_name.name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = newent->d_name.len + 1, .value = newent->d_name.name, }, @@ -1604,7 +1625,7 @@ int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, return 0; } -int fuse_rename2_backing(struct fuse_args *fa, +int fuse_rename2_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1615,7 +1636,7 @@ int fuse_rename2_backing(struct fuse_args *fa, return fuse_rename_backing_common(olddir, oldent, newdir, newent, fri->flags); } -void *fuse_rename2_finalize(struct fuse_args *fa, +void *fuse_rename2_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1623,26 +1644,26 @@ void *fuse_rename2_finalize(struct fuse_args *fa, return NULL; } -int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, +int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { *fri = (struct fuse_rename_in) { .newdir = get_node_id(newdir), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(olddir), .opcode = FUSE_RENAME, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fri), .value = fri, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = oldent->d_name.len + 1, .value = oldent->d_name.name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = newent->d_name.len + 1, .value = newent->d_name.name, }, @@ -1651,7 +1672,7 @@ int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, return 0; } -int fuse_rename_backing(struct fuse_args *fa, +int fuse_rename_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { @@ -1659,7 +1680,7 @@ int fuse_rename_backing(struct fuse_args *fa, return fuse_rename_backing_common(olddir, oldent, newdir, newent, 0); } -void *fuse_rename_finalize(struct fuse_args *fa, +void *fuse_rename_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { @@ -1667,14 +1688,14 @@ void *fuse_rename_finalize(struct fuse_args *fa, } int fuse_unlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *dummy, + struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *dir, struct dentry *entry) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_UNLINK, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1684,7 +1705,7 @@ int fuse_unlink_initialize( } int fuse_unlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { int err = 0; @@ -1713,13 +1734,13 @@ int fuse_unlink_backing( } void *fuse_unlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { return NULL; } -int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, +int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli, struct dentry *entry, struct inode *dir, struct dentry *newent) { @@ -1739,7 +1760,7 @@ int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, return 0; } -int fuse_link_backing(struct fuse_args *fa, struct dentry *entry, +int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent) { int err = 0; @@ -1793,13 +1814,13 @@ err_dst_path: return err; } -void *fuse_link_finalize(struct fuse_args *fa, struct dentry *entry, +void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent) { return NULL; } -int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, +int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1810,16 +1831,16 @@ int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, fgio->fao = (struct fuse_attr_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(entry->d_inode), .opcode = FUSE_GETATTR, .in_numargs = 1, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fgio->fao), .value = &fgio->fao, }, @@ -1864,7 +1885,7 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } -int fuse_getattr_backing(struct fuse_args *fa, +int fuse_getattr_backing(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1887,7 +1908,7 @@ int fuse_getattr_backing(struct fuse_args *fa, return err; } -void *fuse_getattr_finalize(struct fuse_args *fa, +void *fuse_getattr_finalize(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1942,7 +1963,7 @@ static void fattr_to_iattr(struct fuse_conn *fc, } } -int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, +int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsio, struct dentry *dentry, struct iattr *attr, struct file *file) { struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); @@ -1950,7 +1971,7 @@ int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, *fsio = (struct fuse_setattr_io) {0}; iattr_to_fattr(fc, attr, &fsio->fsi, true); - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_SETATTR, .nodeid = get_node_id(dentry->d_inode), .in_numargs = 1, @@ -1964,7 +1985,7 @@ int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, return 0; } -int fuse_setattr_backing(struct fuse_args *fa, +int fuse_setattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file) { struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); @@ -1991,18 +2012,18 @@ int fuse_setattr_backing(struct fuse_args *fa, return res; } -void *fuse_setattr_finalize(struct fuse_args *fa, +void *fuse_setattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file) { return NULL; } int fuse_statfs_initialize( - struct fuse_args *fa, struct fuse_statfs_out *fso, + struct fuse_bpf_args *fa, struct fuse_statfs_out *fso, struct dentry *dentry, struct kstatfs *buf) { *fso = (struct fuse_statfs_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(d_inode(dentry)), .opcode = FUSE_STATFS, .out_numargs = 1, @@ -2015,7 +2036,7 @@ int fuse_statfs_initialize( } int fuse_statfs_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf) { int err = 0; @@ -2037,7 +2058,7 @@ int fuse_statfs_backing( } void *fuse_statfs_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf) { struct fuse_statfs_out *fso = fa->out_args[0].value; @@ -2047,7 +2068,7 @@ void *fuse_statfs_finalize( return NULL; } -int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, +int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2063,11 +2084,11 @@ int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, * We ought to only make that buffer if it's been requested, so leaving * this unimplemented for the moment */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_READLINK, .nodeid = get_node_id(inode), .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = dentry->d_name.len + 1, .value = dentry->d_name.name, }, @@ -2082,7 +2103,7 @@ int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, return 0; } -int fuse_get_link_backing(struct fuse_args *fa, +int fuse_get_link_backing(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2109,7 +2130,7 @@ int fuse_get_link_backing(struct fuse_args *fa, return 0; } -void *fuse_get_link_finalize(struct fuse_args *fa, +void *fuse_get_link_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2117,18 +2138,18 @@ void *fuse_get_link_finalize(struct fuse_args *fa, } int fuse_symlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *unused, + struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *dir, struct dentry *entry, const char *link, int len) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_SYMLINK, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = len, .value = link, }, @@ -2138,7 +2159,7 @@ int fuse_symlink_initialize( } int fuse_symlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len) { int err = 0; @@ -2177,15 +2198,15 @@ out: } void *fuse_symlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len) { return NULL; } -int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, +int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { struct fuse_file *ff = file->private_data; u8 *page = (u8 *)__get_free_page(GFP_KERNEL); @@ -2193,21 +2214,21 @@ int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, if (!page) return -ENOMEM; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = ff->nodeid, .opcode = FUSE_READDIR, .in_numargs = 1, - .out_argvar = true, + .flags = FUSE_BPF_OUT_ARGVAR, .out_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(frio->fri), .value = &frio->fri, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(frio->fro), .value = &frio->fro, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = PAGE_SIZE, .value = page, }, @@ -2255,9 +2276,35 @@ static int filldir(struct dir_context *ctx, const char *name, int namelen, return 0; } -int fuse_readdir_backing(struct fuse_args *fa, +static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx) +{ + while (nbytes >= FUSE_NAME_OFFSET) { + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + size_t reclen = FUSE_DIRENT_SIZE(dirent); + + if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) + return -EIO; + if (reclen > nbytes) + break; + if (memchr(dirent->name, '/', dirent->namelen) != NULL) + return -EIO; + + ctx->pos = dirent->off; + if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino, + dirent->type)) + break; + + buf += reclen; + nbytes -= reclen; + } + + return 0; +} + + +int fuse_readdir_backing(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { struct fuse_file *ff = file->private_data; struct file *backing_dir = ff->backing_file; @@ -2274,6 +2321,9 @@ int fuse_readdir_backing(struct fuse_args *fa, if (!ec.addr) return -ENOMEM; + if (!is_continued) + backing_dir->f_pos = file->f_pos; + err = iterate_dir(backing_dir, &ec.ctx); if (ec.offset == 0) *allow_force = false; @@ -2284,34 +2334,35 @@ int fuse_readdir_backing(struct fuse_args *fa, return err; } -void *fuse_readdir_finalize(struct fuse_args *fa, +void *fuse_readdir_finalize(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { - int err = 0; + struct fuse_read_out *fro = fa->out_args[0].value; struct fuse_file *ff = file->private_data; struct file *backing_dir = ff->backing_file; - struct fuse_read_out *fro = fa->out_args[0].value; + int err = 0; - err = fuse_parse_dirfile(fa->out_args[1].value, - fa->out_args[1].size, file, ctx); + err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx); *force_again = !!fro->again; if (*force_again && !*allow_force) err = -EINVAL; + + ctx->pos = fro->offset; backing_dir->f_pos = fro->offset; free_page((unsigned long) fa->out_args[1].value); return ERR_PTR(err); } -int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, +int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask) { *fai = (struct fuse_access_in) { .mask = mask, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_ACCESS, .nodeid = get_node_id(inode), .in_numargs = 1, @@ -2322,7 +2373,7 @@ int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, return 0; } -int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask) +int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask) { struct fuse_inode *fi = get_fuse_inode(inode); const struct fuse_access_in *fai = fa->in_args[0].value; @@ -2331,7 +2382,74 @@ int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask) fi->backing_inode, fai->mask); } -void *fuse_access_finalize(struct fuse_args *fa, struct inode *inode, int mask) +void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask) { return NULL; } + +int __init fuse_bpf_init(void) +{ + fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req", + sizeof(struct fuse_bpf_aio_req), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fuse_bpf_aio_request_cachep) + return -ENOMEM; + + return 0; +} + +void __exit fuse_bpf_cleanup(void) +{ + kmem_cache_destroy(fuse_bpf_aio_request_cachep); +} + +ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *bpf_args) +{ + int i; + ssize_t res; + struct fuse_args args = { + .nodeid = bpf_args->nodeid, + .opcode = bpf_args->opcode, + .error_in = bpf_args->error_in, + .in_numargs = bpf_args->in_numargs, + .out_numargs = bpf_args->out_numargs, + .force = !!(bpf_args->flags & FUSE_BPF_FORCE), + .out_argvar = !!(bpf_args->flags & FUSE_BPF_OUT_ARGVAR), + }; + + for (i = 0; i < args.in_numargs; ++i) + args.in_args[i] = (struct fuse_in_arg) { + .size = bpf_args->in_args[i].size, + .value = bpf_args->in_args[i].value, + }; + for (i = 0; i < args.out_numargs; ++i) + args.out_args[i] = (struct fuse_arg) { + .size = bpf_args->out_args[i].size, + .value = bpf_args->out_args[i].value, + }; + + res = fuse_simple_request(fm, &args); + + *bpf_args = (struct fuse_bpf_args) { + .nodeid = args.nodeid, + .opcode = args.opcode, + .error_in = args.error_in, + .in_numargs = args.in_numargs, + .out_numargs = args.out_numargs, + }; + if (args.force) + bpf_args->flags |= FUSE_BPF_FORCE; + if (args.out_argvar) + bpf_args->flags |= FUSE_BPF_OUT_ARGVAR; + for (i = 0; i < args.in_numargs; ++i) + bpf_args->in_args[i] = (struct fuse_bpf_in_arg) { + .size = args.in_args[i].size, + .value = args.in_args[i].value, + }; + for (i = 0; i < args.out_numargs; ++i) + bpf_args->out_args[i] = (struct fuse_bpf_arg) { + .size = args.out_args[i].size, + .value = args.out_args[i].value, + }; + return res; +} diff --git a/fs/fuse/control.c b/fs/fuse/control.c index cc7e94d73c6cc..a4b16bc59f7a3 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -395,7 +395,7 @@ int __init fuse_ctl_init(void) return register_filesystem(&fuse_ctl_fs_type); } -void __exit fuse_ctl_cleanup(void) +void fuse_ctl_cleanup(void) { unregister_filesystem(&fuse_ctl_fs_type); } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b8ef63c4fc27c..c13be2fa891f5 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -208,10 +208,13 @@ static unsigned int fuse_req_hash(u64 unique) /** * A new request is available, wake fiq->waitq */ -static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) +static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock) { - wake_up(&fiq->waitq); + if (sync) + wake_up_sync(&fiq->waitq); + else + wake_up(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); spin_unlock(&fiq->lock); } @@ -224,14 +227,14 @@ const struct fuse_iqueue_ops fuse_dev_fiq_ops = { EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); static void queue_request_and_unlock(struct fuse_iqueue *fiq, - struct fuse_req *req) + struct fuse_req *req, bool sync) __releases(fiq->lock) { req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, (struct fuse_arg *) req->args->in_args); list_add_tail(&req->list, &fiq->pending); - fiq->ops->wake_pending_and_unlock(fiq); + fiq->ops->wake_pending_and_unlock(fiq, sync); } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, @@ -251,7 +254,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; - fiq->ops->wake_forget_and_unlock(fiq); + fiq->ops->wake_forget_and_unlock(fiq, false); } else { kfree(forget); spin_unlock(&fiq->lock); @@ -271,7 +274,7 @@ static void flush_bg_queue(struct fuse_conn *fc) fc->active_background++; spin_lock(&fiq->lock); req->in.h.unique = fuse_get_unique(fiq); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, false); } } @@ -364,7 +367,7 @@ static int queue_interrupt(struct fuse_req *req) spin_unlock(&fiq->lock); return 0; } - fiq->ops->wake_interrupt_and_unlock(fiq); + fiq->ops->wake_interrupt_and_unlock(fiq, false); } else { spin_unlock(&fiq->lock); } @@ -431,7 +434,7 @@ static void __fuse_request_send(struct fuse_req *req) /* acquire extra reference, since request is still needed after fuse_request_end() */ __fuse_get_request(req); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, true); request_wait_answer(req); /* Pairs with smp_wmb() in fuse_request_end() */ @@ -607,7 +610,7 @@ static int fuse_simple_notify_reply(struct fuse_mount *fm, spin_lock(&fiq->lock); if (fiq->connected) { - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, false); } else { err = -ENODEV; spin_unlock(&fiq->lock); @@ -690,11 +693,7 @@ static void fuse_copy_finish(struct fuse_copy_state *cs) flush_dcache_page(cs->pg); set_page_dirty_lock(cs->pg); } - /* - * The page could be GUP page(see iov_iter_get_pages in - * fuse_copy_fill) so use put_user_page to release it. - */ - put_user_page(cs->pg); + put_page(cs->pg); } cs->pg = NULL; } @@ -796,7 +795,8 @@ static int fuse_check_page(struct page *page) 1 << PG_active | 1 << PG_workingset | 1 << PG_reclaim | - 1 << PG_waiters))) { + 1 << PG_waiters | + LRU_GEN_MASK | LRU_REFS_MASK))) { dump_page(page, "fuse: trying to steal weird page"); return 1; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a8070719881c9..d492898b33f52 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1643,7 +1643,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct fuse_err_ret fer; - fer = fuse_bpf_backing(inode, struct fuse_read_in, + fer = fuse_bpf_backing(inode, struct fuse_file_read_iter_io, fuse_file_read_iter_initialize, fuse_file_read_iter_backing, fuse_file_read_iter_finalize, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 87f2f2e5c5a89..00e0c53242e76 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -308,12 +308,48 @@ struct fuse_file { bool flock:1; }; +/** One input argument of a request */ +struct fuse_in_arg { + unsigned size; + const void *value; +}; + +/** One output argument of a request */ +struct fuse_arg { + unsigned size; + void *value; +}; + /** FUSE page descriptor */ struct fuse_page_desc { unsigned int length; unsigned int offset; }; +struct fuse_args { + uint64_t nodeid; + uint32_t opcode; + uint32_t error_in; + unsigned short in_numargs; + unsigned short out_numargs; + int force:1; + int noreply:1; + int nocreds:1; + int in_pages:1; + int out_pages:1; + int user_pages:1; + int out_argvar:1; + int page_zeroing:1; + int page_replace:1; + int may_block:1; + struct fuse_in_arg in_args[FUSE_MAX_IN_ARGS]; + struct fuse_arg out_args[FUSE_MAX_OUT_ARGS]; + void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); + + /* Path used for completing d_canonical_path */ + struct path *canonical_path; +}; + struct fuse_args_pages { struct fuse_args args; struct page **pages; @@ -436,19 +472,19 @@ struct fuse_iqueue_ops { /** * Signal that a forget has been queued */ - void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that an INTERRUPT request has been queued */ - void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that a request has been queued */ - void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** @@ -987,10 +1023,6 @@ struct fuse_io_args { void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos, size_t count, int opcode); - -int fuse_parse_dirfile(char *buf, size_t nbytes, struct file *file, - struct dir_context *ctx); - /** * Send OPEN or OPENDIR request */ @@ -1059,7 +1091,7 @@ int fuse_dev_init(void); void fuse_dev_cleanup(void); int fuse_ctl_init(void); -void __exit fuse_ctl_cleanup(void); +void fuse_ctl_cleanup(void); /** * Simple request sending that does request allocation and freeing @@ -1320,11 +1352,11 @@ struct fuse_open_io { struct fuse_open_out foo; }; -int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foi, +int fuse_open_initialize(struct fuse_bpf_args *fa, struct fuse_open_io *foi, struct inode *inode, struct file *file, bool isdir); -int fuse_open_backing(struct fuse_args *fa, +int fuse_open_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir); -void *fuse_open_finalize(struct fuse_args *fa, +void *fuse_open_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir); struct fuse_create_open_io { @@ -1334,103 +1366,103 @@ struct fuse_create_open_io { }; int fuse_create_open_initialize( - struct fuse_args *fa, struct fuse_create_open_io *fcoi, + struct fuse_bpf_args *fa, struct fuse_create_open_io *fcoi, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); int fuse_create_open_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); void *fuse_create_open_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); int fuse_mknod_initialize( - struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); int fuse_mknod_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); void *fuse_mknod_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); int fuse_mkdir_initialize( - struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode); int fuse_mkdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode); void *fuse_mkdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode); int fuse_rmdir_initialize( - struct fuse_args *fa, struct fuse_dummy_io *fmi, + struct fuse_bpf_args *fa, struct fuse_dummy_io *fmi, struct inode *dir, struct dentry *entry); int fuse_rmdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); void *fuse_rmdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); -int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, +int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -int fuse_rename2_backing(struct fuse_args *fa, +int fuse_rename2_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -void *fuse_rename2_finalize(struct fuse_args *fa, +void *fuse_rename2_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, +int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); -int fuse_rename_backing(struct fuse_args *fa, +int fuse_rename_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); -void *fuse_rename_finalize(struct fuse_args *fa, +void *fuse_rename_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); int fuse_unlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *fmi, + struct fuse_bpf_args *fa, struct fuse_dummy_io *fmi, struct inode *dir, struct dentry *entry); int fuse_unlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); void *fuse_unlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); -int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, +int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli, struct dentry *entry, struct inode *dir, struct dentry *newent); -int fuse_link_backing(struct fuse_args *fa, struct dentry *entry, +int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent); -void *fuse_link_finalize(struct fuse_args *fa, struct dentry *entry, +void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent); -int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, +int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file); -int fuse_releasedir_initialize(struct fuse_args *fa, +int fuse_releasedir_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file); -int fuse_release_backing(struct fuse_args *fa, +int fuse_release_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file); -void *fuse_release_finalize(struct fuse_args *fa, +void *fuse_release_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file); -int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, +int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi, struct file *file, fl_owner_t id); -int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id); -void *fuse_flush_finalize(struct fuse_args *fa, +int fuse_flush_backing(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id); +void *fuse_flush_finalize(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id); struct fuse_lseek_io { @@ -1438,37 +1470,37 @@ struct fuse_lseek_io { struct fuse_lseek_out flo; }; -int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *fli, +int fuse_lseek_initialize(struct fuse_bpf_args *fa, struct fuse_lseek_io *fli, struct file *file, loff_t offset, int whence); -int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence); -void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence); +int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence); +void *fuse_lseek_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence); struct fuse_copy_file_range_io { struct fuse_copy_file_range_in fci; struct fuse_write_out fwo; }; -int fuse_copy_file_range_initialize(struct fuse_args *fa, +int fuse_copy_file_range_initialize(struct fuse_bpf_args *fa, struct fuse_copy_file_range_io *fcf, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -int fuse_copy_file_range_backing(struct fuse_args *fa, +int fuse_copy_file_range_backing(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -void *fuse_copy_file_range_finalize(struct fuse_args *fa, +void *fuse_copy_file_range_finalize(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync); -int fuse_fsync_backing(struct fuse_args *fa, +int fuse_fsync_backing(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync); -void *fuse_fsync_finalize(struct fuse_args *fa, +void *fuse_fsync_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync); -int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_dir_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync); struct fuse_getxattr_io { @@ -1477,51 +1509,59 @@ struct fuse_getxattr_io { }; int fuse_getxattr_initialize( - struct fuse_args *fa, struct fuse_getxattr_io *fgio, + struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, const char *name, void *value, size_t size); int fuse_getxattr_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size); void *fuse_getxattr_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size); -int fuse_listxattr_initialize(struct fuse_args *fa, +int fuse_listxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, char *list, size_t size); -int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_listxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size); -void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_listxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size); -int fuse_setxattr_initialize(struct fuse_args *fa, +int fuse_setxattr_initialize(struct fuse_bpf_args *fa, struct fuse_setxattr_in *fsxi, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_setxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -void *fuse_setxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_setxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int fuse_removexattr_initialize(struct fuse_args *fa, +int fuse_removexattr_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct dentry *dentry, const char *name); -int fuse_removexattr_backing(struct fuse_args *fa, +int fuse_removexattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name); -void *fuse_removexattr_finalize(struct fuse_args *fa, +void *fuse_removexattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name); +struct fuse_read_iter_out { + uint64_t ret; +}; +struct fuse_file_read_iter_io { + struct fuse_read_in fri; + struct fuse_read_iter_out frio; +}; + int fuse_file_read_iter_initialize( - struct fuse_args *fa, struct fuse_read_in *fri, + struct fuse_bpf_args *fa, struct fuse_file_read_iter_io *fri, struct kiocb *iocb, struct iov_iter *to); -int fuse_file_read_iter_backing(struct fuse_args *fa, +int fuse_file_read_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to); -void *fuse_file_read_iter_finalize(struct fuse_args *fa, +void *fuse_file_read_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to); struct fuse_write_iter_out { @@ -1534,21 +1574,21 @@ struct fuse_file_write_iter_io { }; int fuse_file_write_iter_initialize( - struct fuse_args *fa, struct fuse_file_write_iter_io *fwio, + struct fuse_bpf_args *fa, struct fuse_file_write_iter_io *fwio, struct kiocb *iocb, struct iov_iter *from); -int fuse_file_write_iter_backing(struct fuse_args *fa, +int fuse_file_write_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from); -void *fuse_file_write_iter_finalize(struct fuse_args *fa, +void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from); ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma); -int fuse_file_fallocate_initialize(struct fuse_args *fa, +int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa, struct fuse_fallocate_in *ffi, struct file *file, int mode, loff_t offset, loff_t length); -int fuse_file_fallocate_backing(struct fuse_args *fa, +int fuse_file_fallocate_backing(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length); -void *fuse_file_fallocate_finalize(struct fuse_args *fa, +void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length); struct fuse_lookup_io { @@ -1556,24 +1596,24 @@ struct fuse_lookup_io { struct fuse_entry_bpf feb; }; -int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *feo, +int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *feo, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, +int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, +struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, +int fuse_revalidate_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -void *fuse_revalidate_finalize(struct fuse_args *fa, struct inode *dir, +void *fuse_revalidate_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_canonical_path_initialize(struct fuse_args *fa, +int fuse_canonical_path_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *fdi, const struct path *path, struct path *canonical_path); -int fuse_canonical_path_backing(struct fuse_args *fa, const struct path *path, +int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path); -void *fuse_canonical_path_finalize(struct fuse_args *fa, +void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path); @@ -1581,13 +1621,13 @@ struct fuse_getattr_io { struct fuse_getattr_in fgi; struct fuse_attr_out fao; }; -int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, +int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); -int fuse_getattr_backing(struct fuse_args *fa, +int fuse_getattr_backing(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); -void *fuse_getattr_finalize(struct fuse_args *fa, +void *fuse_getattr_finalize(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); @@ -1596,38 +1636,38 @@ struct fuse_setattr_io { struct fuse_attr_out fao; }; -int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsi, +int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsi, struct dentry *dentry, struct iattr *attr, struct file *file); -int fuse_setattr_backing(struct fuse_args *fa, +int fuse_setattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file); -void *fuse_setattr_finalize(struct fuse_args *fa, +void *fuse_setattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file); -int fuse_statfs_initialize(struct fuse_args *fa, struct fuse_statfs_out *fso, +int fuse_statfs_initialize(struct fuse_bpf_args *fa, struct fuse_statfs_out *fso, struct dentry *dentry, struct kstatfs *buf); -int fuse_statfs_backing(struct fuse_args *fa, +int fuse_statfs_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf); -void *fuse_statfs_finalize(struct fuse_args *fa, +void *fuse_statfs_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf); -int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *dummy, +int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); -int fuse_get_link_backing(struct fuse_args *fa, +int fuse_get_link_backing(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); -void *fuse_get_link_finalize(struct fuse_args *fa, +void *fuse_get_link_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); int fuse_symlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *unused, + struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *dir, struct dentry *entry, const char *link, int len); int fuse_symlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len); void *fuse_symlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len); struct fuse_read_io { @@ -1635,20 +1675,20 @@ struct fuse_read_io { struct fuse_read_out fro; }; -int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, +int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); -int fuse_readdir_backing(struct fuse_args *fa, + bool *force_again, bool *allow_force, bool is_continued); +int fuse_readdir_backing(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); -void *fuse_readdir_finalize(struct fuse_args *fa, + bool *force_again, bool *allow_force, bool is_continued); +void *fuse_readdir_finalize(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); + bool *force_again, bool *allow_force, bool is_continued); -int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, +int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask); -int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask); -void *fuse_access_finalize(struct fuse_args *fa, struct inode *inode, int mask); +int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask); +void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask); /* * FUSE caches dentries and attributes with separate timeout. The @@ -1784,16 +1824,21 @@ struct fuse_err_ret { bool ret; }; +int __init fuse_bpf_init(void); +void __exit fuse_bpf_cleanup(void); + +ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *args); + /* * expression statement to wrap the backing filter logic * struct inode *inode: inode with bpf and backing inode * typedef io: (typically complex) type whose components fuse_args can point to. * An instance of this type is created locally and passed to initialize - * void initialize(struct fuse_args *fa, io *in_out, args...): function that sets + * void initialize(struct fuse_bpf_args *fa, io *in_out, args...): function that sets * up fa and io based on args - * int backing(struct fuse_args *fa, args...): function that actually performs + * int backing(struct fuse_bpf_args *fa, args...): function that actually performs * the backing io operation - * void *finalize(struct fuse_args *, args...): function that performs any final + * void *finalize(struct fuse_bpf_args *, args...): function that performs any final * work needed to commit the backing io */ #define fuse_bpf_backing(inode, io, initialize, backing, finalize, \ @@ -1804,7 +1849,7 @@ struct fuse_err_ret { struct fuse_inode *fuse_inode = get_fuse_inode(inode); \ struct fuse_mount *fm = get_fuse_mount(inode); \ io feo = {0}; \ - struct fuse_args fa = {0}, fa_backup = {0}; \ + struct fuse_bpf_args fa = {0}, fa_backup = {0}; \ bool locked; \ ssize_t res; \ void *err; \ @@ -1828,7 +1873,7 @@ struct fuse_err_ret { fa_backup = fa; \ fa.opcode |= FUSE_PREFILTER; \ for (i = 0; i < fa.in_numargs; ++i) \ - fa.out_args[i] = (struct fuse_arg) { \ + fa.out_args[i] = (struct fuse_bpf_arg) { \ .size = fa.in_args[i].size, \ .value = (void *)fa.in_args[i].value, \ }; \ @@ -1847,7 +1892,7 @@ struct fuse_err_ret { \ if (ext_flags & FUSE_BPF_USER_FILTER) { \ locked = fuse_lock_inode(inode); \ - res = fuse_simple_request(fm, &fa); \ + res = fuse_bpf_simple_request(fm, &fa); \ fuse_unlock_inode(inode, locked); \ if (res < 0) { \ fer = (struct fuse_err_ret) { \ @@ -1863,12 +1908,12 @@ struct fuse_err_ret { \ fa.opcode &= ~FUSE_PREFILTER; \ for (i = 0; i < fa.in_numargs; ++i) \ - fa.in_args[i] = (struct fuse_in_arg) { \ + fa.in_args[i] = (struct fuse_bpf_in_arg) { \ .size = fa.out_args[i].size, \ .value = fa.out_args[i].value, \ }; \ - for (i = 0; i < fa.out_numargs; ++i) \ - fa.out_args[i] = (struct fuse_arg) { \ + for (i = 0; i < fa_backup.out_numargs; ++i) \ + fa.out_args[i] = (struct fuse_bpf_arg) { \ .size = fa_backup.out_args[i].size, \ .value = fa_backup.out_args[i].value, \ }; \ @@ -1886,7 +1931,7 @@ struct fuse_err_ret { fa.opcode |= FUSE_POSTFILTER; \ for (i = 0; i < fa.out_numargs; ++i) \ fa.in_args[fa.in_numargs++] = \ - (struct fuse_in_arg) { \ + (struct fuse_bpf_in_arg) { \ .size = fa.out_args[i].size, \ .value = fa.out_args[i].value, \ }; \ @@ -1905,7 +1950,7 @@ struct fuse_err_ret { fa.out_args[1].size = fa_backup.out_args[1].size; \ fa.out_numargs = fa_backup.out_numargs; \ locked = fuse_lock_inode(inode); \ - res = fuse_simple_request(fm, &fa); \ + res = fuse_bpf_simple_request(fm, &fa); \ fuse_unlock_inode(inode, locked); \ if (res < 0) { \ fer.result = ERR_PTR(res); \ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ee18e23215935..fa692f9e4ef34 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -27,6 +27,7 @@ MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Filesystem in Userspace"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; @@ -1902,11 +1903,21 @@ static int __init fuse_init(void) if (res) goto err_sysfs_cleanup; +#ifdef CONFIG_FUSE_BPF + res = fuse_bpf_init(); + if (res) + goto err_ctl_cleanup; +#endif + sanitize_global_limit(&max_user_bgreq); sanitize_global_limit(&max_user_congthresh); return 0; +#ifdef CONFIG_FUSE_BPF + err_ctl_cleanup: + fuse_ctl_cleanup(); +#endif err_sysfs_cleanup: fuse_sysfs_cleanup(); err_dev_cleanup: @@ -1924,6 +1935,9 @@ static void __exit fuse_exit(void) fuse_ctl_cleanup(); fuse_sysfs_cleanup(); fuse_fs_cleanup(); +#ifdef CONFIG_FUSE_BPF + fuse_bpf_cleanup(); +#endif fuse_dev_cleanup(); } diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 4a8a3d5425b3e..e802426d42a9d 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -121,7 +121,7 @@ static bool fuse_emit(struct file *file, struct dir_context *ctx, dirent->type); } -int fuse_parse_dirfile(char *buf, size_t nbytes, struct file *file, +static int parse_dirfile(char *buf, size_t nbytes, struct file *file, struct dir_context *ctx) { while (nbytes >= FUSE_NAME_OFFSET) { @@ -360,7 +360,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) res = parse_dirplusfile(page_address(page), res, file, ctx, attr_version); } else { - res = fuse_parse_dirfile(page_address(page), res, file, + res = parse_dirfile(page_address(page), res, file, ctx); } } @@ -574,13 +574,17 @@ int fuse_readdir(struct file *file, struct dir_context *ctx) #ifdef CONFIG_FUSE_BPF struct fuse_err_ret fer; bool force_again, allow_force; + bool is_continued = false; + again: fer = fuse_bpf_backing(inode, struct fuse_read_io, fuse_readdir_initialize, fuse_readdir_backing, fuse_readdir_finalize, - file, ctx, &force_again, &allow_force); - if (force_again && !IS_ERR(fer.result)) + file, ctx, &force_again, &allow_force, is_continued); + if (force_again && !IS_ERR(fer.result)) { + is_continued = true; goto again; + } if (fer.ret) return PTR_ERR(fer.result); diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index b9cfb1165ff42..90a574ba92cf9 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -971,7 +971,7 @@ static struct virtio_driver virtio_fs_driver = { #endif }; -static void virtio_fs_wake_forget_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_forget_and_unlock(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock) { struct fuse_forget_link *link; @@ -1006,7 +1006,8 @@ __releases(fiq->lock) kfree(link); } -static void virtio_fs_wake_interrupt_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_interrupt_and_unlock(struct fuse_iqueue *fiq, + bool sync) __releases(fiq->lock) { /* @@ -1221,7 +1222,8 @@ out: return ret; } -static void virtio_fs_wake_pending_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_pending_and_unlock(struct fuse_iqueue *fiq, + bool sync) __releases(fiq->lock) { unsigned int queue_id = VQ_REQUEST; /* TODO multiqueue */ diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c7393ee9cf683..81925fd2985fd 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -260,6 +260,7 @@ static void __exit exit_gfs2_fs(void) MODULE_DESCRIPTION("Global File System"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_gfs2_fs); module_exit(exit_gfs2_fs); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index eb775e93de97c..5e8eef9990e32 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1389,8 +1389,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp) start = r.start >> bs_shift; end = start + (r.len >> bs_shift); - minlen = max_t(u64, r.minlen, sdp->sd_sb.sb_bsize); - minlen = max_t(u64, minlen, + minlen = max_t(u64, r.minlen, q->limits.discard_granularity) >> bs_shift; if (end <= start || minlen > sdp->sd_max_rg_data) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 12d9bae393631..6432d65a08727 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -29,6 +29,7 @@ static struct kmem_cache *hfs_inode_cachep; MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static int hfs_sync_fs(struct super_block *sb, int wait) { diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 807119ae5adf7..2b0031c6daeab 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -617,6 +617,7 @@ out: MODULE_AUTHOR("Brad Boyer"); MODULE_DESCRIPTION("Extended Macintosh Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *hfsplus_inode_cachep; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index a7dbfc8920227..d7598d70f329c 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -791,3 +791,4 @@ static void __exit exit_hpfs_fs(void) module_init(init_hpfs_fs) module_exit(exit_hpfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 84db0382765db..2227913674a4f 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -131,8 +131,14 @@ struct mount_info { struct path mi_backing_dir_path; struct dentry *mi_index_dir; + /* For stacking mounts, if true, this indicates if the index dir needs + * to be freed for this SB otherwise it was created by lower level SB */ + bool mi_index_free; struct dentry *mi_incomplete_dir; + /* For stacking mounts, if true, this indicates if the incomplete dir + * needs to be freed for this SB. Similar to mi_index_free */ + bool mi_incomplete_free; const struct cred *mi_owner; diff --git a/fs/incfs/main.c b/fs/incfs/main.c index 23347acac8bf7..213faa5e91176 100644 --- a/fs/incfs/main.c +++ b/fs/incfs/main.c @@ -44,5 +44,6 @@ module_init(init_incfs_module); module_exit(cleanup_incfs_module); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("Eugene Zemtsov "); MODULE_DESCRIPTION("Incremental File System"); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 8d21f6decaee0..e97b843a4da53 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -437,7 +437,8 @@ static int incfs_init_dentry(struct dentry *dentry, struct path *path) } static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, - const char *name) + const char *name, + bool *created) { struct dentry *index_dentry; struct inode *backing_inode = d_inode(backing_dir); @@ -450,6 +451,7 @@ static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, return index_dentry; } else if (d_really_is_positive(index_dentry)) { /* Index already exists. */ + *created = false; return index_dentry; } @@ -469,6 +471,7 @@ static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, return ERR_PTR(-EINVAL); } + *created = true; return index_dentry; } @@ -1747,6 +1750,7 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, struct super_block *src_fs_sb = NULL; struct inode *root_inode = NULL; struct super_block *sb = sget(type, NULL, set_anon_super, flags, NULL); + bool dir_created = false; int error = 0; if (IS_ERR(sb)) @@ -1763,17 +1767,23 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, BUILD_BUG_ON(PAGE_SIZE != INCFS_DATA_FILE_BLOCK_SIZE); + if (!dev_name) { + pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); + error = -ENOENT; + goto err_deactivate; + } + error = parse_options(&options, (char *)data); if (error != 0) { pr_err("incfs: Options parsing error. %d\n", error); - goto err; + goto err_deactivate; } sb->s_bdi->ra_pages = options.readahead_pages; if (!dev_name) { pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); error = -ENOENT; - goto err; + goto err_free_opts; } error = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, @@ -1782,57 +1792,66 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, !d_really_is_positive(backing_dir_path.dentry)) { pr_err("incfs: Error accessing: %s.\n", dev_name); - goto err; + goto err_free_opts; } src_fs_sb = backing_dir_path.dentry->d_sb; sb->s_maxbytes = src_fs_sb->s_maxbytes; + sb->s_stack_depth = src_fs_sb->s_stack_depth + 1; - mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + error = -EINVAL; + goto err_put_path; + } + mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); if (IS_ERR_OR_NULL(mi)) { error = PTR_ERR(mi); pr_err("incfs: Error allocating mount info. %d\n", error); - mi = NULL; - goto err; + goto err_put_path; } + sb->s_fs_info = mi; + mi->mi_backing_dir_path = backing_dir_path; index_dir = open_or_create_special_dir(backing_dir_path.dentry, - INCFS_INDEX_NAME); + INCFS_INDEX_NAME, &dir_created); if (IS_ERR_OR_NULL(index_dir)) { error = PTR_ERR(index_dir); pr_err("incfs: Can't find or create .index dir in %s\n", dev_name); /* No need to null index_dir since we don't put it */ - goto err; + goto err_put_path; } + mi->mi_index_dir = index_dir; + mi->mi_index_free = dir_created; incomplete_dir = open_or_create_special_dir(backing_dir_path.dentry, - INCFS_INCOMPLETE_NAME); + INCFS_INCOMPLETE_NAME, + &dir_created); if (IS_ERR_OR_NULL(incomplete_dir)) { error = PTR_ERR(incomplete_dir); pr_err("incfs: Can't find or create .incomplete dir in %s\n", dev_name); /* No need to null incomplete_dir since we don't put it */ - goto err; + goto err_put_path; } mi->mi_incomplete_dir = incomplete_dir; + mi->mi_incomplete_free = dir_created; - sb->s_fs_info = mi; root_inode = fetch_regular_inode(sb, backing_dir_path.dentry); if (IS_ERR(root_inode)) { error = PTR_ERR(root_inode); - goto err; + goto err_put_path; } sb->s_root = d_make_root(root_inode); if (!sb->s_root) { error = -ENOMEM; - goto err; + goto err_put_path; } error = incfs_init_dentry(sb->s_root, &backing_dir_path); if (error) - goto err; + goto err_put_path; mi->mi_backing_dir_path = backing_dir_path; sb->s_flags |= SB_ACTIVE; @@ -1840,12 +1859,14 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, pr_debug("incfs: mount\n"); free_options(&options); return dget(sb->s_root); -err: - sb->s_fs_info = NULL; + +err_put_path: path_put(&backing_dir_path); - incfs_free_mount_info(mi); - deactivate_locked_super(sb); +err_free_opts: free_options(&options); +err_deactivate: + deactivate_locked_super(sb); + pr_err("incfs: mount failed %d\n", error); return ERR_PTR(error); } @@ -1880,14 +1901,26 @@ out: void incfs_kill_sb(struct super_block *sb) { struct mount_info *mi = sb->s_fs_info; - struct inode *dinode = d_inode(mi->mi_backing_dir_path.dentry); + struct inode *dinode = NULL; pr_debug("incfs: unmount\n"); - vfs_rmdir(dinode, mi->mi_index_dir); - vfs_rmdir(dinode, mi->mi_incomplete_dir); + if (mi) { + if (mi->mi_backing_dir_path.dentry) + dinode = d_inode(mi->mi_backing_dir_path.dentry); + + if (dinode) { + if (mi->mi_index_dir && mi->mi_index_free) + vfs_rmdir(dinode, mi->mi_index_dir); + + if (mi->mi_incomplete_dir && mi->mi_incomplete_free) + vfs_rmdir(dinode, mi->mi_incomplete_dir); + } + + incfs_free_mount_info(mi); + sb->s_fs_info = NULL; + } kill_anon_super(sb); - incfs_free_mount_info(mi); } static int show_options(struct seq_file *m, struct dentry *root) diff --git a/fs/inode.c b/fs/inode.c index 638d5d5bf42df..9246236bcdcaf 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -307,7 +307,7 @@ void drop_nlink(struct inode *inode) if (!inode->i_nlink) atomic_long_inc(&inode->i_sb->s_remove_count); } -EXPORT_SYMBOL(drop_nlink); +EXPORT_SYMBOL_NS(drop_nlink, ANDROID_GKI_VFS_EXPORT_ONLY); /** * clear_nlink - directly zero an inode's link count @@ -346,7 +346,7 @@ void set_nlink(struct inode *inode, unsigned int nlink) inode->__i_nlink = nlink; } } -EXPORT_SYMBOL(set_nlink); +EXPORT_SYMBOL_NS(set_nlink, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inc_nlink - directly increment an inode's link count @@ -399,7 +399,7 @@ void inode_init_once(struct inode *inode) __address_space_init_once(&inode->i_data); i_size_ordered_init(inode); } -EXPORT_SYMBOL(inode_init_once); +EXPORT_SYMBOL_NS(inode_init_once, ANDROID_GKI_VFS_EXPORT_ONLY); static void init_once(void *foo) { @@ -423,7 +423,7 @@ void ihold(struct inode *inode) { WARN_ON(atomic_inc_return(&inode->i_count) < 2); } -EXPORT_SYMBOL(ihold); +EXPORT_SYMBOL_NS(ihold, ANDROID_GKI_VFS_EXPORT_ONLY); static void inode_lru_list_add(struct inode *inode) { @@ -503,7 +503,7 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); } -EXPORT_SYMBOL(__insert_inode_hash); +EXPORT_SYMBOL_NS(__insert_inode_hash, ANDROID_GKI_VFS_EXPORT_ONLY); /** * __remove_inode_hash - remove an inode from the hash @@ -519,7 +519,7 @@ void __remove_inode_hash(struct inode *inode) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); } -EXPORT_SYMBOL(__remove_inode_hash); +EXPORT_SYMBOL_NS(__remove_inode_hash, ANDROID_GKI_VFS_EXPORT_ONLY); void clear_inode(struct inode *inode) { @@ -539,7 +539,7 @@ void clear_inode(struct inode *inode) /* don't need i_lock here, no concurrent mods to i_state */ inode->i_state = I_FREEING | I_CLEAR; } -EXPORT_SYMBOL(clear_inode); +EXPORT_SYMBOL_NS(clear_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Free the inode passed in, removing it from the lists it is still connected @@ -1001,7 +1001,7 @@ void unlock_new_inode(struct inode *inode) wake_up_bit(&inode->i_state, __I_NEW); spin_unlock(&inode->i_lock); } -EXPORT_SYMBOL(unlock_new_inode); +EXPORT_SYMBOL_NS(unlock_new_inode, ANDROID_GKI_VFS_EXPORT_ONLY); void discard_new_inode(struct inode *inode) { @@ -1158,7 +1158,7 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, } return inode; } -EXPORT_SYMBOL(iget5_locked); +EXPORT_SYMBOL_NS(iget5_locked, ANDROID_GKI_VFS_EXPORT_ONLY); /** * iget_locked - obtain an inode from a mounted file system @@ -1290,7 +1290,7 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved) return res; } -EXPORT_SYMBOL(iunique); +EXPORT_SYMBOL_NS(iunique, ANDROID_GKI_VFS_EXPORT_ONLY); struct inode *igrab(struct inode *inode) { @@ -1373,7 +1373,7 @@ again: } return inode; } -EXPORT_SYMBOL(ilookup5); +EXPORT_SYMBOL_NS(ilookup5, ANDROID_GKI_VFS_EXPORT_ONLY); /** * ilookup - search for an inode in the inode cache @@ -1853,7 +1853,7 @@ void touch_atime(const struct path *path) skip_update: sb_end_write(inode->i_sb); } -EXPORT_SYMBOL(touch_atime); +EXPORT_SYMBOL_NS(touch_atime, ANDROID_GKI_VFS_EXPORT_ONLY); /* * The logic we want is @@ -1949,7 +1949,7 @@ int file_remove_privs(struct file *file) return error; } -EXPORT_SYMBOL(file_remove_privs); +EXPORT_SYMBOL_NS(file_remove_privs, ANDROID_GKI_VFS_EXPORT_ONLY); /** * file_update_time - update mtime and ctime time @@ -2130,7 +2130,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) " inode %s:%lu\n", mode, inode->i_sb->s_id, inode->i_ino); } -EXPORT_SYMBOL(init_special_inode); +EXPORT_SYMBOL_NS(init_special_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_init_owner - Init uid,gid,mode for new inode according to posix standards @@ -2156,7 +2156,7 @@ void inode_init_owner(struct inode *inode, const struct inode *dir, inode->i_gid = current_fsgid(); inode->i_mode = mode; } -EXPORT_SYMBOL(inode_init_owner); +EXPORT_SYMBOL_NS(inode_init_owner, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_owner_or_capable - check current task permissions to inode @@ -2210,7 +2210,7 @@ void inode_dio_wait(struct inode *inode) if (atomic_read(&inode->i_dio_count)) __inode_dio_wait(inode); } -EXPORT_SYMBOL(inode_dio_wait); +EXPORT_SYMBOL_NS(inode_dio_wait, ANDROID_GKI_VFS_EXPORT_ONLY); /* * inode_set_flags - atomically set some inode flags @@ -2234,7 +2234,7 @@ void inode_set_flags(struct inode *inode, unsigned int flags, WARN_ON_ONCE(flags & ~mask); set_mask_bits(&inode->i_flags, mask, flags); } -EXPORT_SYMBOL(inode_set_flags); +EXPORT_SYMBOL_NS(inode_set_flags, ANDROID_GKI_VFS_EXPORT_ONLY); void inode_nohighmem(struct inode *inode) { @@ -2271,7 +2271,7 @@ struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode) WARN(1, "invalid file time granularity: %u", gran); return t; } -EXPORT_SYMBOL(timestamp_truncate); +EXPORT_SYMBOL_NS(timestamp_truncate, ANDROID_GKI_VFS_EXPORT_ONLY); /** * current_time - Return FS time diff --git a/fs/io_uring.c b/fs/io_uring.c index 5959b0359524c..fd188b9721511 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -3220,15 +3220,13 @@ static ssize_t loop_rw_iter(int rw, struct io_kiocb *req, struct iov_iter *iter) ret = nr; break; } - ret += nr; if (!iov_iter_is_bvec(iter)) { iov_iter_advance(iter, nr); } else { - req->rw.addr += nr; req->rw.len -= nr; - if (!req->rw.len) - break; + req->rw.addr += nr; } + ret += nr; if (nr != iovec.iov_len) break; } @@ -7350,7 +7348,6 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset) fput(fpl->fp[i]); } else { kfree_skb(skb); - free_uid(fpl->user); kfree(fpl); } diff --git a/fs/ioctl.c b/fs/ioctl.c index 4e6cc0a7d69c9..32d8bd3f958b6 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -146,7 +146,7 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, return 1; return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; } -EXPORT_SYMBOL(fiemap_fill_next_extent); +EXPORT_SYMBOL_NS(fiemap_fill_next_extent, ANDROID_GKI_VFS_EXPORT_ONLY); /** * fiemap_prep - check validity of requested flags for fiemap @@ -191,7 +191,7 @@ int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, ret = filemap_write_and_wait(inode->i_mapping); return ret; } -EXPORT_SYMBOL(fiemap_prep); +EXPORT_SYMBOL_NS(fiemap_prep, ANDROID_GKI_VFS_EXPORT_ONLY); static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) { diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index f62b5a5015668..ecbc8ef0da176 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1612,3 +1612,4 @@ static void __exit exit_iso9660_fs(void) module_init(init_iso9660_fs) module_exit(exit_iso9660_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile index 126b4da6c7de8..b64f93331643b 100644 --- a/fs/jbd2/Makefile +++ b/fs/jbd2/Makefile @@ -3,6 +3,8 @@ # Makefile for the linux journaling routines. # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + obj-$(CONFIG_JBD2) += jbd2.o jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b748329bb0bab..099e4319851d8 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -3014,6 +3014,7 @@ static void __exit journal_exit(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(journal_init); module_exit(journal_exit); diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 837cd55fd4c5e..b288c8ae1236b 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -415,15 +415,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); ret = -EIO; - goto out_sum_exit; + goto out_free; } jffs2_calc_trigger_levels(c); return 0; - out_sum_exit: - jffs2_sum_exit(c); out_free: kvfree(c->blocks); diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 7170de78cd260..78858f6e95839 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -602,8 +602,8 @@ out_root: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); kvfree(c->blocks); - jffs2_clear_xattr_subsystem(c); out_inohash: + jffs2_clear_xattr_subsystem(c); kfree(c->inocache_list); out_wbuf: jffs2_flash_cleanup(c); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 29671e33a1714..b676056826beb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -136,7 +136,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (!s) { JFFS2_WARNING("Can't allocate memory for summary\n"); ret = -ENOMEM; - goto out_buf; + goto out; } } @@ -275,15 +275,13 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } ret = 0; out: - jffs2_sum_reset_collected(s); - kfree(s); - out_buf: if (buf_size) kfree(flashbuf); #ifndef __ECOS else mtd_unpoint(c->mtd, 0, c->mtd->size); #endif + kfree(s); return ret; } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 81ca58c10b728..16dcc359fd359 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -439,3 +439,4 @@ MODULE_DESCRIPTION("The Journalling Flash File System, v2"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for // the sake of this tag. It's Free Software. +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index e58ae29a223d7..aedad59f8a458 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -148,7 +148,6 @@ static const s8 budtab[256] = { * 0 - success * -ENOMEM - insufficient memory * -EIO - i/o error - * -EINVAL - wrong bmap data */ int dbMount(struct inode *ipbmap) { @@ -180,12 +179,6 @@ int dbMount(struct inode *ipbmap) bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree); bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage); bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); - if (!bmp->db_numag) { - release_metapage(mp); - kfree(bmp); - return -EINVAL; - } - bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel); bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag); bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index b2dc4d1f9dcc5..8a02b9bdea19b 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -37,6 +37,7 @@ MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *jfs_inode_cachep; diff --git a/fs/libfs.c b/fs/libfs.c index 1b4a215f7b749..40359a0b57e13 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -225,7 +225,7 @@ ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t { return -EISDIR; } -EXPORT_SYMBOL(generic_read_dir); +EXPORT_SYMBOL_NS(generic_read_dir, ANDROID_GKI_VFS_EXPORT_ONLY); const struct file_operations simple_dir_operations = { .open = dcache_dir_open, diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 34f546404aa11..8a9d4a28290d1 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -719,4 +719,5 @@ static void __exit exit_minix_fs(void) module_init(init_minix_fs) module_exit(exit_minix_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/mpage.c b/fs/mpage.c index 00ac5c329b59f..55d2bfa062920 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -428,7 +428,7 @@ void mpage_readahead(struct readahead_control *rac, get_block_t get_block) if (args.bio) mpage_bio_submit(REQ_OP_READ, REQ_RAHEAD, args.bio); } -EXPORT_SYMBOL(mpage_readahead); +EXPORT_SYMBOL_NS(mpage_readahead, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This isn't called much at all @@ -446,7 +446,7 @@ int mpage_readpage(struct page *page, get_block_t get_block) mpage_bio_submit(REQ_OP_READ, 0, args.bio); return 0; } -EXPORT_SYMBOL(mpage_readpage); +EXPORT_SYMBOL_NS(mpage_readpage, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Writing is not so simple. diff --git a/fs/namei.c b/fs/namei.c index 1e6f5f6751a2b..d7b609a6f6dc9 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2533,7 +2533,7 @@ int kern_path(const char *name, unsigned int flags, struct path *path) return filename_lookup(AT_FDCWD, getname_kernel(name), flags, path, NULL); } -EXPORT_SYMBOL(kern_path); +EXPORT_SYMBOL_NS(kern_path, ANDROID_GKI_VFS_EXPORT_ONLY); /** * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair @@ -2887,7 +2887,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, fsnotify_create(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_create); +EXPORT_SYMBOL_NS(vfs_create, ANDROID_GKI_VFS_EXPORT_ONLY); int vfs_mkobj(struct dentry *dentry, umode_t mode, int (*f)(struct dentry *, umode_t, void *), @@ -3727,7 +3727,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) fsnotify_mkdir(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_mkdir); +EXPORT_SYMBOL_NS(vfs_mkdir, ANDROID_GKI_VFS_EXPORT_ONLY); static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode) { @@ -3801,7 +3801,7 @@ out: d_delete_notify(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_rmdir); +EXPORT_SYMBOL_NS(vfs_rmdir, ANDROID_GKI_VFS_EXPORT_ONLY); long do_rmdir(int dfd, struct filename *name) { @@ -3924,7 +3924,7 @@ out: return error; } -EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL_NS(vfs_unlink, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Make sure that the actual truncation of the file will occur outside its @@ -4159,7 +4159,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de fsnotify_link(dir, inode, new_dentry); return error; } -EXPORT_SYMBOL(vfs_link); +EXPORT_SYMBOL_NS(vfs_link, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Hardlinks are often used in delicate situations. We avoid @@ -4419,7 +4419,7 @@ out: return error; } -EXPORT_SYMBOL(vfs_rename); +EXPORT_SYMBOL_NS(vfs_rename, ANDROID_GKI_VFS_EXPORT_ONLY); static int do_renameat2(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags) diff --git a/fs/namespace.c b/fs/namespace.c index 046b084136c51..6d1f11a6b2904 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -415,7 +415,7 @@ int mnt_want_write_file(struct file *file) sb_end_write(file_inode(file)->i_sb); return ret; } -EXPORT_SYMBOL_GPL(mnt_want_write_file); +EXPORT_SYMBOL_NS_GPL(mnt_want_write_file, ANDROID_GKI_VFS_EXPORT_ONLY); /** * __mnt_drop_write - give up write access to a mount @@ -457,7 +457,7 @@ void mnt_drop_write_file(struct file *file) __mnt_drop_write_file(file); sb_end_write(file_inode(file)->i_sb); } -EXPORT_SYMBOL(mnt_drop_write_file); +EXPORT_SYMBOL_NS(mnt_drop_write_file, ANDROID_GKI_VFS_EXPORT_ONLY); static int mnt_make_readonly(struct mount *mnt) { diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a5209643ac36c..b44219ce60b86 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -353,11 +353,12 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, struct cb_process_state *cps) { struct cb_devicenotifyargs *args = argp; - const struct pnfs_layoutdriver_type *ld = NULL; uint32_t i; __be32 res = 0; + struct nfs_client *clp = cps->clp; + struct nfs_server *server = NULL; - if (!cps->clp) { + if (!clp) { res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); goto out; } @@ -365,15 +366,23 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, for (i = 0; i < args->ndevs; i++) { struct cb_devicenotifyitem *dev = &args->devs[i]; - if (!ld || ld->id != dev->cbd_layout_type) { - pnfs_put_layoutdriver(ld); - ld = pnfs_find_layoutdriver(dev->cbd_layout_type); - if (!ld) - continue; + if (!server || + server->pnfs_curr_ld->id != dev->cbd_layout_type) { + rcu_read_lock(); + list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) + if (server->pnfs_curr_ld && + server->pnfs_curr_ld->id == dev->cbd_layout_type) { + rcu_read_unlock(); + goto found; + } + rcu_read_unlock(); + continue; } - nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id); + + found: + nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id); } - pnfs_put_layoutdriver(ld); + out: kfree(args->devs); return res; diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index ca8a4aa351dc9..1725079a05276 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -272,6 +272,10 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, n = ntohl(*p++); if (n == 0) goto out; + if (n > ULONG_MAX / sizeof(*args->devs)) { + status = htonl(NFS4ERR_BADXDR); + goto out; + } args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); if (!args->devs) { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f27ecc2e490f2..f17ad75d0afd8 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -2337,6 +2337,7 @@ static void __exit exit_nfs_fs(void) /* Not quite true; I just maintain it */ MODULE_AUTHOR("Olaf Kirch "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_param(enable_ino64, bool, 0644); module_init(init_nfs_fs) diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 5e6453e9b3079..f6676af37d5db 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -948,7 +948,7 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, error = decode_filename_inline(xdr, &entry->name, &entry->len); if (unlikely(error)) - return -EAGAIN; + return error; /* * The type (size and byte order) of nfscookie isn't defined in diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b5a9379b14504..dff6b52d26a85 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -1964,6 +1964,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, bool plus) { struct user_namespace *userns = rpc_userns(entry->server->client); + struct nfs_entry old = *entry; __be32 *p; int error; u64 new_cookie; @@ -1983,15 +1984,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, error = decode_fileid3(xdr, &entry->ino); if (unlikely(error)) - return -EAGAIN; + return error; error = decode_inline_filename3(xdr, &entry->name, &entry->len); if (unlikely(error)) - return -EAGAIN; + return error; error = decode_cookie3(xdr, &new_cookie); if (unlikely(error)) - return -EAGAIN; + return error; entry->d_type = DT_UNKNOWN; @@ -1999,7 +2000,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, entry->fattr->valid = 0; error = decode_post_op_attr(xdr, entry->fattr, userns); if (unlikely(error)) - return -EAGAIN; + return error; if (entry->fattr->valid & NFS_ATTR_FATTR_V3) entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); @@ -2014,8 +2015,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, return -EAGAIN; if (*p != xdr_zero) { error = decode_nfs_fh3(xdr, entry->fh); - if (unlikely(error)) - return -EAGAIN; + if (unlikely(error)) { + if (error == -E2BIG) + goto out_truncated; + return error; + } } else zero_nfs_fh3(entry->fh); } @@ -2024,6 +2028,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, entry->cookie = new_cookie; return 0; + +out_truncated: + dprintk("NFS: directory entry contains invalid file handle\n"); + *entry = old; + return -EAGAIN; } /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4d4ce7fd4e707..a3612c184f887 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8208,7 +8208,6 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) case -NFS4ERR_DEADSESSION: nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); - return; } if (args->dir == NFS4_CDFC4_FORE_OR_BOTH && res->dir != NFS4_CDFS4_BOTH) { diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index d09bcfd7db894..b422e8a09d251 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -309,6 +309,7 @@ static void __exit exit_nfs_v4(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_nfs_v4); module_exit(exit_nfs_v4); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index b3b9eff5d5727..5370e082aded5 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -92,17 +92,6 @@ find_pnfs_driver(u32 id) return local; } -const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id) -{ - return find_pnfs_driver(id); -} - -void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld) -{ - if (ld) - module_put(ld->owner); -} - void unset_pnfs_layoutdriver(struct nfs_server *nfss) { diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 11d9ed9addc06..0212fe32e63aa 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -236,8 +236,6 @@ struct pnfs_devicelist { extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); -extern const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id); -extern void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld); /* nfs4proc.c */ extern size_t max_response_pages(struct nfs_server *server); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index cc926e69ee9ba..bde4c362841f0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -314,10 +314,7 @@ static void nfs_mapping_set_error(struct page *page, int error) struct address_space *mapping = page_file_mapping(page); SetPageError(page); - filemap_set_wb_err(mapping, error); - if (mapping->host) - errseq_set(&mapping->host->i_sb->s_wb_err, - error == -ENOSPC ? -ENOSPC : -EIO); + mapping_set_error(mapping, error); nfs_set_pageerror(mapping); } diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index acd0898e3866d..e5aad1c10ea32 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -641,7 +641,7 @@ nfsd_file_cache_init(void) if (!nfsd_filecache_wq) goto out; - nfsd_file_hashtbl = kvcalloc(NFSD_FILE_HASH_SIZE, + nfsd_file_hashtbl = kcalloc(NFSD_FILE_HASH_SIZE, sizeof(*nfsd_file_hashtbl), GFP_KERNEL); if (!nfsd_file_hashtbl) { pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n"); @@ -708,7 +708,7 @@ out_err: nfsd_file_slab = NULL; kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab = NULL; - kvfree(nfsd_file_hashtbl); + kfree(nfsd_file_hashtbl); nfsd_file_hashtbl = NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq = NULL; @@ -854,7 +854,7 @@ nfsd_file_cache_shutdown(void) fsnotify_wait_marks_destroyed(); kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab = NULL; - kvfree(nfsd_file_hashtbl); + kfree(nfsd_file_hashtbl); nfsd_file_hashtbl = NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq = NULL; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 84dd68091f422..d01d7929753ef 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4607,14 +4607,6 @@ nfsd_break_deleg_cb(struct file_lock *fl) return ret; } -/** - * nfsd_breaker_owns_lease - Check if lease conflict was resolved - * @fl: Lock state to check - * - * Return values: - * %true: Lease conflict was resolved - * %false: Lease conflict was not resolved. - */ static bool nfsd_breaker_owns_lease(struct file_lock *fl) { struct nfs4_delegation *dl = fl->fl_owner; @@ -4622,11 +4614,11 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl) struct nfs4_client *clp; if (!i_am_nfsd()) - return false; + return NULL; rqst = kthread_data(current); /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) - return false; + return NULL; clp = *(rqst->rq_lease_breaker); return dl->dl_stid.sc_client == clp; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index dedec4771ecc2..2796ecfdfd5d0 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1584,5 +1584,6 @@ static void __exit exit_nfsd(void) MODULE_AUTHOR("Olaf Kirch "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_nfsd) module_exit(exit_nfsd) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index bbd01e8397f6e..9c9de2b66e641 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -223,7 +223,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) unsigned long cnt = argp->len; unsigned int nvecs; - dprintk("nfsd: WRITE %s %u bytes at %d\n", + dprintk("nfsd: WRITE %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), argp->len, argp->offset); diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index b8cc6a4b2e0ec..0ff336b0b25f9 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -33,7 +33,7 @@ struct nfsd_readargs { struct nfsd_writeargs { svc_fh fh; __u32 offset; - __u32 len; + int len; struct kvec first; }; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 4abd928b0bc83..ab1a5e8467f21 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -53,6 +53,7 @@ MODULE_AUTHOR("NTT Corp."); MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " "(NILFS)"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *nilfs_inode_cachep; struct kmem_cache *nilfs_transaction_cachep; diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 52ccd34b1e792..06c368ce3aa22 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -541,8 +541,8 @@ struct nls_table *load_nls_default(void) } EXPORT_SYMBOL(unregister_nls); -EXPORT_SYMBOL(unload_nls); -EXPORT_SYMBOL(load_nls); -EXPORT_SYMBOL(load_nls_default); +EXPORT_SYMBOL_NS(unload_nls, ANDROID_GKI_VFS_EXPORT_ONLY); +EXPORT_SYMBOL_NS(load_nls, ANDROID_GKI_VFS_EXPORT_ONLY); +EXPORT_SYMBOL_NS(load_nls_default, ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 162b3f160353c..498b8a435d7e1 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -578,3 +578,4 @@ module_init(init_nls_euc_jp) module_exit(exit_nls_euc_jp) MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c index a80a741a8676d..99ceec9085ecd 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -80,3 +80,4 @@ module_init(init_nls_koi8_ru) module_exit(exit_nls_koi8_ru) MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index cf222c9225d6d..ea18e4a2a691d 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1881,10 +1881,6 @@ int ntfs_read_inode_mount(struct inode *vi) } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); - if (!ni->attr_list_size) { - ntfs_error(sb, "Attr_list_size is zero"); - goto put_err_out; - } ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 0d7e948cb29c9..56edd625cf4d2 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3186,6 +3186,7 @@ MODULE_AUTHOR("Anton Altaparmakov "); MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc."); MODULE_VERSION(NTFS_VERSION); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); #ifdef DEBUG module_param(debug_msgs, bint, 0); MODULE_PARM_DESC(debug_msgs, "Enable debug messages."); diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 583820ec63e2d..5b3a8681f87ef 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -615,6 +615,7 @@ static void __exit exit_dlmfs_fs(void) MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("OCFS2 DLM-Filesystem"); module_init(init_dlmfs_fs) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 477ad05a34ea2..f48369c021114 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -71,6 +71,7 @@ static struct dentry *ocfs2_debugfs_root; MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("OCFS2 cluster file system"); struct mount_options @@ -1110,6 +1111,17 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } + root = d_make_root(inode); + if (!root) { + status = -ENOMEM; + mlog_errno(status); + goto read_super_error; + } + + sb->s_root = root; + + ocfs2_complete_mount_recovery(osb); + osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj); if (!osb->osb_dev_kset) { @@ -1127,17 +1139,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } - root = d_make_root(inode); - if (!root) { - status = -ENOMEM; - mlog_errno(status); - goto read_super_error; - } - - sb->s_root = root; - - ocfs2_complete_mount_recovery(osb); - if (ocfs2_mount_local(osb)) snprintf(nodestr, sizeof(nodestr), "local"); else diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index ce93ccca86392..27143a2cd962a 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -20,6 +20,7 @@ MODULE_AUTHOR("Bob Copeland "); MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) { diff --git a/fs/open.c b/fs/open.c index 78f32d483aefb..b9d55ca3763b6 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1158,7 +1158,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode) } return file; } -EXPORT_SYMBOL(filp_open); +EXPORT_SYMBOL_NS(filp_open, ANDROID_GKI_VFS_EXPORT_ONLY); /* ANDROID: Allow drivers to open only block files from kernel mode */ struct file *filp_open_block(const char *filename, int flags, umode_t mode) @@ -1390,7 +1390,7 @@ int generic_file_open(struct inode * inode, struct file * filp) return 0; } -EXPORT_SYMBOL(generic_file_open); +EXPORT_SYMBOL_NS(generic_file_open, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This is used by subsystems that don't want seekable diff --git a/fs/orangefs/orangefs-mod.c b/fs/orangefs/orangefs-mod.c index 74a3d6337ef43..a76a6ba8b3553 100644 --- a/fs/orangefs/orangefs-mod.c +++ b/fs/orangefs/orangefs-mod.c @@ -36,6 +36,7 @@ int orangefs_dcache_timeout_msecs = 50; int orangefs_getattr_timeout_msecs = 50; MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("ORANGEFS Development Team"); MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS"); MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)"); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index e7f7163fae104..4a2ce2eeee887 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -20,6 +20,7 @@ MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Overlay filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct ovl_dir_cache; diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c index 2e244ada1f970..6d8d4bf208377 100644 --- a/fs/proc/bootconfig.c +++ b/fs/proc/bootconfig.c @@ -32,8 +32,6 @@ static int __init copy_xbc_key_value_list(char *dst, size_t size) int ret = 0; key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL); - if (!key) - return -ENOMEM; xbc_for_each_key_value(leaf, val) { ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 13f8e6f3d30f3..b1bcbe7aca0eb 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) name = arch_vma_name(vma); if (!name) { - const char *anon_name; + struct anon_vma_name *anon_name; if (!mm) { name = "[vdso]"; @@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) goto done; } - anon_name = vma_anon_name(vma); + anon_name = anon_vma_name(vma); if (anon_name) { seq_pad(m, ' '); - seq_printf(m, "[anon:%s]", anon_name); + seq_printf(m, "[anon:%s]", anon_name->name); } } diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index ce03c3dbb5c30..b1ebf7b61732c 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -143,22 +143,21 @@ static void pstore_timer_kick(void) mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); } -static bool pstore_cannot_block_path(enum kmsg_dump_reason reason) +/* + * Should pstore_dump() wait for a concurrent pstore_dump()? If + * not, the current pstore_dump() will report a failure to dump + * and return. + */ +static bool pstore_cannot_wait(enum kmsg_dump_reason reason) { - /* - * In case of NMI path, pstore shouldn't be blocked - * regardless of reason. - */ + /* In NMI path, pstore shouldn't block regardless of reason. */ if (in_nmi()) return true; switch (reason) { /* In panic case, other cpus are stopped by smp_send_stop(). */ case KMSG_DUMP_PANIC: - /* - * Emergency restart shouldn't be blocked by spinning on - * pstore_info::buf_lock. - */ + /* Emergency restart shouldn't be blocked. */ case KMSG_DUMP_EMERG: return true; default: @@ -389,19 +388,21 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long total = 0; const char *why; unsigned int part = 1; - unsigned long flags = 0; int ret; why = kmsg_dump_reason_str(reason); - if (pstore_cannot_block_path(reason)) { - if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) { - pr_err("dump skipped in %s path because of concurrent dump\n", - in_nmi() ? "NMI" : why); + if (down_trylock(&psinfo->buf_lock)) { + /* Failed to acquire lock: give up if we cannot wait. */ + if (pstore_cannot_wait(reason)) { + pr_err("dump skipped in %s path: may corrupt error record\n", + in_nmi() ? "NMI" : why); + return; + } + if (down_interruptible(&psinfo->buf_lock)) { + pr_err("could not grab semaphore?!\n"); return; } - } else { - spin_lock_irqsave(&psinfo->buf_lock, flags); } oopscount++; @@ -463,7 +464,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, total += record.size; part++; } - spin_unlock_irqrestore(&psinfo->buf_lock, flags); + + up(&psinfo->buf_lock); } static struct kmsg_dumper pstore_dumper = { @@ -589,7 +591,7 @@ int pstore_register(struct pstore_info *psi) psi->write_user = pstore_write_user_compat; psinfo = psi; mutex_init(&psinfo->read_mutex); - spin_lock_init(&psinfo->buf_lock); + sema_init(&psinfo->buf_lock, 1); if (psi->flags & PSTORE_FLAGS_DMESG) allocate_buf_for_compression(); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 3fb7fc819b4fc..704fb7d09f0e2 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -420,4 +420,5 @@ static void __exit exit_qnx4_fs(void) module_init(init_qnx4_fs) module_exit(exit_qnx4_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c index 61191f7bdf62d..ac771f0e02388 100644 --- a/fs/qnx6/inode.c +++ b/fs/qnx6/inode.c @@ -679,3 +679,4 @@ static void __exit exit_qnx6_fs(void) module_init(init_qnx6_fs) module_exit(exit_qnx6_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/read_write.c b/fs/read_write.c index 75f764b434184..ae703cb905997 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -471,7 +471,7 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) return ret; return __kernel_read(file, buf, count, pos); } -EXPORT_SYMBOL(kernel_read); +EXPORT_SYMBOL_NS(kernel_read, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { @@ -580,7 +580,7 @@ ssize_t kernel_write(struct file *file, const void *buf, size_t count, file_end_write(file); return ret; } -EXPORT_SYMBOL(kernel_write); +EXPORT_SYMBOL_NS(kernel_write, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 913f5af9bf248..d84c2f2df0b72 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2655,6 +2655,7 @@ MODULE_ALIAS_FS("reiserfs"); MODULE_DESCRIPTION("ReiserFS journaled filesystem"); MODULE_AUTHOR("Hans Reiser "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_reiserfs_fs); module_exit(exit_reiserfs_fs); diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 259f684d9236e..c335658c2e0f3 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -666,3 +666,4 @@ module_exit(exit_romfs_fs); MODULE_DESCRIPTION("Direct-MTD Capable RomFS"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */ +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/splice.c b/fs/splice.c index 866d5c2367b23..036a47937c18e 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -326,7 +326,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, return ret; } -EXPORT_SYMBOL(generic_file_splice_read); +EXPORT_SYMBOL_NS(generic_file_splice_read, ANDROID_GKI_VFS_EXPORT_ONLY); const struct pipe_buf_operations default_pipe_buf_ops = { .release = generic_pipe_buf_release, @@ -722,7 +722,7 @@ done: return ret; } -EXPORT_SYMBOL(iter_file_splice_write); +EXPORT_SYMBOL_NS(iter_file_splice_write, ANDROID_GKI_VFS_EXPORT_ONLY); /** * generic_splice_sendpage - splice data from a pipe to a socket diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 88cc94be10765..83c48769f4140 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -498,3 +498,4 @@ module_exit(exit_squashfs_fs); MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); MODULE_AUTHOR("Phillip Lougher "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/stat.c b/fs/stat.c index 1196af4d1ea03..c8a078f3acf89 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -49,7 +49,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) stat->blksize = i_blocksize(inode); stat->blocks = inode->i_blocks; } -EXPORT_SYMBOL(generic_fillattr); +EXPORT_SYMBOL_NS(generic_fillattr, ANDROID_GKI_VFS_EXPORT_ONLY); /** * vfs_getattr_nosec - getattr without security checks diff --git a/fs/super.c b/fs/super.c index bae3fe80f852e..ae2b97dabe312 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1435,7 +1435,7 @@ error_bdev: error: return ERR_PTR(error); } -EXPORT_SYMBOL(mount_bdev); +EXPORT_SYMBOL_NS(mount_bdev, ANDROID_GKI_VFS_EXPORT_ONLY); void kill_block_super(struct super_block *sb) { @@ -1449,7 +1449,7 @@ void kill_block_super(struct super_block *sb) blkdev_put(bdev, mode | FMODE_EXCL); } -EXPORT_SYMBOL(kill_block_super); +EXPORT_SYMBOL_NS(kill_block_super, ANDROID_GKI_VFS_EXPORT_ONLY); #endif struct dentry *mount_nodev(struct file_system_type *fs_type, diff --git a/fs/sync.c b/fs/sync.c index 8e1c2272470fe..9bbaa61994fc3 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -66,7 +66,7 @@ int sync_filesystem(struct super_block *sb) return ret; return __sync_filesystem(sb, 1); } -EXPORT_SYMBOL(sync_filesystem); +EXPORT_SYMBOL_NS(sync_filesystem, ANDROID_GKI_VFS_EXPORT_ONLY); static void sync_inodes_one_sb(struct super_block *sb, void *arg) { diff --git a/fs/sysv/super.c b/fs/sysv/super.c index cc8e2ed155c84..e5383bff5dade 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -592,3 +592,4 @@ static void __exit exit_sysv_fs(void) module_init(init_sysv_fs) module_exit(exit_sysv_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index bd250ed0a26fa..a17cb7c8214f0 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -432,8 +432,6 @@ out_inode: make_bad_inode(inode); if (!instantiated) iput(inode); - else if (whiteout) - iput(*whiteout); out_budg: ubifs_release_budget(c, &req); if (!instantiated) @@ -1325,7 +1323,6 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, if (flags & RENAME_WHITEOUT) { union ubifs_dev_desc *dev = NULL; - struct ubifs_budget_req wht_req; dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) { @@ -1347,23 +1344,6 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); ubifs_assert(c, !whiteout_ui->dirty); - - memset(&wht_req, 0, sizeof(struct ubifs_budget_req)); - wht_req.dirtied_ino = 1; - wht_req.dirtied_ino_d = ALIGN(whiteout_ui->data_len, 8); - /* - * To avoid deadlock between space budget (holds ui_mutex and - * waits wb work) and writeback work(waits ui_mutex), do space - * budget before ubifs inodes locked. - */ - err = ubifs_budget_space(c, &wht_req); - if (err) { - iput(whiteout); - goto out_release; - } - - /* Add the old_dentry size to the old_dir size. */ - old_sz -= CALC_DENT_SIZE(fname_len(&old_nm)); } lock_4_inodes(old_dir, new_dir, new_inode, whiteout); @@ -1438,6 +1418,18 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, } if (whiteout) { + struct ubifs_budget_req wht_req = { .dirtied_ino = 1, + .dirtied_ino_d = \ + ALIGN(ubifs_inode(whiteout)->data_len, 8) }; + + err = ubifs_budget_space(c, &wht_req); + if (err) { + kfree(whiteout_ui->data); + whiteout_ui->data_len = 0; + iput(whiteout); + goto out_release; + } + inc_nlink(whiteout); mark_inode_dirty(whiteout); diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 354457e846cda..f4826b6da6828 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -570,7 +570,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping, } if (!PagePrivate(page)) { - attach_page_private(page, (void *)1); + SetPagePrivate(page); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } @@ -947,7 +947,7 @@ static int do_writepage(struct page *page, int len) release_existing_page_budget(c); atomic_long_dec(&c->dirty_pg_cnt); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); kunmap(page); @@ -1303,7 +1303,7 @@ static void ubifs_invalidatepage(struct page *page, unsigned int offset, release_existing_page_budget(c); atomic_long_dec(&c->dirty_pg_cnt); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); } @@ -1470,8 +1470,8 @@ static int ubifs_migrate_page(struct address_space *mapping, return rc; if (PagePrivate(page)) { - detach_page_private(page); - attach_page_private(newpage, (void *)1); + ClearPagePrivate(page); + SetPagePrivate(newpage); } if (mode != MIGRATE_SYNC_NO_COPY) @@ -1495,7 +1495,7 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) return 0; ubifs_assert(c, PagePrivate(page)); ubifs_assert(c, 0); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); return 1; } @@ -1566,7 +1566,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf) else { if (!PageChecked(page)) ubifs_convert_page_budget(c); - attach_page_private(page, (void *)1); + SetPagePrivate(page); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 89b671ad0f9aa..eae9cf5a57b05 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -846,42 +846,16 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) */ n = aligned_len >> c->max_write_shift; if (n) { - int m = n - 1; - + n <<= c->max_write_shift; dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, wbuf->offs); - - if (m) { - /* '(n-1)<max_write_shift < len' is always true. */ - m <<= c->max_write_shift; - err = ubifs_leb_write(c, wbuf->lnum, buf + written, - wbuf->offs, m); - if (err) - goto out; - wbuf->offs += m; - aligned_len -= m; - len -= m; - written += m; - } - - /* - * The non-written len of buf may be less than 'n' because - * parameter 'len' is not 8 bytes aligned, so here we read - * min(len, n) bytes from buf. - */ - n = 1 << c->max_write_shift; - memcpy(wbuf->buf, buf + written, min(len, n)); - if (n > len) { - ubifs_assert(c, n - len < 8); - ubifs_pad(c, wbuf->buf + len, n - len); - } - - err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, n); + err = ubifs_leb_write(c, wbuf->lnum, buf + written, + wbuf->offs, n); if (err) goto out; wbuf->offs += n; aligned_len -= n; - len -= min(len, n); + len -= n; written += n; } diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 8db380a000325..4363d85a3fd40 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -107,7 +107,7 @@ static int setflags(struct inode *inode, int flags) struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1, - .dirtied_ino_d = ALIGN(ui->data_len, 8) }; + .dirtied_ino_d = ui->data_len }; err = ubifs_budget_space(c, &req); if (err) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 6a8f9efc2e2f0..54093d0a8f025 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2475,6 +2475,7 @@ static void __exit ubifs_exit(void) module_exit(ubifs_exit); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_VERSION(__stringify(UBIFS_VERSION)); MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); MODULE_DESCRIPTION("UBIFS - UBI File System"); diff --git a/fs/udf/super.c b/fs/udf/super.c index 3448098e54768..c31c5c44b9fe5 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2545,5 +2545,6 @@ static unsigned int udf_count_free(struct super_block *sb) MODULE_AUTHOR("Ben Fennema"); MODULE_DESCRIPTION("Universal Disk Format Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_udf_fs) module_exit(exit_udf_fs) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 983558b572c70..e0d7149f76ca3 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1542,3 +1542,4 @@ static void __exit exit_ufs_fs(void) module_init(init_ufs_fs) module_exit(exit_ufs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 1c171cb26412e..da8c8409528dc 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -880,7 +880,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file) new_flags, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), - NULL_VM_UFFD_CTX, vma_anon_name(vma)); + NULL_VM_UFFD_CTX, anon_vma_name(vma)); if (prev) vma = prev; else @@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), ((struct vm_userfaultfd_ctx){ ctx }), - vma_anon_name(vma)); + anon_vma_name(vma)); if (prev) { vma = prev; goto next; @@ -1617,7 +1617,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx, prev = vma_merge(mm, prev, start, vma_end, new_flags, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), - NULL_VM_UFFD_CTX, vma_anon_name(vma)); + NULL_VM_UFFD_CTX, anon_vma_name(vma)); if (prev) { vma = prev; goto next; diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c index c578e772cbd58..0d4a0408cbd7e 100644 --- a/fs/vboxsf/super.c +++ b/fs/vboxsf/super.c @@ -482,4 +482,5 @@ module_exit(vboxsf_fini); MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access"); MODULE_AUTHOR("Oracle Corporation"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_ALIAS_FS("vboxsf"); diff --git a/fs/verity/Makefile b/fs/verity/Makefile index 435559a4fa9ea..4b8323450f90a 100644 --- a/fs/verity/Makefile +++ b/fs/verity/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + obj-$(CONFIG_FS_VERITY) += enable.o \ hash_algs.o \ init.o \ diff --git a/fs/xattr.c b/fs/xattr.c index d6bf5a7e2420e..f157f0b1bdfc2 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -291,7 +291,7 @@ retry_deleg: } return error; } -EXPORT_SYMBOL_GPL(vfs_setxattr); +EXPORT_SYMBOL_NS_GPL(vfs_setxattr, ANDROID_GKI_VFS_EXPORT_ONLY); static ssize_t xattr_getsecurity(struct inode *inode, const char *name, void *value, @@ -405,7 +405,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { return __vfs_getxattr(dentry, dentry->d_inode, name, value, size, 0); } -EXPORT_SYMBOL_GPL(vfs_getxattr); +EXPORT_SYMBOL_NS_GPL(vfs_getxattr, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_listxattr(struct dentry *dentry, char *list, size_t size) @@ -425,7 +425,7 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size) } return error; } -EXPORT_SYMBOL_GPL(vfs_listxattr); +EXPORT_SYMBOL_NS_GPL(vfs_listxattr, ANDROID_GKI_VFS_EXPORT_ONLY); int __vfs_removexattr(struct dentry *dentry, const char *name) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e3e229e52512a..6a7724a3560ac 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -2224,3 +2224,4 @@ module_exit(exit_xfs_fs); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index e60759d8bb5fb..0ed752c6ef25f 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -1800,5 +1800,6 @@ MODULE_AUTHOR("Damien Le Moal"); MODULE_DESCRIPTION("Zone file system for zoned block devices"); MODULE_LICENSE("GPL"); MODULE_ALIAS_FS("zonefs"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(zonefs_init); module_exit(zonefs_exit); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 5a9786e6b5546..0571701ab1c57 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -82,9 +82,6 @@ struct coredump_params { unsigned long mm_flags; loff_t written; loff_t pos; - int vma_count; - size_t vma_data_size; - struct core_vma_metadata *vma_meta; }; /* diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index 0e6e84db06f67..c8fc9792ac776 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -24,7 +24,6 @@ #include #include #include -#include /* percpu_counter batch for blkg_[rw]stats, per-cpu drift doesn't matter */ #define BLKG_STAT_CPU_BATCH (INT_MAX / 2) @@ -600,21 +599,6 @@ static inline void blkcg_clear_delay(struct blkcg_gq *blkg) atomic_dec(&blkg->blkcg->css.cgroup->congestion_count); } -/** - * blk_cgroup_mergeable - Determine whether to allow or disallow merges - * @rq: request to merge into - * @bio: bio to merge - * - * @bio and @rq should belong to the same cgroup and their issue_as_root should - * match. The latter is necessary as we don't want to throttle e.g. a metadata - * update because it happens to be next to a regular IO. - */ -static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio) -{ - return rq->bio->bi_blkg == bio->bi_blkg && - bio_issue_as_root_blkg(rq->bio) == bio_issue_as_root_blkg(bio); -} - void blk_cgroup_bio_start(struct bio *bio); void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta); void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay); @@ -670,7 +654,6 @@ static inline void blkg_put(struct blkcg_gq *blkg) { } static inline bool blkcg_punt_bio_submit(struct bio *bio) { return false; } static inline void blkcg_bio_issue_init(struct bio *bio) { } static inline void blk_cgroup_bio_start(struct bio *bio) { } -static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio) { return true; } #define blk_queue_for_each_rl(rl, q) \ for ((rl) = &(q)->root_rl; (rl); (rl) = NULL) diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index cd894eaea3496..142c98a3497d9 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -78,7 +78,7 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, #endif /* CONFIG_BPF_LSM */ #endif #ifdef CONFIG_FUSE_BPF -BPF_PROG_TYPE(BPF_PROG_TYPE_FUSE, fuse, struct fuse_args, struct fuse_args) +BPF_PROG_TYPE(BPF_PROG_TYPE_FUSE, fuse, struct fuse_bpf_args, struct fuse_bpf_args) #endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 67b2190b1daef..ceecd7829d355 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -435,6 +435,18 @@ static inline void cgroup_put(struct cgroup *cgrp) css_put(&cgrp->self); } +extern struct mutex cgroup_mutex; + +static inline void cgroup_lock(void) +{ + mutex_lock(&cgroup_mutex); +} + +static inline void cgroup_unlock(void) +{ + mutex_unlock(&cgroup_mutex); +} + /** * task_css_set_check - obtain a task's css_set with extra access conditions * @task: the task to obtain css_set for @@ -449,7 +461,6 @@ static inline void cgroup_put(struct cgroup *cgrp) * as locks used during the cgroup_subsys::attach() methods. */ #ifdef CONFIG_PROVE_RCU -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; #define task_css_set_check(task, __c) \ rcu_dereference_check((task)->cgroups, \ @@ -709,6 +720,8 @@ struct cgroup; static inline u64 cgroup_id(struct cgroup *cgrp) { return 1; } static inline void css_get(struct cgroup_subsys_state *css) {} static inline void css_put(struct cgroup_subsys_state *css) {} +static inline void cgroup_lock(void) {} +static inline void cgroup_unlock(void) {} static inline int cgroup_attach_task_all(struct task_struct *from, struct task_struct *t) { return 0; } static inline int cgroupstats_build(struct cgroupstats *stats, diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 5300d0cb70f7e..e58e8c2077828 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -11,8 +11,6 @@ struct core_vma_metadata { unsigned long start, end; unsigned long flags; unsigned long dump_size; - unsigned long pgoff; - struct file *file; }; /* @@ -26,6 +24,9 @@ extern int dump_align(struct coredump_params *cprm, int align); extern void dump_truncate(struct coredump_params *cprm); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + size_t *vma_data_size_ptr); #ifdef CONFIG_COREDUMP extern void do_coredump(const kernel_siginfo_t *siginfo); #else diff --git a/include/linux/damon.h b/include/linux/damon.h new file mode 100644 index 0000000000000..5e1e3a128b77a --- /dev/null +++ b/include/linux/damon.h @@ -0,0 +1,511 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DAMON api + * + * Author: SeongJae Park + */ + +#ifndef _DAMON_H_ +#define _DAMON_H_ + +#include +#include +#include +#include + +/* Minimal region size. Every damon_region is aligned by this. */ +#define DAMON_MIN_REGION PAGE_SIZE +/* Max priority score for DAMON-based operation schemes */ +#define DAMOS_MAX_SCORE (99) + +/* Get a random number in [l, r) */ +static inline unsigned long damon_rand(unsigned long l, unsigned long r) +{ + return l + prandom_u32_max(r - l); +} + +/** + * struct damon_addr_range - Represents an address region of [@start, @end). + * @start: Start address of the region (inclusive). + * @end: End address of the region (exclusive). + */ +struct damon_addr_range { + unsigned long start; + unsigned long end; +}; + +/** + * struct damon_region - Represents a monitoring target region. + * @ar: The address range of the region. + * @sampling_addr: Address of the sample for the next access check. + * @nr_accesses: Access frequency of this region. + * @list: List head for siblings. + * @age: Age of this region. + * + * @age is initially zero, increased for each aggregation interval, and reset + * to zero again if the access frequency is significantly changed. If two + * regions are merged into a new region, both @nr_accesses and @age of the new + * region are set as region size-weighted average of those of the two regions. + */ +struct damon_region { + struct damon_addr_range ar; + unsigned long sampling_addr; + unsigned int nr_accesses; + struct list_head list; + + unsigned int age; +/* private: Internal value for age calculation. */ + unsigned int last_nr_accesses; +}; + +/** + * struct damon_target - Represents a monitoring target. + * @id: Unique identifier for this target. + * @nr_regions: Number of monitoring target regions of this target. + * @regions_list: Head of the monitoring target regions of this target. + * @list: List head for siblings. + * + * Each monitoring context could have multiple targets. For example, a context + * for virtual memory address spaces could have multiple target processes. The + * @id of each target should be unique among the targets of the context. For + * example, in the virtual address monitoring context, it could be a pidfd or + * an address of an mm_struct. + */ +struct damon_target { + unsigned long id; + unsigned int nr_regions; + struct list_head regions_list; + struct list_head list; +}; + +/** + * enum damos_action - Represents an action of a Data Access Monitoring-based + * Operation Scheme. + * + * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED. + * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD. + * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. + * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. + * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. + * @DAMOS_STAT: Do nothing but count the stat. + */ +enum damos_action { + DAMOS_WILLNEED, + DAMOS_COLD, + DAMOS_PAGEOUT, + DAMOS_HUGEPAGE, + DAMOS_NOHUGEPAGE, + DAMOS_STAT, /* Do nothing but only record the stat */ +}; + +/** + * struct damos_quota - Controls the aggressiveness of the given scheme. + * @ms: Maximum milliseconds that the scheme can use. + * @sz: Maximum bytes of memory that the action can be applied. + * @reset_interval: Charge reset interval in milliseconds. + * + * @weight_sz: Weight of the region's size for prioritization. + * @weight_nr_accesses: Weight of the region's nr_accesses for prioritization. + * @weight_age: Weight of the region's age for prioritization. + * + * To avoid consuming too much CPU time or IO resources for applying the + * &struct damos->action to large memory, DAMON allows users to set time and/or + * size quotas. The quotas can be set by writing non-zero values to &ms and + * &sz, respectively. If the time quota is set, DAMON tries to use only up to + * &ms milliseconds within &reset_interval for applying the action. If the + * size quota is set, DAMON tries to apply the action only up to &sz bytes + * within &reset_interval. + * + * Internally, the time quota is transformed to a size quota using estimated + * throughput of the scheme's action. DAMON then compares it against &sz and + * uses smaller one as the effective quota. + * + * For selecting regions within the quota, DAMON prioritizes current scheme's + * target memory regions using the &struct damon_primitive->get_scheme_score. + * You could customize the prioritization logic by setting &weight_sz, + * &weight_nr_accesses, and &weight_age, because monitoring primitives are + * encouraged to respect those. + */ +struct damos_quota { + unsigned long ms; + unsigned long sz; + unsigned long reset_interval; + + unsigned int weight_sz; + unsigned int weight_nr_accesses; + unsigned int weight_age; + +/* private: */ + /* For throughput estimation */ + unsigned long total_charged_sz; + unsigned long total_charged_ns; + + unsigned long esz; /* Effective size quota in bytes */ + + /* For charging the quota */ + unsigned long charged_sz; + unsigned long charged_from; + struct damon_target *charge_target_from; + unsigned long charge_addr_from; + + /* For prioritization */ + unsigned long histogram[DAMOS_MAX_SCORE + 1]; + unsigned int min_score; +}; + +/** + * enum damos_wmark_metric - Represents the watermark metric. + * + * @DAMOS_WMARK_NONE: Ignore the watermarks of the given scheme. + * @DAMOS_WMARK_FREE_MEM_RATE: Free memory rate of the system in [0,1000]. + */ +enum damos_wmark_metric { + DAMOS_WMARK_NONE, + DAMOS_WMARK_FREE_MEM_RATE, +}; + +/** + * struct damos_watermarks - Controls when a given scheme should be activated. + * @metric: Metric for the watermarks. + * @interval: Watermarks check time interval in microseconds. + * @high: High watermark. + * @mid: Middle watermark. + * @low: Low watermark. + * + * If &metric is &DAMOS_WMARK_NONE, the scheme is always active. Being active + * means DAMON does monitoring and applying the action of the scheme to + * appropriate memory regions. Else, DAMON checks &metric of the system for at + * least every &interval microseconds and works as below. + * + * If &metric is higher than &high, the scheme is inactivated. If &metric is + * between &mid and &low, the scheme is activated. If &metric is lower than + * &low, the scheme is inactivated. + */ +struct damos_watermarks { + enum damos_wmark_metric metric; + unsigned long interval; + unsigned long high; + unsigned long mid; + unsigned long low; + +/* private: */ + bool activated; +}; + +/** + * struct damos_stat - Statistics on a given scheme. + * @nr_tried: Total number of regions that the scheme is tried to be applied. + * @sz_tried: Total size of regions that the scheme is tried to be applied. + * @nr_applied: Total number of regions that the scheme is applied. + * @sz_applied: Total size of regions that the scheme is applied. + * @qt_exceeds: Total number of times the quota of the scheme has exceeded. + */ +struct damos_stat { + unsigned long nr_tried; + unsigned long sz_tried; + unsigned long nr_applied; + unsigned long sz_applied; + unsigned long qt_exceeds; +}; + +/** + * struct damos - Represents a Data Access Monitoring-based Operation Scheme. + * @min_sz_region: Minimum size of target regions. + * @max_sz_region: Maximum size of target regions. + * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions. + * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions. + * @min_age_region: Minimum age of target regions. + * @max_age_region: Maximum age of target regions. + * @action: &damo_action to be applied to the target regions. + * @quota: Control the aggressiveness of this scheme. + * @wmarks: Watermarks for automated (in)activation of this scheme. + * @stat: Statistics of this scheme. + * @list: List head for siblings. + * + * For each aggregation interval, DAMON finds regions which fit in the + * condition (&min_sz_region, &max_sz_region, &min_nr_accesses, + * &max_nr_accesses, &min_age_region, &max_age_region) and applies &action to + * those. To avoid consuming too much CPU time or IO resources for the + * &action, "a is used. + * + * To do the work only when needed, schemes can be activated for specific + * system situations using &wmarks. If all schemes that registered to the + * monitoring context are inactive, DAMON stops monitoring either, and just + * repeatedly checks the watermarks. + * + * If all schemes that registered to a &struct damon_ctx are inactive, DAMON + * stops monitoring and just repeatedly checks the watermarks. + * + * After applying the &action to each region, &stat_count and &stat_sz is + * updated to reflect the number of regions and total size of regions that the + * &action is applied. + */ +struct damos { + unsigned long min_sz_region; + unsigned long max_sz_region; + unsigned int min_nr_accesses; + unsigned int max_nr_accesses; + unsigned int min_age_region; + unsigned int max_age_region; + enum damos_action action; + struct damos_quota quota; + struct damos_watermarks wmarks; + struct damos_stat stat; + struct list_head list; +}; + +struct damon_ctx; + +/** + * struct damon_primitive - Monitoring primitives for given use cases. + * + * @init: Initialize primitive-internal data structures. + * @update: Update primitive-internal data structures. + * @prepare_access_checks: Prepare next access check of target regions. + * @check_accesses: Check the accesses to target regions. + * @reset_aggregated: Reset aggregated accesses monitoring results. + * @get_scheme_score: Get the score of a region for a scheme. + * @apply_scheme: Apply a DAMON-based operation scheme. + * @target_valid: Determine if the target is valid. + * @cleanup: Clean up the context. + * + * DAMON can be extended for various address spaces and usages. For this, + * users should register the low level primitives for their target address + * space and usecase via the &damon_ctx.primitive. Then, the monitoring thread + * (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting + * the monitoring, @update after each &damon_ctx.primitive_update_interval, and + * @check_accesses, @target_valid and @prepare_access_checks after each + * &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each + * &damon_ctx.aggr_interval. + * + * @init should initialize primitive-internal data structures. For example, + * this could be used to construct proper monitoring target regions and link + * those to @damon_ctx.adaptive_targets. + * @update should update the primitive-internal data structures. For example, + * this could be used to update monitoring target regions for current status. + * @prepare_access_checks should manipulate the monitoring regions to be + * prepared for the next access check. + * @check_accesses should check the accesses to each region that made after the + * last preparation and update the number of observed accesses of each region. + * It should also return max number of observed accesses that made as a result + * of its update. The value will be used for regions adjustment threshold. + * @reset_aggregated should reset the access monitoring results that aggregated + * by @check_accesses. + * @get_scheme_score should return the priority score of a region for a scheme + * as an integer in [0, &DAMOS_MAX_SCORE]. + * @apply_scheme is called from @kdamond when a region for user provided + * DAMON-based operation scheme is found. It should apply the scheme's action + * to the region and return bytes of the region that the action is successfully + * applied. + * @target_valid should check whether the target is still valid for the + * monitoring. + * @cleanup is called from @kdamond just before its termination. + */ +struct damon_primitive { + void (*init)(struct damon_ctx *context); + void (*update)(struct damon_ctx *context); + void (*prepare_access_checks)(struct damon_ctx *context); + unsigned int (*check_accesses)(struct damon_ctx *context); + void (*reset_aggregated)(struct damon_ctx *context); + int (*get_scheme_score)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + unsigned long (*apply_scheme)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + bool (*target_valid)(void *target); + void (*cleanup)(struct damon_ctx *context); +}; + +/** + * struct damon_callback - Monitoring events notification callbacks. + * + * @before_start: Called before starting the monitoring. + * @after_sampling: Called after each sampling. + * @after_aggregation: Called after each aggregation. + * @before_terminate: Called before terminating the monitoring. + * @private: User private data. + * + * The monitoring thread (&damon_ctx.kdamond) calls @before_start and + * @before_terminate just before starting and finishing the monitoring, + * respectively. Therefore, those are good places for installing and cleaning + * @private. + * + * The monitoring thread calls @after_sampling and @after_aggregation for each + * of the sampling intervals and aggregation intervals, respectively. + * Therefore, users can safely access the monitoring results without additional + * protection. For the reason, users are recommended to use these callback for + * the accesses to the results. + * + * If any callback returns non-zero, monitoring stops. + */ +struct damon_callback { + void *private; + + int (*before_start)(struct damon_ctx *context); + int (*after_sampling)(struct damon_ctx *context); + int (*after_aggregation)(struct damon_ctx *context); + void (*before_terminate)(struct damon_ctx *context); +}; + +/** + * struct damon_ctx - Represents a context for each monitoring. This is the + * main interface that allows users to set the attributes and get the results + * of the monitoring. + * + * @sample_interval: The time between access samplings. + * @aggr_interval: The time between monitor results aggregations. + * @primitive_update_interval: The time between monitoring primitive updates. + * + * For each @sample_interval, DAMON checks whether each region is accessed or + * not. It aggregates and keeps the access information (number of accesses to + * each region) for @aggr_interval time. DAMON also checks whether the target + * memory regions need update (e.g., by ``mmap()`` calls from the application, + * in case of virtual memory monitoring) and applies the changes for each + * @primitive_update_interval. All time intervals are in micro-seconds. + * Please refer to &struct damon_primitive and &struct damon_callback for more + * detail. + * + * @kdamond: Kernel thread who does the monitoring. + * @kdamond_stop: Notifies whether kdamond should stop. + * @kdamond_lock: Mutex for the synchronizations with @kdamond. + * + * For each monitoring context, one kernel thread for the monitoring is + * created. The pointer to the thread is stored in @kdamond. + * + * Once started, the monitoring thread runs until explicitly required to be + * terminated or every monitoring target is invalid. The validity of the + * targets is checked via the &damon_primitive.target_valid of @primitive. The + * termination can also be explicitly requested by writing non-zero to + * @kdamond_stop. The thread sets @kdamond to NULL when it terminates. + * Therefore, users can know whether the monitoring is ongoing or terminated by + * reading @kdamond. Reads and writes to @kdamond and @kdamond_stop from + * outside of the monitoring thread must be protected by @kdamond_lock. + * + * Note that the monitoring thread protects only @kdamond and @kdamond_stop via + * @kdamond_lock. Accesses to other fields must be protected by themselves. + * + * @primitive: Set of monitoring primitives for given use cases. + * @callback: Set of callbacks for monitoring events notifications. + * + * @min_nr_regions: The minimum number of adaptive monitoring regions. + * @max_nr_regions: The maximum number of adaptive monitoring regions. + * @adaptive_targets: Head of monitoring targets (&damon_target) list. + * @schemes: Head of schemes (&damos) list. + */ +struct damon_ctx { + unsigned long sample_interval; + unsigned long aggr_interval; + unsigned long primitive_update_interval; + +/* private: internal use only */ + struct timespec64 last_aggregation; + struct timespec64 last_primitive_update; + +/* public: */ + struct task_struct *kdamond; + struct mutex kdamond_lock; + + struct damon_primitive primitive; + struct damon_callback callback; + + unsigned long min_nr_regions; + unsigned long max_nr_regions; + struct list_head adaptive_targets; + struct list_head schemes; +}; + +static inline struct damon_region *damon_next_region(struct damon_region *r) +{ + return container_of(r->list.next, struct damon_region, list); +} + +static inline struct damon_region *damon_prev_region(struct damon_region *r) +{ + return container_of(r->list.prev, struct damon_region, list); +} + +static inline struct damon_region *damon_last_region(struct damon_target *t) +{ + return list_last_entry(&t->regions_list, struct damon_region, list); +} + +#define damon_for_each_region(r, t) \ + list_for_each_entry(r, &t->regions_list, list) + +#define damon_for_each_region_safe(r, next, t) \ + list_for_each_entry_safe(r, next, &t->regions_list, list) + +#define damon_for_each_target(t, ctx) \ + list_for_each_entry(t, &(ctx)->adaptive_targets, list) + +#define damon_for_each_target_safe(t, next, ctx) \ + list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list) + +#define damon_for_each_scheme(s, ctx) \ + list_for_each_entry(s, &(ctx)->schemes, list) + +#define damon_for_each_scheme_safe(s, next, ctx) \ + list_for_each_entry_safe(s, next, &(ctx)->schemes, list) + +#ifdef CONFIG_DAMON + +struct damon_region *damon_new_region(unsigned long start, unsigned long end); + +/* + * Add a region between two other regions + */ +static inline void damon_insert_region(struct damon_region *r, + struct damon_region *prev, struct damon_region *next, + struct damon_target *t) +{ + __list_add(&r->list, &prev->list, &next->list); + t->nr_regions++; +} + +void damon_add_region(struct damon_region *r, struct damon_target *t); +void damon_destroy_region(struct damon_region *r, struct damon_target *t); + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks); +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s); +void damon_destroy_scheme(struct damos *s); + +struct damon_target *damon_new_target(unsigned long id); +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t); +bool damon_targets_empty(struct damon_ctx *ctx); +void damon_free_target(struct damon_target *t); +void damon_destroy_target(struct damon_target *t); +unsigned int damon_nr_regions(struct damon_target *t); + +struct damon_ctx *damon_new_ctx(void); +void damon_destroy_ctx(struct damon_ctx *ctx); +int damon_set_targets(struct damon_ctx *ctx, + unsigned long *ids, ssize_t nr_ids); +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long primitive_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg); +int damon_set_schemes(struct damon_ctx *ctx, + struct damos **schemes, ssize_t nr_schemes); +int damon_nr_running_ctxs(void); + +int damon_start(struct damon_ctx **ctxs, int nr_ctxs); +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); + +#endif /* CONFIG_DAMON */ + +#ifdef CONFIG_DAMON_VADDR +bool damon_va_target_valid(void *t); +void damon_va_set_primitives(struct damon_ctx *ctx); +#endif /* CONFIG_DAMON_VADDR */ + +#ifdef CONFIG_DAMON_PADDR +bool damon_pa_target_valid(void *t); +void damon_pa_set_primitives(struct damon_ctx *ctx); +#endif /* CONFIG_DAMON_PADDR */ + +#endif /* _DAMON_H */ diff --git a/include/linux/delay.h b/include/linux/delay.h index 1d0e2ce6b6d9f..abecbccab6e44 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -20,6 +20,7 @@ */ #include +#include extern unsigned long loops_per_jiffy; @@ -58,8 +59,15 @@ void calibrate_delay(void); void __attribute__((weak)) calibration_delay_done(void); void msleep(unsigned int msecs); unsigned long msleep_interruptible(unsigned int msecs); +void usleep_range_state(unsigned long min, unsigned long max, + unsigned int state); void usleep_range(unsigned long min, unsigned long max); +static inline void usleep_idle_range(unsigned long min, unsigned long max) +{ + usleep_range_state(min, max, TASK_IDLE); +} + static inline void ssleep(unsigned int seconds) { msleep(seconds * 1000); diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 03befff63edaa..7270f12e2c780 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -61,21 +61,13 @@ */ #define DMA_ATTR_PRIVILEGED (1UL << 9) -/* - * This is a hint to the DMA-mapping subsystem that the device is expected - * to overwrite the entire mapped size, thus the caller does not require any - * of the previous buffer contents to be preserved. This allows - * bounce-buffering implementations to optimise DMA_FROM_DEVICE transfers. - */ -#define DMA_ATTR_OVERWRITE (1UL << 10) - /* * DMA_ATTR_SYS_CACHE_ONLY: used to indicate that the buffer should be mapped * with the correct memory attributes so that it can be cached in the system * or last level cache. This is useful for buffers that are being mapped for * devices that are non-coherent, but can use the system cache. */ -#define DMA_ATTR_SYS_CACHE_ONLY (1UL << 14) +#define DMA_ATTR_SYS_CACHE_ONLY (1UL << 10) /* * DMA_ATTR_SYS_CACHE_ONLY_NWA: used to indicate that the buffer should be @@ -84,7 +76,7 @@ * useful for buffers that are being mapped for devices that are non-coherent, * but can use the system cache. */ -#define DMA_ATTR_SYS_CACHE_ONLY_NWA (1UL << 15) +#define DMA_ATTR_SYS_CACHE_ONLY_NWA (1UL << 11) /* * A dma_addr_t can hold any valid DMA or bus address for the platform. It can diff --git a/include/linux/export.h b/include/linux/export.h index 8889809924156..3b25f680180fa 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -190,8 +190,10 @@ struct kernel_symbol { #define EXPORT_SYMBOL(sym) _EXPORT_SYMBOL(sym, "") #define EXPORT_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_gpl") #define EXPORT_SYMBOL_GPL_FUTURE(sym) _EXPORT_SYMBOL(sym, "_gpl_future") -#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) -#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) +#define _EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) +#define _EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) +#define EXPORT_SYMBOL_NS(sym, ns) _EXPORT_SYMBOL_NS(sym, ns) +#define EXPORT_SYMBOL_NS_GPL(sym, ns) _EXPORT_SYMBOL_NS_GPL(sym, ns) #ifdef CONFIG_UNUSED_SYMBOLS #define EXPORT_UNUSED_SYMBOL(sym) _EXPORT_SYMBOL(sym, "_unused") diff --git a/include/linux/gfp.h b/include/linux/gfp.h index def31f0f5a077..ae480a3d5307c 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -262,13 +262,9 @@ struct vm_area_struct; /* Room for N __GFP_FOO bits */ #ifdef CONFIG_CMA -#define __GFP_BITS_SHIFT (25 + \ - 3 * IS_ENABLED(CONFIG_KASAN_HW_TAGS) + \ - IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT (28 + IS_ENABLED(CONFIG_LOCKDEP)) #else -#define __GFP_BITS_SHIFT (24 + \ - 3 * IS_ENABLED(CONFIG_KASAN_HW_TAGS) + \ - IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT (27 + IS_ENABLED(CONFIG_LOCKDEP)) #endif #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index e147ea6794670..bf5c5f32c65e4 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -51,7 +51,6 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev) case ARPHRD_VOID: case ARPHRD_NONE: case ARPHRD_RAWIP: - case ARPHRD_PIMREG: return false; default: return true; diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 1f503288f222b..90c54edfe5565 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -17,19 +17,14 @@ struct task_struct; #include #include -/* kasan_data struct is used in KUnit tests for KASAN expected failures */ -struct kunit_kasan_expectation { - bool report_found; -}; - #endif typedef unsigned int __bitwise kasan_vmalloc_flags_t; -#define KASAN_VMALLOC_NONE 0x00u -#define KASAN_VMALLOC_INIT 0x01u -#define KASAN_VMALLOC_VM_ALLOC 0x02u -#define KASAN_VMALLOC_PROT_NORMAL 0x04u +#define KASAN_VMALLOC_NONE ((__force kasan_vmalloc_flags_t)0x00u) +#define KASAN_VMALLOC_INIT ((__force kasan_vmalloc_flags_t)0x01u) +#define KASAN_VMALLOC_VM_ALLOC ((__force kasan_vmalloc_flags_t)0x02u) +#define KASAN_VMALLOC_PROT_NORMAL ((__force kasan_vmalloc_flags_t)0x04u) #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 6ea0873708b1d..531cb39a00f75 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -332,6 +332,11 @@ struct mem_cgroup { struct deferred_split deferred_split_queue; #endif +#ifdef CONFIG_LRU_GEN + /* per-memcg mm_struct list */ + struct lru_gen_mm_list mm_list; +#endif + ANDROID_OEM_DATA(1); struct mem_cgroup_per_node *nodeinfo[0]; /* WARNING: nodeinfo must be the last member here */ @@ -735,6 +740,23 @@ static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg, void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); +/* try to stablize page_memcg() for all the pages in a memcg */ +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + rcu_read_lock(); + + if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) + return true; + + rcu_read_unlock(); + return false; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + /* idx can be of type enum memcg_stat_item or node_stat_item */ static inline void mod_memcg_state(struct mem_cgroup *memcg, int idx, int val) @@ -1153,6 +1175,18 @@ static inline void unlock_page_memcg(struct page *page) { } +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + /* to match page_memcg_rcu() */ + rcu_read_lock(); + return true; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + static inline void mem_cgroup_handle_over_high(void) { } diff --git a/include/linux/mm.h b/include/linux/mm.h index f8ae933c9ed31..c93e896ab4d83 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1107,6 +1107,8 @@ vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf); #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) +#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) +#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) /* * Define the bit shifts to access each section. For non-existent @@ -1286,7 +1288,6 @@ static inline void put_page(struct page *page) */ #define GUP_PIN_COUNTING_BIAS (1U << 10) -void put_user_page(struct page *page); void unpin_user_page(struct page *page); void unpin_user_pages_dirty_lock(struct page **pages, unsigned long npages, bool make_dirty); @@ -2672,13 +2673,13 @@ extern struct vm_area_struct *__vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon, struct file *file, pgoff_t pgoff, struct mempolicy *mpol, struct vm_userfaultfd_ctx uff, - const char *, bool keep_locked); + struct anon_vma_name *, bool keep_locked); static inline struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon, struct file *file, pgoff_t off, struct mempolicy *pol, struct vm_userfaultfd_ctx uff, - const char *anon_name) + struct anon_vma_name *anon_name) { return __vma_merge(mm, prev, addr, end, vm_flags, anon, file, off, pol, uff, anon_name, false); @@ -3397,11 +3398,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma) #ifdef CONFIG_ANON_VMA_NAME int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name); + unsigned long len_in, + struct anon_vma_name *anon_name); #else static inline int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name) { + unsigned long len_in, struct anon_vma_name *anon_name) { return 0; } #endif diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 589e828f8fa81..af0790da3b9fe 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -31,6 +31,8 @@ static __always_inline void __update_lru_size(struct lruvec *lruvec, { struct pglist_data *pgdat = lruvec_pgdat(lruvec); + lockdep_assert_held(&pgdat->lru_lock); + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); __mod_zone_page_state(&pgdat->node_zones[zid], NR_ZONE_LRU_BASE + lru, nr_pages); @@ -46,133 +48,363 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, #endif } +/** + * __clear_page_lru_flags - clear page lru flags before releasing a page + * @page: the page that was on lru and now has a zero reference + */ +static __always_inline void __clear_page_lru_flags(struct page *page) +{ + VM_BUG_ON_PAGE(!PageLRU(page), page); + + __ClearPageLRU(page); + + /* this shouldn't happen, so leave the flags to bad_page() */ + if (PageActive(page) && PageUnevictable(page)) + return; + + __ClearPageActive(page); + __ClearPageUnevictable(page); +} + +/** + * page_lru - which LRU list should a page be on? + * @page: the page to test + * + * Returns the LRU list a page should be on, as an index + * into the array of LRU lists. + */ +static __always_inline enum lru_list page_lru(struct page *page) +{ + enum lru_list lru; + + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + + if (PageUnevictable(page)) + return LRU_UNEVICTABLE; + + lru = page_is_file_lru(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON; + if (PageActive(page)) + lru += LRU_ACTIVE; + + return lru; +} + +#ifdef CONFIG_LRU_GEN + +static inline bool lru_gen_enabled(void) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); +#else + DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); +#endif +} + +static inline bool lru_gen_in_fault(void) +{ + return current->in_lru_fault; +} + +static inline int lru_gen_from_seq(unsigned long seq) +{ + return seq % MAX_NR_GENS; +} + +static inline int lru_hist_from_seq(unsigned long seq) +{ + return seq % NR_HIST_GENS; +} + +static inline int lru_tier_from_refs(int refs) +{ + VM_BUG_ON(refs > BIT(LRU_REFS_WIDTH)); + + /* see the comment on MAX_NR_TIERS */ + return order_base_2(refs + 1); +} + +static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) +{ + unsigned long max_seq = lruvec->lrugen.max_seq; + + VM_BUG_ON(gen >= MAX_NR_GENS); + + /* see the comment on MIN_NR_GENS */ + return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); +} + +static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + enum lru_list lru = type * LRU_INACTIVE_FILE; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(old_gen != -1 && old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen != -1 && new_gen >= MAX_NR_GENS); + VM_BUG_ON(old_gen == -1 && new_gen == -1); + + if (old_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], + lrugen->nr_pages[old_gen][type][zone] - delta); + if (new_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], + lrugen->nr_pages[new_gen][type][zone] + delta); + + /* addition */ + if (old_gen < 0) { + if (lru_gen_is_active(lruvec, new_gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, delta); + return; + } + + /* deletion */ + if (new_gen < 0) { + if (lru_gen_is_active(lruvec, old_gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, -delta); + return; + } + + /* promotion */ + if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { + __update_lru_size(lruvec, lru, zone, -delta); + __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); + } + + /* demotion requires isolation, e.g., lru_deactivate_fn() */ + VM_BUG_ON(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (PageUnevictable(page) || !lrugen->enabled) + return false; + /* + * There are three common cases for this page: + * 1. If it's hot, e.g., freshly faulted in or previously hot and + * migrated, add it to the youngest generation. + * 2. If it's cold but can't be evicted immediately, i.e., an anon page + * not in swapcache or a dirty page pending writeback, add it to the + * second oldest generation. + * 3. Everything else (clean, cold) is added to the oldest generation. + */ + if (PageActive(page)) + gen = lru_gen_from_seq(lrugen->max_seq); + else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || + (PageReclaim(page) && (PageDirty(page) || PageWriteback(page)))) + gen = lru_gen_from_seq(lrugen->min_seq[type] + 1); + else + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(new_flags & LRU_GEN_MASK, page); + + /* see the comment on MIN_NR_GENS */ + new_flags &= ~(LRU_GEN_MASK | BIT(PG_active)); + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, -1, gen); + /* for rotate_reclaimable_page() */ + if (reclaiming) + list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); + else + list_add(&page->lru, &lrugen->lists[gen][type][zone]); + + return true; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + + do { + new_flags = old_flags = READ_ONCE(page->flags); + if (!(new_flags & LRU_GEN_MASK)) + return false; + + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + + gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + + new_flags &= ~LRU_GEN_MASK; + if (!(new_flags & BIT(PG_referenced))) + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for shrink_page_list() */ + if (reclaiming) + new_flags &= ~(BIT(PG_referenced) | BIT(PG_reclaim)); + else if (lru_gen_is_active(lruvec, gen)) + new_flags |= BIT(PG_active); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, gen, -1); + list_del(&page->lru); + + return true; +} + +#else + +static inline bool lru_gen_enabled(void) +{ + return false; +} + +static inline bool lru_gen_in_fault(void) +{ + return false; +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +#endif /* CONFIG_LRU_GEN */ + static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, false)) + return; + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add(&page->lru, &lruvec->lists[lru]); } static __always_inline void add_page_to_lru_list_tail(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, true)) + return; + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add_tail(&page->lru, &lruvec->lists[lru]); } static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + if (lru_gen_del_page(lruvec, page, false)) + return; + list_del(&page->lru); - update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page)); + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); } -/** - * page_lru_base_type - which LRU list type should a page be on? - * @page: the page to test - * - * Used for LRU list index arithmetic. - * - * Returns the base LRU type - file or anon - @page should be on. +#ifdef CONFIG_ANON_VMA_NAME +/* + * mmap_lock should be read-locked when calling anon_vma_name(). Caller should + * either keep holding the lock while using the returned pointer or it should + * raise anon_vma_name refcount before releasing the lock. */ -static inline enum lru_list page_lru_base_type(struct page *page) +extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma); +extern struct anon_vma_name *anon_vma_name_alloc(const char *name); +extern void anon_vma_name_free(struct kref *kref); + +/* mmap_lock should be read-locked */ +static inline void anon_vma_name_get(struct anon_vma_name *anon_name) { - if (page_is_file_lru(page)) - return LRU_INACTIVE_FILE; - return LRU_INACTIVE_ANON; + if (anon_name) + kref_get(&anon_name->kref); } -/** - * page_off_lru - which LRU list was page on? clearing its lru flags. - * @page: the page to test - * - * Returns the LRU list a page was on, as an index into the array of LRU - * lists; and clears its Unevictable or Active flags, ready for freeing. - */ -static __always_inline enum lru_list page_off_lru(struct page *page) +static inline void anon_vma_name_put(struct anon_vma_name *anon_name) { - enum lru_list lru; - - if (PageUnevictable(page)) { - __ClearPageUnevictable(page); - lru = LRU_UNEVICTABLE; - } else { - lru = page_lru_base_type(page); - if (PageActive(page)) { - __ClearPageActive(page); - lru += LRU_ACTIVE; - } - } - return lru; + if (anon_name) + kref_put(&anon_name->kref, anon_vma_name_free); } -/** - * page_lru - which LRU list should a page be on? - * @page: the page to test - * - * Returns the LRU list a page should be on, as an index - * into the array of LRU lists. - */ -static __always_inline enum lru_list page_lru(struct page *page) +static inline +struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name) { - enum lru_list lru; + /* Prevent anon_name refcount saturation early on */ + if (kref_read(&anon_name->kref) < REFCOUNT_MAX) { + anon_vma_name_get(anon_name); + return anon_name; - if (PageUnevictable(page)) - lru = LRU_UNEVICTABLE; - else { - lru = page_lru_base_type(page); - if (PageActive(page)) - lru += LRU_ACTIVE; } - return lru; + return anon_vma_name_alloc(anon_name->name); } -#ifdef CONFIG_ANON_VMA_NAME -/* - * mmap_lock should be read-locked when calling vma_anon_name() and while using - * the returned pointer. - */ -extern const char *vma_anon_name(struct vm_area_struct *vma); - -/* - * mmap_lock should be read-locked for orig_vma->vm_mm. - * mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be - * isolated. - */ -extern void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma); +static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma, + struct vm_area_struct *new_vma) +{ + struct anon_vma_name *anon_name = anon_vma_name(orig_vma); -/* - * mmap_lock should be write-locked or vma should have been isolated under - * write-locked mmap_lock protection. - */ -extern void free_vma_anon_name(struct vm_area_struct *vma); + if (anon_name) + new_vma->anon_name = anon_vma_name_reuse(anon_name); +} -/* mmap_lock should be read-locked */ -static inline bool is_same_vma_anon_name(struct vm_area_struct *vma, - const char *name) +static inline void free_anon_vma_name(struct vm_area_struct *vma) { - const char *vma_name = vma_anon_name(vma); + /* + * Not using anon_vma_name because it generates a warning if mmap_lock + * is not held, which might be the case here. + */ + if (!vma->vm_file) + anon_vma_name_put(vma->anon_name); +} - /* either both NULL, or pointers to same string */ - if (vma_name == name) +static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1, + struct anon_vma_name *anon_name2) +{ + if (anon_name1 == anon_name2) return true; - return name && vma_name && !strcmp(name, vma_name); + return anon_name1 && anon_name2 && + !strcmp(anon_name1->name, anon_name2->name); } #else /* CONFIG_ANON_VMA_NAME */ -static inline const char *vma_anon_name(struct vm_area_struct *vma) +static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma) { return NULL; } -static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma) {} -static inline void free_vma_anon_name(struct vm_area_struct *vma) {} -static inline bool is_same_vma_anon_name(struct vm_area_struct *vma, - const char *name) + +static inline struct anon_vma_name *anon_vma_name_alloc(const char *name) +{ + return NULL; +} + +static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {} +static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {} +static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma, + struct vm_area_struct *new_vma) {} +static inline void free_anon_vma_name(struct vm_area_struct *vma) {} + +static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1, + struct anon_vma_name *anon_name2) { return true; } + #endif /* CONFIG_ANON_VMA_NAME */ #endif diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 04f1003826148..988f4e6a4e39f 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -3,6 +3,7 @@ #define _LINUX_MM_TYPES_H #include +#include #include #include @@ -16,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -86,6 +89,7 @@ struct page { * by the page owner. */ struct list_head lru; + /* See page-flags.h for PAGE_MAPPING_FLAGS */ struct address_space *mapping; pgoff_t index; /* Our offset within mapping. */ @@ -356,7 +360,10 @@ struct vm_area_struct { struct rb_node rb; unsigned long rb_subtree_last; } shared; - /* Serialized by mmap_sem. */ + /* + * Serialized by mmap_sem. Never use directly because it is + * valid only when vm_file is NULL. Use anon_vma_name instead. + */ struct anon_vma_name *anon_name; }; @@ -611,6 +618,23 @@ struct mm_struct { u32 pasid; #endif +#ifdef CONFIG_LRU_GEN + struct { + /* this mm_struct is on lru_gen_mm_list */ + struct list_head list; +#ifdef CONFIG_MEMCG + /* points to the memcg of "owner" above */ + struct mem_cgroup *memcg; +#endif + /* + * Set when switching to this mm_struct, as a hint of + * whether it has been used since the last time per-node + * page table walkers cleared the corresponding bits. + */ + nodemask_t nodes; + } lru_gen; +#endif /* CONFIG_LRU_GEN */ + ANDROID_KABI_RESERVE(1); } __randomize_layout; @@ -638,6 +662,65 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) return (struct cpumask *)&mm->cpu_bitmap; } +#ifdef CONFIG_LRU_GEN + +struct lru_gen_mm_list { + /* mm_struct list for page table walkers */ + struct list_head fifo; + /* protects the list above */ + spinlock_t lock; +}; + +void lru_gen_add_mm(struct mm_struct *mm); +void lru_gen_del_mm(struct mm_struct *mm); +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm); +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ + INIT_LIST_HEAD(&mm->lru_gen.list); +#ifdef CONFIG_MEMCG + mm->lru_gen.memcg = NULL; +#endif + nodes_clear(mm->lru_gen.nodes); +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ + /* unlikely but not a bug when racing with lru_gen_migrate_mm() */ + VM_WARN_ON(list_empty(&mm->lru_gen.list)); + + if (!(current->flags & PF_KTHREAD) && !nodes_full(mm->lru_gen.nodes)) + nodes_setall(mm->lru_gen.nodes); +} + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_add_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_del_mm(struct mm_struct *mm) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_migrate_mm(struct mm_struct *mm) +{ +} +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ +} + +#endif /* CONFIG_LRU_GEN */ + struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index f72b488b790b8..b149f792e3ea2 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -277,6 +277,206 @@ enum lruvec_flags { */ }; +#endif /* !__GENERATING_BOUNDS_H */ + +/* + * Evictable pages are divided into multiple generations. The youngest and the + * oldest generation numbers, max_seq and min_seq, are monotonically increasing. + * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An + * offset within MAX_NR_GENS, gen, indexes the LRU list of the corresponding + * generation. The gen counter in page->flags stores gen+1 while a page is on + * one of lrugen->lists[]. Otherwise it stores 0. + * + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the + * eviction. The first check takes care of the accessed bit set on the initial + * fault; the second check makes sure this page hasn't been used since then. + * This process, AKA second chance, requires a minimum of two generations, + * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive + * LRU, these two generations are considered active; the rest of generations, if + * they exist, are considered inactive. See lru_gen_is_active(). PG_active is + * always cleared while a page is on one of lrugen->lists[] so that the aging + * needs not to worry about it. And it's set again when a page considered active + * is isolated for non-reclaiming purposes, e.g., migration. See + * lru_gen_add_page() and lru_gen_del_page(). + * + * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * page tables. It requires order_base_2(MAX_NR_GENS+1) bits in page->flags. + */ +#define MIN_NR_GENS 2U +#define MAX_NR_GENS 4U + +/* + * Each generation is divided into multiple tiers. Tiers represent different + * ranges of numbers of accesses through file descriptors. A page accessed N + * times through file descriptors is in tier order_base_2(N). A page in the + * first tier (N=0,1) is marked by PG_referenced unless it was faulted in + * though page tables or read ahead. A page in any other tier (N>1) is marked + * by PG_referenced and PG_workingset. + * + * In contrast to moving across generations which requires the LRU lock, moving + * across tiers only requires operations on page->flags and therefore has a + * negligible cost in the buffered access path. In the eviction path, + * comparisons of refaulted/(evicted+protected) from the first tier and the + * rest infer whether pages accessed multiple times through file descriptors + * are statistically hot and thus worth protecting. + * + * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * file descriptors. It requires MAX_NR_TIERS-2 additional bits in page->flags. + */ +#define MAX_NR_TIERS 4U + +#ifndef __GENERATING_BOUNDS_H + +struct lruvec; +struct page_vma_mapped_walk; + +#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) +#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) +#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) + +#ifdef CONFIG_LRU_GEN + +enum { + LRU_GEN_ANON, + LRU_GEN_FILE, +}; + +enum { + LRU_GEN_CORE, + LRU_GEN_MM_WALK, + LRU_GEN_NONLEAF_YOUNG, + NR_LRU_GEN_CAPS +}; + +#define MIN_LRU_BATCH BITS_PER_LONG +#define MAX_LRU_BATCH (MIN_LRU_BATCH * 128) + +/* whether to keep historical stats from evicted generations */ +#ifdef CONFIG_LRU_GEN_STATS +#define NR_HIST_GENS MAX_NR_GENS +#else +#define NR_HIST_GENS 1U +#endif + +/* + * The youngest generation number is stored in max_seq for both anon and file + * types as they are aged on an equal footing. The oldest generation numbers are + * stored in min_seq[] separately for anon and file types as clean file pages + * can be evicted regardless of swap constraints. + * + * Normally anon and file min_seq are in sync. But if swapping is constrained, + * e.g., out of swap space, file min_seq is allowed to advance and leave anon + * min_seq behind. + */ +struct lru_gen_struct { + /* the aging increments the youngest generation number */ + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ + unsigned long min_seq[ANON_AND_FILE]; + /* the birth time of each generation in jiffies */ + unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists */ + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the sizes of the above lists */ + unsigned long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the exponential moving average of refaulted */ + unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; + /* the exponential moving average of evicted+protected */ + unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; + /* the first tier doesn't need protection, hence the minus one */ + unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; + /* can be modified without holding the LRU lock */ + atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + /* whether the multi-gen LRU is enabled */ + bool enabled; +}; + +enum { + MM_PTE_TOTAL, /* total leaf entries */ + MM_PTE_OLD, /* old leaf entries */ + MM_PTE_YOUNG, /* young leaf entries */ + MM_PMD_TOTAL, /* total non-leaf entries */ + MM_PMD_FOUND, /* non-leaf entries found in Bloom filters */ + MM_PMD_ADDED, /* non-leaf entries added to Bloom filters */ + NR_MM_STATS +}; + +/* mnemonic codes for the mm stats above */ +#define MM_STAT_CODES "toydfa" + +/* double-buffering Bloom filters */ +#define NR_BLOOM_FILTERS 2 + +struct lru_gen_mm_state { + /* set to max_seq after each iteration */ + unsigned long seq; + /* where the current iteration starts (inclusive) */ + struct list_head *head; + /* where the last iteration ends (exclusive) */ + struct list_head *tail; + /* to wait for the last page table walker to finish */ + struct wait_queue_head wait; + /* Bloom filters flip after each iteration */ + unsigned long *filters[NR_BLOOM_FILTERS]; + /* the mm stats for debugging */ + unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; + /* the number of concurrent page table walkers */ + int nr_walkers; +}; + +struct lru_gen_mm_walk { + /* the lruvec under reclaim */ + struct lruvec *lruvec; + /* unstable max_seq from lru_gen_struct */ + unsigned long max_seq; + /* the next address within an mm to scan */ + unsigned long next_addr; + /* to batch page table entries */ + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)]; + /* to batch promoted pages */ + int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* to batch the mm stats */ + int mm_stats[NR_MM_STATS]; + /* total batched items */ + int batched; + bool can_swap; + bool full_scan; +}; + +void lru_gen_init_lruvec(struct lruvec *lruvec); +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg); +void lru_gen_exit_memcg(struct mem_cgroup *memcg); +#endif + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_init_lruvec(struct lruvec *lruvec) +{ +} + +static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ +} + +static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ +} +#endif + +#endif /* CONFIG_LRU_GEN */ + struct lruvec { struct list_head lists[NR_LRU_LISTS]; /* @@ -292,9 +492,16 @@ struct lruvec { unsigned long refaults[ANON_AND_FILE]; /* Various lruvec state flags (enum lruvec_flags) */ unsigned long flags; +#ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ + struct lru_gen_struct lrugen; + /* to concurrently iterate lru_gen_mm_list */ + struct lru_gen_mm_state mm_state; +#endif #ifdef CONFIG_MEMCG struct pglist_data *pgdat; #endif + ANDROID_VENDOR_DATA(1); }; /* Isolate unmapped pages */ @@ -340,6 +547,11 @@ struct per_cpu_pageset { #endif }; +struct per_cpu_pageset_ext { + spinlock_t lock; /* Protects pageset.pcp.lists field */ + struct per_cpu_pageset pageset; +}; + struct per_cpu_nodestat { s8 stat_threshold; s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS]; @@ -827,6 +1039,11 @@ typedef struct pglist_data { unsigned long flags; +#ifdef CONFIG_LRU_GEN + /* kswap mm walk data */ + struct lru_gen_mm_walk mm_walk; +#endif + ZONE_PADDING(_pad2_) /* Per-node vmstats */ diff --git a/include/linux/module.h b/include/linux/module.h index 4fa2f7de56e61..c5c3ce08f6466 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -293,7 +293,8 @@ extern typeof(name) __mod_##type##__##name##_device_table \ * files require multiple MODULE_FIRMWARE() specifiers */ #define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) -#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) +#define _MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) +#define MODULE_IMPORT_NS(ns) _MODULE_IMPORT_NS(ns) struct notifier_block; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index db2eaff77f41a..aac07940de09d 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1083,7 +1083,6 @@ struct nand_manufacturer { * @lock: Lock protecting the suspended field. Also used to serialize accesses * to the NAND device * @suspended: Set to 1 when the device is suspended, 0 when it's not - * @resume_wq: wait queue to sleep if rawnand is in suspended state. * @cur_cs: Currently selected target. -1 means no target selected, otherwise we * should always have cur_cs >= 0 && cur_cs < nanddev_ntargets(). * NAND Controller drivers should not modify this value, but they're @@ -1136,7 +1135,6 @@ struct nand_chip { /* Internals */ struct mutex lock; unsigned int suspended : 1; - wait_queue_head_t resume_wq; int cur_cs; int read_retries; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3639d7ae68e84..9dadd780a2a67 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4027,8 +4027,7 @@ void netdev_run_todo(void); */ static inline void dev_put(struct net_device *dev) { - if (dev) - this_cpu_dec(*dev->pcpu_refcnt); + this_cpu_dec(*dev->pcpu_refcnt); } /** @@ -4039,8 +4038,7 @@ static inline void dev_put(struct net_device *dev) */ static inline void dev_hold(struct net_device *dev) { - if (dev) - this_cpu_inc(*dev->pcpu_refcnt); + this_cpu_inc(*dev->pcpu_refcnt); } /* Carrier loss detection, dial on demand. The functions netif_carrier_on diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index ac398e143c9a1..89fe4e3592f93 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -486,6 +486,7 @@ static inline int num_node_state(enum node_states state) #define first_online_node 0 #define first_memory_node 0 #define next_online_node(nid) (MAX_NUMNODES) +#define next_memory_node(nid) (MAX_NUMNODES) #define nr_node_ids 1U #define nr_online_nodes 1U diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h index 7d4ec26d8a3ed..c1946cdb845fe 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h @@ -21,16 +21,17 @@ #elif MAX_NR_ZONES <= 8 #define ZONES_SHIFT 3 #else -#error ZONES_SHIFT -- too many zones configured adjust calculation +#error ZONES_SHIFT "Too many zones configured" #endif +#define ZONES_WIDTH ZONES_SHIFT + #ifdef CONFIG_SPARSEMEM #include - -/* SECTION_SHIFT #bits space required to store a section # */ #define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS) - -#endif /* CONFIG_SPARSEMEM */ +#else +#define SECTIONS_SHIFT 0 +#endif #ifndef BUILD_VDSO32_64 /* @@ -54,17 +55,29 @@ #define SECTIONS_WIDTH 0 #endif -#define ZONES_WIDTH ZONES_SHIFT - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ + <= BITS_PER_LONG - NR_PAGEFLAGS #define NODES_WIDTH NODES_SHIFT -#else -#ifdef CONFIG_SPARSEMEM_VMEMMAP +#elif defined(CONFIG_SPARSEMEM_VMEMMAP) #error "Vmemmap: No space for nodes field in page flags" -#endif +#else #define NODES_WIDTH 0 #endif +/* + * Note that this #define MUST have a value so that it can be tested with + * the IS_ENABLED() macro. + */ +#if NODES_SHIFT != 0 && NODES_WIDTH == 0 +#define NODE_NOT_IN_PAGE_FLAGS 1 +#endif + +#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS) +#define KASAN_TAG_WIDTH 8 +#else +#define KASAN_TAG_WIDTH 0 +#endif + #ifdef CONFIG_NUMA_BALANCING #define LAST__PID_SHIFT 8 #define LAST__PID_MASK ((1 << LAST__PID_SHIFT)-1) @@ -77,36 +90,20 @@ #define LAST_CPUPID_SHIFT 0 #endif -#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS) -#define KASAN_TAG_WIDTH 8 -#else -#define KASAN_TAG_WIDTH 0 -#endif - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT+KASAN_TAG_WIDTH \ - <= BITS_PER_LONG - NR_PAGEFLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT #else #define LAST_CPUPID_WIDTH 0 #endif -#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH+LAST_CPUPID_WIDTH+KASAN_TAG_WIDTH \ - > BITS_PER_LONG - NR_PAGEFLAGS -#error "Not enough bits in page flags" -#endif - -/* - * We are going to use the flags for the page to node mapping if its in - * there. This includes the case where there is no node, so it is implicit. - * Note that this #define MUST have a value so that it can be tested with - * the IS_ENABLED() macro. - */ -#if !(NODES_WIDTH > 0 || NODES_SHIFT == 0) -#define NODE_NOT_IN_PAGE_FLAGS 1 +#if LAST_CPUPID_SHIFT != 0 && LAST_CPUPID_WIDTH == 0 +#define LAST_CPUPID_NOT_IN_PAGE_FLAGS #endif -#if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0 -#define LAST_CPUPID_NOT_IN_PAGE_FLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS +#error "Not enough bits in page flags" #endif #endif diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 1c5027fdc2a9e..1d2a9a3103da7 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -132,7 +132,7 @@ enum pageflags { #ifdef CONFIG_MEMORY_FAILURE PG_hwpoison, /* hardware poisoned page. Don't touch */ #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) PG_young, PG_idle, #endif @@ -440,7 +440,7 @@ PAGEFLAG_FALSE(HWPoison) #define __PG_HWPOISON 0 #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) TESTPAGEFLAG(Young, young, PF_ANY) SETPAGEFLAG(Young, young, PF_ANY) TESTCLEARFLAG(Young, young, PF_ANY) @@ -803,7 +803,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) 1UL << PG_private | 1UL << PG_private_2 | \ 1UL << PG_writeback | 1UL << PG_reserved | \ 1UL << PG_slab | 1UL << PG_active | \ - 1UL << PG_unevictable | __PG_MLOCKED) + 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) /* * Flags checked when a page is prepped for return by the page allocator. @@ -814,7 +814,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) * alloc-free cycle to prevent from reusing the page. */ #define PAGE_FLAGS_CHECK_AT_PREP \ - (((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) + ((((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) #define PAGE_FLAGS_PRIVATE \ (1UL << PG_private | 1UL << PG_private_2) diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index cd45c1927d903..2e64843c14689 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -20,12 +20,10 @@ enum page_ext_flags { PAGE_EXT_OWNER, PAGE_EXT_OWNER_ALLOCATED, #if defined(CONFIG_PAGE_PINNER) - /* page refcount was increased by GUP or follow_page(FOLL_GET) */ - PAGE_EXT_GET, /* page migration failed */ PAGE_EXT_PINNER_MIGRATION_FAILED, #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) PAGE_EXT_YOUNG, PAGE_EXT_IDLE, #endif diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h index 1e894d34bdceb..d8a6aecf99cb9 100644 --- a/include/linux/page_idle.h +++ b/include/linux/page_idle.h @@ -6,7 +6,7 @@ #include #include -#ifdef CONFIG_IDLE_PAGE_TRACKING +#ifdef CONFIG_PAGE_IDLE_FLAG #ifdef CONFIG_64BIT static inline bool page_is_young(struct page *page) @@ -106,7 +106,7 @@ static inline void clear_page_idle(struct page *page) } #endif /* CONFIG_64BIT */ -#else /* !CONFIG_IDLE_PAGE_TRACKING */ +#else /* !CONFIG_PAGE_IDLE_FLAG */ static inline bool page_is_young(struct page *page) { @@ -135,6 +135,6 @@ static inline void clear_page_idle(struct page *page) { } -#endif /* CONFIG_IDLE_PAGE_TRACKING */ +#endif /* CONFIG_PAGE_IDLE_FLAG */ #endif /* _LINUX_MM_PAGE_IDLE_H */ diff --git a/include/linux/page_pinner.h b/include/linux/page_pinner.h index ba14d7636dc00..4d574d1ced59c 100644 --- a/include/linux/page_pinner.h +++ b/include/linux/page_pinner.h @@ -9,34 +9,14 @@ extern struct static_key_false page_pinner_inited; extern struct static_key_true failure_tracking; extern struct page_ext_operations page_pinner_ops; -extern void __reset_page_pinner(struct page *page, unsigned int order, bool free); -extern void __set_page_pinner(struct page *page, unsigned int order); -extern void __dump_page_pinner(struct page *page); -void __page_pinner_migration_failed(struct page *page); -void __page_pinner_mark_migration_failed_pages(struct list_head *page_list); - -static inline void reset_page_pinner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __reset_page_pinner(page, order, false); -} +extern void __free_page_pinner(struct page *page, unsigned int order); +void __page_pinner_failure_detect(struct page *page); +void __page_pinner_put_page(struct page *page); static inline void free_page_pinner(struct page *page, unsigned int order) { if (static_branch_unlikely(&page_pinner_inited)) - __reset_page_pinner(page, order, true); -} - -static inline void set_page_pinner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __set_page_pinner(page, order); -} - -static inline void dump_page_pinner(struct page *page) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __dump_page_pinner(page); + __free_page_pinner(page, order); } static inline void page_pinner_put_page(struct page *page) @@ -44,7 +24,7 @@ static inline void page_pinner_put_page(struct page *page) if (!static_branch_unlikely(&failure_tracking)) return; - __page_pinner_migration_failed(page); + __page_pinner_put_page(page); } static inline void page_pinner_failure_detect(struct page *page) @@ -52,37 +32,17 @@ static inline void page_pinner_failure_detect(struct page *page) if (!static_branch_unlikely(&failure_tracking)) return; - __page_pinner_migration_failed(page); -} - -static inline void page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ - if (!static_branch_unlikely(&failure_tracking)) - return; - - __page_pinner_mark_migration_failed_pages(page_list); + __page_pinner_failure_detect(page); } #else -static inline void reset_page_pinner(struct page *page, unsigned int order) -{ -} static inline void free_page_pinner(struct page *page, unsigned int order) { } -static inline void set_page_pinner(struct page *page, unsigned int order) -{ -} -static inline void dump_page_pinner(struct page *page) -{ -} static inline void page_pinner_put_page(struct page *page) { } static inline void page_pinner_failure_detect(struct page *page) { } -static inline void page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ -} #endif /* CONFIG_PAGE_PINNER */ #endif /* __LINUX_PAGE_PINNER_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 4d2c9a3c83bd3..605ac0bd908a6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -647,7 +647,6 @@ struct pci_bus { struct bin_attribute *legacy_io; /* Legacy I/O for this bus */ struct bin_attribute *legacy_mem; /* Legacy mem */ unsigned int is_added:1; - unsigned int unsafe_warn:1; /* warned about RW1C config write */ ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index eb724505951f8..ab7287e59c070 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -194,7 +194,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, #endif #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) @@ -215,7 +215,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, BUILD_BUG(); return 0; } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH @@ -241,6 +241,19 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif +#ifndef arch_has_hw_pte_young +/* + * Return whether the accessed bit is supported on the local CPU. + * + * This stub assumes accessing through an old PTE triggers a page fault. + * Architectures that automatically set the access bit should overwrite it. + */ +static inline bool arch_has_hw_pte_young(void) +{ + return false; +} +#endif + #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long address, diff --git a/include/linux/pstore.h b/include/linux/pstore.h index e97a8188f0fd8..eb93a54cff31f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -87,7 +87,7 @@ struct pstore_record { * @owner: module which is responsible for this backend driver * @name: name of the backend driver * - * @buf_lock: spinlock to serialize access to @buf + * @buf_lock: semaphore to serialize access to @buf * @buf: preallocated crash dump buffer * @bufsize: size of @buf available for crash dump bytes (must match * smallest number of bytes available for writing to a @@ -178,7 +178,7 @@ struct pstore_info { struct module *owner; const char *name; - spinlock_t buf_lock; + struct semaphore buf_lock; char *buf; size_t bufsize; diff --git a/include/linux/sched.h b/include/linux/sched.h index 637d25c313740..df2259962ba1e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -835,6 +835,10 @@ struct task_struct { #ifdef CONFIG_MEMCG unsigned in_user_fault:1; #endif +#ifdef CONFIG_LRU_GEN + /* whether the LRU algorithm may apply to this access */ + unsigned in_lru_fault:1; +#endif #ifdef CONFIG_COMPAT_BRK unsigned brk_randomized:1; #endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 52004d800c935..0a361d4b58de6 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -472,8 +472,6 @@ extern void uart_handle_cts_change(struct uart_port *uport, extern void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag); -void uart_xchar_out(struct uart_port *uport, int offset); - #ifdef CONFIG_MAGIC_SYSRQ_SERIAL #define SYSRQ_TIMEOUT (HZ * 5) diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index b1af87330f863..cf27b080e1482 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -618,7 +618,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, static inline struct ti_sci_resource * devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev, - u32 dev_id, u32 sub_type) + u32 dev_id, u32 sub_type); { return ERR_PTR(-EINVAL); } diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 6d9d1520612b8..b998e4b736912 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -603,8 +603,6 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) return -EBADMSG; - if (len > SIZE_MAX / sizeof(*p)) - return -EBADMSG; p = xdr_inline_decode(xdr, len * sizeof(*p)); if (unlikely(!p)) return -EBADMSG; diff --git a/include/linux/swap.h b/include/linux/swap.h index beda0a50d0b91..dfdf026dc54d1 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -130,6 +130,10 @@ union swap_header { */ struct reclaim_state { unsigned long reclaimed_slab; +#ifdef CONFIG_LRU_GEN + /* per-thread mm walk data */ + struct lru_gen_mm_walk *mm_walk; +#endif }; #ifdef __KERNEL__ @@ -281,6 +285,7 @@ struct swap_info_struct { */ struct work_struct discard_work; /* discard worker */ struct swap_cluster_list discard_clusters; /* discard clusters list */ + ANDROID_VENDOR_DATA(1); struct plist_node avail_lists[]; /* * entries in swap_avail_heads, one * entry per node. @@ -350,6 +355,7 @@ extern void lru_add_drain_cpu(int cpu); extern void lru_add_drain_cpu_zone(struct zone *zone); extern void lru_add_drain_all(void); extern void rotate_reclaimable_page(struct page *page); +extern void activate_page(struct page *page); extern void deactivate_file_page(struct page *page); extern void deactivate_page(struct page *page); extern void mark_page_lazyfree(struct page *page); diff --git a/include/linux/swap_slots.h b/include/linux/swap_slots.h index 347f1a3041905..c4dc91ebbaa87 100644 --- a/include/linux/swap_slots.h +++ b/include/linux/swap_slots.h @@ -19,6 +19,7 @@ struct swap_slots_cache { spinlock_t free_lock; /* protects slots_ret, n_ret */ swp_entry_t *slots_ret; int n_ret; + ANDROID_VENDOR_DATA(1); }; void disable_swap_slots_cache_lock(void); diff --git a/include/linux/wait.h b/include/linux/wait.h index 9b8b0833100a0..5dfae54f88fde 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -219,6 +219,7 @@ void __wake_up_pollfree(struct wait_queue_head *wq_head); #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL) #define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE) +#define wake_up_sync(x) __wake_up_sync((x), TASK_NORMAL) /* * Wakeup macros to be used to report events to the targets. diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 4d8589244dc75..b1c7172869939 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -197,8 +197,7 @@ struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr); struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, struct sockaddr_vm *dst); void vsock_remove_sock(struct vsock_sock *vsk); -void vsock_for_each_connected_socket(struct vsock_transport *transport, - void (*fn)(struct sock *sk)); +void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)); int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); bool vsock_find_cid(unsigned int cid); diff --git a/include/net/esp.h b/include/net/esp.h index 90cd02ff77ef6..9c5637d41d951 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,8 +4,6 @@ #include -#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER) - struct ip_esp_hdr; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) diff --git a/include/net/sock.h b/include/net/sock.h index f458d74d3623b..fd78d61b8fec2 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2683,7 +2683,6 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; -#define SKB_FRAG_PAGE_ORDER get_order(32768) DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) diff --git a/include/net/udp.h b/include/net/udp.h index 4017f257628f3..435cc009e6eaa 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -467,7 +467,6 @@ void udp_init(void); DECLARE_STATIC_KEY_FALSE(udp_encap_needed_key); void udp_encap_enable(void); -void udp_encap_disable(void); #if IS_ENABLED(CONFIG_IPV6) DECLARE_STATIC_KEY_FALSE(udpv6_encap_needed_key); void udpv6_encap_enable(void); diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 24ece06bad9ef..2ea453dac8762 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -177,8 +177,9 @@ static inline void udp_tunnel_encap_enable(struct socket *sock) #if IS_ENABLED(CONFIG_IPV6) if (sock->sk->sk_family == PF_INET6) ipv6_stub->udpv6_encap_enable(); + else #endif - udp_encap_enable(); + udp_encap_enable(); } #define UDP_TUNNEL_NIC_MAX_TABLES 4 diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 0dd9dbc2ae21c..d54a6cb496dac 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -206,6 +206,7 @@ struct scsi_device { unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device * creation time */ unsigned ignore_media_change:1; /* Ignore MEDIA CHANGE on resume */ + unsigned silence_suspend:1; /* Do not print runtime PM related messages */ bool offline_already; /* Device offline message logged */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 5ffc2efedd9f8..2336bf9243e18 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -398,8 +398,6 @@ struct snd_pcm_runtime { wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; bool stop_operating; /* sync_stop will be called */ - struct mutex buffer_mutex; /* protect for buffer changes */ - atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */ /* -- private section -- */ void *private_data; diff --git a/include/trace/events/damon.h b/include/trace/events/damon.h new file mode 100644 index 0000000000000..c79f1d4c39afe --- /dev/null +++ b/include/trace/events/damon.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM damon + +#if !defined(_TRACE_DAMON_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_DAMON_H + +#include +#include +#include + +TRACE_EVENT(damon_aggregated, + + TP_PROTO(struct damon_target *t, unsigned int target_id, + struct damon_region *r, unsigned int nr_regions), + + TP_ARGS(t, target_id, r, nr_regions), + + TP_STRUCT__entry( + __field(unsigned long, target_id) + __field(unsigned int, nr_regions) + __field(unsigned long, start) + __field(unsigned long, end) + __field(unsigned int, nr_accesses) + __field(unsigned int, age) + ), + + TP_fast_assign( + __entry->target_id = target_id; + __entry->nr_regions = nr_regions; + __entry->start = r->ar.start; + __entry->end = r->ar.end; + __entry->nr_accesses = r->nr_accesses; + __entry->age = r->age; + ), + + TP_printk("target_id=%lu nr_regions=%u %lu-%lu: %u %u", + __entry->target_id, __entry->nr_regions, + __entry->start, __entry->end, + __entry->nr_accesses, __entry->age) +); + +#endif /* _TRACE_DAMON_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 4973265655a7f..70ae5497b73a6 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -95,17 +95,6 @@ TRACE_DEFINE_ENUM(ES_REFERENCED_B); { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}, \ { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) -TRACE_DEFINE_ENUM(EXT4_FC_REASON_XATTR); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_CROSS_RENAME); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_NOMEM); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_SWAP_BOOT); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_RESIZE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_RENAME_DIR); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_FALLOC_RANGE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_INODE_JOURNAL_DATA); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX); - #define show_fc_reason(reason) \ __print_symbolic(reason, \ { EXT4_FC_REASON_XATTR, "XATTR"}, \ @@ -2910,50 +2899,41 @@ TRACE_EVENT(ext4_fc_commit_stop, #define FC_REASON_NAME_STAT(reason) \ show_fc_reason(reason), \ - __entry->fc_ineligible_rc[reason] + __entry->sbi->s_fc_stats.fc_ineligible_reason_count[reason] TRACE_EVENT(ext4_fc_stats, - TP_PROTO(struct super_block *sb), + TP_PROTO(struct super_block *sb), - TP_ARGS(sb), + TP_ARGS(sb), - TP_STRUCT__entry( - __field(dev_t, dev) - __array(unsigned int, fc_ineligible_rc, EXT4_FC_REASON_MAX) - __field(unsigned long, fc_commits) - __field(unsigned long, fc_ineligible_commits) - __field(unsigned long, fc_numblks) - ), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(struct ext4_sb_info *, sbi) + __field(int, count) + ), - TP_fast_assign( - int i; + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->sbi = EXT4_SB(sb); + ), + + TP_printk("dev %d:%d fc ineligible reasons:\n" + "%s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d; " + "num_commits:%ld, ineligible: %ld, numblks: %ld", + MAJOR(__entry->dev), MINOR(__entry->dev), + FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), + FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), + FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), + __entry->sbi->s_fc_stats.fc_num_commits, + __entry->sbi->s_fc_stats.fc_ineligible_commits, + __entry->sbi->s_fc_stats.fc_numblks) - __entry->dev = sb->s_dev; - for (i = 0; i < EXT4_FC_REASON_MAX; i++) { - __entry->fc_ineligible_rc[i] = - EXT4_SB(sb)->s_fc_stats.fc_ineligible_reason_count[i]; - } - __entry->fc_commits = EXT4_SB(sb)->s_fc_stats.fc_num_commits; - __entry->fc_ineligible_commits = - EXT4_SB(sb)->s_fc_stats.fc_ineligible_commits; - __entry->fc_numblks = EXT4_SB(sb)->s_fc_stats.fc_numblks; - ), - - TP_printk("dev %d,%d fc ineligible reasons:\n" - "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u " - "num_commits:%lu, ineligible: %lu, numblks: %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), - FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), - FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), - __entry->fc_commits, __entry->fc_ineligible_commits, - __entry->fc_numblks) ); #define DEFINE_TRACE_DENTRY_EVENT(__type) \ diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index d26bfc4951291..12d76932e390e 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -83,7 +83,7 @@ #define IF_HAVE_PG_HWPOISON(flag,string) #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) #define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string} #else #define IF_HAVE_PG_IDLE(flag,string) diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h index 8fd1babae761b..e1735fe7c76af 100644 --- a/include/trace/events/pagemap.h +++ b/include/trace/events/pagemap.h @@ -27,24 +27,21 @@ TRACE_EVENT(mm_lru_insertion, - TP_PROTO( - struct page *page, - int lru - ), + TP_PROTO(struct page *page), - TP_ARGS(page, lru), + TP_ARGS(page), TP_STRUCT__entry( __field(struct page *, page ) __field(unsigned long, pfn ) - __field(int, lru ) + __field(enum lru_list, lru ) __field(unsigned long, flags ) ), TP_fast_assign( __entry->page = page; __entry->pfn = page_to_pfn(page); - __entry->lru = lru; + __entry->lru = page_lru(page); __entry->flags = trace_pagemap_flags(page); ), diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 4a3ab0ed6e062..e70c90116edae 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -83,15 +83,12 @@ enum rxrpc_call_trace { rxrpc_call_error, rxrpc_call_got, rxrpc_call_got_kernel, - rxrpc_call_got_timer, rxrpc_call_got_userid, rxrpc_call_new_client, rxrpc_call_new_service, rxrpc_call_put, rxrpc_call_put_kernel, rxrpc_call_put_noqueue, - rxrpc_call_put_notimer, - rxrpc_call_put_timer, rxrpc_call_put_userid, rxrpc_call_queued, rxrpc_call_queued_ref, @@ -281,15 +278,12 @@ enum rxrpc_tx_point { EM(rxrpc_call_error, "*E*") \ EM(rxrpc_call_got, "GOT") \ EM(rxrpc_call_got_kernel, "Gke") \ - EM(rxrpc_call_got_timer, "GTM") \ EM(rxrpc_call_got_userid, "Gus") \ EM(rxrpc_call_new_client, "NWc") \ EM(rxrpc_call_new_service, "NWs") \ EM(rxrpc_call_put, "PUT") \ EM(rxrpc_call_put_kernel, "Pke") \ - EM(rxrpc_call_put_noqueue, "PnQ") \ - EM(rxrpc_call_put_notimer, "PnT") \ - EM(rxrpc_call_put_timer, "PTM") \ + EM(rxrpc_call_put_noqueue, "PNQ") \ EM(rxrpc_call_put_userid, "Pus") \ EM(rxrpc_call_queued, "QUE") \ EM(rxrpc_call_queued_ref, "QUR") \ diff --git a/include/trace/hooks/avc.h b/include/trace/hooks/avc.h index 2c76e02fc3c52..1d205382e6df4 100644 --- a/include/trace/hooks/avc.h +++ b/include/trace/hooks/avc.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_AVC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_AVC_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/binder.h b/include/trace/hooks/binder.h index ffba8746e58ba..d7419ef64de21 100644 --- a/include/trace/hooks/binder.h +++ b/include/trace/hooks/binder.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_BINDER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BINDER_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/block.h b/include/trace/hooks/block.h index 0d9d7db399680..ca9762a9be5b0 100644 --- a/include/trace/hooks/block.h +++ b/include/trace/hooks/block.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BLOCK_H -#include #include struct blk_mq_tag_set; diff --git a/include/trace/hooks/bug.h b/include/trace/hooks/bug.h index 685859e0eaf79..3bd683e54f713 100644 --- a/include/trace/hooks/bug.h +++ b/include/trace/hooks/bug.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_BUG_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BUG_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/cgroup.h b/include/trace/hooks/cgroup.h index 6b6d7918c5186..e33d3519d6765 100644 --- a/include/trace/hooks/cgroup.h +++ b/include/trace/hooks/cgroup.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CGROUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CGROUP_H -#include #include struct task_struct; diff --git a/include/trace/hooks/cpu.h b/include/trace/hooks/cpu.h index 645702996b000..b368736e72857 100644 --- a/include/trace/hooks/cpu.h +++ b/include/trace/hooks/cpu.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CPU_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPU_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/cpufreq.h b/include/trace/hooks/cpufreq.h index 5142cd5a07de4..70f90a3ef25c2 100644 --- a/include/trace/hooks/cpufreq.h +++ b/include/trace/hooks/cpufreq.h @@ -8,7 +8,6 @@ #define _TRACE_HOOK_CPUFREQ_H #include -#include #include DECLARE_HOOK(android_vh_show_max_freq, diff --git a/include/trace/hooks/cpuidle.h b/include/trace/hooks/cpuidle.h index 6d1f4bf7f1edb..c2ddabe37b00b 100644 --- a/include/trace/hooks/cpuidle.h +++ b/include/trace/hooks/cpuidle.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_CPUIDLE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPUIDLE_H -#include #include struct cpuidle_device; diff --git a/include/trace/hooks/cpuidle_psci.h b/include/trace/hooks/cpuidle_psci.h index 94b01eba0b4ec..eef0032c0879b 100644 --- a/include/trace/hooks/cpuidle_psci.h +++ b/include/trace/hooks/cpuidle_psci.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CPUIDLE_PSCI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPUIDLE_PSCI_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/creds.h b/include/trace/hooks/creds.h index dd877e3a1f3e4..92b0d8e981f3a 100644 --- a/include/trace/hooks/creds.h +++ b/include/trace/hooks/creds.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CREDS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CREDS_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/debug.h b/include/trace/hooks/debug.h index ac006d7fdd0a2..90d81041a48b5 100644 --- a/include/trace/hooks/debug.h +++ b/include/trace/hooks/debug.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_DEBUG_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_DEBUG_H -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/dtask.h b/include/trace/hooks/dtask.h index 3c49af0e65608..b483037e10131 100644 --- a/include/trace/hooks/dtask.h +++ b/include/trace/hooks/dtask.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_DTASK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_DTASK_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/epoch.h b/include/trace/hooks/epoch.h index f1c5342c822e3..c3f018edf1306 100644 --- a/include/trace/hooks/epoch.h +++ b/include/trace/hooks/epoch.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_EPOCH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_EPOCH_H -#include #include DECLARE_HOOK(android_vh_show_suspend_epoch_val, diff --git a/include/trace/hooks/fault.h b/include/trace/hooks/fault.h index 1daf2d250f310..8803a1b3d2f08 100644 --- a/include/trace/hooks/fault.h +++ b/include/trace/hooks/fault.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_FAULT_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FAULT_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/fips140.h b/include/trace/hooks/fips140.h index 3aebf61687915..fd4a42c013c74 100644 --- a/include/trace/hooks/fips140.h +++ b/include/trace/hooks/fips140.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_FIPS140_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FIPS140_H -#include #include struct crypto_aes_ctx; diff --git a/include/trace/hooks/fpsimd.h b/include/trace/hooks/fpsimd.h index a4a3ce228fff9..3365c298e6bc1 100644 --- a/include/trace/hooks/fpsimd.h +++ b/include/trace/hooks/fpsimd.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_FPSIMD_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FPSIMD_H -#include #include struct task_struct; diff --git a/include/trace/hooks/fs.h b/include/trace/hooks/fs.h index 90acad536bdba..1c8d692be3afa 100644 --- a/include/trace/hooks/fs.h +++ b/include/trace/hooks/fs.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_FS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FS_H -#include #include DECLARE_HOOK(android_vh_ep_create_wakeup_source, TP_PROTO(char *name, int len), diff --git a/include/trace/hooks/ftrace_dump.h b/include/trace/hooks/ftrace_dump.h index ed3be8a0d74b1..b63d9c8094260 100644 --- a/include/trace/hooks/ftrace_dump.h +++ b/include/trace/hooks/ftrace_dump.h @@ -10,7 +10,6 @@ #include #include -#include #include DECLARE_HOOK(android_vh_ftrace_oops_enter, diff --git a/include/trace/hooks/futex.h b/include/trace/hooks/futex.h index 0692dd68d93c4..3acf8128dc3e6 100644 --- a/include/trace/hooks/futex.h +++ b/include/trace/hooks/futex.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_FUTEX_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FUTEX_H -#include #include #include /* diff --git a/include/trace/hooks/gic.h b/include/trace/hooks/gic.h index 2f7d3cfa6d9b3..d33786f2de95b 100644 --- a/include/trace/hooks/gic.h +++ b/include/trace/hooks/gic.h @@ -8,7 +8,6 @@ #define _TRACE_HOOK_GIC_H -#include #include struct gic_chip_data; diff --git a/include/trace/hooks/gic_v3.h b/include/trace/hooks/gic_v3.h index 3afb7379145d1..337f7e1348c18 100644 --- a/include/trace/hooks/gic_v3.h +++ b/include/trace/hooks/gic_v3.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_GIC_V3_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_GIC_V3_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/gpiolib.h b/include/trace/hooks/gpiolib.h index 96aca935f953d..24cb3f54fb82e 100644 --- a/include/trace/hooks/gpiolib.h +++ b/include/trace/hooks/gpiolib.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_GPIOLIB_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_GPIOLIB_H -#include #include #include "../drivers/gpio/gpiolib.h" diff --git a/include/trace/hooks/gup.h b/include/trace/hooks/gup.h new file mode 100644 index 0000000000000..47ea47eeede40 --- /dev/null +++ b/include/trace/hooks/gup.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gup +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH trace/hooks +#if !defined(_TRACE_HOOK_GUP_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_GUP_H +#include + +struct page; + +DECLARE_HOOK(android_vh_try_grab_compound_head, + TP_PROTO(struct page *page, int refs, unsigned int flags, bool *ret), + TP_ARGS(page, refs, flags, ret)); + +DECLARE_HOOK(android_vh___get_user_pages_remote, + TP_PROTO(int *locked, unsigned int *gup_flags, struct page **pages), + TP_ARGS(locked, gup_flags, pages)); + +DECLARE_HOOK(android_vh_get_user_pages, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); + +DECLARE_HOOK(android_vh_internal_get_user_pages_fast, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); + +DECLARE_HOOK(android_vh_pin_user_pages, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); +#endif /* _TRACE_HOOK_GUP_H */ +/* This part must be outside protection */ +#include diff --git a/include/trace/hooks/hung_task.h b/include/trace/hooks/hung_task.h index b355828df349e..1559d3ed774f0 100644 --- a/include/trace/hooks/hung_task.h +++ b/include/trace/hooks/hung_task.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_HUNG_TASK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_HUNG_TASK_H -#include #include DECLARE_HOOK(android_vh_check_uninterruptible_tasks, diff --git a/include/trace/hooks/i2c.h b/include/trace/hooks/i2c.h index 71536ad67f670..306c0f8cab51f 100644 --- a/include/trace/hooks/i2c.h +++ b/include/trace/hooks/i2c.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_I2C_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_I2C_H -#include #include DECLARE_HOOK(android_vh_of_i2c_get_board_info, diff --git a/include/trace/hooks/iommu.h b/include/trace/hooks/iommu.h index c9a52193c4e94..6c30cb7932fa6 100644 --- a/include/trace/hooks/iommu.h +++ b/include/trace/hooks/iommu.h @@ -9,7 +9,6 @@ #include -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/ipv6.h b/include/trace/hooks/ipv6.h index c1998af0c5a0a..64a5481612332 100644 --- a/include/trace/hooks/ipv6.h +++ b/include/trace/hooks/ipv6.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_IPV6_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_IPV6_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/logbuf.h b/include/trace/hooks/logbuf.h index f73ad597fc648..72c34f7fbad0c 100644 --- a/include/trace/hooks/logbuf.h +++ b/include/trace/hooks/logbuf.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_LOGBUF_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_LOGBUF_H -#include #include struct printk_ringbuffer; diff --git a/include/trace/hooks/memory.h b/include/trace/hooks/memory.h index 4b3f77a72d82c..940af43d736c5 100644 --- a/include/trace/hooks/memory.h +++ b/include/trace/hooks/memory.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MEMORY_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MEMORY_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h index ac6142a6e02ad..9b583a3371011 100644 --- a/include/trace/hooks/mm.h +++ b/include/trace/hooks/mm.h @@ -11,7 +11,6 @@ #include #include -#include #include struct cma; diff --git a/include/trace/hooks/mmc_core.h b/include/trace/hooks/mmc_core.h index ad367782d59f6..2e36dd8b2b67a 100644 --- a/include/trace/hooks/mmc_core.h +++ b/include/trace/hooks/mmc_core.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_MMC_CORE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MMC_CORE_H -#include #include struct mmc_host; diff --git a/include/trace/hooks/module.h b/include/trace/hooks/module.h index 281cb0d37c12c..78b49869ca65c 100644 --- a/include/trace/hooks/module.h +++ b/include/trace/hooks/module.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MODULE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MODULE_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/mpam.h b/include/trace/hooks/mpam.h index 8479fe7c2356f..b62f965032da7 100644 --- a/include/trace/hooks/mpam.h +++ b/include/trace/hooks/mpam.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MPAM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MPAM_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/net.h b/include/trace/hooks/net.h index 6715aa4eb668d..0b6de6f659cf7 100644 --- a/include/trace/hooks/net.h +++ b/include/trace/hooks/net.h @@ -6,7 +6,6 @@ #if !defined(_TRACE_HOOK_NET_VH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_NET_VH_H -#include #include struct packet_type; diff --git a/include/trace/hooks/pci.h b/include/trace/hooks/pci.h new file mode 100644 index 0000000000000..00d38980ec499 --- /dev/null +++ b/include/trace/hooks/pci.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pci +#define TRACE_INCLUDE_PATH trace/hooks + +#if !defined(_TRACE_HOOK_PCI_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_PCI_H +#include +/* + * Following tracepoints are not exported in tracefs and provide a + * mechanism for vendor modules to hook and extend functionality + */ + +DECLARE_RESTRICTED_HOOK(android_rvh_pci_d3_sleep, + TP_PROTO(struct pci_dev *dev, unsigned int *delay), + TP_ARGS(dev, delay), 1); + +#endif /* _TRACE_HOOK_PCI_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/hooks/pm_domain.h b/include/trace/hooks/pm_domain.h index 548e350e80908..f6b1c3808ce98 100644 --- a/include/trace/hooks/pm_domain.h +++ b/include/trace/hooks/pm_domain.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_PM_DOMAIN_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PM_DOMAIN_H -#include #include struct generic_pm_domain; diff --git a/include/trace/hooks/power.h b/include/trace/hooks/power.h index 149ea08580b80..195538679f322 100644 --- a/include/trace/hooks/power.h +++ b/include/trace/hooks/power.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_POWER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_POWER_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/preemptirq.h b/include/trace/hooks/preemptirq.h index b4d32c473f3ac..4fbab929f4cf5 100644 --- a/include/trace/hooks/preemptirq.h +++ b/include/trace/hooks/preemptirq.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_PREEMPTIRQ_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PREEMPTIRQ_H -#include #include DECLARE_RESTRICTED_HOOK(android_rvh_preempt_disable, diff --git a/include/trace/hooks/printk.h b/include/trace/hooks/printk.h index e4df6e4bf7a8a..5ec4d743d67f5 100644 --- a/include/trace/hooks/printk.h +++ b/include/trace/hooks/printk.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_PRINTK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PRINTK_H -#include #include DECLARE_HOOK(android_vh_printk_hotplug, diff --git a/include/trace/hooks/psi.h b/include/trace/hooks/psi.h index 62d1a0ee7b635..bd704c16185b4 100644 --- a/include/trace/hooks/psi.h +++ b/include/trace/hooks/psi.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_PSI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PSI_H -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/remoteproc.h b/include/trace/hooks/remoteproc.h index 7cc5e93d2ebe5..ee0a2f0ea147f 100644 --- a/include/trace/hooks/remoteproc.h +++ b/include/trace/hooks/remoteproc.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_RPROC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_RPROC_H -#include #include struct rproc; diff --git a/include/trace/hooks/rwsem.h b/include/trace/hooks/rwsem.h index d644a6e212598..9737879e3bc8f 100644 --- a/include/trace/hooks/rwsem.h +++ b/include/trace/hooks/rwsem.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_RWSEM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_RWSEM_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sched.h b/include/trace/hooks/sched.h index a9884beaf2e8a..79e8b401b3a07 100644 --- a/include/trace/hooks/sched.h +++ b/include/trace/hooks/sched.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SCHED_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a @@ -405,6 +404,30 @@ DECLARE_HOOK(android_vh_setscheduler_uclamp, TP_PROTO(struct task_struct *tsk, int clamp_id, unsigned int value), TP_ARGS(tsk, clamp_id, value)); +DECLARE_RESTRICTED_HOOK(android_rvh_attach_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_detach_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_load_avg, + TP_PROTO(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(now, cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_remove_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_blocked_fair, + TP_PROTO(struct rq *rq), + TP_ARGS(rq), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_rt_rq_load_avg, + TP_PROTO(u64 now, struct rq *rq, struct task_struct *tsk, int running), + TP_ARGS(now, rq, tsk, running), 1); + /* macro versions of hooks are no longer required */ #endif /* _TRACE_HOOK_SCHED_H */ diff --git a/include/trace/hooks/scmi.h b/include/trace/hooks/scmi.h index ea2db9f07a9f8..d889d3334b9cb 100644 --- a/include/trace/hooks/scmi.h +++ b/include/trace/hooks/scmi.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_SCMI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SCMI_H -#include #include DECLARE_HOOK(android_vh_scmi_timeout_sync, diff --git a/include/trace/hooks/selinux.h b/include/trace/hooks/selinux.h index 2ad6484d2c553..ebd6187c41082 100644 --- a/include/trace/hooks/selinux.h +++ b/include/trace/hooks/selinux.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SELINUX_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SELINUX_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/shmem_fs.h b/include/trace/hooks/shmem_fs.h index 08e63033070e9..0077707072c5c 100644 --- a/include/trace/hooks/shmem_fs.h +++ b/include/trace/hooks/shmem_fs.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SHMEM_FS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SHMEM_FS_H -#include #include struct page; diff --git a/include/trace/hooks/signal.h b/include/trace/hooks/signal.h index a0db2e8cf77d3..937e6c49b7ca8 100644 --- a/include/trace/hooks/signal.h +++ b/include/trace/hooks/signal.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SIGNAL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SIGNAL_H -#include #include struct task_struct; diff --git a/include/trace/hooks/snd_compr.h b/include/trace/hooks/snd_compr.h index c42ed8d6bc301..2e63aff9e4f94 100644 --- a/include/trace/hooks/snd_compr.h +++ b/include/trace/hooks/snd_compr.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_SND_COMPR_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SND_COMPR_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/softlockup.h b/include/trace/hooks/softlockup.h index 9294913f91df3..072f30007d712 100644 --- a/include/trace/hooks/softlockup.h +++ b/include/trace/hooks/softlockup.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_SOFTLOCKUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SOFTLOCKUP_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sound.h b/include/trace/hooks/sound.h index 2bf018edf3926..3dfd589d264d1 100644 --- a/include/trace/hooks/sound.h +++ b/include/trace/hooks/sound.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SOUND_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SOUND_H -#include #include #include diff --git a/include/trace/hooks/sys.h b/include/trace/hooks/sys.h index 9e5d7a5cb2cf1..e2d5d6d4fc142 100644 --- a/include/trace/hooks/sys.h +++ b/include/trace/hooks/sys.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SYS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYS_H -#include #include struct task_struct; diff --git a/include/trace/hooks/syscall_check.h b/include/trace/hooks/syscall_check.h index d39802aa4a1e6..56d8267297ca2 100644 --- a/include/trace/hooks/syscall_check.h +++ b/include/trace/hooks/syscall_check.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SYSCALL_CHECK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYSCALL_CHECK_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sysrqcrash.h b/include/trace/hooks/sysrqcrash.h index d163f898a9f6e..0056322c38179 100644 --- a/include/trace/hooks/sysrqcrash.h +++ b/include/trace/hooks/sysrqcrash.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_SYSRQCRASH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYSRQCRASH_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/thermal.h b/include/trace/hooks/thermal.h index 25d6151b29190..78ce2a5ea49bf 100644 --- a/include/trace/hooks/thermal.h +++ b/include/trace/hooks/thermal.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_THERMAL_H -#include #include #include diff --git a/include/trace/hooks/timer.h b/include/trace/hooks/timer.h index 174d958e4c314..67ef865dad4ad 100644 --- a/include/trace/hooks/timer.h +++ b/include/trace/hooks/timer.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_TIMER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TIMER_H -#include #include DECLARE_HOOK(android_vh_timer_calc_index, diff --git a/include/trace/hooks/topology.h b/include/trace/hooks/topology.h index 74014027160c8..5d29893ba477d 100644 --- a/include/trace/hooks/topology.h +++ b/include/trace/hooks/topology.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_TOPOLOGY_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TOPOLOGY_H -#include #include #include diff --git a/include/trace/hooks/traps.h b/include/trace/hooks/traps.h index 350a14369acc9..38749535aa4d0 100644 --- a/include/trace/hooks/traps.h +++ b/include/trace/hooks/traps.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_TRAPS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TRAPS_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/typec.h b/include/trace/hooks/typec.h index b7be4d8577081..6634dbb82917f 100644 --- a/include/trace/hooks/typec.h +++ b/include/trace/hooks/typec.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_TYPEC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TYPEC_H -#include #include #include /* diff --git a/include/trace/hooks/ufshcd.h b/include/trace/hooks/ufshcd.h index 744a1db41631d..eebde088cd240 100644 --- a/include/trace/hooks/ufshcd.h +++ b/include/trace/hooks/ufshcd.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_UFSHCD_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_UFSHCD_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/usb.h b/include/trace/hooks/usb.h index f8459473042e4..f4d5ff04b6b88 100644 --- a/include/trace/hooks/usb.h +++ b/include/trace/hooks/usb.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_USB_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_USB_H -#include #include #include /* diff --git a/include/trace/hooks/user.h b/include/trace/hooks/user.h index b5b507ccd9c26..773eed2ea75a4 100644 --- a/include/trace/hooks/user.h +++ b/include/trace/hooks/user.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_USER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_USER_H -#include #include struct user_struct; diff --git a/include/trace/hooks/v4l2core.h b/include/trace/hooks/v4l2core.h index 32b6e96ba627b..615e1ce8ff9e9 100644 --- a/include/trace/hooks/v4l2core.h +++ b/include/trace/hooks/v4l2core.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_V4L2CORE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_V4L2_CORE_H -#include #include struct v4l2_format; diff --git a/include/trace/hooks/v4l2mc.h b/include/trace/hooks/v4l2mc.h index 8a4653bd4a4de..952c3ffe26e5c 100644 --- a/include/trace/hooks/v4l2mc.h +++ b/include/trace/hooks/v4l2mc.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_V4L2MC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_V4L2MC_H -#include #include struct media_link; diff --git a/include/trace/hooks/vendor_hooks.h b/include/trace/hooks/vendor_hooks.h index f51a9ac310457..a283509abbf61 100644 --- a/include/trace/hooks/vendor_hooks.h +++ b/include/trace/hooks/vendor_hooks.h @@ -7,7 +7,9 @@ * will override the DECLARE_RESTRICTED_HOOK and break the second include. */ +#ifndef __GENKSYMS__ #include +#endif #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/vmscan.h b/include/trace/hooks/vmscan.h index b6b77d9895cdd..4a3af8e75839f 100644 --- a/include/trace/hooks/vmscan.h +++ b/include/trace/hooks/vmscan.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_VMSCAN_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_VMSCAN_H -#include #include DECLARE_HOOK(android_vh_tune_scan_type, diff --git a/include/trace/hooks/workqueue.h b/include/trace/hooks/workqueue.h index 0ffe56433a4c8..dee037d0b7c04 100644 --- a/include/trace/hooks/workqueue.h +++ b/include/trace/hooks/workqueue.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_WORKQUEUE_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/wqlockup.h b/include/trace/hooks/wqlockup.h index 21e23ad6b9d90..2572ebf5eff46 100644 --- a/include/trace/hooks/wqlockup.h +++ b/include/trace/hooks/wqlockup.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_WQLOCKUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_WQLOCKUP_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 8b4a27b17606d..26b6bee72039a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1491,8 +1491,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 1, if current task belongs to the cgroup2. - * * 0, if current task does not belong to the cgroup2. + * * 0, if current task belongs to the cgroup2. + * * 1, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) @@ -2164,8 +2164,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * The non-negative copied *buf* length equal to or less than - * *size* on success, or a negative error in case of failure. + * A non-negative value equal to or less than *size* on success, + * or a negative error in case of failure. * * long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description @@ -3449,8 +3449,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * The non-negative copied *buf* length equal to or less than - * *size* on success, or a negative error in case of failure. + * A non-negative value equal to or less than *size* on success, + * or a negative error in case of failure. * * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u32 len, u64 flags) * Description diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 98aaf3d84c5d0..f0521a39a5863 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -965,42 +965,44 @@ struct fuse_removemapping_one { #define FUSE_REMOVEMAPPING_MAX_ENTRY \ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) -struct fuse_mount; +/* + * Fuse BPF Args + * + * Used to communicate with bpf programs to allow checking or altering certain values. + * The end_offset allows the bpf verifier to check boundaries statically. This reflects + * the ends of the buffer. size shows the length that was actually used. + * + */ /** One input argument of a request */ -struct fuse_in_arg { - unsigned size; +struct fuse_bpf_in_arg { + uint32_t size; const void *value; + const void *end_offset; }; /** One output argument of a request */ -struct fuse_arg { - unsigned size; +struct fuse_bpf_arg { + uint32_t size; void *value; + void *end_offset; }; -struct fuse_args { +#define FUSE_MAX_IN_ARGS 5 +#define FUSE_MAX_OUT_ARGS 3 + +#define FUSE_BPF_FORCE (1 << 0) +#define FUSE_BPF_OUT_ARGVAR (1 << 6) + +struct fuse_bpf_args { uint64_t nodeid; uint32_t opcode; uint32_t error_in; - unsigned short in_numargs; - unsigned short out_numargs; - int force:1; - int noreply:1; - int nocreds:1; - int in_pages:1; - int out_pages:1; - int user_pages:1; - int out_argvar:1; - int page_zeroing:1; - int page_replace:1; - int may_block:1; - struct fuse_in_arg in_args[5]; - struct fuse_arg out_args[3]; - void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); - - /* Path used for completing d_canonical_path */ - struct path *canonical_path; + uint32_t in_numargs; + uint32_t out_numargs; + uint32_t flags; + struct fuse_bpf_in_arg in_args[FUSE_MAX_IN_ARGS]; + struct fuse_bpf_arg out_args[FUSE_MAX_OUT_ARGS]; }; #define FUSE_BPF_USER_FILTER 1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2380257670457..facb29ebef2dd 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1072,9 +1072,7 @@ struct kvm_ppc_resize_hpt { /* #define KVM_CAP_HYPERV_ENFORCE_CPUID 199 #define KVM_CAP_SREGS2 200 -*/ #define KVM_CAP_EXIT_HYPERCALL 201 -/* #define KVM_CAP_PPC_RPT_INVALIDATE 202 #define KVM_CAP_BINARY_STATS_FD 203 #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 2bf93c0d6354b..b1484a5a3c360 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -55,6 +55,8 @@ #define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18) +#define PSCI_1_1_FN64_MEM_PROTECT PSCI_0_2_FN64(19) + /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff #define PSCI_0_2_POWER_STATE_ID_SHIFT 0 diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 77ee207623a9b..9a402fdb60e97 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -105,11 +105,23 @@ struct rseq { * Read and set by the kernel. Set by user-space with single-copy * atomicity semantics. This field should only be updated by the * thread which registered this data structure. Aligned on 64-bit. - * - * 32-bit architectures should update the low order bits of the - * rseq_cs field, leaving the high order bits initialized to 0. */ - __u64 rseq_cs; + union { + __u64 ptr64; +#ifdef __LP64__ + __u64 ptr; +#else + struct { +#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || defined(__BIG_ENDIAN) + __u32 padding; /* Initialized to zero. */ + __u32 ptr32; +#else /* LITTLE */ + __u32 ptr32; + __u32 padding; /* Initialized to zero. */ +#endif /* ENDIAN */ + } ptr; +#endif + } rseq_cs; /* * Restartable sequences flags field. diff --git a/kernel/audit.h b/kernel/audit.h index 1918019e6aaf7..3b9c0945225a1 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -191,10 +191,6 @@ struct audit_context { struct { char *name; } module; - struct { - struct audit_ntp_data ntp_data; - struct timespec64 tk_injoffset; - } time; }; int fds[2]; struct audit_proctitle proctitle; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 07e2788bbbf12..638f424859edc 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1214,53 +1214,6 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) from_kuid(&init_user_ns, name->fcap.rootid)); } -static void audit_log_time(struct audit_context *context, struct audit_buffer **ab) -{ - const struct audit_ntp_data *ntp = &context->time.ntp_data; - const struct timespec64 *tk = &context->time.tk_injoffset; - static const char * const ntp_name[] = { - "offset", - "freq", - "status", - "tai", - "tick", - "adjust", - }; - int type; - - if (context->type == AUDIT_TIME_ADJNTPVAL) { - for (type = 0; type < AUDIT_NTP_NVALS; type++) { - if (ntp->vals[type].newval != ntp->vals[type].oldval) { - if (!*ab) { - *ab = audit_log_start(context, - GFP_KERNEL, - AUDIT_TIME_ADJNTPVAL); - if (!*ab) - return; - } - audit_log_format(*ab, "op=%s old=%lli new=%lli", - ntp_name[type], - ntp->vals[type].oldval, - ntp->vals[type].newval); - audit_log_end(*ab); - *ab = NULL; - } - } - } - if (tk->tv_sec != 0 || tk->tv_nsec != 0) { - if (!*ab) { - *ab = audit_log_start(context, GFP_KERNEL, - AUDIT_TIME_INJOFFSET); - if (!*ab) - return; - } - audit_log_format(*ab, "sec=%lli nsec=%li", - (long long)tk->tv_sec, tk->tv_nsec); - audit_log_end(*ab); - *ab = NULL; - } -} - static void show_special(struct audit_context *context, int *call_panic) { struct audit_buffer *ab; @@ -1366,11 +1319,6 @@ static void show_special(struct audit_context *context, int *call_panic) audit_log_format(ab, "(null)"); break; - case AUDIT_TIME_ADJNTPVAL: - case AUDIT_TIME_INJOFFSET: - /* this call deviates from the rest, eating the buffer */ - audit_log_time(context, &ab); - break; } audit_log_end(ab); } @@ -2612,26 +2560,31 @@ void __audit_fanotify(unsigned int response) void __audit_tk_injoffset(struct timespec64 offset) { - struct audit_context *context = audit_context(); + audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_INJOFFSET, + "sec=%lli nsec=%li", + (long long)offset.tv_sec, offset.tv_nsec); +} + +static void audit_log_ntp_val(const struct audit_ntp_data *ad, + const char *op, enum audit_ntp_type type) +{ + const struct audit_ntp_val *val = &ad->vals[type]; + + if (val->newval == val->oldval) + return; - /* only set type if not already set by NTP */ - if (!context->type) - context->type = AUDIT_TIME_INJOFFSET; - memcpy(&context->time.tk_injoffset, &offset, sizeof(offset)); + audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL, + "op=%s old=%lli new=%lli", op, val->oldval, val->newval); } void __audit_ntp_log(const struct audit_ntp_data *ad) { - struct audit_context *context = audit_context(); - int type; - - for (type = 0; type < AUDIT_NTP_NVALS; type++) - if (ad->vals[type].newval != ad->vals[type].oldval) { - /* unconditionally set type, overwriting TK */ - context->type = AUDIT_TIME_ADJNTPVAL; - memcpy(&context->time.ntp_data, ad, sizeof(*ad)); - break; - } + audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET); + audit_log_ntp_val(ad, "freq", AUDIT_NTP_FREQ); + audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS); + audit_log_ntp_val(ad, "tai", AUDIT_NTP_TAI); + audit_log_ntp_val(ad, "tick", AUDIT_NTP_TICK); + audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST); } void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries, diff --git a/kernel/bounds.c b/kernel/bounds.c index 9795d75b09b23..10dd9e6b03e55 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -22,6 +22,13 @@ int main(void) DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); #endif DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); +#ifdef CONFIG_LRU_GEN + DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); + DEFINE(LRU_REFS_WIDTH, MAX_NR_TIERS - 2); +#else + DEFINE(LRU_GEN_WIDTH, 0); + DEFINE(LRU_REFS_WIDTH, 0); +#endif /* End of constants */ return 0; diff --git a/kernel/bpf/bpf_fuse.c b/kernel/bpf/bpf_fuse.c index 2a4db5ce06b48..00738c84b76e6 100644 --- a/kernel/bpf/bpf_fuse.c +++ b/kernel/bpf/bpf_fuse.c @@ -36,12 +36,12 @@ static bool fuse_prog_is_valid_access(int off, int size, { int i; - if (off < 0 || off > offsetofend(struct fuse_args, out_args)) + if (off < 0 || off > offsetofend(struct fuse_bpf_args, out_args)) return false; /* TODO This is garbage. Do it properly */ for (i = 0; i < 5; i++) { - if (off == offsetof(struct fuse_args, in_args[i].value)) { + if (off == offsetof(struct fuse_bpf_args, in_args[i].value)) { info->reg_type = PTR_TO_RDONLY_BUF; info->ctx_field_size = 256; if (type != BPF_READ) @@ -50,7 +50,7 @@ static bool fuse_prog_is_valid_access(int off, int size, } } for (i = 0; i < 3; i++) { - if (off == offsetof(struct fuse_args, out_args[i].value)) { + if (off == offsetof(struct fuse_bpf_args, out_args[i].value)) { info->reg_type = PTR_TO_RDWR_BUF; info->ctx_field_size = 256; return true; diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 4575d2d60cb10..56cd7e6589ff3 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -358,7 +358,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, } static struct perf_callchain_entry * -get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) +get_callchain_entry_for_task(struct task_struct *task, u32 init_nr) { #ifdef CONFIG_STACKTRACE struct perf_callchain_entry *entry; @@ -369,8 +369,9 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) if (!entry) return NULL; - entry->nr = stack_trace_save_tsk(task, (unsigned long *)entry->ip, - max_depth, 0); + entry->nr = init_nr + + stack_trace_save_tsk(task, (unsigned long *)(entry->ip + init_nr), + sysctl_perf_event_max_stack - init_nr, 0); /* stack_trace_save_tsk() works on unsigned long array, while * perf_callchain_entry uses u64 array. For 32-bit systems, it is @@ -382,7 +383,7 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) int i; /* copy data from the end to avoid using extra buffer */ - for (i = entry->nr - 1; i >= 0; i--) + for (i = entry->nr - 1; i >= (int)init_nr; i--) to[i] = (u64)(from[i]); } @@ -399,19 +400,27 @@ static long __bpf_get_stackid(struct bpf_map *map, { struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map); struct stack_map_bucket *bucket, *new_bucket, *old_bucket; + u32 max_depth = map->value_size / stack_map_data_size(map); + /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ + u32 init_nr = sysctl_perf_event_max_stack - max_depth; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; u32 hash, id, trace_nr, trace_len; bool user = flags & BPF_F_USER_STACK; u64 *ips; bool hash_matches; - if (trace->nr <= skip) + /* get_perf_callchain() guarantees that trace->nr >= init_nr + * and trace-nr <= sysctl_perf_event_max_stack, so trace_nr <= max_depth + */ + trace_nr = trace->nr - init_nr; + + if (trace_nr <= skip) /* skipping more than usable stack trace */ return -EFAULT; - trace_nr = trace->nr - skip; + trace_nr -= skip; trace_len = trace_nr * sizeof(u64); - ips = trace->ip + skip; + ips = trace->ip + skip + init_nr; hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0); id = hash & (smap->n_buckets - 1); bucket = READ_ONCE(smap->buckets[id]); @@ -468,7 +477,8 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, u64, flags) { u32 max_depth = map->value_size / stack_map_data_size(map); - u32 skip = flags & BPF_F_SKIP_FIELD_MASK; + /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ + u32 init_nr = sysctl_perf_event_max_stack - max_depth; bool user = flags & BPF_F_USER_STACK; struct perf_callchain_entry *trace; bool kernel = !user; @@ -477,12 +487,8 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID))) return -EINVAL; - max_depth += skip; - if (max_depth > sysctl_perf_event_max_stack) - max_depth = sysctl_perf_event_max_stack; - - trace = get_perf_callchain(regs, 0, kernel, user, max_depth, - false, false); + trace = get_perf_callchain(regs, init_nr, kernel, user, + sysctl_perf_event_max_stack, false, false); if (unlikely(!trace)) /* couldn't fetch the stack trace */ @@ -573,7 +579,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, struct perf_callchain_entry *trace_in, void *buf, u32 size, u64 flags) { - u32 trace_nr, copy_len, elem_size, num_elem, max_depth; + u32 init_nr, trace_nr, copy_len, elem_size, num_elem; bool user_build_id = flags & BPF_F_USER_BUILD_ID; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; bool user = flags & BPF_F_USER_STACK; @@ -598,28 +604,30 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, goto err_fault; num_elem = size / elem_size; - max_depth = num_elem + skip; - if (sysctl_perf_event_max_stack < max_depth) - max_depth = sysctl_perf_event_max_stack; + if (sysctl_perf_event_max_stack < num_elem) + init_nr = 0; + else + init_nr = sysctl_perf_event_max_stack - num_elem; if (trace_in) trace = trace_in; else if (kernel && task) - trace = get_callchain_entry_for_task(task, max_depth); + trace = get_callchain_entry_for_task(task, init_nr); else - trace = get_perf_callchain(regs, 0, kernel, user, max_depth, + trace = get_perf_callchain(regs, init_nr, kernel, user, + sysctl_perf_event_max_stack, false, false); if (unlikely(!trace)) goto err_fault; - if (trace->nr < skip) + trace_nr = trace->nr - init_nr; + if (trace_nr < skip) goto err_fault; - trace_nr = trace->nr - skip; + trace_nr -= skip; trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; - - ips = trace->ip + skip; + ips = trace->ip + skip + init_nr; if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index 6aca805a25c49..df99cb9071471 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -65,25 +65,6 @@ static inline struct cgroup_fs_context *cgroup_fc2context(struct fs_context *fc) return container_of(kfc, struct cgroup_fs_context, kfc); } -struct cgroup_pidlist; - -struct cgroup_file_ctx { - struct cgroup_namespace *ns; - - struct { - void *trigger; - } psi; - - struct { - bool started; - struct css_task_iter iter; - } procs; - - struct { - struct cgroup_pidlist *pidlist; - } procs1; -}; - /* * A cgroup can be associated with multiple css_sets as different tasks may * belong to different cgroups on different hierarchies. In the other @@ -165,7 +146,6 @@ struct cgroup_mgctx { #define DEFINE_CGROUP_MGCTX(name) \ struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; extern struct cgroup_subsys *cgroup_subsys[]; extern struct list_head cgroup_roots; diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 185fbb6a0011a..f931f6547423f 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -394,7 +394,6 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) * next pid to display, if any */ struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *cgrp = seq_css(s)->cgroup; struct cgroup_pidlist *l; enum cgroup_filetype type = seq_cft(s)->private; @@ -404,24 +403,25 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) mutex_lock(&cgrp->pidlist_mutex); /* - * !NULL @ctx->procs1.pidlist indicates that this isn't the first - * start() after open. If the matching pidlist is around, we can use - * that. Look for it. Note that @ctx->procs1.pidlist can't be used - * directly. It could already have been destroyed. + * !NULL @of->priv indicates that this isn't the first start() + * after open. If the matching pidlist is around, we can use that. + * Look for it. Note that @of->priv can't be used directly. It + * could already have been destroyed. */ - if (ctx->procs1.pidlist) - ctx->procs1.pidlist = cgroup_pidlist_find(cgrp, type); + if (of->priv) + of->priv = cgroup_pidlist_find(cgrp, type); /* * Either this is the first start() after open or the matching * pidlist has been destroyed inbetween. Create a new one. */ - if (!ctx->procs1.pidlist) { - ret = pidlist_array_load(cgrp, type, &ctx->procs1.pidlist); + if (!of->priv) { + ret = pidlist_array_load(cgrp, type, + (struct cgroup_pidlist **)&of->priv); if (ret) return ERR_PTR(ret); } - l = ctx->procs1.pidlist; + l = of->priv; if (pid) { int end = l->length; @@ -449,8 +449,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) static void cgroup_pidlist_stop(struct seq_file *s, void *v) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; - struct cgroup_pidlist *l = ctx->procs1.pidlist; + struct cgroup_pidlist *l = of->priv; if (l) mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, @@ -461,8 +460,7 @@ static void cgroup_pidlist_stop(struct seq_file *s, void *v) static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; - struct cgroup_pidlist *l = ctx->procs1.pidlist; + struct cgroup_pidlist *l = of->priv; pid_t *p = v; pid_t *end = l->list + l->length; /* @@ -547,7 +545,6 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct cgroup *cgrp; - struct cgroup_file_ctx *ctx; BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); @@ -555,9 +552,8 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of, * Release agent gets called with all capabilities, * require capabilities to set release agent. */ - ctx = of->priv; - if ((ctx->ns->user_ns != &init_user_ns) || - !file_ns_capable(of->file, &init_user_ns, CAP_SYS_ADMIN)) + if ((of->file->f_cred->user_ns != &init_user_ns) || + !capable(CAP_SYS_ADMIN)) return -EPERM; cgrp = cgroup_kn_lock_live(of->kn, false); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index c1e1a5c34e774..e914646569b60 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3617,7 +3617,6 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, size_t nbytes, enum psi_res res) { - struct cgroup_file_ctx *ctx = of->priv; struct psi_trigger *new; struct cgroup *cgrp; struct psi_group *psi; @@ -3630,7 +3629,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, cgroup_kn_unlock(of->kn); /* Allow only one trigger per file descriptor */ - if (ctx->psi.trigger) { + if (of->priv) { cgroup_put(cgrp); return -EBUSY; } @@ -3642,7 +3641,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, return PTR_ERR(new); } - smp_store_release(&ctx->psi.trigger, new); + smp_store_release(&of->priv, new); cgroup_put(cgrp); return nbytes; @@ -3672,15 +3671,12 @@ static ssize_t cgroup_cpu_pressure_write(struct kernfs_open_file *of, static __poll_t cgroup_pressure_poll(struct kernfs_open_file *of, poll_table *pt) { - struct cgroup_file_ctx *ctx = of->priv; - return psi_trigger_poll(&ctx->psi.trigger, of->file, pt); + return psi_trigger_poll(&of->priv, of->file, pt); } static void cgroup_pressure_release(struct kernfs_open_file *of) { - struct cgroup_file_ctx *ctx = of->priv; - - psi_trigger_destroy(ctx->psi.trigger); + psi_trigger_destroy(of->priv); } bool cgroup_psi_enabled(void) @@ -3733,43 +3729,24 @@ static ssize_t cgroup_freeze_write(struct kernfs_open_file *of, static int cgroup_file_open(struct kernfs_open_file *of) { struct cftype *cft = of->kn->priv; - struct cgroup_file_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->ns = current->nsproxy->cgroup_ns; - get_cgroup_ns(ctx->ns); - of->priv = ctx; - - if (!cft->open) - return 0; - ret = cft->open(of); - if (ret) { - put_cgroup_ns(ctx->ns); - kfree(ctx); - } - return ret; + if (cft->open) + return cft->open(of); + return 0; } static void cgroup_file_release(struct kernfs_open_file *of) { struct cftype *cft = of->kn->priv; - struct cgroup_file_ctx *ctx = of->priv; if (cft->release) cft->release(of); - put_cgroup_ns(ctx->ns); - kfree(ctx); } static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; + struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; struct cgroup *cgrp = of->kn->parent->priv; struct cftype *cft = of->kn->priv; struct cgroup_subsys_state *css; @@ -3786,7 +3763,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, */ if ((cgrp->root->flags & CGRP_ROOT_NS_DELEGATE) && !(cft->flags & CFTYPE_NS_DELEGATABLE) && - ctx->ns != &init_cgroup_ns && ctx->ns->root_cset->dfl_cgrp == cgrp) + ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp) return -EPERM; if (cft->write) @@ -4694,21 +4671,21 @@ void css_task_iter_end(struct css_task_iter *it) static void cgroup_procs_release(struct kernfs_open_file *of) { - struct cgroup_file_ctx *ctx = of->priv; - - if (ctx->procs.started) - css_task_iter_end(&ctx->procs.iter); + if (of->priv) { + css_task_iter_end(of->priv); + kfree(of->priv); + } } static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; + struct css_task_iter *it = of->priv; if (pos) (*pos)++; - return css_task_iter_next(&ctx->procs.iter); + return css_task_iter_next(it); } static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, @@ -4716,18 +4693,21 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, { struct kernfs_open_file *of = s->private; struct cgroup *cgrp = seq_css(s)->cgroup; - struct cgroup_file_ctx *ctx = of->priv; - struct css_task_iter *it = &ctx->procs.iter; + struct css_task_iter *it = of->priv; /* * When a seq_file is seeked, it's always traversed sequentially * from position 0, so we can simply keep iterating on !0 *pos. */ - if (!ctx->procs.started) { + if (!it) { if (WARN_ON_ONCE((*pos))) return ERR_PTR(-EINVAL); + + it = kzalloc(sizeof(*it), GFP_KERNEL); + if (!it) + return ERR_PTR(-ENOMEM); + of->priv = it; css_task_iter_start(&cgrp->self, iter_flags, it); - ctx->procs.started = true; } else if (!(*pos)) { css_task_iter_end(it); css_task_iter_start(&cgrp->self, iter_flags, it); @@ -4778,9 +4758,9 @@ static int cgroup_may_write(const struct cgroup *cgrp, struct super_block *sb) static int cgroup_procs_write_permission(struct cgroup *src_cgrp, struct cgroup *dst_cgrp, - struct super_block *sb, - struct cgroup_namespace *ns) + struct super_block *sb) { + struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; struct cgroup *com_cgrp = src_cgrp; int ret; @@ -4809,12 +4789,11 @@ static int cgroup_procs_write_permission(struct cgroup *src_cgrp, static int cgroup_attach_permissions(struct cgroup *src_cgrp, struct cgroup *dst_cgrp, - struct super_block *sb, bool threadgroup, - struct cgroup_namespace *ns) + struct super_block *sb, bool threadgroup) { int ret = 0; - ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb, ns); + ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb); if (ret) return ret; @@ -4831,7 +4810,6 @@ static int cgroup_attach_permissions(struct cgroup *src_cgrp, static ssize_t cgroup_procs_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *src_cgrp, *dst_cgrp; struct task_struct *task; ssize_t ret; @@ -4852,8 +4830,7 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of, spin_unlock_irq(&css_set_lock); ret = cgroup_attach_permissions(src_cgrp, dst_cgrp, - of->file->f_path.dentry->d_sb, true, - ctx->ns); + of->file->f_path.dentry->d_sb, true); if (ret) goto out_finish; @@ -4875,7 +4852,6 @@ static void *cgroup_threads_start(struct seq_file *s, loff_t *pos) static ssize_t cgroup_threads_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *src_cgrp, *dst_cgrp; struct task_struct *task; ssize_t ret; @@ -4899,8 +4875,7 @@ static ssize_t cgroup_threads_write(struct kernfs_open_file *of, /* thread migrations follow the cgroup.procs delegation rule */ ret = cgroup_attach_permissions(src_cgrp, dst_cgrp, - of->file->f_path.dentry->d_sb, false, - ctx->ns); + of->file->f_path.dentry->d_sb, false); if (ret) goto out_finish; @@ -6083,8 +6058,7 @@ static int cgroup_css_set_fork(struct kernel_clone_args *kargs) goto err; ret = cgroup_attach_permissions(cset->dfl_cgrp, dst_cgrp, sb, - !(kargs->flags & CLONE_THREAD), - current->nsproxy->cgroup_ns); + !(kargs->flags & CLONE_THREAD)); if (ret) goto err; diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 13417f0045f02..6226502ce0499 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -350,7 +350,7 @@ int kdb_getarea_size(void *res, unsigned long addr, size_t size) */ int kdb_putarea_size(unsigned long addr, void *res, size_t size) { - int ret = copy_to_kernel_nofault((char *)addr, (char *)res, size); + int ret = copy_from_kernel_nofault((char *)addr, (char *)res, size); if (ret) { if (!KDB_STATE(SUPPRESS)) { kdb_printf("kdb_putarea: Bad address 0x%lx\n", addr); diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c index f8ae546798651..10d07ace46c15 100644 --- a/kernel/dma/debug.c +++ b/kernel/dma/debug.c @@ -928,7 +928,7 @@ static __init int dma_debug_cmdline(char *str) global_disable = true; } - return 1; + return 0; } static __init int dma_debug_entries_cmdline(char *str) @@ -937,7 +937,7 @@ static __init int dma_debug_entries_cmdline(char *str) return -EINVAL; if (!get_option(&str, &nr_prealloc_entries)) nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES; - return 1; + return 0; } __setup("dma_debug=", dma_debug_cmdline); diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index aca0690550e2f..87c40517e8227 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -579,8 +579,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, mem->slots[index + i].orig_addr = slot_addr(orig_addr, i); tlb_addr = slot_addr(mem->start, index) + offset; if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && - (!(attrs & DMA_ATTR_OVERWRITE) || dir == DMA_TO_DEVICE || - dir == DMA_BIDIRECTIONAL)) + (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE); return tlb_addr; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 9554e408cda60..f58a026dd2d30 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10266,11 +10266,8 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr, } /* ready to consume more filters */ - kfree(filename); - filename = NULL; state = IF_STATE_ACTION; filter = NULL; - kernel = 0; } } diff --git a/kernel/exit.c b/kernel/exit.c index f61ac326daabd..24a302ecde59f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -423,6 +423,7 @@ assign_new_owner: goto retry; } WRITE_ONCE(mm->owner, c); + lru_gen_migrate_mm(mm); task_unlock(c); put_task_struct(c); } diff --git a/kernel/fork.c b/kernel/fork.c index 7ea0443320faf..965d97bec20e3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -375,14 +375,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) *new = data_race(*orig); INIT_VMA(new); new->vm_next = new->vm_prev = NULL; - dup_vma_anon_name(orig, new); + dup_anon_vma_name(orig, new); } return new; } void vm_area_free(struct vm_area_struct *vma) { - free_vma_anon_name(vma); + free_anon_vma_name(vma); kmem_cache_free(vm_area_cachep, vma); } @@ -1100,6 +1100,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, goto fail_nocontext; mm->user_ns = get_user_ns(user_ns); + lru_gen_init_mm(mm); return mm; fail_nocontext: @@ -1142,6 +1143,7 @@ static inline void __mmput(struct mm_struct *mm) } if (mm->binfmt) module_put(mm->binfmt->module); + lru_gen_del_mm(mm); mmdrop(mm); } @@ -2537,6 +2539,13 @@ pid_t kernel_clone(struct kernel_clone_args *args) get_task_struct(p); } + if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { + /* lock the task to synchronize with memcg migration */ + task_lock(p); + lru_gen_add_mm(p->mm); + task_unlock(p); + } + wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ diff --git a/kernel/futex.c b/kernel/futex.c index 3cd0ae850fdef..20b27a9551e73 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -587,7 +587,7 @@ again: lock_page(page); shmem_swizzled = PageSwapCache(page) || page->mapping; unlock_page(page); - put_user_page(page); + put_page(page); if (shmem_swizzled) goto again; @@ -637,7 +637,7 @@ again: if (READ_ONCE(page->mapping) != mapping) { rcu_read_unlock(); - put_user_page(page); + put_page(page); goto again; } @@ -645,7 +645,7 @@ again: inode = READ_ONCE(mapping->host); if (!inode) { rcu_read_unlock(); - put_user_page(page); + put_page(page); goto again; } @@ -657,7 +657,7 @@ again: } out: - put_user_page(page); + put_page(page); return err; } diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index e8bdce6fdd647..f76fdb9255323 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -191,7 +191,7 @@ static int klp_find_object_symbol(const char *objname, const char *name, return -EINVAL; } -static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab, +static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symndx, Elf_Shdr *relasec, const char *sec_objname) { @@ -219,7 +219,7 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab, relas = (Elf_Rela *) relasec->sh_addr; /* For each rela in this klp relocation section */ for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) { - sym = (Elf_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); + sym = (Elf64_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); if (sym->st_shndx != SHN_LIVEPATCH) { pr_err("symbol %s is not marked as a livepatch symbol\n", strtab + sym->st_name); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index b6683cefe19a4..af4b35450556f 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -182,9 +182,11 @@ static DECLARE_BITMAP(list_entries_in_use, MAX_LOCKDEP_ENTRIES); static struct hlist_head lock_keys_hash[KEYHASH_SIZE]; unsigned long nr_lock_classes; unsigned long nr_zapped_classes; -unsigned long max_lock_class_idx; +#ifndef CONFIG_DEBUG_LOCKDEP +static +#endif struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); +static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); static inline struct lock_class *hlock_class(struct held_lock *hlock) { @@ -335,7 +337,7 @@ static inline void lock_release_holdtime(struct held_lock *hlock) * elements. These elements are linked together by the lock_entry member in * struct lock_class. */ -static LIST_HEAD(all_lock_classes); +LIST_HEAD(all_lock_classes); static LIST_HEAD(free_lock_classes); /** @@ -1237,7 +1239,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) struct lockdep_subclass_key *key; struct hlist_head *hash_head; struct lock_class *class; - int idx; DEBUG_LOCKS_WARN_ON(!irqs_disabled()); @@ -1303,9 +1304,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) * of classes. */ list_move_tail(&class->lock_entry, &all_lock_classes); - idx = class - lock_classes; - if (idx > max_lock_class_idx) - max_lock_class_idx = idx; if (verbose(class)) { graph_unlock(); @@ -5921,8 +5919,6 @@ static void zap_class(struct pending_free *pf, struct lock_class *class) WRITE_ONCE(class->name, NULL); nr_lock_classes--; __clear_bit(class - lock_classes, lock_classes_in_use); - if (class - lock_classes == max_lock_class_idx) - max_lock_class_idx--; } else { WARN_ONCE(true, "%s() failed for class %s\n", __func__, class->name); @@ -6213,13 +6209,7 @@ void lockdep_reset_lock(struct lockdep_map *lock) lockdep_reset_lock_reg(lock); } -/* - * Unregister a dynamically allocated key. - * - * Unlike lockdep_register_key(), a search is always done to find a matching - * key irrespective of debug_locks to avoid potential invalid access to freed - * memory in lock_class entry. - */ +/* Unregister a dynamically allocated key. */ void lockdep_unregister_key(struct lock_class_key *key) { struct hlist_head *hash_head = keyhashentry(key); @@ -6234,8 +6224,10 @@ void lockdep_unregister_key(struct lock_class_key *key) return; raw_local_irq_save(flags); - lockdep_lock(); + if (!graph_lock()) + goto out_irq; + pf = get_pending_free(); hlist_for_each_entry_rcu(k, hash_head, hash_entry) { if (k == key) { hlist_del_rcu(&k->hash_entry); @@ -6243,13 +6235,11 @@ void lockdep_unregister_key(struct lock_class_key *key) break; } } - WARN_ON_ONCE(!found && debug_locks); - if (found) { - pf = get_pending_free(); - __lockdep_free_key_range(pf, key, 1); - call_rcu_zapped(pf); - } - lockdep_unlock(); + WARN_ON_ONCE(!found); + __lockdep_free_key_range(pf, key, 1); + call_rcu_zapped(pf); + graph_unlock(); +out_irq: raw_local_irq_restore(flags); /* Wait until is_dynamic_key() has finished accessing k->hash_entry. */ diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h index a19b016353478..de49f9e1c11ba 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -121,6 +121,7 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ = #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5) +extern struct list_head all_lock_classes; extern struct lock_chain lock_chains[]; #define LOCK_USAGE_CHARS (2*XXX_LOCK_USAGE_STATES + 1) @@ -150,10 +151,6 @@ extern unsigned int nr_large_chain_blocks; extern unsigned int max_lockdep_depth; extern unsigned int max_bfs_queue_depth; -extern unsigned long max_lock_class_idx; - -extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -extern unsigned long lock_classes_in_use[]; #ifdef CONFIG_PROVE_LOCKING extern unsigned long lockdep_count_forward_deps(struct lock_class *); @@ -208,6 +205,7 @@ struct lockdep_stats { }; DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats); +extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; #define __debug_atomic_inc(ptr) \ this_cpu_inc(lockdep_stats.ptr); diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c index ccb5292d1e194..02ef87f50df29 100644 --- a/kernel/locking/lockdep_proc.c +++ b/kernel/locking/lockdep_proc.c @@ -24,33 +24,14 @@ #include "lockdep_internals.h" -/* - * Since iteration of lock_classes is done without holding the lockdep lock, - * it is not safe to iterate all_lock_classes list directly as the iteration - * may branch off to free_lock_classes or the zapped list. Iteration is done - * directly on the lock_classes array by checking the lock_classes_in_use - * bitmap and max_lock_class_idx. - */ -#define iterate_lock_classes(idx, class) \ - for (idx = 0, class = lock_classes; idx <= max_lock_class_idx; \ - idx++, class++) - static void *l_next(struct seq_file *m, void *v, loff_t *pos) { - struct lock_class *class = v; - - ++class; - *pos = class - lock_classes; - return (*pos > max_lock_class_idx) ? NULL : class; + return seq_list_next(v, &all_lock_classes, pos); } static void *l_start(struct seq_file *m, loff_t *pos) { - unsigned long idx = *pos; - - if (idx > max_lock_class_idx) - return NULL; - return lock_classes + idx; + return seq_list_start_head(&all_lock_classes, *pos); } static void l_stop(struct seq_file *m, void *v) @@ -76,16 +57,14 @@ static void print_name(struct seq_file *m, struct lock_class *class) static int l_show(struct seq_file *m, void *v) { - struct lock_class *class = v; + struct lock_class *class = list_entry(v, struct lock_class, lock_entry); struct lock_list *entry; char usage[LOCK_USAGE_CHARS]; - int idx = class - lock_classes; - if (v == lock_classes) + if (v == &all_lock_classes) { seq_printf(m, "all lock classes:\n"); - - if (!test_bit(idx, lock_classes_in_use)) return 0; + } seq_printf(m, "%p", class->key); #ifdef CONFIG_DEBUG_LOCKDEP @@ -239,11 +218,8 @@ static int lockdep_stats_show(struct seq_file *m, void *v) #ifdef CONFIG_PROVE_LOCKING struct lock_class *class; - unsigned long idx; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) { if (class->usage_mask == 0) nr_unused++; @@ -276,7 +252,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) sum_forward_deps += lockdep_count_forward_deps(class); } - #ifdef CONFIG_DEBUG_LOCKDEP DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused); #endif @@ -368,8 +343,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) seq_printf(m, " max bfs queue depth: %11u\n", max_bfs_queue_depth); #endif - seq_printf(m, " max lock class index: %11lu\n", - max_lock_class_idx); lockdep_stats_debug_show(m); seq_printf(m, " debug_locks: %11u\n", debug_locks); @@ -647,16 +620,12 @@ static int lock_stat_open(struct inode *inode, struct file *file) if (!res) { struct lock_stat_data *iter = data->stats; struct seq_file *m = file->private_data; - unsigned long idx; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) { iter->class = class; iter->stats = lock_stats(class); iter++; } - data->iter_end = iter; sort(data->stats, data->iter_end - data->stats, @@ -674,7 +643,6 @@ static ssize_t lock_stat_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct lock_class *class; - unsigned long idx; char c; if (count) { @@ -684,11 +652,8 @@ static ssize_t lock_stat_write(struct file *file, const char __user *buf, if (c != '0') return count; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) clear_lock_stats(class); - } } return count; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 731aca37637dc..b13fe337fa51e 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1323,7 +1323,7 @@ static int __init resumedelay_setup(char *str) int rc = kstrtouint(str, 0, &resume_delay); if (rc) - pr_warn("resumedelay: bad option string '%s'\n", str); + return rc; return 1; } diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index be480ae5cb2aa..e1ed58adb69e4 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -157,22 +157,22 @@ static int __init setup_test_suspend(char *value) value++; suspend_type = strsep(&value, ","); if (!suspend_type) - return 1; + return 0; repeat = strsep(&value, ","); if (repeat) { if (kstrtou32(repeat, 0, &test_repeat_count_max)) - return 1; + return 0; } for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) if (!strcmp(pm_labels[i], suspend_type)) { test_state_label = pm_labels[i]; - return 1; + return 0; } printk(warn_bad_state, suspend_type); - return 1; + return 0; } __setup("test_suspend", setup_test_suspend); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 3a1af08a3636a..db4a07651bc1d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -149,10 +149,8 @@ static int __control_devkmsg(char *str) static int __init control_devkmsg(char *str) { - if (__control_devkmsg(str) < 0) { - pr_warn("printk.devkmsg: bad option string '%s'\n", str); + if (__control_devkmsg(str) < 0) return 1; - } /* * Set sysctl string accordingly: @@ -171,7 +169,7 @@ static int __init control_devkmsg(char *str) */ devkmsg_log |= DEVKMSG_LOG_MASK_LOCK; - return 1; + return 0; } __setup("printk.devkmsg=", control_devkmsg); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index d99f73f83bf5f..eb4d04cb3aaf5 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -370,26 +370,6 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) return !err; } -static int check_ptrace_options(unsigned long data) -{ - if (data & ~(unsigned long)PTRACE_O_MASK) - return -EINVAL; - - if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { - if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || - !IS_ENABLED(CONFIG_SECCOMP)) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || - current->ptrace & PT_SUSPEND_SECCOMP) - return -EPERM; - } - return 0; -} - static int ptrace_attach(struct task_struct *task, long request, unsigned long addr, unsigned long flags) @@ -401,16 +381,8 @@ static int ptrace_attach(struct task_struct *task, long request, if (seize) { if (addr != 0) goto out; - /* - * This duplicates the check in check_ptrace_options() because - * ptrace_attach() and ptrace_setoptions() have historically - * used different error codes for unknown ptrace options. - */ if (flags & ~(unsigned long)PTRACE_O_MASK) goto out; - retval = check_ptrace_options(flags); - if (retval) - return retval; flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); } else { flags = PT_PTRACED; @@ -683,11 +655,22 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds static int ptrace_setoptions(struct task_struct *child, unsigned long data) { unsigned flags; - int ret; - ret = check_ptrace_options(data); - if (ret) - return ret; + if (data & ~(unsigned long)PTRACE_O_MASK) + return -EINVAL; + + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { + if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || + !IS_ENABLED(CONFIG_SECCOMP)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || + current->ptrace & PT_SUSPEND_SECCOMP) + return -EPERM; + } /* Avoid intermediate state when all opts are cleared */ flags = child->ptrace; diff --git a/kernel/rcu/Kconfig b/kernel/rcu/Kconfig index b71e21f73c403..97bfe2a891dbc 100644 --- a/kernel/rcu/Kconfig +++ b/kernel/rcu/Kconfig @@ -212,6 +212,20 @@ config RCU_BOOST_DELAY Accept the default if unsure. +config RCU_EXP_KTHREAD + bool "Perform RCU expedited work in a real-time kthread" + depends on RCU_BOOST && RCU_EXPERT + default !PREEMPT_RT && NR_CPUS <= 32 + help + Use this option to further reduce the latencies of expedited + grace periods at the expense of being more disruptive. + + This option is disabled by default on PREEMPT_RT=y kernels which + disable expedited grace periods after boot by unconditionally + setting rcupdate.rcu_normal_after_boot=1. + + Accept the default if unsure. + config RCU_NOCB_CPU bool "Offload RCU callback processing from boot-selected CPUs" depends on TREE_RCU diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index fcf95d1eec69a..7befcfae5fb5a 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -524,7 +524,12 @@ int rcu_get_gp_kthreads_prio(void); void rcu_fwd_progress_check(unsigned long j); void rcu_force_quiescent_state(void); extern struct workqueue_struct *rcu_gp_wq; +#ifdef CONFIG_RCU_EXP_KTHREAD +extern struct kthread_worker *rcu_exp_gp_kworker; +extern struct kthread_worker *rcu_exp_par_gp_kworker; +#else /* !CONFIG_RCU_EXP_KTHREAD */ extern struct workqueue_struct *rcu_par_gp_wq; +#endif /* CONFIG_RCU_EXP_KTHREAD */ #endif /* #else #ifdef CONFIG_TINY_RCU */ #ifdef CONFIG_RCU_NOCB_CPU diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 1628dcb6e45a8..5b5f80ad0e7aa 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4234,6 +4234,51 @@ static int rcu_pm_notify(struct notifier_block *self, return NOTIFY_OK; } +#ifdef CONFIG_RCU_EXP_KTHREAD +struct kthread_worker *rcu_exp_gp_kworker; +struct kthread_worker *rcu_exp_par_gp_kworker; + +static void __init rcu_start_exp_gp_kworkers(void) +{ + const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker"; + const char *gp_kworker_name = "rcu_exp_gp_kthread_worker"; + struct sched_param param = { .sched_priority = kthread_prio }; + + rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) { + pr_err("Failed to create %s!\n", gp_kworker_name); + return; + } + + rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) { + pr_err("Failed to create %s!\n", par_gp_kworker_name); + kthread_destroy_worker(rcu_exp_gp_kworker); + return; + } + + sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m); + sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO, + ¶m); +} + +static inline void rcu_alloc_par_gp_wq(void) +{ +} +#else /* !CONFIG_RCU_EXP_KTHREAD */ +struct workqueue_struct *rcu_par_gp_wq; + +static void __init rcu_start_exp_gp_kworkers(void) +{ +} + +static inline void rcu_alloc_par_gp_wq(void) +{ + rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); + WARN_ON(!rcu_par_gp_wq); +} +#endif /* CONFIG_RCU_EXP_KTHREAD */ + /* * Spawn the kthreads that handle RCU's grace periods. */ @@ -4279,6 +4324,8 @@ static int __init rcu_spawn_gp_kthread(void) rcu_spawn_nocb_kthreads(); rcu_spawn_boost_kthreads(); rcu_spawn_core_kthreads(); + /* Create kthread worker for expedited GPs */ + rcu_start_exp_gp_kworkers(); return 0; } early_initcall(rcu_spawn_gp_kthread); @@ -4501,7 +4548,6 @@ static void __init rcu_dump_rcu_node_tree(void) } struct workqueue_struct *rcu_gp_wq; -struct workqueue_struct *rcu_par_gp_wq; static void __init kfree_rcu_batch_init(void) { @@ -4554,8 +4600,7 @@ void __init rcu_init(void) /* Create workqueue for expedited GPs and for Tree SRCU. */ rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0); WARN_ON(!rcu_gp_wq); - rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); - WARN_ON(!rcu_par_gp_wq); + rcu_alloc_par_gp_wq(); srcu_init(); /* Fill in default value for rcutree.qovld boot parameter. */ diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index e4f66b8f7c470..12432de6c9203 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -23,7 +24,11 @@ /* Communicate arguments to a workqueue handler. */ struct rcu_exp_work { unsigned long rew_s; +#ifdef CONFIG_RCU_EXP_KTHREAD + struct kthread_work rew_work; +#else struct work_struct rew_work; +#endif /* CONFIG_RCU_EXP_KTHREAD */ }; /* RCU's kthread states for tracing. */ diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index 6aeb5f517ce2c..bde4080a936f1 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -334,15 +334,13 @@ fastpath: * Select the CPUs within the specified rcu_node that the upcoming * expedited grace period needs to wait for. */ -static void sync_rcu_exp_select_node_cpus(struct work_struct *wp) +static void __sync_rcu_exp_select_node_cpus(struct rcu_exp_work *rewp) { int cpu; unsigned long flags; unsigned long mask_ofl_test; unsigned long mask_ofl_ipi; int ret; - struct rcu_exp_work *rewp = - container_of(wp, struct rcu_exp_work, rew_work); struct rcu_node *rnp = container_of(rewp, struct rcu_node, rew); raw_spin_lock_irqsave_rcu_node(rnp, flags); @@ -417,13 +415,119 @@ retry_ipi: rcu_report_exp_cpu_mult(rnp, mask_ofl_test, false); } +static void rcu_exp_sel_wait_wake(unsigned long s); + +#ifdef CONFIG_RCU_EXP_KTHREAD +static void sync_rcu_exp_select_node_cpus(struct kthread_work *wp) +{ + struct rcu_exp_work *rewp = + container_of(wp, struct rcu_exp_work, rew_work); + + __sync_rcu_exp_select_node_cpus(rewp); +} + +static inline bool rcu_gp_par_worker_started(void) +{ + return !!READ_ONCE(rcu_exp_par_gp_kworker); +} + +static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp) +{ + kthread_init_work(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); + /* + * Use rcu_exp_par_gp_kworker, because flushing a work item from + * another work item on the same kthread worker can result in + * deadlock. + */ + kthread_queue_work(rcu_exp_par_gp_kworker, &rnp->rew.rew_work); +} + +static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp) +{ + kthread_flush_work(&rnp->rew.rew_work); +} + +/* + * Work-queue handler to drive an expedited grace period forward. + */ +static void wait_rcu_exp_gp(struct kthread_work *wp) +{ + struct rcu_exp_work *rewp; + + rewp = container_of(wp, struct rcu_exp_work, rew_work); + rcu_exp_sel_wait_wake(rewp->rew_s); +} + +static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew) +{ + kthread_init_work(&rew->rew_work, wait_rcu_exp_gp); + kthread_queue_work(rcu_exp_gp_kworker, &rew->rew_work); +} + +static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew) +{ +} +#else /* !CONFIG_RCU_EXP_KTHREAD */ +static void sync_rcu_exp_select_node_cpus(struct work_struct *wp) +{ + struct rcu_exp_work *rewp = + container_of(wp, struct rcu_exp_work, rew_work); + + __sync_rcu_exp_select_node_cpus(rewp); +} + +static inline bool rcu_gp_par_worker_started(void) +{ + return !!READ_ONCE(rcu_par_gp_wq); +} + +static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp) +{ + int cpu = find_next_bit(&rnp->ffmask, BITS_PER_LONG, -1); + + INIT_WORK(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); + /* If all offline, queue the work on an unbound CPU. */ + if (unlikely(cpu > rnp->grphi - rnp->grplo)) + cpu = WORK_CPU_UNBOUND; + else + cpu += rnp->grplo; + queue_work_on(cpu, rcu_par_gp_wq, &rnp->rew.rew_work); +} + +static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp) +{ + flush_work(&rnp->rew.rew_work); +} + +/* + * Work-queue handler to drive an expedited grace period forward. + */ +static void wait_rcu_exp_gp(struct work_struct *wp) +{ + struct rcu_exp_work *rewp; + + rewp = container_of(wp, struct rcu_exp_work, rew_work); + rcu_exp_sel_wait_wake(rewp->rew_s); +} + +static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew) +{ + INIT_WORK_ONSTACK(&rew->rew_work, wait_rcu_exp_gp); + queue_work(rcu_gp_wq, &rew->rew_work); +} + +static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew) +{ + destroy_work_on_stack(&rew->rew_work); +} +#endif /* CONFIG_RCU_EXP_KTHREAD */ + /* * Select the nodes that the upcoming expedited grace period needs * to wait for. */ static void sync_rcu_exp_select_cpus(void) { - int cpu; struct rcu_node *rnp; trace_rcu_exp_grace_period(rcu_state.name, rcu_exp_gp_seq_endval(), TPS("reset")); @@ -435,28 +539,21 @@ static void sync_rcu_exp_select_cpus(void) rnp->exp_need_flush = false; if (!READ_ONCE(rnp->expmask)) continue; /* Avoid early boot non-existent wq. */ - if (!READ_ONCE(rcu_par_gp_wq) || + if (!rcu_gp_par_worker_started() || rcu_scheduler_active != RCU_SCHEDULER_RUNNING || rcu_is_last_leaf_node(rnp)) { - /* No workqueues yet or last leaf, do direct call. */ + /* No worker started yet or last leaf, do direct call. */ sync_rcu_exp_select_node_cpus(&rnp->rew.rew_work); continue; } - INIT_WORK(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); - cpu = find_next_bit(&rnp->ffmask, BITS_PER_LONG, -1); - /* If all offline, queue the work on an unbound CPU. */ - if (unlikely(cpu > rnp->grphi - rnp->grplo)) - cpu = WORK_CPU_UNBOUND; - else - cpu += rnp->grplo; - queue_work_on(cpu, rcu_par_gp_wq, &rnp->rew.rew_work); + sync_rcu_exp_select_cpus_queue_work(rnp); rnp->exp_need_flush = true; } - /* Wait for workqueue jobs (if any) to complete. */ + /* Wait for jobs (if any) to complete. */ rcu_for_each_leaf_node(rnp) if (rnp->exp_need_flush) - flush_work(&rnp->rew.rew_work); + sync_rcu_exp_select_cpus_flush_work(rnp); } /* @@ -619,17 +716,6 @@ static void rcu_exp_sel_wait_wake(unsigned long s) rcu_exp_wait_wake(s); } -/* - * Work-queue handler to drive an expedited grace period forward. - */ -static void wait_rcu_exp_gp(struct work_struct *wp) -{ - struct rcu_exp_work *rewp; - - rewp = container_of(wp, struct rcu_exp_work, rew_work); - rcu_exp_sel_wait_wake(rewp->rew_s); -} - #ifdef CONFIG_PREEMPT_RCU /* @@ -845,20 +931,19 @@ void synchronize_rcu_expedited(void) } else { /* Marshall arguments & schedule the expedited grace period. */ rew.rew_s = s; - INIT_WORK_ONSTACK(&rew.rew_work, wait_rcu_exp_gp); - queue_work(rcu_gp_wq, &rew.rew_work); + synchronize_rcu_expedited_queue_work(&rew); } /* Wait for expedited grace period to complete. */ rnp = rcu_get_root(); wait_event(rnp->exp_wq[rcu_seq_ctr(s) & 0x3], sync_exp_work_done(s)); - smp_mb(); /* Workqueue actions happen before return. */ + smp_mb(); /* Work actions happen before return. */ /* Let the next expedited grace period start. */ mutex_unlock(&rcu_state.exp_mutex); if (likely(!boottime)) - destroy_work_on_stack(&rew.rew_work); + synchronize_rcu_expedited_destroy_work(&rew); } EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index f5ba0740f9b50..39e8f78182a85 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -541,7 +541,6 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) /* Unboost if we were boosted. */ if (IS_ENABLED(CONFIG_RCU_BOOST) && drop_boost_mutex) rt_mutex_futex_unlock(&rnp->boost_mtx); - } else { local_irq_restore(flags); } diff --git a/kernel/rseq.c b/kernel/rseq.c index 6ca29dddceabc..0077713bf2400 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -120,13 +120,8 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) u32 sig; int ret; -#ifdef CONFIG_64BIT - if (get_user(ptr, &t->rseq->rseq_cs)) + if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr))) return -EFAULT; -#else - if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr))) - return -EFAULT; -#endif if (!ptr) { memset(rseq_cs, 0, sizeof(*rseq_cs)); return 0; @@ -209,13 +204,9 @@ static int clear_rseq_cs(struct task_struct *t) * * Set rseq_cs to NULL. */ -#ifdef CONFIG_64BIT - return put_user(0UL, &t->rseq->rseq_cs); -#else - if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs))) + if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64))) return -EFAULT; return 0; -#endif } /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ad3bc6b0ae065..507ed2aed0e8e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -39,7 +39,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp); -EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_thermal_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); @@ -4004,6 +4003,7 @@ context_switch(struct rq *rq, struct task_struct *prev, * finish_task_switch()'s mmdrop(). */ switch_mm_irqs_off(prev->active_mm, next->mm, next); + lru_gen_use_mm(next->mm); if (!prev->mm) { // from kernel /* will mmdrop() in finish_task_switch(). */ diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index f799bcb36071c..9c95334d857e2 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -910,15 +910,25 @@ void print_numa_stats(struct seq_file *m, int node, unsigned long tsf, static void sched_show_numa(struct task_struct *p, struct seq_file *m) { #ifdef CONFIG_NUMA_BALANCING + struct mempolicy *pol; + if (p->mm) P(mm->numa_scan_seq); + task_lock(p); + pol = p->mempolicy; + if (pol && !(pol->flags & MPOL_F_MORON)) + pol = NULL; + mpol_get(pol); + task_unlock(p); + P(numa_pages_migrated); P(numa_preferred_nid); P(total_numa_faults); SEQ_printf(m, "current_node=%d, numa_group_id=%d\n", task_node(p), task_numa_group_id(p)); show_numa_stats(p, m); + mpol_put(pol); #endif } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 4d478fe31f98b..ff561e3763f4b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3763,6 +3763,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se)); } + trace_android_rvh_attach_entity_load_avg(cfs_rq, se); + enqueue_load_avg(cfs_rq, se); cfs_rq->avg.util_avg += se->avg.util_avg; cfs_rq->avg.util_sum += se->avg.util_sum; @@ -3786,6 +3788,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s */ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { + trace_android_rvh_detach_entity_load_avg(cfs_rq, se); + dequeue_load_avg(cfs_rq, se); sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg); sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum); @@ -3825,6 +3829,8 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s decayed = update_cfs_rq_load_avg(now, cfs_rq); decayed |= propagate_entity_load_avg(se); + trace_android_rvh_update_load_avg(now, cfs_rq, se); + if (!se->avg.last_update_time && (flags & DO_ATTACH)) { /* @@ -3896,6 +3902,8 @@ static void remove_entity_load_avg(struct sched_entity *se) sync_entity_load_avg(se); + trace_android_rvh_remove_entity_load_avg(cfs_rq, se); + raw_spin_lock_irqsave(&cfs_rq->removed.lock, flags); ++cfs_rq->removed.nr; cfs_rq->removed.util_avg += se->avg.util_avg; @@ -8108,6 +8116,8 @@ static bool __update_blocked_fair(struct rq *rq, bool *done) bool decayed = false; int cpu = cpu_of(rq); + trace_android_rvh_update_blocked_fair(rq); + /* * Iterates the task_group tree in a bottom up fashion, see * list_add_leaf_cfs_rq() for details. diff --git a/kernel/sched/pelt.c b/kernel/sched/pelt.c index cd54fab42cf4e..e15a2fad146ef 100644 --- a/kernel/sched/pelt.c +++ b/kernel/sched/pelt.c @@ -30,6 +30,7 @@ int pelt_load_avg_period = PELT32_LOAD_AVG_PERIOD; int pelt_load_avg_max = PELT32_LOAD_AVG_MAX; +EXPORT_SYMBOL_GPL(pelt_load_avg_max); const u32 *pelt_runnable_avg_yN_inv = pelt32_runnable_avg_yN_inv; static int __init set_pelt(char *str) @@ -216,9 +217,8 @@ accumulate_sum(u64 delta, struct sched_avg *sa, * load_avg = u_0` + y*(u_0 + u_1*y + u_2*y^2 + ... ) * = u_0 + u_1*y + u_2*y^2 + ... [re-labeling u_i --> u_{i+1}] */ -static __always_inline int -___update_load_sum(u64 now, struct sched_avg *sa, - unsigned long load, unsigned long runnable, int running) +int ___update_load_sum(u64 now, struct sched_avg *sa, + unsigned long load, unsigned long runnable, int running) { u64 delta; @@ -268,6 +268,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa, return 1; } +EXPORT_SYMBOL_GPL(___update_load_sum); /* * When syncing *_avg with *_sum, we must take into account the current @@ -293,8 +294,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa, * the period_contrib of cfs_rq when updating the sched_avg of a sched_entity * if it's more convenient. */ -static __always_inline void -___update_load_avg(struct sched_avg *sa, unsigned long load) +void ___update_load_avg(struct sched_avg *sa, unsigned long load) { u32 divider = get_pelt_divider(sa); @@ -305,6 +305,7 @@ ___update_load_avg(struct sched_avg *sa, unsigned long load) sa->runnable_avg = div_u64(sa->runnable_sum, divider); WRITE_ONCE(sa->util_avg, sa->util_sum / divider); } +EXPORT_SYMBOL_GPL(___update_load_avg); /* * sched_entity: diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index d7e73977b0aed..3e1866534db52 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1685,6 +1685,7 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f */ if (rq->curr->sched_class != &rt_sched_class) update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 0); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 0); rt_queue_push_tasks(rq); } @@ -1737,6 +1738,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) update_curr_rt(rq); update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 1); /* * The previous task needs to be made eligible for pushing @@ -2500,6 +2502,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) update_curr_rt(rq); update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 1); watchdog(rq, p); diff --git a/kernel/scs.c b/kernel/scs.c index b83bc9251f996..b7e1b096d9060 100644 --- a/kernel/scs.c +++ b/kernel/scs.c @@ -32,15 +32,19 @@ static void *__scs_alloc(int node) for (i = 0; i < NR_CACHED_SCS; i++) { s = this_cpu_xchg(scs_cache[i], NULL); if (s) { - kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_NONE); + s = kasan_unpoison_vmalloc(s, SCS_SIZE, + KASAN_VMALLOC_PROT_NORMAL); memset(s, 0, SCS_SIZE); - return s; + goto out; } } - return __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END, + s = __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END, GFP_SCS, PAGE_KERNEL, 0, node, __builtin_return_address(0)); + +out: + return kasan_reset_tag(s); } void *scs_alloc(int node) @@ -78,7 +82,7 @@ void scs_free(void *s) if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL) return; - kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_NONE); + kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_PROT_NORMAL); vfree_atomic(s); } diff --git a/kernel/sys.c b/kernel/sys.c index ccfb6f05303e3..b9c690c534345 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -2298,15 +2299,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr, { struct mm_struct *mm = current->mm; const char __user *uname; - char *name, *pch; + struct anon_vma_name *anon_name = NULL; int error; switch (opt) { case PR_SET_VMA_ANON_NAME: uname = (const char __user *)arg; if (uname) { - name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN); + char *name, *pch; + name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN); if (IS_ERR(name)) return PTR_ERR(name); @@ -2316,15 +2318,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr, return -EINVAL; } } - } else { - /* Reset the name */ - name = NULL; + /* anon_vma has its own copy */ + anon_name = anon_vma_name_alloc(name); + kfree(name); + if (!anon_name) + return -ENOMEM; + } mmap_write_lock(mm); - error = madvise_set_anon_name(mm, addr, size, name); + error = madvise_set_anon_name(mm, addr, size, anon_name); mmap_write_unlock(mm); - kfree(name); + anon_vma_name_put(anon_name); break; default: error = -EINVAL; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index ed71c41410472..1535065a7d76a 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -2053,26 +2053,44 @@ unsigned long msleep_interruptible(unsigned int msecs) EXPORT_SYMBOL(msleep_interruptible); /** - * usleep_range - Sleep for an approximate time - * @min: Minimum time in usecs to sleep - * @max: Maximum time in usecs to sleep + * usleep_range_state - Sleep for an approximate time in a given state + * @min: Minimum time in usecs to sleep + * @max: Maximum time in usecs to sleep + * @state: State of the current task that will be while sleeping * * In non-atomic context where the exact wakeup time is flexible, use - * usleep_range() instead of udelay(). The sleep improves responsiveness + * usleep_range_state() instead of udelay(). The sleep improves responsiveness * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces * power usage by allowing hrtimers to take advantage of an already- * scheduled interrupt instead of scheduling a new one just for this sleep. */ -void __sched usleep_range(unsigned long min, unsigned long max) +void __sched usleep_range_state(unsigned long min, unsigned long max, + unsigned int state) { ktime_t exp = ktime_add_us(ktime_get(), min); u64 delta = (u64)(max - min) * NSEC_PER_USEC; for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE); + __set_current_state(state); /* Do not return before the requested sleep time has elapsed */ if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS)) break; } } + +/** + * usleep_range - Sleep for an approximate time + * @min: Minimum time in usecs to sleep + * @max: Maximum time in usecs to sleep + * + * In non-atomic context where the exact wakeup time is flexible, use + * usleep_range() instead of udelay(). The sleep improves responsiveness + * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces + * power usage by allowing hrtimers to take advantage of an already- + * scheduled interrupt instead of scheduling a new one just for this sleep. + */ +void __sched usleep_range(unsigned long min, unsigned long max) +{ + usleep_range_state(min, max, TASK_UNINTERRUPTIBLE); +} EXPORT_SYMBOL(usleep_range); diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index 249ed32591449..e3f144d960261 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -274,7 +274,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) return 0; error_p: - while (--i >= 0) + for (i = 0; i < nr_pages; i++) __free_page(pages[i]); kfree(pages); error: @@ -373,7 +373,6 @@ static void __put_watch_queue(struct kref *kref) for (i = 0; i < wqueue->nr_pages; i++) __free_page(wqueue->notes[i]); - kfree(wqueue->notes); bitmap_free(wqueue->notes_bitmap); wfilter = rcu_access_pointer(wqueue->filter); @@ -399,7 +398,6 @@ static void free_watch(struct rcu_head *rcu) put_watch_queue(rcu_access_pointer(watch->queue)); atomic_dec(&watch->cred->user->nr_watches); put_cred(watch->cred); - kfree(watch); } static void __put_watch(struct kref *kref) diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 71e5c58530996..0dd434e40487c 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -52,7 +52,7 @@ static unsigned long kunit_test_timeout(void) * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, * the task will be killed and an oops generated. */ - return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */ + return 300 * MSEC_PER_SEC; /* 5 min */ } void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index 4fb7700a741bd..a4c7cd74cff58 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -4,8 +4,6 @@ # from userspace. # -pound := \# - CC = gcc OPTFLAGS = -O2 # Adjust as desired CFLAGS = -I.. -I ../../../include -g $(OPTFLAGS) @@ -44,7 +42,7 @@ else ifeq ($(HAS_NEON),yes) OBJS += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1 else - HAS_ALTIVEC := $(shell printf '$(pound)include \nvector int a;\n' |\ + HAS_ALTIVEC := $(shell printf '\#include \nvector int a;\n' |\ gcc -c -x c - >/dev/null && rm ./-.o && echo yes) ifeq ($(HAS_ALTIVEC),yes) CFLAGS += -I../../../arch/powerpc/include diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c index 841a55242abaa..a3cf071941ab4 100644 --- a/lib/raid6/test/test.c +++ b/lib/raid6/test/test.c @@ -19,6 +19,7 @@ #define NDISKS 16 /* Including P and Q */ const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); +struct raid6_calls raid6_call; char *dataptrs[NDISKS]; char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 7d3c5111bbfc5..4de52eb5b93b6 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -37,7 +37,7 @@ void *kasan_ptr_result; int kasan_int_result; static struct kunit_resource resource; -static struct kunit_kasan_expectation fail_data; +static struct kunit_kasan_status test_status; static bool multishot; /* @@ -54,58 +54,63 @@ static int kasan_test_init(struct kunit *test) } multishot = kasan_save_enable_multi_shot(); - fail_data.report_found = false; + test_status.report_found = false; + test_status.sync_fault = false; kunit_add_named_resource(test, NULL, NULL, &resource, - "kasan_data", &fail_data); + "kasan_status", &test_status); return 0; } static void kasan_test_exit(struct kunit *test) { kasan_restore_multi_shot(multishot); - KUNIT_EXPECT_FALSE(test, fail_data.report_found); + KUNIT_EXPECT_FALSE(test, test_status.report_found); } /** * KUNIT_EXPECT_KASAN_FAIL() - check that the executed expression produces a * KASAN report; causes a test failure otherwise. This relies on a KUnit - * resource named "kasan_data". Do not use this name for KUnit resources + * resource named "kasan_status". Do not use this name for KUnit resources * outside of KASAN tests. * - * For hardware tag-based KASAN in sync mode, when a tag fault happens, tag + * For hardware tag-based KASAN, when a synchronous tag fault happens, tag * checking is auto-disabled. When this happens, this test handler reenables * tag checking. As tag checking can be only disabled or enabled per CPU, * this handler disables migration (preemption). * - * Since the compiler doesn't see that the expression can change the fail_data + * Since the compiler doesn't see that the expression can change the test_status * fields, it can reorder or optimize away the accesses to those fields. * Use READ/WRITE_ONCE() for the accesses and compiler barriers around the * expression to prevent that. * - * In between KUNIT_EXPECT_KASAN_FAIL checks, fail_data.report_found is kept as - * false. This allows detecting KASAN reports that happen outside of the checks - * by asserting !fail_data.report_found at the start of KUNIT_EXPECT_KASAN_FAIL - * and in kasan_test_exit. + * In between KUNIT_EXPECT_KASAN_FAIL checks, test_status.report_found is kept + * as false. This allows detecting KASAN reports that happen outside of the + * checks by asserting !test_status.report_found at the start of + * KUNIT_EXPECT_KASAN_FAIL and in kasan_test_exit. */ #define KUNIT_EXPECT_KASAN_FAIL(test, expression) do { \ if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ kasan_sync_fault_possible()) \ migrate_disable(); \ - KUNIT_EXPECT_FALSE(test, READ_ONCE(fail_data.report_found)); \ + KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found)); \ barrier(); \ expression; \ barrier(); \ - if (!READ_ONCE(fail_data.report_found)) { \ + if (kasan_async_fault_possible()) \ + kasan_force_async_fault(); \ + if (!READ_ONCE(test_status.report_found)) { \ KUNIT_FAIL(test, KUNIT_SUBTEST_INDENT "KASAN failure " \ "expected in \"" #expression \ "\", but none occurred"); \ } \ - if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) { \ - if (READ_ONCE(fail_data.report_found)) \ - kasan_enable_tagging_sync(); \ + if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ + kasan_sync_fault_possible()) { \ + if (READ_ONCE(test_status.report_found) && \ + READ_ONCE(test_status.sync_fault)) \ + kasan_enable_tagging(); \ migrate_enable(); \ } \ - WRITE_ONCE(fail_data.report_found, false); \ + WRITE_ONCE(test_status.report_found, false); \ } while (0) #define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do { \ @@ -1062,7 +1067,6 @@ static void kmalloc_double_kzfree(struct kunit *test) static void vmalloc_helpers_tags(struct kunit *test) { void *ptr; - int rv; /* This test is intended for tag-based modes. */ KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC); @@ -1080,11 +1084,17 @@ static void vmalloc_helpers_tags(struct kunit *test) KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr)); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr)); - /* Make sure vmalloc'ed memory permissions can be changed. */ - rv = set_memory_ro((unsigned long)ptr, 1); - KUNIT_ASSERT_GE(test, rv, 0); - rv = set_memory_rw((unsigned long)ptr, 1); - KUNIT_ASSERT_GE(test, rv, 0); +#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST) + { + int rv; + + /* Make sure vmalloc'ed memory permissions can be changed. */ + rv = set_memory_ro((unsigned long)ptr, 1); + KUNIT_ASSERT_GE(test, rv, 0); + rv = set_memory_rw((unsigned long)ptr, 1); + KUNIT_ASSERT_GE(test, rv, 0); + } +#endif vfree(ptr); } diff --git a/lib/test_kmod.c b/lib/test_kmod.c index c637f6b5053a9..eab52770070d6 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -1155,7 +1155,6 @@ static struct kmod_test_device *register_test_dev_kmod(void) if (ret) { pr_err("could not register misc device: %d\n", ret); free_test_dev_kmod(test_dev); - test_dev = NULL; goto out; } diff --git a/lib/test_lockup.c b/lib/test_lockup.c index 78a630bbd03df..5359e2d1a2f24 100644 --- a/lib/test_lockup.c +++ b/lib/test_lockup.c @@ -417,14 +417,9 @@ static bool test_kernel_ptr(unsigned long addr, int size) return false; /* should be at least readable kernel address */ - if (!IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) && - (access_ok((void __user *)ptr, 1) || - access_ok((void __user *)ptr + size - 1, 1))) { - pr_err("user space ptr invalid in kernel: %#lx\n", addr); - return true; - } - - if (get_kernel_nofault(buf, ptr) || + if (access_ok(ptr, 1) || + access_ok(ptr + size - 1, 1) || + get_kernel_nofault(buf, ptr) || get_kernel_nofault(buf, ptr + size - 1)) { pr_err("invalid kernel ptr: %#lx\n", addr); return true; @@ -600,5 +595,6 @@ static int __init test_lockup_init(void) module_init(test_lockup_init); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Konstantin Khlebnikov "); MODULE_DESCRIPTION("Test module to generate lockups"); diff --git a/lib/test_xarray.c b/lib/test_xarray.c index e77d4856442c3..8b1c318189ce8 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -1463,25 +1463,6 @@ unlock: XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_create_range_5(struct xarray *xa, - unsigned long index, unsigned int order) -{ - XA_STATE_ORDER(xas, xa, index, order); - unsigned int i; - - xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL); - - for (i = 0; i < order + 10; i++) { - do { - xas_lock(&xas); - xas_create_range(&xas); - xas_unlock(&xas); - } while (xas_nomem(&xas, GFP_KERNEL)); - } - - xa_destroy(xa); -} - static noinline void check_create_range(struct xarray *xa) { unsigned int order; @@ -1509,9 +1490,6 @@ static noinline void check_create_range(struct xarray *xa) check_create_range_4(xa, (3U << order) + 1, order); check_create_range_4(xa, (3U << order) - 1, order); check_create_range_4(xa, (1U << 24) + 1, order); - - check_create_range_5(xa, 0, order); - check_create_range_5(xa, (1U << order), order); } check_create_range_3(); diff --git a/lib/xarray.c b/lib/xarray.c index 75da19a7a9334..ed775dee1074c 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -722,8 +722,6 @@ void xas_create_range(struct xa_state *xas) for (;;) { struct xa_node *node = xas->xa_node; - if (node->shift >= shift) - break; xas->xa_node = xa_parent_locked(xas->xa, node); xas->xa_offset = node->offset - 1; if (node->offset != 0) @@ -1080,7 +1078,6 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order) xa_mk_node(child)); if (xa_is_value(curr)) values--; - xas_update(xas, child); } else { unsigned int canon = offset - xas->xa_sibs; @@ -1095,7 +1092,6 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order) } while (offset-- > xas->xa_offset); node->nr_values += values; - xas_update(xas, node); } EXPORT_SYMBOL_GPL(xas_split); #endif diff --git a/mm/Kconfig b/mm/Kconfig index 7853ccc1c9359..27cdf23dd46ed 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -756,10 +756,18 @@ config DEFERRED_STRUCT_PAGE_INIT lifetime of the system until these kthreads finish the initialisation. +config PAGE_IDLE_FLAG + bool + select PAGE_EXTENSION if !64BIT + help + This adds PG_idle and PG_young flags to 'struct page'. PTE Accessed + bit writers can set the state of the bit in the flags so that PTE + Accessed bit readers may avoid disturbance. + config IDLE_PAGE_TRACKING bool "Enable idle page tracking" depends on SYSFS && MMU - select PAGE_EXTENSION if !64BIT + select PAGE_IDLE_FLAG help This feature allows to estimate the amount of user pages that have not been touched during a given period of time. This information can @@ -907,4 +915,32 @@ config ANON_VMA_NAME area from being merged with adjacent virtual memory areas due to the difference in their name. +# multi-gen LRU { +config LRU_GEN + bool "Multi-Gen LRU" + depends on MMU + # the following options can use up the spare bits in page flags + depends on !MAXSMP && (64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP) + help + A high performance LRU implementation to overcommit memory. See + Documentation/admin-guide/mm/multigen_lru.rst for details. + +config LRU_GEN_ENABLED + bool "Enable by default" + depends on LRU_GEN + help + This option enables the multi-gen LRU by default. + +config LRU_GEN_STATS + bool "Full stats for debugging" + depends on LRU_GEN + help + Do not enable this option unless you plan to look at historical stats + from evicted generations for debugging purpose. + + This option has a per-memcg and per-node memory overhead. +# } + +source "mm/damon/Kconfig" + endmenu diff --git a/mm/Makefile b/mm/Makefile index 8de8651da0695..b90583a89fb5a 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_USERFAULTFD) += userfaultfd.o obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o +obj-$(CONFIG_DAMON) += damon/ obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_ZONE_DEVICE) += memremap.o diff --git a/mm/compaction.c b/mm/compaction.c index c1a02788282b3..6650f5968f261 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1034,7 +1034,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, low_pfn += compound_nr(page) - 1; /* Successfully isolated */ - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_is_file_lru(page), thp_nr_pages(page)); diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig new file mode 100644 index 0000000000000..5bcf05851ad07 --- /dev/null +++ b/mm/damon/Kconfig @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Data Access Monitoring" + +config DAMON + bool "DAMON: Data Access Monitoring Framework" + help + This builds a framework that allows kernel subsystems to monitor + access frequency of each memory region. The information can be useful + for performance-centric DRAM level memory management. + + See https://damonitor.github.io/doc/html/latest-damon/index.html for + more information. + +config DAMON_KUNIT_TEST + bool "Test for damon" if !KUNIT_ALL_TESTS + depends on DAMON && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_VADDR + bool "Data access monitoring primitives for virtual address spaces" + depends on DAMON && MMU + select PAGE_IDLE_FLAG + help + This builds the default data access monitoring primitives for DAMON + that work for virtual address spaces. + +config DAMON_PADDR + bool "Data access monitoring primitives for the physical address space" + depends on DAMON && MMU + select PAGE_IDLE_FLAG + help + This builds the default data access monitoring primitives for DAMON + that works for the physical address space. + +config DAMON_VADDR_KUNIT_TEST + bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS + depends on DAMON_VADDR && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON virtual addresses primitives Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_DBGFS + bool "DAMON debugfs interface" + depends on DAMON_VADDR && DAMON_PADDR && DEBUG_FS + help + This builds the debugfs interface for DAMON. The user space admins + can use the interface for arbitrary data access monitoring. + + If unsure, say N. + +config DAMON_DBGFS_KUNIT_TEST + bool "Test for damon debugfs interface" if !KUNIT_ALL_TESTS + depends on DAMON_DBGFS && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON debugfs interface Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_RECLAIM + bool "Build DAMON-based reclaim (DAMON_RECLAIM)" + depends on DAMON_PADDR + help + This builds the DAMON-based reclamation subsystem. It finds pages + that not accessed for a long time (cold) using DAMON and reclaim + those. + + This is suggested to be used as a proactive and lightweight + reclamation under light memory pressure, while the traditional page + scanning-based reclamation is used for heavy pressure. + +endmenu diff --git a/mm/damon/Makefile b/mm/damon/Makefile new file mode 100644 index 0000000000000..f7d5ac377a2bb --- /dev/null +++ b/mm/damon/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DAMON) := core.o +obj-$(CONFIG_DAMON_VADDR) += prmtv-common.o vaddr.o +obj-$(CONFIG_DAMON_PADDR) += prmtv-common.o paddr.o +obj-$(CONFIG_DAMON_DBGFS) += dbgfs.o +obj-$(CONFIG_DAMON_RECLAIM) += reclaim.o diff --git a/mm/damon/core-test.h b/mm/damon/core-test.h new file mode 100644 index 0000000000000..7008c3735e99f --- /dev/null +++ b/mm/damon/core-test.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Data Access Monitor Unit Tests + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_KUNIT_TEST + +#ifndef _DAMON_CORE_TEST_H +#define _DAMON_CORE_TEST_H + +#include + +static void damon_test_regions(struct kunit *test) +{ + struct damon_region *r; + struct damon_target *t; + + r = damon_new_region(1, 2); + KUNIT_EXPECT_EQ(test, 1ul, r->ar.start); + KUNIT_EXPECT_EQ(test, 2ul, r->ar.end); + KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); + + t = damon_new_target(42); + KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, 1u, damon_nr_regions(t)); + + damon_del_region(r, t); + KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); + + damon_free_target(t); +} + +static unsigned int nr_damon_targets(struct damon_ctx *ctx) +{ + struct damon_target *t; + unsigned int nr_targets = 0; + + damon_for_each_target(t, ctx) + nr_targets++; + + return nr_targets; +} + +static void damon_test_target(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + + t = damon_new_target(42); + KUNIT_EXPECT_EQ(test, 42ul, t->id); + KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); + + damon_add_target(c, t); + KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(c)); + + damon_destroy_target(t); + KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); + + damon_destroy_ctx(c); +} + +/* + * Test kdamond_reset_aggregated() + * + * DAMON checks access to each region and aggregates this information as the + * access frequency of each region. In detail, it increases '->nr_accesses' of + * regions that an access has confirmed. 'kdamond_reset_aggregated()' flushes + * the aggregated information ('->nr_accesses' of each regions) to the result + * buffer. As a result of the flushing, the '->nr_accesses' of regions are + * initialized to zero. + */ +static void damon_test_aggregate(struct kunit *test) +{ + struct damon_ctx *ctx = damon_new_ctx(); + unsigned long target_ids[] = {1, 2, 3}; + unsigned long saddr[][3] = {{10, 20, 30}, {5, 42, 49}, {13, 33, 55} }; + unsigned long eaddr[][3] = {{15, 27, 40}, {31, 45, 55}, {23, 44, 66} }; + unsigned long accesses[][3] = {{42, 95, 84}, {10, 20, 30}, {0, 1, 2} }; + struct damon_target *t; + struct damon_region *r; + int it, ir; + + damon_set_targets(ctx, target_ids, 3); + + it = 0; + damon_for_each_target(t, ctx) { + for (ir = 0; ir < 3; ir++) { + r = damon_new_region(saddr[it][ir], eaddr[it][ir]); + r->nr_accesses = accesses[it][ir]; + damon_add_region(r, t); + } + it++; + } + kdamond_reset_aggregated(ctx); + it = 0; + damon_for_each_target(t, ctx) { + ir = 0; + /* '->nr_accesses' should be zeroed */ + damon_for_each_region(r, t) { + KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); + ir++; + } + /* regions should be preserved */ + KUNIT_EXPECT_EQ(test, 3, ir); + it++; + } + /* targets also should be preserved */ + KUNIT_EXPECT_EQ(test, 3, it); + + damon_destroy_ctx(ctx); +} + +static void damon_test_split_at(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + struct damon_region *r; + + t = damon_new_target(42); + r = damon_new_region(0, 100); + damon_add_region(r, t); + damon_split_region_at(c, t, r, 25); + KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 25ul); + + r = damon_next_region(r); + KUNIT_EXPECT_EQ(test, r->ar.start, 25ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 100ul); + + damon_free_target(t); + damon_destroy_ctx(c); +} + +static void damon_test_merge_two(struct kunit *test) +{ + struct damon_target *t; + struct damon_region *r, *r2, *r3; + int i; + + t = damon_new_target(42); + r = damon_new_region(0, 100); + r->nr_accesses = 10; + damon_add_region(r, t); + r2 = damon_new_region(100, 300); + r2->nr_accesses = 20; + damon_add_region(r2, t); + + damon_merge_two_regions(t, r, r2); + KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 300ul); + KUNIT_EXPECT_EQ(test, r->nr_accesses, 16u); + + i = 0; + damon_for_each_region(r3, t) { + KUNIT_EXPECT_PTR_EQ(test, r, r3); + i++; + } + KUNIT_EXPECT_EQ(test, i, 1); + + damon_free_target(t); +} + +static struct damon_region *__nth_region_of(struct damon_target *t, int idx) +{ + struct damon_region *r; + unsigned int i = 0; + + damon_for_each_region(r, t) { + if (i++ == idx) + return r; + } + + return NULL; +} + +static void damon_test_merge_regions_of(struct kunit *test) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184}; + unsigned long ea[] = {100, 112, 122, 130, 156, 170, 184, 230}; + unsigned int nrs[] = {0, 0, 10, 10, 20, 30, 1, 2}; + + unsigned long saddrs[] = {0, 114, 130, 156, 170}; + unsigned long eaddrs[] = {112, 130, 156, 170, 230}; + int i; + + t = damon_new_target(42); + for (i = 0; i < ARRAY_SIZE(sa); i++) { + r = damon_new_region(sa[i], ea[i]); + r->nr_accesses = nrs[i]; + damon_add_region(r, t); + } + + damon_merge_regions_of(t, 9, 9999); + /* 0-112, 114-130, 130-156, 156-170 */ + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u); + for (i = 0; i < 5; i++) { + r = __nth_region_of(t, i); + KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]); + KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]); + } + damon_free_target(t); +} + +static void damon_test_split_regions_of(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + struct damon_region *r; + + t = damon_new_target(42); + r = damon_new_region(0, 22); + damon_add_region(r, t); + damon_split_regions_of(c, t, 2); + KUNIT_EXPECT_LE(test, damon_nr_regions(t), 2u); + damon_free_target(t); + + t = damon_new_target(42); + r = damon_new_region(0, 220); + damon_add_region(r, t); + damon_split_regions_of(c, t, 4); + KUNIT_EXPECT_LE(test, damon_nr_regions(t), 4u); + damon_free_target(t); + damon_destroy_ctx(c); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_test_target), + KUNIT_CASE(damon_test_regions), + KUNIT_CASE(damon_test_aggregate), + KUNIT_CASE(damon_test_split_at), + KUNIT_CASE(damon_test_merge_two), + KUNIT_CASE(damon_test_merge_regions_of), + KUNIT_CASE(damon_test_split_regions_of), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_CORE_TEST_H */ + +#endif /* CONFIG_DAMON_KUNIT_TEST */ diff --git a/mm/damon/core.c b/mm/damon/core.c new file mode 100644 index 0000000000000..1dd153c31c9e2 --- /dev/null +++ b/mm/damon/core.c @@ -0,0 +1,1075 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Data Access Monitor + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon: " fmt + +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#ifdef CONFIG_DAMON_KUNIT_TEST +#undef DAMON_MIN_REGION +#define DAMON_MIN_REGION 1 +#endif + +static DEFINE_MUTEX(damon_lock); +static int nr_running_ctxs; + +/* + * Construct a damon_region struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_region *damon_new_region(unsigned long start, unsigned long end) +{ + struct damon_region *region; + + region = kmalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return NULL; + + region->ar.start = start; + region->ar.end = end; + region->nr_accesses = 0; + INIT_LIST_HEAD(®ion->list); + + region->age = 0; + region->last_nr_accesses = 0; + + return region; +} + +void damon_add_region(struct damon_region *r, struct damon_target *t) +{ + list_add_tail(&r->list, &t->regions_list); + t->nr_regions++; +} + +static void damon_del_region(struct damon_region *r, struct damon_target *t) +{ + list_del(&r->list); + t->nr_regions--; +} + +static void damon_free_region(struct damon_region *r) +{ + kfree(r); +} + +void damon_destroy_region(struct damon_region *r, struct damon_target *t) +{ + damon_del_region(r, t); + damon_free_region(r); +} + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks) +{ + struct damos *scheme; + + scheme = kmalloc(sizeof(*scheme), GFP_KERNEL); + if (!scheme) + return NULL; + scheme->min_sz_region = min_sz_region; + scheme->max_sz_region = max_sz_region; + scheme->min_nr_accesses = min_nr_accesses; + scheme->max_nr_accesses = max_nr_accesses; + scheme->min_age_region = min_age_region; + scheme->max_age_region = max_age_region; + scheme->action = action; + scheme->stat = (struct damos_stat){}; + INIT_LIST_HEAD(&scheme->list); + + scheme->quota.ms = quota->ms; + scheme->quota.sz = quota->sz; + scheme->quota.reset_interval = quota->reset_interval; + scheme->quota.weight_sz = quota->weight_sz; + scheme->quota.weight_nr_accesses = quota->weight_nr_accesses; + scheme->quota.weight_age = quota->weight_age; + scheme->quota.total_charged_sz = 0; + scheme->quota.total_charged_ns = 0; + scheme->quota.esz = 0; + scheme->quota.charged_sz = 0; + scheme->quota.charged_from = 0; + scheme->quota.charge_target_from = NULL; + scheme->quota.charge_addr_from = 0; + + scheme->wmarks.metric = wmarks->metric; + scheme->wmarks.interval = wmarks->interval; + scheme->wmarks.high = wmarks->high; + scheme->wmarks.mid = wmarks->mid; + scheme->wmarks.low = wmarks->low; + scheme->wmarks.activated = true; + + return scheme; +} + +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) +{ + list_add_tail(&s->list, &ctx->schemes); +} + +static void damon_del_scheme(struct damos *s) +{ + list_del(&s->list); +} + +static void damon_free_scheme(struct damos *s) +{ + kfree(s); +} + +void damon_destroy_scheme(struct damos *s) +{ + damon_del_scheme(s); + damon_free_scheme(s); +} + +/* + * Construct a damon_target struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_target *damon_new_target(unsigned long id) +{ + struct damon_target *t; + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return NULL; + + t->id = id; + t->nr_regions = 0; + INIT_LIST_HEAD(&t->regions_list); + + return t; +} + +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t) +{ + list_add_tail(&t->list, &ctx->adaptive_targets); +} + +bool damon_targets_empty(struct damon_ctx *ctx) +{ + return list_empty(&ctx->adaptive_targets); +} + +static void damon_del_target(struct damon_target *t) +{ + list_del(&t->list); +} + +void damon_free_target(struct damon_target *t) +{ + struct damon_region *r, *next; + + damon_for_each_region_safe(r, next, t) + damon_free_region(r); + kfree(t); +} + +void damon_destroy_target(struct damon_target *t) +{ + damon_del_target(t); + damon_free_target(t); +} + +unsigned int damon_nr_regions(struct damon_target *t) +{ + return t->nr_regions; +} + +struct damon_ctx *damon_new_ctx(void) +{ + struct damon_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->sample_interval = 5 * 1000; + ctx->aggr_interval = 100 * 1000; + ctx->primitive_update_interval = 60 * 1000 * 1000; + + ktime_get_coarse_ts64(&ctx->last_aggregation); + ctx->last_primitive_update = ctx->last_aggregation; + + mutex_init(&ctx->kdamond_lock); + + ctx->min_nr_regions = 10; + ctx->max_nr_regions = 1000; + + INIT_LIST_HEAD(&ctx->adaptive_targets); + INIT_LIST_HEAD(&ctx->schemes); + + return ctx; +} + +static void damon_destroy_targets(struct damon_ctx *ctx) +{ + struct damon_target *t, *next_t; + + if (ctx->primitive.cleanup) { + ctx->primitive.cleanup(ctx); + return; + } + + damon_for_each_target_safe(t, next_t, ctx) + damon_destroy_target(t); +} + +void damon_destroy_ctx(struct damon_ctx *ctx) +{ + struct damos *s, *next_s; + + damon_destroy_targets(ctx); + + damon_for_each_scheme_safe(s, next_s, ctx) + damon_destroy_scheme(s); + + kfree(ctx); +} + +/** + * damon_set_targets() - Set monitoring targets. + * @ctx: monitoring context + * @ids: array of target ids + * @nr_ids: number of entries in @ids + * + * This function should not be called while the kdamond is running. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_set_targets(struct damon_ctx *ctx, + unsigned long *ids, ssize_t nr_ids) +{ + ssize_t i; + struct damon_target *t, *next; + + damon_destroy_targets(ctx); + + for (i = 0; i < nr_ids; i++) { + t = damon_new_target(ids[i]); + if (!t) { + /* The caller should do cleanup of the ids itself */ + damon_for_each_target_safe(t, next, ctx) + damon_destroy_target(t); + return -ENOMEM; + } + damon_add_target(ctx, t); + } + + return 0; +} + +/** + * damon_set_attrs() - Set attributes for the monitoring. + * @ctx: monitoring context + * @sample_int: time interval between samplings + * @aggr_int: time interval between aggregations + * @primitive_upd_int: time interval between monitoring primitive updates + * @min_nr_reg: minimal number of regions + * @max_nr_reg: maximum number of regions + * + * This function should not be called while the kdamond is running. + * Every time interval is in micro-seconds. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long primitive_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg) +{ + if (min_nr_reg < 3) + return -EINVAL; + if (min_nr_reg > max_nr_reg) + return -EINVAL; + + ctx->sample_interval = sample_int; + ctx->aggr_interval = aggr_int; + ctx->primitive_update_interval = primitive_upd_int; + ctx->min_nr_regions = min_nr_reg; + ctx->max_nr_regions = max_nr_reg; + + return 0; +} + +/** + * damon_set_schemes() - Set data access monitoring based operation schemes. + * @ctx: monitoring context + * @schemes: array of the schemes + * @nr_schemes: number of entries in @schemes + * + * This function should not be called while the kdamond of the context is + * running. + * + * Return: 0 if success, or negative error code otherwise. + */ +int damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes, + ssize_t nr_schemes) +{ + struct damos *s, *next; + ssize_t i; + + damon_for_each_scheme_safe(s, next, ctx) + damon_destroy_scheme(s); + for (i = 0; i < nr_schemes; i++) + damon_add_scheme(ctx, schemes[i]); + return 0; +} + +/** + * damon_nr_running_ctxs() - Return number of currently running contexts. + */ +int damon_nr_running_ctxs(void) +{ + int nr_ctxs; + + mutex_lock(&damon_lock); + nr_ctxs = nr_running_ctxs; + mutex_unlock(&damon_lock); + + return nr_ctxs; +} + +/* Returns the size upper limit for each monitoring region */ +static unsigned long damon_region_sz_limit(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long sz = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + sz += r->ar.end - r->ar.start; + } + + if (ctx->min_nr_regions) + sz /= ctx->min_nr_regions; + if (sz < DAMON_MIN_REGION) + sz = DAMON_MIN_REGION; + + return sz; +} + +static int kdamond_fn(void *data); + +/* + * __damon_start() - Starts monitoring with given context. + * @ctx: monitoring context + * + * This function should be called while damon_lock is hold. + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_start(struct damon_ctx *ctx) +{ + int err = -EBUSY; + + mutex_lock(&ctx->kdamond_lock); + if (!ctx->kdamond) { + err = 0; + ctx->kdamond = kthread_run(kdamond_fn, ctx, "kdamond.%d", + nr_running_ctxs); + if (IS_ERR(ctx->kdamond)) { + err = PTR_ERR(ctx->kdamond); + ctx->kdamond = NULL; + } + } + mutex_unlock(&ctx->kdamond_lock); + + return err; +} + +/** + * damon_start() - Starts the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to start monitoring + * @nr_ctxs: size of @ctxs + * + * This function starts a group of monitoring threads for a group of monitoring + * contexts. One thread per each context is created and run in parallel. The + * caller should handle synchronization between the threads by itself. If a + * group of threads that created by other 'damon_start()' call is currently + * running, this function does nothing but returns -EBUSY. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_start(struct damon_ctx **ctxs, int nr_ctxs) +{ + int i; + int err = 0; + + mutex_lock(&damon_lock); + if (nr_running_ctxs) { + mutex_unlock(&damon_lock); + return -EBUSY; + } + + for (i = 0; i < nr_ctxs; i++) { + err = __damon_start(ctxs[i]); + if (err) + break; + nr_running_ctxs++; + } + mutex_unlock(&damon_lock); + + return err; +} + +/* + * __damon_stop() - Stops monitoring of given context. + * @ctx: monitoring context + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_stop(struct damon_ctx *ctx) +{ + struct task_struct *tsk; + + mutex_lock(&ctx->kdamond_lock); + tsk = ctx->kdamond; + if (tsk) { + get_task_struct(tsk); + mutex_unlock(&ctx->kdamond_lock); + kthread_stop(tsk); + put_task_struct(tsk); + return 0; + } + mutex_unlock(&ctx->kdamond_lock); + + return -EPERM; +} + +/** + * damon_stop() - Stops the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to stop monitoring + * @nr_ctxs: size of @ctxs + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs) +{ + int i, err = 0; + + for (i = 0; i < nr_ctxs; i++) { + /* nr_running_ctxs is decremented in kdamond_fn */ + err = __damon_stop(ctxs[i]); + if (err) + return err; + } + + return err; +} + +/* + * damon_check_reset_time_interval() - Check if a time interval is elapsed. + * @baseline: the time to check whether the interval has elapsed since + * @interval: the time interval (microseconds) + * + * See whether the given time interval has passed since the given baseline + * time. If so, it also updates the baseline to current time for next check. + * + * Return: true if the time interval has passed, or false otherwise. + */ +static bool damon_check_reset_time_interval(struct timespec64 *baseline, + unsigned long interval) +{ + struct timespec64 now; + + ktime_get_coarse_ts64(&now); + if ((timespec64_to_ns(&now) - timespec64_to_ns(baseline)) < + interval * 1000) + return false; + *baseline = now; + return true; +} + +/* + * Check whether it is time to flush the aggregated information + */ +static bool kdamond_aggregate_interval_passed(struct damon_ctx *ctx) +{ + return damon_check_reset_time_interval(&ctx->last_aggregation, + ctx->aggr_interval); +} + +/* + * Reset the aggregated monitoring results ('nr_accesses' of each region). + */ +static void kdamond_reset_aggregated(struct damon_ctx *c) +{ + struct damon_target *t; + unsigned int ti = 0; /* target's index */ + + damon_for_each_target(t, c) { + struct damon_region *r; + + damon_for_each_region(r, t) { + trace_damon_aggregated(t, ti, r, damon_nr_regions(t)); + r->last_nr_accesses = r->nr_accesses; + r->nr_accesses = 0; + } + ti++; + } +} + +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r); + +static bool __damos_valid_target(struct damon_region *r, struct damos *s) +{ + unsigned long sz; + + sz = r->ar.end - r->ar.start; + return s->min_sz_region <= sz && sz <= s->max_sz_region && + s->min_nr_accesses <= r->nr_accesses && + r->nr_accesses <= s->max_nr_accesses && + s->min_age_region <= r->age && r->age <= s->max_age_region; +} + +static bool damos_valid_target(struct damon_ctx *c, struct damon_target *t, + struct damon_region *r, struct damos *s) +{ + bool ret = __damos_valid_target(r, s); + + if (!ret || !s->quota.esz || !c->primitive.get_scheme_score) + return ret; + + return c->primitive.get_scheme_score(c, t, r, s) >= s->quota.min_score; +} + +static void damon_do_apply_schemes(struct damon_ctx *c, + struct damon_target *t, + struct damon_region *r) +{ + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long sz = r->ar.end - r->ar.start; + struct timespec64 begin, end; + unsigned long sz_applied = 0; + + if (!s->wmarks.activated) + continue; + + /* Check the quota */ + if (quota->esz && quota->charged_sz >= quota->esz) + continue; + + /* Skip previously charged regions */ + if (quota->charge_target_from) { + if (t != quota->charge_target_from) + continue; + if (r == damon_last_region(t)) { + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + continue; + } + if (quota->charge_addr_from && + r->ar.end <= quota->charge_addr_from) + continue; + + if (quota->charge_addr_from && r->ar.start < + quota->charge_addr_from) { + sz = ALIGN_DOWN(quota->charge_addr_from - + r->ar.start, DAMON_MIN_REGION); + if (!sz) { + if (r->ar.end - r->ar.start <= + DAMON_MIN_REGION) + continue; + sz = DAMON_MIN_REGION; + } + damon_split_region_at(c, t, r, sz); + r = damon_next_region(r); + sz = r->ar.end - r->ar.start; + } + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + } + + if (!damos_valid_target(c, t, r, s)) + continue; + + /* Apply the scheme */ + if (c->primitive.apply_scheme) { + if (quota->esz && + quota->charged_sz + sz > quota->esz) { + sz = ALIGN_DOWN(quota->esz - quota->charged_sz, + DAMON_MIN_REGION); + if (!sz) + goto update_stat; + damon_split_region_at(c, t, r, sz); + } + ktime_get_coarse_ts64(&begin); + sz_applied = c->primitive.apply_scheme(c, t, r, s); + ktime_get_coarse_ts64(&end); + quota->total_charged_ns += timespec64_to_ns(&end) - + timespec64_to_ns(&begin); + quota->charged_sz += sz; + if (quota->esz && quota->charged_sz >= quota->esz) { + quota->charge_target_from = t; + quota->charge_addr_from = r->ar.end + 1; + } + } + if (s->action != DAMOS_STAT) + r->age = 0; + +update_stat: + s->stat.nr_tried++; + s->stat.sz_tried += sz; + if (sz_applied) + s->stat.nr_applied++; + s->stat.sz_applied += sz_applied; + } +} + +/* Shouldn't be called if quota->ms and quota->sz are zero */ +static void damos_set_effective_quota(struct damos_quota *quota) +{ + unsigned long throughput; + unsigned long esz; + + if (!quota->ms) { + quota->esz = quota->sz; + return; + } + + if (quota->total_charged_ns) + throughput = quota->total_charged_sz * 1000000 / + quota->total_charged_ns; + else + throughput = PAGE_SIZE * 1024; + esz = throughput * quota->ms; + + if (quota->sz && quota->sz < esz) + esz = quota->sz; + quota->esz = esz; +} + +static void kdamond_apply_schemes(struct damon_ctx *c) +{ + struct damon_target *t; + struct damon_region *r, *next_r; + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long cumulated_sz; + unsigned int score, max_score = 0; + + if (!s->wmarks.activated) + continue; + + if (!quota->ms && !quota->sz) + continue; + + /* New charge window starts */ + if (time_after_eq(jiffies, quota->charged_from + + msecs_to_jiffies( + quota->reset_interval))) { + if (quota->esz && quota->charged_sz >= quota->esz) + s->stat.qt_exceeds++; + quota->total_charged_sz += quota->charged_sz; + quota->charged_from = jiffies; + quota->charged_sz = 0; + damos_set_effective_quota(quota); + } + + if (!c->primitive.get_scheme_score) + continue; + + /* Fill up the score histogram */ + memset(quota->histogram, 0, sizeof(quota->histogram)); + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + if (!__damos_valid_target(r, s)) + continue; + score = c->primitive.get_scheme_score( + c, t, r, s); + quota->histogram[score] += + r->ar.end - r->ar.start; + if (score > max_score) + max_score = score; + } + } + + /* Set the min score limit */ + for (cumulated_sz = 0, score = max_score; ; score--) { + cumulated_sz += quota->histogram[score]; + if (cumulated_sz >= quota->esz || !score) + break; + } + quota->min_score = score; + } + + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next_r, t) + damon_do_apply_schemes(c, t, r); + } +} + +static inline unsigned long sz_damon_region(struct damon_region *r) +{ + return r->ar.end - r->ar.start; +} + +/* + * Merge two adjacent regions into one region + */ +static void damon_merge_two_regions(struct damon_target *t, + struct damon_region *l, struct damon_region *r) +{ + unsigned long sz_l = sz_damon_region(l), sz_r = sz_damon_region(r); + + l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / + (sz_l + sz_r); + l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r); + l->ar.end = r->ar.end; + damon_destroy_region(r, t); +} + +/* + * Merge adjacent regions having similar access frequencies + * + * t target affected by this merge operation + * thres '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + */ +static void damon_merge_regions_of(struct damon_target *t, unsigned int thres, + unsigned long sz_limit) +{ + struct damon_region *r, *prev = NULL, *next; + + damon_for_each_region_safe(r, next, t) { + if (abs(r->nr_accesses - r->last_nr_accesses) > thres) + r->age = 0; + else + r->age++; + + if (prev && prev->ar.end == r->ar.start && + abs(prev->nr_accesses - r->nr_accesses) <= thres && + sz_damon_region(prev) + sz_damon_region(r) <= sz_limit) + damon_merge_two_regions(t, prev, r); + else + prev = r; + } +} + +/* + * Merge adjacent regions having similar access frequencies + * + * threshold '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + * + * This function merges monitoring target regions which are adjacent and their + * access frequencies are similar. This is for minimizing the monitoring + * overhead under the dynamically changeable access pattern. If a merge was + * unnecessarily made, later 'kdamond_split_regions()' will revert it. + */ +static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold, + unsigned long sz_limit) +{ + struct damon_target *t; + + damon_for_each_target(t, c) + damon_merge_regions_of(t, threshold, sz_limit); +} + +/* + * Split a region in two + * + * r the region to be split + * sz_r size of the first sub-region that will be made + */ +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r) +{ + struct damon_region *new; + + new = damon_new_region(r->ar.start + sz_r, r->ar.end); + if (!new) + return; + + r->ar.end = new->ar.start; + + new->age = r->age; + new->last_nr_accesses = r->last_nr_accesses; + + damon_insert_region(new, r, damon_next_region(r), t); +} + +/* Split every region in the given target into 'nr_subs' regions */ +static void damon_split_regions_of(struct damon_ctx *ctx, + struct damon_target *t, int nr_subs) +{ + struct damon_region *r, *next; + unsigned long sz_region, sz_sub = 0; + int i; + + damon_for_each_region_safe(r, next, t) { + sz_region = r->ar.end - r->ar.start; + + for (i = 0; i < nr_subs - 1 && + sz_region > 2 * DAMON_MIN_REGION; i++) { + /* + * Randomly select size of left sub-region to be at + * least 10 percent and at most 90% of original region + */ + sz_sub = ALIGN_DOWN(damon_rand(1, 10) * + sz_region / 10, DAMON_MIN_REGION); + /* Do not allow blank region */ + if (sz_sub == 0 || sz_sub >= sz_region) + continue; + + damon_split_region_at(ctx, t, r, sz_sub); + sz_region = sz_sub; + } + } +} + +/* + * Split every target region into randomly-sized small regions + * + * This function splits every target region into random-sized small regions if + * current total number of the regions is equal or smaller than half of the + * user-specified maximum number of regions. This is for maximizing the + * monitoring accuracy under the dynamically changeable access patterns. If a + * split was unnecessarily made, later 'kdamond_merge_regions()' will revert + * it. + */ +static void kdamond_split_regions(struct damon_ctx *ctx) +{ + struct damon_target *t; + unsigned int nr_regions = 0; + static unsigned int last_nr_regions; + int nr_subregions = 2; + + damon_for_each_target(t, ctx) + nr_regions += damon_nr_regions(t); + + if (nr_regions > ctx->max_nr_regions / 2) + return; + + /* Maybe the middle of the region has different access frequency */ + if (last_nr_regions == nr_regions && + nr_regions < ctx->max_nr_regions / 3) + nr_subregions = 3; + + damon_for_each_target(t, ctx) + damon_split_regions_of(ctx, t, nr_subregions); + + last_nr_regions = nr_regions; +} + +/* + * Check whether it is time to check and apply the target monitoring regions + * + * Returns true if it is. + */ +static bool kdamond_need_update_primitive(struct damon_ctx *ctx) +{ + return damon_check_reset_time_interval(&ctx->last_primitive_update, + ctx->primitive_update_interval); +} + +/* + * Check whether current monitoring should be stopped + * + * The monitoring is stopped when either the user requested to stop, or all + * monitoring targets are invalid. + * + * Returns true if need to stop current monitoring. + */ +static bool kdamond_need_stop(struct damon_ctx *ctx) +{ + struct damon_target *t; + + if (kthread_should_stop()) + return true; + + if (!ctx->primitive.target_valid) + return false; + + damon_for_each_target(t, ctx) { + if (ctx->primitive.target_valid(t)) + return false; + } + + return true; +} + +static unsigned long damos_wmark_metric_value(enum damos_wmark_metric metric) +{ + struct sysinfo i; + + switch (metric) { + case DAMOS_WMARK_FREE_MEM_RATE: + si_meminfo(&i); + return i.freeram * 1000 / i.totalram; + default: + break; + } + return -EINVAL; +} + +/* + * Returns zero if the scheme is active. Else, returns time to wait for next + * watermark check in micro-seconds. + */ +static unsigned long damos_wmark_wait_us(struct damos *scheme) +{ + unsigned long metric; + + if (scheme->wmarks.metric == DAMOS_WMARK_NONE) + return 0; + + metric = damos_wmark_metric_value(scheme->wmarks.metric); + /* higher than high watermark or lower than low watermark */ + if (metric > scheme->wmarks.high || scheme->wmarks.low > metric) { + if (scheme->wmarks.activated) + pr_debug("deactivate a scheme (%d) for %s wmark\n", + scheme->action, + metric > scheme->wmarks.high ? + "high" : "low"); + scheme->wmarks.activated = false; + return scheme->wmarks.interval; + } + + /* inactive and higher than middle watermark */ + if ((scheme->wmarks.high >= metric && metric >= scheme->wmarks.mid) && + !scheme->wmarks.activated) + return scheme->wmarks.interval; + + if (!scheme->wmarks.activated) + pr_debug("activate a scheme (%d)\n", scheme->action); + scheme->wmarks.activated = true; + return 0; +} + +static void kdamond_usleep(unsigned long usecs) +{ + /* See Documentation/timers/timers-howto.rst for the thresholds */ + if (usecs > 20 * USEC_PER_MSEC) + schedule_timeout_idle(usecs_to_jiffies(usecs)); + else + usleep_idle_range(usecs, usecs + 1); +} + +/* Returns negative error code if it's not activated but should return */ +static int kdamond_wait_activation(struct damon_ctx *ctx) +{ + struct damos *s; + unsigned long wait_time; + unsigned long min_wait_time = 0; + + while (!kdamond_need_stop(ctx)) { + damon_for_each_scheme(s, ctx) { + wait_time = damos_wmark_wait_us(s); + if (!min_wait_time || wait_time < min_wait_time) + min_wait_time = wait_time; + } + if (!min_wait_time) + return 0; + + kdamond_usleep(min_wait_time); + } + return -EBUSY; +} + +/* + * The monitoring daemon that runs as a kernel thread + */ +static int kdamond_fn(void *data) +{ + struct damon_ctx *ctx = (struct damon_ctx *)data; + struct damon_target *t; + struct damon_region *r, *next; + unsigned int max_nr_accesses = 0; + unsigned long sz_limit = 0; + bool done = false; + + pr_debug("kdamond (%d) starts\n", current->pid); + + if (ctx->primitive.init) + ctx->primitive.init(ctx); + if (ctx->callback.before_start && ctx->callback.before_start(ctx)) + done = true; + + sz_limit = damon_region_sz_limit(ctx); + + while (!kdamond_need_stop(ctx) && !done) { + if (kdamond_wait_activation(ctx)) + continue; + + if (ctx->primitive.prepare_access_checks) + ctx->primitive.prepare_access_checks(ctx); + if (ctx->callback.after_sampling && + ctx->callback.after_sampling(ctx)) + done = true; + + kdamond_usleep(ctx->sample_interval); + + if (ctx->primitive.check_accesses) + max_nr_accesses = ctx->primitive.check_accesses(ctx); + + if (kdamond_aggregate_interval_passed(ctx)) { + kdamond_merge_regions(ctx, + max_nr_accesses / 10, + sz_limit); + if (ctx->callback.after_aggregation && + ctx->callback.after_aggregation(ctx)) + done = true; + kdamond_apply_schemes(ctx); + kdamond_reset_aggregated(ctx); + kdamond_split_regions(ctx); + if (ctx->primitive.reset_aggregated) + ctx->primitive.reset_aggregated(ctx); + } + + if (kdamond_need_update_primitive(ctx)) { + if (ctx->primitive.update) + ctx->primitive.update(ctx); + sz_limit = damon_region_sz_limit(ctx); + } + } + damon_for_each_target(t, ctx) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + + if (ctx->callback.before_terminate) + ctx->callback.before_terminate(ctx); + if (ctx->primitive.cleanup) + ctx->primitive.cleanup(ctx); + + pr_debug("kdamond (%d) finishes\n", current->pid); + mutex_lock(&ctx->kdamond_lock); + ctx->kdamond = NULL; + mutex_unlock(&ctx->kdamond_lock); + + mutex_lock(&damon_lock); + nr_running_ctxs--; + mutex_unlock(&damon_lock); + + return 0; +} + +#include "core-test.h" diff --git a/mm/damon/dbgfs-test.h b/mm/damon/dbgfs-test.h new file mode 100644 index 0000000000000..86b9f9528231e --- /dev/null +++ b/mm/damon/dbgfs-test.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DAMON Debugfs Interface Unit Tests + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_DBGFS_KUNIT_TEST + +#ifndef _DAMON_DBGFS_TEST_H +#define _DAMON_DBGFS_TEST_H + +#include + +static void damon_dbgfs_test_str_to_target_ids(struct kunit *test) +{ + char *question; + unsigned long *answers; + unsigned long expected[] = {12, 35, 46}; + ssize_t nr_integers = 0, i; + + question = "123"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)1, nr_integers); + KUNIT_EXPECT_EQ(test, 123ul, answers[0]); + kfree(answers); + + question = "123abc"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)1, nr_integers); + KUNIT_EXPECT_EQ(test, 123ul, answers[0]); + kfree(answers); + + question = "a123"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); + + question = "12 35"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)2, nr_integers); + for (i = 0; i < nr_integers; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = "12 35 46"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)3, nr_integers); + for (i = 0; i < nr_integers; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = "12 35 abc 46"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)2, nr_integers); + for (i = 0; i < 2; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = ""; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); + + question = "\n"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); +} + +static void damon_dbgfs_test_set_targets(struct kunit *test) +{ + struct damon_ctx *ctx = dbgfs_new_ctx(); + unsigned long ids[] = {1, 2, 3}; + char buf[64]; + + /* Make DAMON consider target id as plain number */ + ctx->primitive.target_valid = NULL; + ctx->primitive.cleanup = NULL; + + damon_set_targets(ctx, ids, 3); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "1 2 3\n"); + + damon_set_targets(ctx, NULL, 0); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "\n"); + + damon_set_targets(ctx, (unsigned long []){1, 2}, 2); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "1 2\n"); + + damon_set_targets(ctx, (unsigned long []){2}, 1); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "2\n"); + + damon_set_targets(ctx, NULL, 0); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "\n"); + + dbgfs_destroy_ctx(ctx); +} + +static void damon_dbgfs_test_set_init_regions(struct kunit *test) +{ + struct damon_ctx *ctx = damon_new_ctx(); + unsigned long ids[] = {1, 2, 3}; + /* Each line represents one region in `` `` */ + char * const valid_inputs[] = {"2 10 20\n 2 20 30\n2 35 45", + "2 10 20\n", + "2 10 20\n1 39 59\n1 70 134\n 2 20 25\n", + ""}; + /* Reading the file again will show sorted, clean output */ + char * const valid_expects[] = {"2 10 20\n2 20 30\n2 35 45\n", + "2 10 20\n", + "1 39 59\n1 70 134\n2 10 20\n2 20 25\n", + ""}; + char * const invalid_inputs[] = {"4 10 20\n", /* target not exists */ + "2 10 20\n 2 14 26\n", /* regions overlap */ + "1 10 20\n2 30 40\n 1 5 8"}; /* not sorted by address */ + char *input, *expect; + int i, rc; + char buf[256]; + + damon_set_targets(ctx, ids, 3); + + /* Put valid inputs and check the results */ + for (i = 0; i < ARRAY_SIZE(valid_inputs); i++) { + input = valid_inputs[i]; + expect = valid_expects[i]; + + rc = set_init_regions(ctx, input, strnlen(input, 256)); + KUNIT_EXPECT_EQ(test, rc, 0); + + memset(buf, 0, 256); + sprint_init_regions(ctx, buf, 256); + + KUNIT_EXPECT_STREQ(test, (char *)buf, expect); + } + /* Put invalid inputs and check the return error code */ + for (i = 0; i < ARRAY_SIZE(invalid_inputs); i++) { + input = invalid_inputs[i]; + pr_info("input: %s\n", input); + rc = set_init_regions(ctx, input, strnlen(input, 256)); + KUNIT_EXPECT_EQ(test, rc, -EINVAL); + + memset(buf, 0, 256); + sprint_init_regions(ctx, buf, 256); + + KUNIT_EXPECT_STREQ(test, (char *)buf, ""); + } + + damon_set_targets(ctx, NULL, 0); + damon_destroy_ctx(ctx); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_dbgfs_test_str_to_target_ids), + KUNIT_CASE(damon_dbgfs_test_set_targets), + KUNIT_CASE(damon_dbgfs_test_set_init_regions), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon-dbgfs", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_TEST_H */ + +#endif /* CONFIG_DAMON_KUNIT_TEST */ diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c new file mode 100644 index 0000000000000..5b899601e56c3 --- /dev/null +++ b/mm/damon/dbgfs.c @@ -0,0 +1,990 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Debugfs Interface + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-dbgfs: " fmt + +#include +#include +#include +#include +#include +#include +#include + +static struct damon_ctx **dbgfs_ctxs; +static int dbgfs_nr_ctxs; +static struct dentry **dbgfs_dirs; +static DEFINE_MUTEX(damon_dbgfs_lock); + +/* + * Returns non-empty string on success, negative error code otherwise. + */ +static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + ssize_t ret; + + /* We do not accept continuous write */ + if (*ppos) + return ERR_PTR(-EINVAL); + + kbuf = kmalloc(count + 1, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return ERR_PTR(-ENOMEM); + + ret = simple_write_to_buffer(kbuf, count + 1, ppos, buf, count); + if (ret != count) { + kfree(kbuf); + return ERR_PTR(-EIO); + } + kbuf[ret] = '\0'; + + return kbuf; +} + +static ssize_t dbgfs_attrs_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char kbuf[128]; + int ret; + + mutex_lock(&ctx->kdamond_lock); + ret = scnprintf(kbuf, ARRAY_SIZE(kbuf), "%lu %lu %lu %lu %lu\n", + ctx->sample_interval, ctx->aggr_interval, + ctx->primitive_update_interval, ctx->min_nr_regions, + ctx->max_nr_regions); + mutex_unlock(&ctx->kdamond_lock); + + return simple_read_from_buffer(buf, count, ppos, kbuf, ret); +} + +static ssize_t dbgfs_attrs_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + unsigned long s, a, r, minr, maxr; + char *kbuf; + ssize_t ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + if (sscanf(kbuf, "%lu %lu %lu %lu %lu", + &s, &a, &r, &minr, &maxr) != 5) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + ret = damon_set_attrs(ctx, s, a, r, minr, maxr); + if (!ret) + ret = count; +unlock_out: + mutex_unlock(&ctx->kdamond_lock); +out: + kfree(kbuf); + return ret; +} + +static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len) +{ + struct damos *s; + int written = 0; + int rc; + + damon_for_each_scheme(s, c) { + rc = scnprintf(&buf[written], len - written, + "%lu %lu %u %u %u %u %d %lu %lu %lu %u %u %u %d %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + s->min_sz_region, s->max_sz_region, + s->min_nr_accesses, s->max_nr_accesses, + s->min_age_region, s->max_age_region, + s->action, + s->quota.ms, s->quota.sz, + s->quota.reset_interval, + s->quota.weight_sz, + s->quota.weight_nr_accesses, + s->quota.weight_age, + s->wmarks.metric, s->wmarks.interval, + s->wmarks.high, s->wmarks.mid, s->wmarks.low, + s->stat.nr_tried, s->stat.sz_tried, + s->stat.nr_applied, s->stat.sz_applied, + s->stat.qt_exceeds); + if (!rc) + return -ENOMEM; + + written += rc; + } + return written; +} + +static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + len = sprint_schemes(ctx, kbuf, count); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes) +{ + ssize_t i; + + for (i = 0; i < nr_schemes; i++) + kfree(schemes[i]); + kfree(schemes); +} + +static bool damos_action_valid(int action) +{ + switch (action) { + case DAMOS_WILLNEED: + case DAMOS_COLD: + case DAMOS_PAGEOUT: + case DAMOS_HUGEPAGE: + case DAMOS_NOHUGEPAGE: + case DAMOS_STAT: + return true; + default: + return false; + } +} + +/* + * Converts a string into an array of struct damos pointers + * + * Returns an array of struct damos pointers that converted if the conversion + * success, or NULL otherwise. + */ +static struct damos **str_to_schemes(const char *str, ssize_t len, + ssize_t *nr_schemes) +{ + struct damos *scheme, **schemes; + const int max_nr_schemes = 256; + int pos = 0, parsed, ret; + unsigned long min_sz, max_sz; + unsigned int min_nr_a, max_nr_a, min_age, max_age; + unsigned int action; + + schemes = kmalloc_array(max_nr_schemes, sizeof(scheme), + GFP_KERNEL); + if (!schemes) + return NULL; + + *nr_schemes = 0; + while (pos < len && *nr_schemes < max_nr_schemes) { + struct damos_quota quota = {}; + struct damos_watermarks wmarks; + + ret = sscanf(&str[pos], + "%lu %lu %u %u %u %u %u %lu %lu %lu %u %u %u %u %lu %lu %lu %lu%n", + &min_sz, &max_sz, &min_nr_a, &max_nr_a, + &min_age, &max_age, &action, "a.ms, + "a.sz, "a.reset_interval, + "a.weight_sz, "a.weight_nr_accesses, + "a.weight_age, &wmarks.metric, + &wmarks.interval, &wmarks.high, &wmarks.mid, + &wmarks.low, &parsed); + if (ret != 18) + break; + if (!damos_action_valid(action)) + goto fail; + + if (min_sz > max_sz || min_nr_a > max_nr_a || min_age > max_age) + goto fail; + + if (wmarks.high < wmarks.mid || wmarks.high < wmarks.low || + wmarks.mid < wmarks.low) + goto fail; + + pos += parsed; + scheme = damon_new_scheme(min_sz, max_sz, min_nr_a, max_nr_a, + min_age, max_age, action, "a, &wmarks); + if (!scheme) + goto fail; + + schemes[*nr_schemes] = scheme; + *nr_schemes += 1; + } + return schemes; +fail: + free_schemes_arr(schemes, *nr_schemes); + return NULL; +} + +static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + struct damos **schemes; + ssize_t nr_schemes = 0, ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + schemes = str_to_schemes(kbuf, count, &nr_schemes); + if (!schemes) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + ret = damon_set_schemes(ctx, schemes, nr_schemes); + if (!ret) { + ret = count; + nr_schemes = 0; + } + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); + free_schemes_arr(schemes, nr_schemes); +out: + kfree(kbuf); + return ret; +} + +static inline bool targetid_is_pid(const struct damon_ctx *ctx) +{ + return ctx->primitive.target_valid == damon_va_target_valid; +} + +static ssize_t sprint_target_ids(struct damon_ctx *ctx, char *buf, ssize_t len) +{ + struct damon_target *t; + unsigned long id; + int written = 0; + int rc; + + damon_for_each_target(t, ctx) { + id = t->id; + if (targetid_is_pid(ctx)) + /* Show pid numbers to debugfs users */ + id = (unsigned long)pid_vnr((struct pid *)id); + + rc = scnprintf(&buf[written], len - written, "%lu ", id); + if (!rc) + return -ENOMEM; + written += rc; + } + if (written) + written -= 1; + written += scnprintf(&buf[written], len - written, "\n"); + return written; +} + +static ssize_t dbgfs_target_ids_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + ssize_t len; + char ids_buf[320]; + + mutex_lock(&ctx->kdamond_lock); + len = sprint_target_ids(ctx, ids_buf, 320); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + return len; + + return simple_read_from_buffer(buf, count, ppos, ids_buf, len); +} + +/* + * Converts a string into an array of unsigned long integers + * + * Returns an array of unsigned long integers if the conversion success, or + * NULL otherwise. + */ +static unsigned long *str_to_target_ids(const char *str, ssize_t len, + ssize_t *nr_ids) +{ + unsigned long *ids; + const int max_nr_ids = 32; + unsigned long id; + int pos = 0, parsed, ret; + + *nr_ids = 0; + ids = kmalloc_array(max_nr_ids, sizeof(id), GFP_KERNEL); + if (!ids) + return NULL; + while (*nr_ids < max_nr_ids && pos < len) { + ret = sscanf(&str[pos], "%lu%n", &id, &parsed); + pos += parsed; + if (ret != 1) + break; + ids[*nr_ids] = id; + *nr_ids += 1; + } + + return ids; +} + +static void dbgfs_put_pids(unsigned long *ids, int nr_ids) +{ + int i; + + for (i = 0; i < nr_ids; i++) + put_pid((struct pid *)ids[i]); +} + +static ssize_t dbgfs_target_ids_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + struct damon_target *t, *next_t; + bool id_is_pid = true; + char *kbuf; + unsigned long *targets; + ssize_t nr_targets; + ssize_t ret; + int i; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + if (!strncmp(kbuf, "paddr\n", count)) { + id_is_pid = false; + /* target id is meaningless here, but we set it just for fun */ + scnprintf(kbuf, count, "42 "); + } + + targets = str_to_target_ids(kbuf, count, &nr_targets); + if (!targets) { + ret = -ENOMEM; + goto out; + } + + if (id_is_pid) { + for (i = 0; i < nr_targets; i++) { + targets[i] = (unsigned long)find_get_pid( + (int)targets[i]); + if (!targets[i]) { + dbgfs_put_pids(targets, i); + ret = -EINVAL; + goto free_targets_out; + } + } + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + if (id_is_pid) + dbgfs_put_pids(targets, nr_targets); + ret = -EBUSY; + goto unlock_out; + } + + /* remove previously set targets */ + damon_for_each_target_safe(t, next_t, ctx) { + if (targetid_is_pid(ctx)) + put_pid((struct pid *)t->id); + damon_destroy_target(t); + } + + /* Configure the context for the address space type */ + if (id_is_pid) + damon_va_set_primitives(ctx); + else + damon_pa_set_primitives(ctx); + + ret = damon_set_targets(ctx, targets, nr_targets); + if (ret) { + if (id_is_pid) + dbgfs_put_pids(targets, nr_targets); + } else { + ret = count; + } + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); +free_targets_out: + kfree(targets); +out: + kfree(kbuf); + return ret; +} + +static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len) +{ + struct damon_target *t; + struct damon_region *r; + int written = 0; + int rc; + + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + rc = scnprintf(&buf[written], len - written, + "%lu %lu %lu\n", + t->id, r->ar.start, r->ar.end); + if (!rc) + return -ENOMEM; + written += rc; + } + } + return written; +} + +static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + mutex_unlock(&ctx->kdamond_lock); + len = -EBUSY; + goto out; + } + + len = sprint_init_regions(ctx, kbuf, count); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static int add_init_region(struct damon_ctx *c, + unsigned long target_id, struct damon_addr_range *ar) +{ + struct damon_target *t; + struct damon_region *r, *prev; + unsigned long id; + int rc = -EINVAL; + + if (ar->start >= ar->end) + return -EINVAL; + + damon_for_each_target(t, c) { + id = t->id; + if (targetid_is_pid(c)) + id = (unsigned long)pid_vnr((struct pid *)id); + if (id == target_id) { + r = damon_new_region(ar->start, ar->end); + if (!r) + return -ENOMEM; + damon_add_region(r, t); + if (damon_nr_regions(t) > 1) { + prev = damon_prev_region(r); + if (prev->ar.end > r->ar.start) { + damon_destroy_region(r, t); + return -EINVAL; + } + } + rc = 0; + } + } + return rc; +} + +static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len) +{ + struct damon_target *t; + struct damon_region *r, *next; + int pos = 0, parsed, ret; + unsigned long target_id; + struct damon_addr_range ar; + int err; + + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + + while (pos < len) { + ret = sscanf(&str[pos], "%lu %lu %lu%n", + &target_id, &ar.start, &ar.end, &parsed); + if (ret != 3) + break; + err = add_init_region(c, target_id, &ar); + if (err) + goto fail; + pos += parsed; + } + + return 0; + +fail: + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + return err; +} + +static ssize_t dbgfs_init_regions_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t ret = count; + int err; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + err = set_init_regions(ctx, kbuf, ret); + if (err) + ret = err; + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); + kfree(kbuf); + return ret; +} + +static ssize_t dbgfs_kdamond_pid_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) + len = scnprintf(kbuf, count, "%d\n", ctx->kdamond->pid); + else + len = scnprintf(kbuf, count, "none\n"); + mutex_unlock(&ctx->kdamond_lock); + if (!len) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static int damon_dbgfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return nonseekable_open(inode, file); +} + +static const struct file_operations attrs_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_attrs_read, + .write = dbgfs_attrs_write, +}; + +static const struct file_operations schemes_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_schemes_read, + .write = dbgfs_schemes_write, +}; + +static const struct file_operations target_ids_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_target_ids_read, + .write = dbgfs_target_ids_write, +}; + +static const struct file_operations init_regions_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_init_regions_read, + .write = dbgfs_init_regions_write, +}; + +static const struct file_operations kdamond_pid_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_kdamond_pid_read, +}; + +static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx) +{ + const char * const file_names[] = {"attrs", "schemes", "target_ids", + "init_regions", "kdamond_pid"}; + const struct file_operations *fops[] = {&attrs_fops, &schemes_fops, + &target_ids_fops, &init_regions_fops, &kdamond_pid_fops}; + int i; + + for (i = 0; i < ARRAY_SIZE(file_names); i++) + debugfs_create_file(file_names[i], 0600, dir, ctx, fops[i]); +} + +static void dbgfs_before_terminate(struct damon_ctx *ctx) +{ + struct damon_target *t, *next; + + if (!targetid_is_pid(ctx)) + return; + + mutex_lock(&ctx->kdamond_lock); + damon_for_each_target_safe(t, next, ctx) { + put_pid((struct pid *)t->id); + damon_destroy_target(t); + } + mutex_unlock(&ctx->kdamond_lock); +} + +static struct damon_ctx *dbgfs_new_ctx(void) +{ + struct damon_ctx *ctx; + + ctx = damon_new_ctx(); + if (!ctx) + return NULL; + + damon_va_set_primitives(ctx); + ctx->callback.before_terminate = dbgfs_before_terminate; + return ctx; +} + +static void dbgfs_destroy_ctx(struct damon_ctx *ctx) +{ + damon_destroy_ctx(ctx); +} + +/* + * Make a context of @name and create a debugfs directory for it. + * + * This function should be called while holding damon_dbgfs_lock. + * + * Returns 0 on success, negative error code otherwise. + */ +static int dbgfs_mk_context(char *name) +{ + struct dentry *root, **new_dirs, *new_dir; + struct damon_ctx **new_ctxs, *new_ctx; + + if (damon_nr_running_ctxs()) + return -EBUSY; + + new_ctxs = krealloc(dbgfs_ctxs, sizeof(*dbgfs_ctxs) * + (dbgfs_nr_ctxs + 1), GFP_KERNEL); + if (!new_ctxs) + return -ENOMEM; + dbgfs_ctxs = new_ctxs; + + new_dirs = krealloc(dbgfs_dirs, sizeof(*dbgfs_dirs) * + (dbgfs_nr_ctxs + 1), GFP_KERNEL); + if (!new_dirs) + return -ENOMEM; + dbgfs_dirs = new_dirs; + + root = dbgfs_dirs[0]; + if (!root) + return -ENOENT; + + new_dir = debugfs_create_dir(name, root); + dbgfs_dirs[dbgfs_nr_ctxs] = new_dir; + + new_ctx = dbgfs_new_ctx(); + if (!new_ctx) { + debugfs_remove(new_dir); + dbgfs_dirs[dbgfs_nr_ctxs] = NULL; + return -ENOMEM; + } + + dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx; + dbgfs_fill_ctx_dir(dbgfs_dirs[dbgfs_nr_ctxs], + dbgfs_ctxs[dbgfs_nr_ctxs]); + dbgfs_nr_ctxs++; + + return 0; +} + +static ssize_t dbgfs_mk_context_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + char *ctx_name; + ssize_t ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + ctx_name = kmalloc(count + 1, GFP_KERNEL); + if (!ctx_name) { + kfree(kbuf); + return -ENOMEM; + } + + /* Trim white space */ + if (sscanf(kbuf, "%s", ctx_name) != 1) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&damon_dbgfs_lock); + ret = dbgfs_mk_context(ctx_name); + if (!ret) + ret = count; + mutex_unlock(&damon_dbgfs_lock); + +out: + kfree(kbuf); + kfree(ctx_name); + return ret; +} + +/* + * Remove a context of @name and its debugfs directory. + * + * This function should be called while holding damon_dbgfs_lock. + * + * Return 0 on success, negative error code otherwise. + */ +static int dbgfs_rm_context(char *name) +{ + struct dentry *root, *dir, **new_dirs; + struct damon_ctx **new_ctxs; + int i, j; + + if (damon_nr_running_ctxs()) + return -EBUSY; + + root = dbgfs_dirs[0]; + if (!root) + return -ENOENT; + + dir = debugfs_lookup(name, root); + if (!dir) + return -ENOENT; + + new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs), + GFP_KERNEL); + if (!new_dirs) + return -ENOMEM; + + new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs), + GFP_KERNEL); + if (!new_ctxs) { + kfree(new_dirs); + return -ENOMEM; + } + + for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) { + if (dbgfs_dirs[i] == dir) { + debugfs_remove(dbgfs_dirs[i]); + dbgfs_destroy_ctx(dbgfs_ctxs[i]); + continue; + } + new_dirs[j] = dbgfs_dirs[i]; + new_ctxs[j++] = dbgfs_ctxs[i]; + } + + kfree(dbgfs_dirs); + kfree(dbgfs_ctxs); + + dbgfs_dirs = new_dirs; + dbgfs_ctxs = new_ctxs; + dbgfs_nr_ctxs--; + + return 0; +} + +static ssize_t dbgfs_rm_context_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + ssize_t ret; + char *ctx_name; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + ctx_name = kmalloc(count + 1, GFP_KERNEL); + if (!ctx_name) { + kfree(kbuf); + return -ENOMEM; + } + + /* Trim white space */ + if (sscanf(kbuf, "%s", ctx_name) != 1) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&damon_dbgfs_lock); + ret = dbgfs_rm_context(ctx_name); + if (!ret) + ret = count; + mutex_unlock(&damon_dbgfs_lock); + +out: + kfree(kbuf); + kfree(ctx_name); + return ret; +} + +static ssize_t dbgfs_monitor_on_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + char monitor_on_buf[5]; + bool monitor_on = damon_nr_running_ctxs() != 0; + int len; + + len = scnprintf(monitor_on_buf, 5, monitor_on ? "on\n" : "off\n"); + + return simple_read_from_buffer(buf, count, ppos, monitor_on_buf, len); +} + +static ssize_t dbgfs_monitor_on_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + ssize_t ret; + char *kbuf; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + /* Remove white space */ + if (sscanf(kbuf, "%s", kbuf) != 1) { + kfree(kbuf); + return -EINVAL; + } + + mutex_lock(&damon_dbgfs_lock); + if (!strncmp(kbuf, "on", count)) { + int i; + + for (i = 0; i < dbgfs_nr_ctxs; i++) { + if (damon_targets_empty(dbgfs_ctxs[i])) { + kfree(kbuf); + mutex_unlock(&damon_dbgfs_lock); + return -EINVAL; + } + } + ret = damon_start(dbgfs_ctxs, dbgfs_nr_ctxs); + } else if (!strncmp(kbuf, "off", count)) { + ret = damon_stop(dbgfs_ctxs, dbgfs_nr_ctxs); + } else { + ret = -EINVAL; + } + mutex_unlock(&damon_dbgfs_lock); + + if (!ret) + ret = count; + kfree(kbuf); + return ret; +} + +static const struct file_operations mk_contexts_fops = { + .write = dbgfs_mk_context_write, +}; + +static const struct file_operations rm_contexts_fops = { + .write = dbgfs_rm_context_write, +}; + +static const struct file_operations monitor_on_fops = { + .read = dbgfs_monitor_on_read, + .write = dbgfs_monitor_on_write, +}; + +static int __init __damon_dbgfs_init(void) +{ + struct dentry *dbgfs_root; + const char * const file_names[] = {"mk_contexts", "rm_contexts", + "monitor_on"}; + const struct file_operations *fops[] = {&mk_contexts_fops, + &rm_contexts_fops, &monitor_on_fops}; + int i; + + dbgfs_root = debugfs_create_dir("damon", NULL); + + for (i = 0; i < ARRAY_SIZE(file_names); i++) + debugfs_create_file(file_names[i], 0600, dbgfs_root, NULL, + fops[i]); + dbgfs_fill_ctx_dir(dbgfs_root, dbgfs_ctxs[0]); + + dbgfs_dirs = kmalloc_array(1, sizeof(dbgfs_root), GFP_KERNEL); + if (!dbgfs_dirs) { + debugfs_remove(dbgfs_root); + return -ENOMEM; + } + dbgfs_dirs[0] = dbgfs_root; + + return 0; +} + +/* + * Functions for the initialization + */ + +static int __init damon_dbgfs_init(void) +{ + int rc = -ENOMEM; + + mutex_lock(&damon_dbgfs_lock); + dbgfs_ctxs = kmalloc(sizeof(*dbgfs_ctxs), GFP_KERNEL); + if (!dbgfs_ctxs) + goto out; + dbgfs_ctxs[0] = dbgfs_new_ctx(); + if (!dbgfs_ctxs[0]) { + kfree(dbgfs_ctxs); + goto out; + } + dbgfs_nr_ctxs = 1; + + rc = __damon_dbgfs_init(); + if (rc) { + kfree(dbgfs_ctxs[0]); + kfree(dbgfs_ctxs); + pr_err("%s: dbgfs init failed\n", __func__); + } + +out: + mutex_unlock(&damon_dbgfs_lock); + return rc; +} + +module_init(damon_dbgfs_init); + +#include "dbgfs-test.h" diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c new file mode 100644 index 0000000000000..5e8244f65a1a2 --- /dev/null +++ b/mm/damon/paddr.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Primitives for The Physical Address Space + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-pa: " fmt + +#include +#include +#include +#include +#include + +#include "../internal.h" +#include "prmtv-common.h" + +static bool __damon_pa_mkold(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) + damon_ptep_mkold(pvmw.pte, vma->vm_mm, addr); + else + damon_pmdp_mkold(pvmw.pmd, vma->vm_mm, addr); + } + return true; +} + +static void damon_pa_mkold(unsigned long paddr) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct rmap_walk_control rwc = { + .rmap_one = __damon_pa_mkold, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return; + + if (!page_mapped(page) || !page_rmapping(page)) { + set_page_idle(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) + goto out; + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + +out: + put_page(page); +} + +static void __damon_pa_prepare_access_check(struct damon_ctx *ctx, + struct damon_region *r) +{ + r->sampling_addr = damon_rand(r->ar.start, r->ar.end); + + damon_pa_mkold(r->sampling_addr); +} + +static void damon_pa_prepare_access_checks(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + __damon_pa_prepare_access_check(ctx, r); + } +} + +struct damon_pa_access_chk_result { + unsigned long page_sz; + bool accessed; +}; + +static bool __damon_pa_young(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct damon_pa_access_chk_result *result = arg; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + result->accessed = false; + result->page_sz = PAGE_SIZE; + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) { + result->accessed = pte_young(*pvmw.pte) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + } else { +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + result->accessed = pmd_young(*pvmw.pmd) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + result->page_sz = ((1UL) << HPAGE_PMD_SHIFT); +#else + WARN_ON_ONCE(1); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + } + if (result->accessed) { + page_vma_mapped_walk_done(&pvmw); + break; + } + } + + /* If accessed, stop walking */ + return !result->accessed; +} + +static bool damon_pa_young(unsigned long paddr, unsigned long *page_sz) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct damon_pa_access_chk_result result = { + .page_sz = PAGE_SIZE, + .accessed = false, + }; + struct rmap_walk_control rwc = { + .arg = &result, + .rmap_one = __damon_pa_young, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return false; + + if (!page_mapped(page) || !page_rmapping(page)) { + if (page_is_idle(page)) + result.accessed = false; + else + result.accessed = true; + put_page(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) { + put_page(page); + return NULL; + } + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + put_page(page); + +out: + *page_sz = result.page_sz; + return result.accessed; +} + +static void __damon_pa_check_access(struct damon_ctx *ctx, + struct damon_region *r) +{ + static unsigned long last_addr; + static unsigned long last_page_sz = PAGE_SIZE; + static bool last_accessed; + + /* If the region is in the last checked page, reuse the result */ + if (ALIGN_DOWN(last_addr, last_page_sz) == + ALIGN_DOWN(r->sampling_addr, last_page_sz)) { + if (last_accessed) + r->nr_accesses++; + return; + } + + last_accessed = damon_pa_young(r->sampling_addr, &last_page_sz); + if (last_accessed) + r->nr_accesses++; + + last_addr = r->sampling_addr; +} + +static unsigned int damon_pa_check_accesses(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned int max_nr_accesses = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) { + __damon_pa_check_access(ctx, r); + max_nr_accesses = max(r->nr_accesses, max_nr_accesses); + } + } + + return max_nr_accesses; +} + +bool damon_pa_target_valid(void *t) +{ + return true; +} + +static unsigned long damon_pa_apply_scheme(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + unsigned long addr, applied; + LIST_HEAD(page_list); + + if (scheme->action != DAMOS_PAGEOUT) + return 0; + + for (addr = r->ar.start; addr < r->ar.end; addr += PAGE_SIZE) { + struct page *page = damon_get_page(PHYS_PFN(addr)); + + if (!page) + continue; + + ClearPageReferenced(page); + test_and_clear_page_young(page); + if (isolate_lru_page(page)) { + put_page(page); + continue; + } + if (PageUnevictable(page)) { + putback_lru_page(page); + } else { + list_add(&page->lru, &page_list); + put_page(page); + } + } + applied = reclaim_pages(&page_list); + cond_resched(); + return applied * PAGE_SIZE; +} + +static int damon_pa_scheme_score(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + switch (scheme->action) { + case DAMOS_PAGEOUT: + return damon_pageout_score(context, r, scheme); + default: + break; + } + + return DAMOS_MAX_SCORE; +} + +void damon_pa_set_primitives(struct damon_ctx *ctx) +{ + ctx->primitive.init = NULL; + ctx->primitive.update = NULL; + ctx->primitive.prepare_access_checks = damon_pa_prepare_access_checks; + ctx->primitive.check_accesses = damon_pa_check_accesses; + ctx->primitive.reset_aggregated = NULL; + ctx->primitive.target_valid = damon_pa_target_valid; + ctx->primitive.cleanup = NULL; + ctx->primitive.apply_scheme = damon_pa_apply_scheme; + ctx->primitive.get_scheme_score = damon_pa_scheme_score; +} diff --git a/mm/damon/prmtv-common.c b/mm/damon/prmtv-common.c new file mode 100644 index 0000000000000..92a04f5831d6b --- /dev/null +++ b/mm/damon/prmtv-common.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common Primitives for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include +#include +#include +#include + +#include "prmtv-common.h" + +/* + * Get an online page for a pfn if it's in the LRU list. Otherwise, returns + * NULL. + * + * The body of this function is stolen from the 'page_idle_get_page()'. We + * steal rather than reuse it because the code is quite simple. + */ +struct page *damon_get_page(unsigned long pfn) +{ + struct page *page = pfn_to_online_page(pfn); + + if (!page || !PageLRU(page) || !get_page_unless_zero(page)) + return NULL; + + if (unlikely(!PageLRU(page))) { + put_page(page); + page = NULL; + } + return page; +} + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr) +{ + bool referenced = false; + struct page *page = damon_get_page(pte_pfn(*pte)); + + if (!page) + return; + + if (pte_young(*pte)) { + referenced = true; + *pte = pte_mkold(*pte); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, addr + PAGE_SIZE)) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +} + +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + bool referenced = false; + struct page *page = damon_get_page(pmd_pfn(*pmd)); + + if (!page) + return; + + if (pmd_young(*pmd)) { + referenced = true; + *pmd = pmd_mkold(*pmd); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, + addr + ((1UL) << HPAGE_PMD_SHIFT))) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +} + +#define DAMON_MAX_SUBSCORE (100) +#define DAMON_MAX_AGE_IN_LOG (32) + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s) +{ + unsigned int max_nr_accesses; + int freq_subscore; + unsigned int age_in_sec; + int age_in_log, age_subscore; + unsigned int freq_weight = s->quota.weight_nr_accesses; + unsigned int age_weight = s->quota.weight_age; + int hotness; + + max_nr_accesses = c->aggr_interval / c->sample_interval; + freq_subscore = r->nr_accesses * DAMON_MAX_SUBSCORE / max_nr_accesses; + + age_in_sec = (unsigned long)r->age * c->aggr_interval / 1000000; + for (age_in_log = 0; age_in_log < DAMON_MAX_AGE_IN_LOG && age_in_sec; + age_in_log++, age_in_sec >>= 1) + ; + + /* If frequency is 0, higher age means it's colder */ + if (freq_subscore == 0) + age_in_log *= -1; + + /* + * Now age_in_log is in [-DAMON_MAX_AGE_IN_LOG, DAMON_MAX_AGE_IN_LOG]. + * Scale it to be in [0, 100] and set it as age subscore. + */ + age_in_log += DAMON_MAX_AGE_IN_LOG; + age_subscore = age_in_log * DAMON_MAX_SUBSCORE / + DAMON_MAX_AGE_IN_LOG / 2; + + hotness = (freq_weight * freq_subscore + age_weight * age_subscore); + if (freq_weight + age_weight) + hotness /= freq_weight + age_weight; + /* + * Transform it to fit in [0, DAMOS_MAX_SCORE] + */ + hotness = hotness * DAMOS_MAX_SCORE / DAMON_MAX_SUBSCORE; + + /* Return coldness of the region */ + return DAMOS_MAX_SCORE - hotness; +} diff --git a/mm/damon/prmtv-common.h b/mm/damon/prmtv-common.h new file mode 100644 index 0000000000000..e790cb5f8fe05 --- /dev/null +++ b/mm/damon/prmtv-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common Primitives for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include + +struct page *damon_get_page(unsigned long pfn); + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr); +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr); + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s); diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c new file mode 100644 index 0000000000000..183d4f3b4fde7 --- /dev/null +++ b/mm/damon/reclaim.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON-based page reclamation + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-reclaim: " fmt + +#include +#include +#include +#include +#include + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "damon_reclaim." + +/* + * Enable or disable DAMON_RECLAIM. + * + * You can enable DAMON_RCLAIM by setting the value of this parameter as ``Y``. + * Setting it as ``N`` disables DAMON_RECLAIM. Note that DAMON_RECLAIM could + * do no real monitoring and reclamation due to the watermarks-based activation + * condition. Refer to below descriptions for the watermarks parameter for + * this. + */ +static bool enabled __read_mostly; + +/* + * Time threshold for cold memory regions identification in microseconds. + * + * If a memory region is not accessed for this or longer time, DAMON_RECLAIM + * identifies the region as cold, and reclaims. 120 seconds by default. + */ +static unsigned long min_age __read_mostly = 120000000; +module_param(min_age, ulong, 0600); + +/* + * Limit of time for trying the reclamation in milliseconds. + * + * DAMON_RECLAIM tries to use only up to this time within a time window + * (quota_reset_interval_ms) for trying reclamation of cold pages. This can be + * used for limiting CPU consumption of DAMON_RECLAIM. If the value is zero, + * the limit is disabled. + * + * 10 ms by default. + */ +static unsigned long quota_ms __read_mostly = 10; +module_param(quota_ms, ulong, 0600); + +/* + * Limit of size of memory for the reclamation in bytes. + * + * DAMON_RECLAIM charges amount of memory which it tried to reclaim within a + * time window (quota_reset_interval_ms) and makes no more than this limit is + * tried. This can be used for limiting consumption of CPU and IO. If this + * value is zero, the limit is disabled. + * + * 128 MiB by default. + */ +static unsigned long quota_sz __read_mostly = 128 * 1024 * 1024; +module_param(quota_sz, ulong, 0600); + +/* + * The time/size quota charge reset interval in milliseconds. + * + * The charge reset interval for the quota of time (quota_ms) and size + * (quota_sz). That is, DAMON_RECLAIM does not try reclamation for more than + * quota_ms milliseconds or quota_sz bytes within quota_reset_interval_ms + * milliseconds. + * + * 1 second by default. + */ +static unsigned long quota_reset_interval_ms __read_mostly = 1000; +module_param(quota_reset_interval_ms, ulong, 0600); + +/* + * The watermarks check time interval in microseconds. + * + * Minimal time to wait before checking the watermarks, when DAMON_RECLAIM is + * enabled but inactive due to its watermarks rule. 5 seconds by default. + */ +static unsigned long wmarks_interval __read_mostly = 5000000; +module_param(wmarks_interval, ulong, 0600); + +/* + * Free memory rate (per thousand) for the high watermark. + * + * If free memory of the system in bytes per thousand bytes is higher than + * this, DAMON_RECLAIM becomes inactive, so it does nothing but periodically + * checks the watermarks. 500 (50%) by default. + */ +static unsigned long wmarks_high __read_mostly = 500; +module_param(wmarks_high, ulong, 0600); + +/* + * Free memory rate (per thousand) for the middle watermark. + * + * If free memory of the system in bytes per thousand bytes is between this and + * the low watermark, DAMON_RECLAIM becomes active, so starts the monitoring + * and the reclaiming. 400 (40%) by default. + */ +static unsigned long wmarks_mid __read_mostly = 400; +module_param(wmarks_mid, ulong, 0600); + +/* + * Free memory rate (per thousand) for the low watermark. + * + * If free memory of the system in bytes per thousand bytes is lower than this, + * DAMON_RECLAIM becomes inactive, so it does nothing but periodically checks + * the watermarks. In the case, the system falls back to the LRU-based page + * granularity reclamation logic. 200 (20%) by default. + */ +static unsigned long wmarks_low __read_mostly = 200; +module_param(wmarks_low, ulong, 0600); + +/* + * Sampling interval for the monitoring in microseconds. + * + * The sampling interval of DAMON for the cold memory monitoring. Please refer + * to the DAMON documentation for more detail. 5 ms by default. + */ +static unsigned long sample_interval __read_mostly = 5000; +module_param(sample_interval, ulong, 0600); + +/* + * Aggregation interval for the monitoring in microseconds. + * + * The aggregation interval of DAMON for the cold memory monitoring. Please + * refer to the DAMON documentation for more detail. 100 ms by default. + */ +static unsigned long aggr_interval __read_mostly = 100000; +module_param(aggr_interval, ulong, 0600); + +/* + * Minimum number of monitoring regions. + * + * The minimal number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set lower-bound of the monitoring quality. + * But, setting this too high could result in increased monitoring overhead. + * Please refer to the DAMON documentation for more detail. 10 by default. + */ +static unsigned long min_nr_regions __read_mostly = 10; +module_param(min_nr_regions, ulong, 0600); + +/* + * Maximum number of monitoring regions. + * + * The maximum number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set upper-bound of the monitoring overhead. + * However, setting this too low could result in bad monitoring quality. + * Please refer to the DAMON documentation for more detail. 1000 by default. + */ +static unsigned long max_nr_regions __read_mostly = 1000; +module_param(max_nr_regions, ulong, 0600); + +/* + * Start of the target memory region in physical address. + * + * The start physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_start __read_mostly; +module_param(monitor_region_start, ulong, 0600); + +/* + * End of the target memory region in physical address. + * + * The end physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_end __read_mostly; +module_param(monitor_region_end, ulong, 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); + +/* + * Number of memory regions that tried to be reclaimed. + */ +static unsigned long nr_reclaim_tried_regions __read_mostly; +module_param(nr_reclaim_tried_regions, ulong, 0400); + +/* + * Total bytes of memory regions that tried to be reclaimed. + */ +static unsigned long bytes_reclaim_tried_regions __read_mostly; +module_param(bytes_reclaim_tried_regions, ulong, 0400); + +/* + * Number of memory regions that successfully be reclaimed. + */ +static unsigned long nr_reclaimed_regions __read_mostly; +module_param(nr_reclaimed_regions, ulong, 0400); + +/* + * Total bytes of memory regions that successfully be reclaimed. + */ +static unsigned long bytes_reclaimed_regions __read_mostly; +module_param(bytes_reclaimed_regions, ulong, 0400); + +/* + * Number of times that the time/space quota limits have exceeded + */ +static unsigned long nr_quota_exceeds __read_mostly; +module_param(nr_quota_exceeds, ulong, 0400); + +static struct damon_ctx *ctx; +static struct damon_target *target; + +struct damon_reclaim_ram_walk_arg { + unsigned long start; + unsigned long end; +}; + +static int walk_system_ram(struct resource *res, void *arg) +{ + struct damon_reclaim_ram_walk_arg *a = arg; + + if (a->end - a->start < res->end - res->start) { + a->start = res->start; + a->end = res->end; + } + return 0; +} + +/* + * Find biggest 'System RAM' resource and store its start and end address in + * @start and @end, respectively. If no System RAM is found, returns false. + */ +static bool get_monitoring_region(unsigned long *start, unsigned long *end) +{ + struct damon_reclaim_ram_walk_arg arg = {}; + + walk_system_ram_res(0, ULONG_MAX, &arg, walk_system_ram); + if (arg.end <= arg.start) + return false; + + *start = arg.start; + *end = arg.end; + return true; +} + +static struct damos *damon_reclaim_new_scheme(void) +{ + struct damos_watermarks wmarks = { + .metric = DAMOS_WMARK_FREE_MEM_RATE, + .interval = wmarks_interval, + .high = wmarks_high, + .mid = wmarks_mid, + .low = wmarks_low, + }; + struct damos_quota quota = { + /* + * Do not try reclamation for more than quota_ms milliseconds + * or quota_sz bytes within quota_reset_interval_ms. + */ + .ms = quota_ms, + .sz = quota_sz, + .reset_interval = quota_reset_interval_ms, + /* Within the quota, page out older regions first. */ + .weight_sz = 0, + .weight_nr_accesses = 0, + .weight_age = 1 + }; + struct damos *scheme = damon_new_scheme( + /* Find regions having PAGE_SIZE or larger size */ + PAGE_SIZE, ULONG_MAX, + /* and not accessed at all */ + 0, 0, + /* for min_age or more micro-seconds, and */ + min_age / aggr_interval, UINT_MAX, + /* page out those, as soon as found */ + DAMOS_PAGEOUT, + /* under the quota. */ + "a, + /* (De)activate this according to the watermarks. */ + &wmarks); + + return scheme; +} + +static int damon_reclaim_turn(bool on) +{ + struct damon_region *region; + struct damos *scheme; + int err; + + if (!on) { + err = damon_stop(&ctx, 1); + if (!err) + kdamond_pid = -1; + return err; + } + + err = damon_set_attrs(ctx, sample_interval, aggr_interval, 0, + min_nr_regions, max_nr_regions); + if (err) + return err; + + if (monitor_region_start > monitor_region_end) + return -EINVAL; + if (!monitor_region_start && !monitor_region_end && + !get_monitoring_region(&monitor_region_start, + &monitor_region_end)) + return -EINVAL; + /* DAMON will free this on its own when finish monitoring */ + region = damon_new_region(monitor_region_start, monitor_region_end); + if (!region) + return -ENOMEM; + damon_add_region(region, target); + + /* Will be freed by 'damon_set_schemes()' below */ + scheme = damon_reclaim_new_scheme(); + if (!scheme) { + err = -ENOMEM; + goto free_region_out; + } + err = damon_set_schemes(ctx, &scheme, 1); + if (err) + goto free_scheme_out; + + err = damon_start(&ctx, 1); + if (!err) { + kdamond_pid = ctx->kdamond->pid; + return 0; + } + +free_scheme_out: + damon_destroy_scheme(scheme); +free_region_out: + damon_destroy_region(region, target); + return err; +} + +#define ENABLE_CHECK_INTERVAL_MS 1000 +static struct delayed_work damon_reclaim_timer; +static void damon_reclaim_timer_fn(struct work_struct *work) +{ + static bool last_enabled; + bool now_enabled; + + now_enabled = enabled; + if (last_enabled != now_enabled) { + if (!damon_reclaim_turn(now_enabled)) + last_enabled = now_enabled; + else + enabled = last_enabled; + } + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, + msecs_to_jiffies(ENABLE_CHECK_INTERVAL_MS)); +} +static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn); + +static int enabled_store(const char *val, + const struct kernel_param *kp) +{ + int rc = param_set_bool(val, kp); + + if (rc < 0) + return rc; + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, 0); + + return 0; +} + +static const struct kernel_param_ops enabled_param_ops = { + .set = enabled_store, + .get = param_get_bool, +}; + +module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); +MODULE_PARM_DESC(enabled, + "Enable or disable DAMON_RECLAIM (default: disabled)"); + +static int damon_reclaim_after_aggregation(struct damon_ctx *c) +{ + struct damos *s; + + /* update the stats parameter */ + damon_for_each_scheme(s, c) { + nr_reclaim_tried_regions = s->stat.nr_tried; + bytes_reclaim_tried_regions = s->stat.sz_tried; + nr_reclaimed_regions = s->stat.nr_applied; + bytes_reclaimed_regions = s->stat.sz_applied; + nr_quota_exceeds = s->stat.qt_exceeds; + } + return 0; +} + +static int __init damon_reclaim_init(void) +{ + ctx = damon_new_ctx(); + if (!ctx) + return -ENOMEM; + + damon_pa_set_primitives(ctx); + ctx->callback.after_aggregation = damon_reclaim_after_aggregation; + + /* 4242 means nothing but fun */ + target = damon_new_target(4242); + if (!target) { + damon_destroy_ctx(ctx); + return -ENOMEM; + } + damon_add_target(ctx, target); + + schedule_delayed_work(&damon_reclaim_timer, 0); + return 0; +} + +module_init(damon_reclaim_init); diff --git a/mm/damon/vaddr-test.h b/mm/damon/vaddr-test.h new file mode 100644 index 0000000000000..6a1b9272ea123 --- /dev/null +++ b/mm/damon/vaddr-test.h @@ -0,0 +1,324 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Data Access Monitor Unit Tests + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST + +#ifndef _DAMON_VADDR_TEST_H +#define _DAMON_VADDR_TEST_H + +#include + +static void __link_vmas(struct vm_area_struct *vmas, ssize_t nr_vmas) +{ + int i, j; + unsigned long largest_gap, gap; + + if (!nr_vmas) + return; + + for (i = 0; i < nr_vmas - 1; i++) { + vmas[i].vm_next = &vmas[i + 1]; + + vmas[i].vm_rb.rb_left = NULL; + vmas[i].vm_rb.rb_right = &vmas[i + 1].vm_rb; + + largest_gap = 0; + for (j = i; j < nr_vmas; j++) { + if (j == 0) + continue; + gap = vmas[j].vm_start - vmas[j - 1].vm_end; + if (gap > largest_gap) + largest_gap = gap; + } + vmas[i].rb_subtree_gap = largest_gap; + } + vmas[i].vm_next = NULL; + vmas[i].vm_rb.rb_right = NULL; + vmas[i].rb_subtree_gap = 0; +} + +/* + * Test __damon_va_three_regions() function + * + * In case of virtual memory address spaces monitoring, DAMON converts the + * complex and dynamic memory mappings of each target task to three + * discontiguous regions which cover every mapped areas. However, the three + * regions should not include the two biggest unmapped areas in the original + * mapping, because the two biggest areas are normally the areas between 1) + * heap and the mmap()-ed regions, and 2) the mmap()-ed regions and stack. + * Because these two unmapped areas are very huge but obviously never accessed, + * covering the region is just a waste. + * + * '__damon_va_three_regions() receives an address space of a process. It + * first identifies the start of mappings, end of mappings, and the two biggest + * unmapped areas. After that, based on the information, it constructs the + * three regions and returns. For more detail, refer to the comment of + * 'damon_init_regions_of()' function definition in 'mm/damon.c' file. + * + * For example, suppose virtual address ranges of 10-20, 20-25, 200-210, + * 210-220, 300-305, and 307-330 (Other comments represent this mappings in + * more short form: 10-20-25, 200-210-220, 300-305, 307-330) of a process are + * mapped. To cover every mappings, the three regions should start with 10, + * and end with 305. The process also has three unmapped areas, 25-200, + * 220-300, and 305-307. Among those, 25-200 and 220-300 are the biggest two + * unmapped areas, and thus it should be converted to three regions of 10-25, + * 200-220, and 300-330. + */ +static void damon_test_three_regions_in_vmas(struct kunit *test) +{ + struct damon_addr_range regions[3] = {0,}; + /* 10-20-25, 200-210-220, 300-305, 307-330 */ + struct vm_area_struct vmas[] = { + (struct vm_area_struct) {.vm_start = 10, .vm_end = 20}, + (struct vm_area_struct) {.vm_start = 20, .vm_end = 25}, + (struct vm_area_struct) {.vm_start = 200, .vm_end = 210}, + (struct vm_area_struct) {.vm_start = 210, .vm_end = 220}, + (struct vm_area_struct) {.vm_start = 300, .vm_end = 305}, + (struct vm_area_struct) {.vm_start = 307, .vm_end = 330}, + }; + + __link_vmas(vmas, 6); + + __damon_va_three_regions(&vmas[0], regions); + + KUNIT_EXPECT_EQ(test, 10ul, regions[0].start); + KUNIT_EXPECT_EQ(test, 25ul, regions[0].end); + KUNIT_EXPECT_EQ(test, 200ul, regions[1].start); + KUNIT_EXPECT_EQ(test, 220ul, regions[1].end); + KUNIT_EXPECT_EQ(test, 300ul, regions[2].start); + KUNIT_EXPECT_EQ(test, 330ul, regions[2].end); +} + +static struct damon_region *__nth_region_of(struct damon_target *t, int idx) +{ + struct damon_region *r; + unsigned int i = 0; + + damon_for_each_region(r, t) { + if (i++ == idx) + return r; + } + + return NULL; +} + +/* + * Test 'damon_va_apply_three_regions()' + * + * test kunit object + * regions an array containing start/end addresses of current + * monitoring target regions + * nr_regions the number of the addresses in 'regions' + * three_regions The three regions that need to be applied now + * expected start/end addresses of monitoring target regions that + * 'three_regions' are applied + * nr_expected the number of addresses in 'expected' + * + * The memory mapping of the target processes changes dynamically. To follow + * the change, DAMON periodically reads the mappings, simplifies it to the + * three regions, and updates the monitoring target regions to fit in the three + * regions. The update of current target regions is the role of + * 'damon_va_apply_three_regions()'. + * + * This test passes the given target regions and the new three regions that + * need to be applied to the function and check whether it updates the regions + * as expected. + */ +static void damon_do_test_apply_three_regions(struct kunit *test, + unsigned long *regions, int nr_regions, + struct damon_addr_range *three_regions, + unsigned long *expected, int nr_expected) +{ + struct damon_target *t; + struct damon_region *r; + int i; + + t = damon_new_target(42); + for (i = 0; i < nr_regions / 2; i++) { + r = damon_new_region(regions[i * 2], regions[i * 2 + 1]); + damon_add_region(r, t); + } + + damon_va_apply_three_regions(t, three_regions); + + for (i = 0; i < nr_expected / 2; i++) { + r = __nth_region_of(t, i); + KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]); + KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]); + } +} + +/* + * This function test most common case where the three big regions are only + * slightly changed. Target regions should adjust their boundary (10-20-30, + * 50-55, 70-80, 90-100) to fit with the new big regions or remove target + * regions (57-79) that now out of the three regions. + */ +static void damon_test_apply_three_regions1(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 45-55, 73-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 45, .end = 55}, + (struct damon_addr_range){.start = 73, .end = 104} }; + /* 5-20-27, 45-55, 73-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 45, 55, + 73, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test slightly bigger change. Similar to above, but the second big region + * now require two target regions (50-55, 57-59) to be removed. + */ +static void damon_test_apply_three_regions2(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 56-57, 65-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 56, .end = 57}, + (struct damon_addr_range){.start = 65, .end = 104} }; + /* 5-20-27, 56-57, 65-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 56, 57, + 65, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test a big change. The second big region has totally freed and mapped to + * different area (50-59 -> 61-63). The target regions which were in the old + * second big region (50-55-57-59) should be removed and new target region + * covering the second big region (61-63) should be created. + */ +static void damon_test_apply_three_regions3(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 61-63, 65-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 61, .end = 63}, + (struct damon_addr_range){.start = 65, .end = 104} }; + /* 5-20-27, 61-63, 65-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 61, 63, + 65, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test another big change. Both of the second and third big regions (50-59 + * and 70-100) has totally freed and mapped to different area (30-32 and + * 65-68). The target regions which were in the old second and third big + * regions should now be removed and new target regions covering the new second + * and third big regions should be created. + */ +static void damon_test_apply_three_regions4(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-7, 30-32, 65-68 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 7}, + (struct damon_addr_range){.start = 30, .end = 32}, + (struct damon_addr_range){.start = 65, .end = 68} }; + /* expect 5-7, 30-32, 65-68 */ + unsigned long expected[] = {5, 7, 30, 32, 65, 68}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +static void damon_test_split_evenly_fail(struct kunit *test, + unsigned long start, unsigned long end, unsigned int nr_pieces) +{ + struct damon_target *t = damon_new_target(42); + struct damon_region *r = damon_new_region(start, end); + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, + damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL); + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u); + + damon_for_each_region(r, t) { + KUNIT_EXPECT_EQ(test, r->ar.start, start); + KUNIT_EXPECT_EQ(test, r->ar.end, end); + } + + damon_free_target(t); +} + +static void damon_test_split_evenly_succ(struct kunit *test, + unsigned long start, unsigned long end, unsigned int nr_pieces) +{ + struct damon_target *t = damon_new_target(42); + struct damon_region *r = damon_new_region(start, end); + unsigned long expected_width = (end - start) / nr_pieces; + unsigned long i = 0; + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, + damon_va_evenly_split_region(t, r, nr_pieces), 0); + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces); + + damon_for_each_region(r, t) { + if (i == nr_pieces - 1) + break; + KUNIT_EXPECT_EQ(test, + r->ar.start, start + i++ * expected_width); + KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width); + } + KUNIT_EXPECT_EQ(test, r->ar.start, start + i * expected_width); + KUNIT_EXPECT_EQ(test, r->ar.end, end); + damon_free_target(t); +} + +static void damon_test_split_evenly(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5), + -EINVAL); + + damon_test_split_evenly_fail(test, 0, 100, 0); + damon_test_split_evenly_succ(test, 0, 100, 10); + damon_test_split_evenly_succ(test, 5, 59, 5); + damon_test_split_evenly_fail(test, 5, 6, 2); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_test_three_regions_in_vmas), + KUNIT_CASE(damon_test_apply_three_regions1), + KUNIT_CASE(damon_test_apply_three_regions2), + KUNIT_CASE(damon_test_apply_three_regions3), + KUNIT_CASE(damon_test_apply_three_regions4), + KUNIT_CASE(damon_test_split_evenly), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon-primitives", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_VADDR_TEST_H */ + +#endif /* CONFIG_DAMON_VADDR_KUNIT_TEST */ diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c new file mode 100644 index 0000000000000..89b6468da2b9b --- /dev/null +++ b/mm/damon/vaddr.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Primitives for Virtual Address Spaces + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-va: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "prmtv-common.h" + +#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST +#undef DAMON_MIN_REGION +#define DAMON_MIN_REGION 1 +#endif + +/* + * 't->id' should be the pointer to the relevant 'struct pid' having reference + * count. Caller must put the returned task, unless it is NULL. + */ +static inline struct task_struct *damon_get_task_struct(struct damon_target *t) +{ + return get_pid_task((struct pid *)t->id, PIDTYPE_PID); +} + +/* + * Get the mm_struct of the given target + * + * Caller _must_ put the mm_struct after use, unless it is NULL. + * + * Returns the mm_struct of the target on success, NULL on failure + */ +static struct mm_struct *damon_get_mm(struct damon_target *t) +{ + struct task_struct *task; + struct mm_struct *mm; + + task = damon_get_task_struct(t); + if (!task) + return NULL; + + mm = get_task_mm(task); + put_task_struct(task); + return mm; +} + +/* + * Functions for the initial monitoring target regions construction + */ + +/* + * Size-evenly split a region into 'nr_pieces' small regions + * + * Returns 0 on success, or negative error code otherwise. + */ +static int damon_va_evenly_split_region(struct damon_target *t, + struct damon_region *r, unsigned int nr_pieces) +{ + unsigned long sz_orig, sz_piece, orig_end; + struct damon_region *n = NULL, *next; + unsigned long start; + + if (!r || !nr_pieces) + return -EINVAL; + + orig_end = r->ar.end; + sz_orig = r->ar.end - r->ar.start; + sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION); + + if (!sz_piece) + return -EINVAL; + + r->ar.end = r->ar.start + sz_piece; + next = damon_next_region(r); + for (start = r->ar.end; start + sz_piece <= orig_end; + start += sz_piece) { + n = damon_new_region(start, start + sz_piece); + if (!n) + return -ENOMEM; + damon_insert_region(n, r, next, t); + r = n; + } + /* complement last region for possible rounding error */ + if (n) + n->ar.end = orig_end; + + return 0; +} + +static unsigned long sz_range(struct damon_addr_range *r) +{ + return r->end - r->start; +} + +/* + * Find three regions separated by two biggest unmapped regions + * + * vma the head vma of the target address space + * regions an array of three address ranges that results will be saved + * + * This function receives an address space and finds three regions in it which + * separated by the two biggest unmapped regions in the space. Please refer to + * below comments of '__damon_va_init_regions()' function to know why this is + * necessary. + * + * Returns 0 if success, or negative error code otherwise. + */ +static int __damon_va_three_regions(struct vm_area_struct *vma, + struct damon_addr_range regions[3]) +{ + struct damon_addr_range gap = {0}, first_gap = {0}, second_gap = {0}; + struct vm_area_struct *last_vma = NULL; + unsigned long start = 0; + struct rb_root rbroot; + + /* Find two biggest gaps so that first_gap > second_gap > others */ + for (; vma; vma = vma->vm_next) { + if (!last_vma) { + start = vma->vm_start; + goto next; + } + + if (vma->rb_subtree_gap <= sz_range(&second_gap)) { + rbroot.rb_node = &vma->vm_rb; + vma = rb_entry(rb_last(&rbroot), + struct vm_area_struct, vm_rb); + goto next; + } + + gap.start = last_vma->vm_end; + gap.end = vma->vm_start; + if (sz_range(&gap) > sz_range(&second_gap)) { + swap(gap, second_gap); + if (sz_range(&second_gap) > sz_range(&first_gap)) + swap(second_gap, first_gap); + } +next: + last_vma = vma; + } + + if (!sz_range(&second_gap) || !sz_range(&first_gap)) + return -EINVAL; + + /* Sort the two biggest gaps by address */ + if (first_gap.start > second_gap.start) + swap(first_gap, second_gap); + + /* Store the result */ + regions[0].start = ALIGN(start, DAMON_MIN_REGION); + regions[0].end = ALIGN(first_gap.start, DAMON_MIN_REGION); + regions[1].start = ALIGN(first_gap.end, DAMON_MIN_REGION); + regions[1].end = ALIGN(second_gap.start, DAMON_MIN_REGION); + regions[2].start = ALIGN(second_gap.end, DAMON_MIN_REGION); + regions[2].end = ALIGN(last_vma->vm_end, DAMON_MIN_REGION); + + return 0; +} + +/* + * Get the three regions in the given target (task) + * + * Returns 0 on success, negative error code otherwise. + */ +static int damon_va_three_regions(struct damon_target *t, + struct damon_addr_range regions[3]) +{ + struct mm_struct *mm; + int rc; + + mm = damon_get_mm(t); + if (!mm) + return -EINVAL; + + mmap_read_lock(mm); + rc = __damon_va_three_regions(mm->mmap, regions); + mmap_read_unlock(mm); + + mmput(mm); + return rc; +} + +/* + * Initialize the monitoring target regions for the given target (task) + * + * t the given target + * + * Because only a number of small portions of the entire address space + * is actually mapped to the memory and accessed, monitoring the unmapped + * regions is wasteful. That said, because we can deal with small noises, + * tracking every mapping is not strictly required but could even incur a high + * overhead if the mapping frequently changes or the number of mappings is + * high. The adaptive regions adjustment mechanism will further help to deal + * with the noise by simply identifying the unmapped areas as a region that + * has no access. Moreover, applying the real mappings that would have many + * unmapped areas inside will make the adaptive mechanism quite complex. That + * said, too huge unmapped areas inside the monitoring target should be removed + * to not take the time for the adaptive mechanism. + * + * For the reason, we convert the complex mappings to three distinct regions + * that cover every mapped area of the address space. Also the two gaps + * between the three regions are the two biggest unmapped areas in the given + * address space. In detail, this function first identifies the start and the + * end of the mappings and the two biggest unmapped areas of the address space. + * Then, it constructs the three regions as below: + * + * [mappings[0]->start, big_two_unmapped_areas[0]->start) + * [big_two_unmapped_areas[0]->end, big_two_unmapped_areas[1]->start) + * [big_two_unmapped_areas[1]->end, mappings[nr_mappings - 1]->end) + * + * As usual memory map of processes is as below, the gap between the heap and + * the uppermost mmap()-ed region, and the gap between the lowermost mmap()-ed + * region and the stack will be two biggest unmapped regions. Because these + * gaps are exceptionally huge areas in usual address space, excluding these + * two biggest unmapped regions will be sufficient to make a trade-off. + * + * + * + * + * (other mmap()-ed regions and small unmapped regions) + * + * + * + */ +static void __damon_va_init_regions(struct damon_ctx *ctx, + struct damon_target *t) +{ + struct damon_target *ti; + struct damon_region *r; + struct damon_addr_range regions[3]; + unsigned long sz = 0, nr_pieces; + int i, tidx = 0; + + if (damon_va_three_regions(t, regions)) { + damon_for_each_target(ti, ctx) { + if (ti == t) + break; + tidx++; + } + pr_debug("Failed to get three regions of %dth target\n", tidx); + return; + } + + for (i = 0; i < 3; i++) + sz += regions[i].end - regions[i].start; + if (ctx->min_nr_regions) + sz /= ctx->min_nr_regions; + if (sz < DAMON_MIN_REGION) + sz = DAMON_MIN_REGION; + + /* Set the initial three regions of the target */ + for (i = 0; i < 3; i++) { + r = damon_new_region(regions[i].start, regions[i].end); + if (!r) { + pr_err("%d'th init region creation failed\n", i); + return; + } + damon_add_region(r, t); + + nr_pieces = (regions[i].end - regions[i].start) / sz; + damon_va_evenly_split_region(t, r, nr_pieces); + } +} + +/* Initialize '->regions_list' of every target (task) */ +static void damon_va_init(struct damon_ctx *ctx) +{ + struct damon_target *t; + + damon_for_each_target(t, ctx) { + /* the user may set the target regions as they want */ + if (!damon_nr_regions(t)) + __damon_va_init_regions(ctx, t); + } +} + +/* + * Functions for the dynamic monitoring target regions update + */ + +/* + * Check whether a region is intersecting an address range + * + * Returns true if it is. + */ +static bool damon_intersect(struct damon_region *r, + struct damon_addr_range *re) +{ + return !(r->ar.end <= re->start || re->end <= r->ar.start); +} + +/* + * Update damon regions for the three big regions of the given target + * + * t the given target + * bregions the three big regions of the target + */ +static void damon_va_apply_three_regions(struct damon_target *t, + struct damon_addr_range bregions[3]) +{ + struct damon_region *r, *next; + unsigned int i; + + /* Remove regions which are not in the three big regions now */ + damon_for_each_region_safe(r, next, t) { + for (i = 0; i < 3; i++) { + if (damon_intersect(r, &bregions[i])) + break; + } + if (i == 3) + damon_destroy_region(r, t); + } + + /* Adjust intersecting regions to fit with the three big regions */ + for (i = 0; i < 3; i++) { + struct damon_region *first = NULL, *last; + struct damon_region *newr; + struct damon_addr_range *br; + + br = &bregions[i]; + /* Get the first and last regions which intersects with br */ + damon_for_each_region(r, t) { + if (damon_intersect(r, br)) { + if (!first) + first = r; + last = r; + } + if (r->ar.start >= br->end) + break; + } + if (!first) { + /* no damon_region intersects with this big region */ + newr = damon_new_region( + ALIGN_DOWN(br->start, + DAMON_MIN_REGION), + ALIGN(br->end, DAMON_MIN_REGION)); + if (!newr) + continue; + damon_insert_region(newr, damon_prev_region(r), r, t); + } else { + first->ar.start = ALIGN_DOWN(br->start, + DAMON_MIN_REGION); + last->ar.end = ALIGN(br->end, DAMON_MIN_REGION); + } + } +} + +/* + * Update regions for current memory mappings + */ +static void damon_va_update(struct damon_ctx *ctx) +{ + struct damon_addr_range three_regions[3]; + struct damon_target *t; + + damon_for_each_target(t, ctx) { + if (damon_va_three_regions(t, three_regions)) + continue; + damon_va_apply_three_regions(t, three_regions); + } +} + +static int damon_mkold_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pte_t *pte; + spinlock_t *ptl; + + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (pmd_huge(*pmd)) { + damon_pmdp_mkold(pmd, walk->mm, addr); + spin_unlock(ptl); + return 0; + } + spin_unlock(ptl); + } + + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return 0; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + damon_ptep_mkold(pte, walk->mm, addr); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +#ifdef CONFIG_HUGETLB_PAGE +static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long addr) +{ + bool referenced = false; + pte_t entry = huge_ptep_get(pte); + struct page *page = pte_page(entry); + + if (!page) + return; + + get_page(page); + + if (pte_young(entry)) { + referenced = true; + entry = pte_mkold(entry); + huge_ptep_set_access_flags(vma, addr, pte, entry, + vma->vm_flags & VM_WRITE); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, + addr + huge_page_size(hstate_vma(vma)))) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +} + +static int damon_mkold_hugetlb_entry(pte_t *pte, unsigned long hmask, + unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct hstate *h = hstate_vma(walk->vma); + spinlock_t *ptl; + pte_t entry; + + ptl = huge_pte_lock(h, walk->mm, pte); + entry = huge_ptep_get(pte); + if (!pte_present(entry)) + goto out; + + damon_hugetlb_mkold(pte, walk->mm, walk->vma, addr); + +out: + spin_unlock(ptl); + return 0; +} +#else +#define damon_mkold_hugetlb_entry NULL +#endif /* CONFIG_HUGETLB_PAGE */ + +static const struct mm_walk_ops damon_mkold_ops = { + .pmd_entry = damon_mkold_pmd_entry, + .hugetlb_entry = damon_mkold_hugetlb_entry, +}; + +static void damon_va_mkold(struct mm_struct *mm, unsigned long addr) +{ + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_mkold_ops, NULL); + mmap_read_unlock(mm); +} + +/* + * Functions for the access checking of the regions + */ + +static void __damon_va_prepare_access_check(struct damon_ctx *ctx, + struct mm_struct *mm, struct damon_region *r) +{ + r->sampling_addr = damon_rand(r->ar.start, r->ar.end); + + damon_va_mkold(mm, r->sampling_addr); +} + +static void damon_va_prepare_access_checks(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct mm_struct *mm; + struct damon_region *r; + + damon_for_each_target(t, ctx) { + mm = damon_get_mm(t); + if (!mm) + continue; + damon_for_each_region(r, t) + __damon_va_prepare_access_check(ctx, mm, r); + mmput(mm); + } +} + +struct damon_young_walk_private { + unsigned long *page_sz; + bool young; +}; + +static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pte_t *pte; + spinlock_t *ptl; + struct page *page; + struct damon_young_walk_private *priv = walk->private; + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (!pmd_huge(*pmd)) { + spin_unlock(ptl); + goto regular_page; + } + page = damon_get_page(pmd_pfn(*pmd)); + if (!page) + goto huge_out; + if (pmd_young(*pmd) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, + addr)) { + *priv->page_sz = ((1UL) << HPAGE_PMD_SHIFT); + priv->young = true; + } + put_page(page); +huge_out: + spin_unlock(ptl); + return 0; + } + +regular_page: +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return -EINVAL; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + page = damon_get_page(pte_pfn(*pte)); + if (!page) + goto out; + if (pte_young(*pte) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, addr)) { + *priv->page_sz = PAGE_SIZE; + priv->young = true; + } + put_page(page); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +#ifdef CONFIG_HUGETLB_PAGE +static int damon_young_hugetlb_entry(pte_t *pte, unsigned long hmask, + unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct damon_young_walk_private *priv = walk->private; + struct hstate *h = hstate_vma(walk->vma); + struct page *page; + spinlock_t *ptl; + pte_t entry; + + ptl = huge_pte_lock(h, walk->mm, pte); + entry = huge_ptep_get(pte); + if (!pte_present(entry)) + goto out; + + page = pte_page(entry); + if (!page) + goto out; + + get_page(page); + + if (pte_young(entry) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, addr)) { + *priv->page_sz = huge_page_size(h); + priv->young = true; + } + + put_page(page); + +out: + spin_unlock(ptl); + return 0; +} +#else +#define damon_young_hugetlb_entry NULL +#endif /* CONFIG_HUGETLB_PAGE */ + +static const struct mm_walk_ops damon_young_ops = { + .pmd_entry = damon_young_pmd_entry, + .hugetlb_entry = damon_young_hugetlb_entry, +}; + +static bool damon_va_young(struct mm_struct *mm, unsigned long addr, + unsigned long *page_sz) +{ + struct damon_young_walk_private arg = { + .page_sz = page_sz, + .young = false, + }; + + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_young_ops, &arg); + mmap_read_unlock(mm); + return arg.young; +} + +/* + * Check whether the region was accessed after the last preparation + * + * mm 'mm_struct' for the given virtual address space + * r the region to be checked + */ +static void __damon_va_check_access(struct damon_ctx *ctx, + struct mm_struct *mm, struct damon_region *r) +{ + static struct mm_struct *last_mm; + static unsigned long last_addr; + static unsigned long last_page_sz = PAGE_SIZE; + static bool last_accessed; + + /* If the region is in the last checked page, reuse the result */ + if (mm == last_mm && (ALIGN_DOWN(last_addr, last_page_sz) == + ALIGN_DOWN(r->sampling_addr, last_page_sz))) { + if (last_accessed) + r->nr_accesses++; + return; + } + + last_accessed = damon_va_young(mm, r->sampling_addr, &last_page_sz); + if (last_accessed) + r->nr_accesses++; + + last_mm = mm; + last_addr = r->sampling_addr; +} + +static unsigned int damon_va_check_accesses(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct mm_struct *mm; + struct damon_region *r; + unsigned int max_nr_accesses = 0; + + damon_for_each_target(t, ctx) { + mm = damon_get_mm(t); + if (!mm) + continue; + damon_for_each_region(r, t) { + __damon_va_check_access(ctx, mm, r); + max_nr_accesses = max(r->nr_accesses, max_nr_accesses); + } + mmput(mm); + } + + return max_nr_accesses; +} + +/* + * Functions for the target validity check and cleanup + */ + +bool damon_va_target_valid(void *target) +{ + struct damon_target *t = target; + struct task_struct *task; + + task = damon_get_task_struct(t); + if (task) { + put_task_struct(task); + return true; + } + + return false; +} + +#ifndef CONFIG_ADVISE_SYSCALLS +static unsigned long damos_madvise(struct damon_target *target, + struct damon_region *r, int behavior) +{ + return 0; +} +#else +static unsigned long damos_madvise(struct damon_target *target, + struct damon_region *r, int behavior) +{ + struct mm_struct *mm; + unsigned long start = PAGE_ALIGN(r->ar.start); + unsigned long len = PAGE_ALIGN(r->ar.end - r->ar.start); + unsigned long applied; + + mm = damon_get_mm(target); + if (!mm) + return 0; + + applied = do_madvise(mm, start, len, behavior) ? 0 : len; + mmput(mm); + + return applied; +} +#endif /* CONFIG_ADVISE_SYSCALLS */ + +static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + int madv_action; + + switch (scheme->action) { + case DAMOS_WILLNEED: + madv_action = MADV_WILLNEED; + break; + case DAMOS_COLD: + madv_action = MADV_COLD; + break; + case DAMOS_PAGEOUT: + madv_action = MADV_PAGEOUT; + break; + case DAMOS_HUGEPAGE: + madv_action = MADV_HUGEPAGE; + break; + case DAMOS_NOHUGEPAGE: + madv_action = MADV_NOHUGEPAGE; + break; + case DAMOS_STAT: + return 0; + default: + return 0; + } + + return damos_madvise(t, r, madv_action); +} + +static int damon_va_scheme_score(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + + switch (scheme->action) { + case DAMOS_PAGEOUT: + return damon_pageout_score(context, r, scheme); + default: + break; + } + + return DAMOS_MAX_SCORE; +} + +void damon_va_set_primitives(struct damon_ctx *ctx) +{ + ctx->primitive.init = damon_va_init; + ctx->primitive.update = damon_va_update; + ctx->primitive.prepare_access_checks = damon_va_prepare_access_checks; + ctx->primitive.check_accesses = damon_va_check_accesses; + ctx->primitive.reset_aggregated = NULL; + ctx->primitive.target_valid = damon_va_target_valid; + ctx->primitive.cleanup = NULL; + ctx->primitive.apply_scheme = damon_va_apply_scheme; + ctx->primitive.get_scheme_score = damon_va_scheme_score; +} + +#include "vaddr-test.h" diff --git a/mm/debug.c b/mm/debug.c index aa44dea5276f5..061e2eb08981e 100644 --- a/mm/debug.c +++ b/mm/debug.c @@ -192,7 +192,6 @@ void dump_page(struct page *page, const char *reason) { __dump_page(page, reason); dump_page_owner(page); - dump_page_pinner(page); } EXPORT_SYMBOL(dump_page); diff --git a/mm/gup.c b/mm/gup.c index 54b0a694712e2..b831cdecdc947 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -25,6 +25,9 @@ #include "internal.h" +#undef CREATE_TRACE_POINTS +#include + struct follow_page_context { struct dev_pagemap *pgmap; unsigned int page_mask; @@ -116,11 +119,14 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page, int refs, unsigned int flags) { + bool vendor_ret = false; + + trace_android_vh_try_grab_compound_head(page, refs, flags, &vendor_ret); + if (vendor_ret) + return NULL; + if (flags & FOLL_GET) { - struct page *head = try_get_compound_head(page, refs); - if (head) - set_page_pinner(head, compound_order(head)); - return head; + return try_get_compound_head(page, refs); } else if (flags & FOLL_PIN) { int orig_refs = refs; @@ -175,8 +181,6 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags) refs *= GUP_PIN_COUNTING_BIAS; } - if (flags & FOLL_GET) - reset_page_pinner(page, compound_order(page)); put_page_refs(page, refs); } @@ -206,13 +210,7 @@ bool __must_check try_grab_page(struct page *page, unsigned int flags) WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN)); if (flags & FOLL_GET) { - bool ret = try_get_page(page); - - if (ret) { - page = compound_head(page); - set_page_pinner(page, compound_order(page)); - } - return ret; + return try_get_page(page); } else if (flags & FOLL_PIN) { int refs = 1; @@ -255,24 +253,6 @@ void unpin_user_page(struct page *page) } EXPORT_SYMBOL(unpin_user_page); -/* - * put_user_page() - release a page obtained using get_user_pages() or - * follow_page(FOLL_GET) - * @page: pointer to page to be released - * - * Pages that were obtained via get_user_pages()/follow_page(FOLL_GET) must be - * released via put_user_page. - * note: If it's not a page from GUP or follow_page(FOLL_GET), it's harmless. - */ -void put_user_page(struct page *page) -{ - struct page *head = compound_head(page); - - reset_page_pinner(head, compound_order(head)); - put_page(page); -} -EXPORT_SYMBOL(put_user_page); - /** * unpin_user_pages_dirty_lock() - release and optionally dirty gup-pinned pages * @pages: array of pages to be maybe marked dirty, and definitely released. @@ -1760,6 +1740,10 @@ static long __get_user_pages_remote(struct mm_struct *mm, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas, int *locked) { + unsigned int orig_gup_flags = gup_flags; + + trace_android_vh___get_user_pages_remote(locked, &gup_flags, pages); + /* * Parts of FOLL_LONGTERM behavior are incompatible with * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on @@ -1767,16 +1751,24 @@ static long __get_user_pages_remote(struct mm_struct *mm, * callers that do request FOLL_LONGTERM, but do not set locked. So, * allow what we can. */ +retry: if (gup_flags & FOLL_LONGTERM) { + long ret; + if (WARN_ON_ONCE(locked)) return -EINVAL; /* * This will check the vmas (even if our vmas arg is NULL) * and return -ENOTSUPP if DAX isn't allowed in this case: */ - return __gup_longterm_locked(mm, start, nr_pages, pages, + ret = __gup_longterm_locked(mm, start, nr_pages, pages, vmas, gup_flags | FOLL_TOUCH | FOLL_REMOTE); + if (ret < 0 && orig_gup_flags != gup_flags) { + gup_flags = orig_gup_flags; + goto retry; + } else + return ret; } return __get_user_pages_locked(mm, start, nr_pages, pages, vmas, @@ -1895,11 +1887,23 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { + long ret; + unsigned int orig_gup_flags; + if (!is_valid_gup_flags(gup_flags)) return -EINVAL; - return __gup_longterm_locked(current->mm, start, nr_pages, + orig_gup_flags = gup_flags; + trace_android_vh_get_user_pages(&gup_flags, pages); +retry: + ret = __gup_longterm_locked(current->mm, start, nr_pages, pages, vmas, gup_flags | FOLL_TOUCH); + if (ret < 0 && orig_gup_flags != gup_flags) { + gup_flags = orig_gup_flags; + goto retry; + } + + return ret; } EXPORT_SYMBOL(get_user_pages); @@ -2707,6 +2711,7 @@ static int internal_get_user_pages_fast(unsigned long start, /* Slow path: try to get the remaining pages with get_user_pages */ start += nr_pinned << PAGE_SHIFT; pages += nr_pinned; + trace_android_vh_internal_get_user_pages_fast(&gup_flags, pages); ret = __gup_longterm_unlocked(start, nr_pages - nr_pinned, gup_flags, pages); if (ret < 0) { @@ -2932,6 +2937,7 @@ long pin_user_pages(unsigned long start, unsigned long nr_pages, return -EINVAL; gup_flags |= FOLL_PIN; + trace_android_vh_pin_user_pages(&gup_flags, pages); return __gup_longterm_locked(current->mm, start, nr_pages, pages, vmas, gup_flags); } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1eea5787fd639..123f3e0328712 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2402,7 +2402,8 @@ static void __split_huge_page_tail(struct page *head, int tail, #ifdef CONFIG_64BIT (1L << PG_arch_2) | #endif - (1L << PG_dirty))); + (1L << PG_dirty) | + LRU_GEN_MASK | LRU_REFS_MASK)); /* ->mapping in first tail page is compound_mapcount */ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index fad1887e54c05..9e1b6544bfa8e 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -172,12 +172,7 @@ void kasan_init_hw_tags_cpu(void) * Enable async or asymm modes only when explicitly requested * through the command line. */ - if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) - hw_enable_tagging_async(); - else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM) - hw_enable_tagging_asymm(); - else - hw_enable_tagging_sync(); + kasan_enable_tagging(); } /* kasan_init_hw_tags() is called once on boot CPU. */ @@ -341,13 +336,19 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size) #endif -#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) - -void kasan_enable_tagging_sync(void) +void kasan_enable_tagging(void) { - hw_enable_tagging_sync(); + if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) + hw_enable_tagging_async(); + else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM) + hw_enable_tagging_asymm(); + else + hw_enable_tagging_sync(); } -EXPORT_SYMBOL_GPL(kasan_enable_tagging_sync); + +#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) + +EXPORT_SYMBOL_GPL(kasan_enable_tagging); void kasan_force_async_fault(void) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 3fb9a1e847194..e6417aca1ebf0 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -7,6 +7,16 @@ #include #include +#if IS_ENABLED(CONFIG_KUNIT) + +/* Used in KUnit-compatible KASAN tests. */ +struct kunit_kasan_status { + bool report_found; + bool sync_fault; +}; + +#endif + #ifdef CONFIG_KASAN_HW_TAGS #include @@ -339,25 +349,27 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #define hw_set_mem_tag_range(addr, size, tag, init) \ arch_set_mem_tag_range((addr), (size), (tag), (init)) +void kasan_enable_tagging(void); + #else /* CONFIG_KASAN_HW_TAGS */ #define hw_enable_tagging_sync() #define hw_enable_tagging_async() #define hw_enable_tagging_asymm() +static inline void kasan_enable_tagging(void) { } + #endif /* CONFIG_KASAN_HW_TAGS */ #if defined(CONFIG_KASAN_HW_TAGS) && IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) -void kasan_enable_tagging_sync(void); void kasan_force_async_fault(void); -#else /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ +#else /* CONFIG_KASAN_HW_TAGS && CONFIG_KASAN_KUNIT_TEST */ -static inline void kasan_enable_tagging_sync(void) { } static inline void kasan_force_async_fault(void) { } -#endif /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ +#endif /* CONFIG_KASAN_HW_TAGS && CONFIG_KASAN_KUNIT_TEST */ #ifdef CONFIG_KASAN_SW_TAGS u8 kasan_random_tag(void); diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 5f22ddfa2d7a1..98c186f9d9503 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -344,20 +344,21 @@ static bool report_enabled(void) } #if IS_ENABLED(CONFIG_KUNIT) -static void kasan_update_kunit_status(struct kunit *cur_test) +static void kasan_update_kunit_status(struct kunit *cur_test, bool sync) { struct kunit_resource *resource; - struct kunit_kasan_expectation *kasan_data; + struct kunit_kasan_status *status; - resource = kunit_find_named_resource(cur_test, "kasan_data"); + resource = kunit_find_named_resource(cur_test, "kasan_status"); if (!resource) { kunit_set_failure(cur_test); return; } - kasan_data = (struct kunit_kasan_expectation *)resource->data; - WRITE_ONCE(kasan_data->report_found, true); + status = (struct kunit_kasan_status *)resource->data; + WRITE_ONCE(status->report_found, true); + WRITE_ONCE(status->sync_fault, sync); kunit_put_resource(resource); } #endif /* IS_ENABLED(CONFIG_KUNIT) */ @@ -371,7 +372,7 @@ void kasan_report_invalid_free(void *object, unsigned long ip) #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, true); #endif /* IS_ENABLED(CONFIG_KUNIT) */ start_report(&flags); @@ -391,7 +392,7 @@ void kasan_report_async(void) #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, false); #endif /* IS_ENABLED(CONFIG_KUNIT) */ start_report(&flags); @@ -413,7 +414,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write, #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, true); #endif /* IS_ENABLED(CONFIG_KUNIT) */ disable_trace_on_warning(); diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 47fee6d7d0a57..a3438661c777b 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -484,10 +484,11 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, return (void *)start; /* - * Don't tag executable memory. + * Don't tag executable memory with the tag-based mode. * The kernel doesn't tolerate having the PC register tagged. */ - if (!(flags & KASAN_VMALLOC_PROT_NORMAL)) + if (IS_ENABLED(CONFIG_KASAN_SW_TAGS) && + !(flags & KASAN_VMALLOC_PROT_NORMAL)) return (void *)start; start = set_tag(start, kasan_random_tag()); diff --git a/mm/kmemleak.c b/mm/kmemleak.c index b4867ab7b35aa..c8dc0470efa6d 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -795,8 +795,6 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) unsigned long flags; struct kmemleak_object *object; struct kmemleak_scan_area *area = NULL; - unsigned long untagged_ptr; - unsigned long untagged_objp; object = find_and_get_object(ptr, 1); if (!object) { @@ -805,9 +803,6 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) return; } - untagged_ptr = (unsigned long)kasan_reset_tag((void *)ptr); - untagged_objp = (unsigned long)kasan_reset_tag((void *)object->pointer); - if (scan_area_cache) area = kmem_cache_alloc(scan_area_cache, gfp_kmemleak_mask(gfp)); @@ -819,8 +814,8 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) goto out_unlock; } if (size == SIZE_MAX) { - size = untagged_objp + object->size - untagged_ptr; - } else if (untagged_ptr + size > untagged_objp + object->size) { + size = object->pointer + object->size - ptr; + } else if (ptr + size > object->pointer + object->size) { kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); dump_object_info(object); kmem_cache_free(scan_area_cache, area); diff --git a/mm/ksm.c b/mm/ksm.c index e2464c04ede28..25b8362a4f895 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -484,7 +484,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr) NULL); else ret = VM_FAULT_WRITE; - put_user_page(page); + put_page(page); } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); /* * We must loop because handle_mm_fault() may back out if there's @@ -569,7 +569,7 @@ static struct page *get_mergeable_page(struct rmap_item *rmap_item) flush_anon_page(vma, page, addr); flush_dcache_page(page); } else { - put_user_page(page); + put_page(page); out: page = NULL; } @@ -1950,7 +1950,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, * Don't substitute a ksm page for a forked page. */ if (page == tree_page) { - put_user_page(tree_page); + put_page(tree_page); return NULL; } @@ -1958,10 +1958,10 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, parent = *new; if (ret < 0) { - put_user_page(tree_page); + put_page(tree_page); new = &parent->rb_left; } else if (ret > 0) { - put_user_page(tree_page); + put_page(tree_page); new = &parent->rb_right; } else if (!ksm_merge_across_nodes && page_to_nid(tree_page) != nid) { @@ -1970,7 +1970,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, * it will be flushed out and put in the right unstable * tree next time: only merge with it when across_nodes. */ - put_user_page(tree_page); + put_page(tree_page); return NULL; } else { *tree_pagep = tree_page; @@ -2151,7 +2151,7 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) */ split = PageTransCompound(page) && compound_head(page) == compound_head(tree_page); - put_user_page(tree_page); + put_page(tree_page); if (kpage) { /* * The pages were successfully merged: insert new @@ -2320,11 +2320,11 @@ next_mm: &rmap_item->rmap_list; ksm_scan.address += PAGE_SIZE; } else - put_user_page(*page); + put_page(*page); mmap_read_unlock(mm); return rmap_item; } - put_user_page(*page); + put_page(*page); ksm_scan.address += PAGE_SIZE; cond_resched(); } diff --git a/mm/madvise.c b/mm/madvise.c index 2b5b2b3f6cbef..8920a7125389f 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -63,7 +63,7 @@ static int madvise_need_mmap_write(int behavior) } #ifdef CONFIG_ANON_VMA_NAME -static struct anon_vma_name *anon_vma_name_alloc(const char *name) +struct anon_vma_name *anon_vma_name_alloc(const char *name) { struct anon_vma_name *anon_name; size_t count; @@ -79,78 +79,48 @@ static struct anon_vma_name *anon_vma_name_alloc(const char *name) return anon_name; } -static void vma_anon_name_free(struct kref *kref) +void anon_vma_name_free(struct kref *kref) { struct anon_vma_name *anon_name = container_of(kref, struct anon_vma_name, kref); kfree(anon_name); } -static inline bool has_vma_anon_name(struct vm_area_struct *vma) +struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma) { - return !vma->vm_file && vma->anon_name; -} - -const char *vma_anon_name(struct vm_area_struct *vma) -{ - if (!has_vma_anon_name(vma)) - return NULL; - mmap_assert_locked(vma->vm_mm); - return vma->anon_name->name; -} - -void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma) -{ - if (!has_vma_anon_name(orig_vma)) - return; - - kref_get(&orig_vma->anon_name->kref); - new_vma->anon_name = orig_vma->anon_name; -} - -void free_vma_anon_name(struct vm_area_struct *vma) -{ - struct anon_vma_name *anon_name; - - if (!has_vma_anon_name(vma)) - return; + if (vma->vm_file) + return NULL; - anon_name = vma->anon_name; - vma->anon_name = NULL; - kref_put(&anon_name->kref, vma_anon_name_free); + return vma->anon_name; } /* mmap_lock should be write-locked */ -static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) +static int replace_anon_vma_name(struct vm_area_struct *vma, + struct anon_vma_name *anon_name) { - const char *anon_name; + struct anon_vma_name *orig_name = anon_vma_name(vma); - if (!name) { - free_vma_anon_name(vma); + if (!anon_name) { + vma->anon_name = NULL; + anon_vma_name_put(orig_name); return 0; } - anon_name = vma_anon_name(vma); - if (anon_name) { - /* Same name, nothing to do here */ - if (!strcmp(name, anon_name)) - return 0; + if (anon_vma_name_eq(orig_name, anon_name)) + return 0; - free_vma_anon_name(vma); - } - vma->anon_name = anon_vma_name_alloc(name); - if (!vma->anon_name) - return -ENOMEM; + vma->anon_name = anon_vma_name_reuse(anon_name); + anon_vma_name_put(orig_name); return 0; } #else /* CONFIG_ANON_VMA_NAME */ -static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) +static int replace_anon_vma_name(struct vm_area_struct *vma, + struct anon_vma_name *anon_name) { - if (name) + if (anon_name) return -EINVAL; return 0; @@ -159,17 +129,19 @@ static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) /* * Update the vm_flags on region of a vma, splitting it or merging it as * necessary. Must be called with mmap_sem held for writing; + * Caller should ensure anon_name stability by raising its refcount even when + * anon_name belongs to a valid vma because this function might free that vma. */ static int madvise_update_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, unsigned long new_flags, - const char *name) + struct anon_vma_name *anon_name) { struct mm_struct *mm = vma->vm_mm; int error; pgoff_t pgoff; - if (new_flags == vma->vm_flags && is_same_vma_anon_name(vma, name)) { + if (new_flags == vma->vm_flags && anon_vma_name_eq(anon_vma_name(vma), anon_name)) { *prev = vma; return 0; } @@ -177,7 +149,7 @@ static int madvise_update_vma(struct vm_area_struct *vma, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, name); + vma->vm_userfaultfd_ctx, anon_name); if (*prev) { vma = *prev; goto success; @@ -209,7 +181,7 @@ success: WRITE_ONCE(vma->vm_flags, new_flags); vm_write_end(vma); if (!vma->vm_file) { - error = replace_vma_anon_name(vma, name); + error = replace_anon_vma_name(vma, anon_name); if (error) return error; } @@ -923,6 +895,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma, unsigned long behavior) { int error; + struct anon_vma_name *anon_name; unsigned long new_flags = vma->vm_flags; switch (behavior) { @@ -985,8 +958,11 @@ static int madvise_vma_behavior(struct vm_area_struct *vma, break; } + anon_name = anon_vma_name(vma); + anon_vma_name_get(anon_name); error = madvise_update_vma(vma, prev, start, end, new_flags, - vma_anon_name(vma)); + anon_name); + anon_vma_name_put(anon_name); out: /* @@ -1172,7 +1148,7 @@ int madvise_walk_vmas(struct mm_struct *mm, unsigned long start, static int madvise_vma_anon_name(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, - unsigned long name) + unsigned long anon_name) { int error; @@ -1181,7 +1157,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma, return -EBADF; error = madvise_update_vma(vma, prev, start, end, vma->vm_flags, - (const char *)name); + (struct anon_vma_name *)anon_name); /* * madvise() returns EAGAIN if kernel resources, such as @@ -1193,7 +1169,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma, } int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name) + unsigned long len_in, struct anon_vma_name *anon_name) { unsigned long end; unsigned long len; @@ -1213,7 +1189,7 @@ int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, if (end == start) return 0; - return madvise_walk_vmas(mm, start, end, (unsigned long)name, + return madvise_walk_vmas(mm, start, end, (unsigned long)anon_name, madvise_vma_anon_name); } #endif /* CONFIG_ANON_VMA_NAME */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 008e72c2b9805..eed533d29bd77 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2883,6 +2883,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg) * - LRU isolation * - lock_page_memcg() * - exclusive reference + * - mem_cgroup_trylock_pages() */ page->mem_cgroup = memcg; } @@ -5254,6 +5255,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) static void mem_cgroup_free(struct mem_cgroup *memcg) { + lru_gen_exit_memcg(memcg); memcg_wb_domain_exit(memcg); /* * Flush percpu vmstats and vmevents to guarantee the value correctness @@ -5329,6 +5331,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) #endif idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); trace_android_vh_mem_cgroup_alloc(memcg); + lru_gen_init_memcg(memcg); return memcg; fail: mem_cgroup_id_remove(memcg); @@ -6223,6 +6226,29 @@ static void mem_cgroup_move_task(void) } #endif +#ifdef CONFIG_LRU_GEN +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ + struct cgroup_subsys_state *css; + struct task_struct *task = NULL; + + cgroup_taskset_for_each_leader(task, css, tset) + break; + + if (!task) + return; + + task_lock(task); + if (task->mm && task->mm->owner == task) + lru_gen_migrate_mm(task->mm); + task_unlock(task); +} +#else +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Cgroup retains root cgroups across [un]mount cycles making it necessary * to verify whether we're attached to the default hierarchy on each mount @@ -6575,6 +6601,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .css_free = mem_cgroup_css_free, .css_reset = mem_cgroup_css_reset, .can_attach = mem_cgroup_can_attach, + .attach = mem_cgroup_attach, .cancel_attach = mem_cgroup_cancel_attach, .post_attach = mem_cgroup_move_task, .bind = mem_cgroup_bind, @@ -7123,7 +7150,7 @@ static int __init cgroup_memory(char *s) if (!strcmp(token, "nokmem")) cgroup_memory_nokmem = true; } - return 1; + return 0; } __setup("cgroup.memory=", cgroup_memory); diff --git a/mm/memory.c b/mm/memory.c index 7261bfd5c5375..a038d72a81106 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -126,18 +126,6 @@ int randomize_va_space __read_mostly = 2; #endif -#ifndef arch_faults_on_old_pte -static inline bool arch_faults_on_old_pte(void) -{ - /* - * Those arches which don't have hw access flag feature need to - * implement their own helper. By default, "true" means pagefault - * will be hit on old pte. - */ - return true; -} -#endif - #ifndef arch_wants_old_prefaulted_pte static inline bool arch_wants_old_prefaulted_pte(void) { @@ -2880,7 +2868,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src, * On architectures with software "accessed" bits, we would * take a double page fault, so mark it accessed here. */ - if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) { + if (!arch_has_hw_pte_young() && !pte_young(vmf->orig_pte)) { pte_t entry; vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); @@ -3612,7 +3600,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) if (data_race(si->flags & SWP_SYNCHRONOUS_IO) && __swap_count(entry) == 1) { /* skip swapcache */ - gfp_t flags = GFP_HIGHUSER_MOVABLE; + gfp_t flags = GFP_HIGHUSER_MOVABLE | __GFP_CMA; trace_android_rvh_set_skip_swapcache_flags(&flags); page = alloc_page_vma(flags, vma, vmf->address); @@ -3652,7 +3640,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) ret = VM_FAULT_RETRY; goto out; } else { - page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, + page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE | __GFP_CMA, vmf); swapcache = page; } @@ -3982,20 +3970,11 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) return ret; if (unlikely(PageHWPoison(vmf->page))) { - struct page *page = vmf->page; - vm_fault_t poisonret = VM_FAULT_HWPOISON; - if (ret & VM_FAULT_LOCKED) { - if (page_mapped(page)) - unmap_mapping_pages(page_mapping(page), - page->index, 1, false); - /* Retry if a clean page was removed from the cache. */ - if (invalidate_inode_page(page)) - poisonret = VM_FAULT_NOPAGE; - unlock_page(page); - } - put_page(page); + if (ret & VM_FAULT_LOCKED) + unlock_page(vmf->page); + put_page(vmf->page); vmf->page = NULL; - return poisonret; + return VM_FAULT_HWPOISON; } if (unlikely(!(ret & VM_FAULT_LOCKED))) @@ -4913,6 +4892,10 @@ static inline void mm_account_fault(struct pt_regs *regs, else perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); } + +static void lru_gen_enter_fault(struct vm_area_struct *vma); +static void lru_gen_exit_fault(void); + #ifdef CONFIG_SPECULATIVE_PAGE_FAULT #ifndef CONFIG_ARCH_HAS_PTE_SPECIAL @@ -5104,7 +5087,9 @@ static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm, } mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vmf.vma); ret = handle_pte_fault(&vmf); + lru_gen_exit_fault(); mem_cgroup_exit_user_fault(); if (ret != VM_FAULT_RETRY) { @@ -5180,6 +5165,27 @@ bool can_reuse_spf_vma(struct vm_area_struct *vma, unsigned long address) } #endif /* CONFIG_SPECULATIVE_PAGE_FAULT */ +#ifdef CONFIG_LRU_GEN +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ + /* the LRU algorithm doesn't apply to sequential or random reads */ + current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); +} + +static void lru_gen_exit_fault(void) +{ + current->in_lru_fault = false; +} +#else +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ +} + +static void lru_gen_exit_fault(void) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * By the time we get here, we already hold the mm semaphore * @@ -5211,11 +5217,15 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, if (flags & FAULT_FLAG_USER) mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vma); + if (unlikely(is_vm_hugetlb_page(vma))) ret = hugetlb_fault(vma->vm_mm, vma, address, flags); else ret = __handle_mm_fault(vma, address, flags); + lru_gen_exit_fault(); + if (flags & FAULT_FLAG_USER) { mem_cgroup_exit_user_fault(); /* @@ -5544,7 +5554,7 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, buf, maddr + offset, bytes); } kunmap(page); - put_user_page(page); + put_page(page); } len -= bytes; buf += bytes; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 1ae78937af424..3b2584088d281 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -814,6 +814,7 @@ static int vma_replace_policy(struct vm_area_struct *vma, static int mbind_range(struct mm_struct *mm, unsigned long start, unsigned long end, struct mempolicy *new_pol) { + struct vm_area_struct *next; struct vm_area_struct *prev; struct vm_area_struct *vma; int err = 0; @@ -828,7 +829,8 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (start > vma->vm_start) prev = vma; - for (; vma && vma->vm_start < end; prev = vma, vma = vma->vm_next) { + for (; vma && vma->vm_start < end; prev = vma, vma = next) { + next = vma->vm_next; vmstart = max(start, vma->vm_start); vmend = min(end, vma->vm_end); @@ -840,9 +842,13 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, vma->anon_vma, vma->vm_file, pgoff, new_pol, vma->vm_userfaultfd_ctx, - vma_anon_name(vma)); + anon_vma_name(vma)); if (prev) { vma = prev; + next = vma->vm_next; + if (mpol_equal(vma_policy(vma), new_pol)) + continue; + /* vma_merge() joined vma && vma->next, case 8 */ goto replace; } if (vma->vm_start != vmstart) { diff --git a/mm/migrate.c b/mm/migrate.c index 26f8595de076c..4d25efd7fca47 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1655,7 +1655,7 @@ out_putpage: * isolate_lru_page() or drop the page ref if it was * not isolated. */ - put_user_page(page); + put_page(page); out: mmap_read_unlock(mm); return err; diff --git a/mm/mlock.c b/mm/mlock.c index a90b46d863346..49fe3d9ca2846 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -119,7 +119,7 @@ static bool __munlock_isolate_lru_page(struct page *page, bool getpage) if (getpage) get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); return true; } @@ -472,14 +472,6 @@ void munlock_vma_pages_range(struct vm_area_struct *vma, */ page = follow_page(vma, start, FOLL_GET | FOLL_DUMP); if (page && !IS_ERR(page)) { - /* - * munlock_vma_pages_range uses follow_page(FOLL_GET) - * so it need to use put_user_page but the munlock - * path is quite complicated to deal with each put - * sites correctly so just unattribute them to avoid - * false positive at this moment. - */ - reset_page_pinner(page, compound_order(page)); if (PageTransTail(page)) { VM_BUG_ON_PAGE(PageMlocked(page), page); put_page(page); /* follow_page_mask() */ @@ -550,7 +542,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, vma_anon_name(vma)); + vma->vm_userfaultfd_ctx, anon_vma_name(vma)); if (*prev) { vma = *prev; goto success; diff --git a/mm/mm_init.c b/mm/mm_init.c index b06a30fbedff7..9351e8a25a80d 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -19,10 +19,6 @@ #ifdef CONFIG_DEBUG_MEMORY_INIT int __meminitdata mminit_loglevel; -#ifndef SECTIONS_SHIFT -#define SECTIONS_SHIFT 0 -#endif - /* The zonelists are simply reported, validation is manual. */ void __init mminit_verify_zonelist(void) { @@ -69,14 +65,16 @@ void __init mminit_verify_pageflags_layout(void) shift = 8 * sizeof(unsigned long); width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH - - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; + - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", - "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", + "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", SECTIONS_WIDTH, NODES_WIDTH, ZONES_WIDTH, LAST_CPUPID_WIDTH, KASAN_TAG_WIDTH, + LRU_GEN_WIDTH, + LRU_REFS_WIDTH, NR_PAGEFLAGS); mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", diff --git a/mm/mmap.c b/mm/mmap.c index bfdecbb21bb2e..cb5fded3aa0b4 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1084,7 +1084,7 @@ again: static inline int is_mergeable_vma(struct vm_area_struct *vma, struct file *file, unsigned long vm_flags, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { /* * VM_SOFTDIRTY should not prevent from VMA merging, if we @@ -1102,7 +1102,7 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, return 0; if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx)) return 0; - if (!is_same_vma_anon_name(vma, anon_name)) + if (!anon_vma_name_eq(anon_vma_name(vma), anon_name)) return 0; return 1; } @@ -1137,7 +1137,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { @@ -1159,7 +1159,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { @@ -1220,7 +1220,7 @@ struct vm_area_struct *__vma_merge(struct mm_struct *mm, struct anon_vma *anon_vma, struct file *file, pgoff_t pgoff, struct mempolicy *policy, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name, bool keep_locked) + struct anon_vma_name *anon_name, bool keep_locked) { pgoff_t pglen = (end - addr) >> PAGE_SHIFT; struct vm_area_struct *area, *next; @@ -2676,7 +2676,7 @@ static int __init cmdline_parse_stack_guard_gap(char *p) if (!*endptr) stack_guard_gap = val << PAGE_SHIFT; - return 1; + return 0; } __setup("stack_guard_gap=", cmdline_parse_stack_guard_gap); @@ -3410,7 +3410,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, new_vma = __vma_merge(mm, prev, addr, addr + len, vma->vm_flags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), vma->vm_userfaultfd_ctx, - vma_anon_name(vma), true); + anon_vma_name(vma), true); if (new_vma) { /* * Source vma may have been merged into new_vma diff --git a/mm/mmzone.c b/mm/mmzone.c index 2241281ffe167..1470eea5454ae 100644 --- a/mm/mmzone.c +++ b/mm/mmzone.c @@ -96,6 +96,8 @@ void lruvec_init(struct lruvec *lruvec) for_each_lru(lru) INIT_LIST_HEAD(&lruvec->lists[lru]); + + lru_gen_init_lruvec(lruvec); } #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) diff --git a/mm/mprotect.c b/mm/mprotect.c index 02886b6617198..b7f744ce02953 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -454,7 +454,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *pprev = vma_merge(mm, *pprev, start, end, newflags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, vma_anon_name(vma)); + vma->vm_userfaultfd_ctx, anon_vma_name(vma)); if (*pprev) { vma = *pprev; VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a3a877d804040..757cb85124b03 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -83,6 +83,18 @@ /* Free Page Internal flags: for internal, non-pcp variants of free_pages(). */ typedef int __bitwise fpi_t; +static inline struct per_cpu_pageset_ext *pcp_to_pageset_ext(struct per_cpu_pages *pcp) +{ + struct per_cpu_pageset *ps = container_of(pcp, struct per_cpu_pageset, pcp); + + return container_of(ps, struct per_cpu_pageset_ext, pageset); +} + +static inline struct per_cpu_pageset_ext *pageset_to_pageset_ext(struct per_cpu_pageset *ps) +{ + return container_of(ps, struct per_cpu_pageset_ext, pageset); +} + /* No special request */ #define FPI_NONE ((__force fpi_t)0) @@ -123,6 +135,20 @@ typedef int __bitwise fpi_t; static DEFINE_MUTEX(pcp_batch_high_lock); #define MIN_PERCPU_PAGELIST_FRACTION (8) +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +/* + * On SMP, spin_trylock is sufficient protection. + * On PREEMPT_RT, spin_trylock is equivalent on both SMP and UP. + */ +#define pcp_trylock_prepare(flags) do { } while (0) +#define pcp_trylock_finish(flag) do { } while (0) +#else + +/* UP spin_trylock always succeeds so disable IRQs to prevent re-entrancy. */ +#define pcp_trylock_prepare(flags) local_irq_save(flags) +#define pcp_trylock_finish(flags) local_irq_restore(flags) +#endif + #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DEFINE_PER_CPU(int, numa_node); EXPORT_PER_CPU_SYMBOL(numa_node); @@ -141,13 +167,7 @@ DEFINE_PER_CPU(int, _numa_mem_); /* Kernel "local memory" node */ EXPORT_PER_CPU_SYMBOL(_numa_mem_); #endif -/* work_structs for global per-cpu drains */ -struct pcpu_drain { - struct zone *zone; - struct work_struct work; -}; static DEFINE_MUTEX(pcpu_drain_mutex); -static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain); #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY volatile unsigned long latent_entropy __latent_entropy; @@ -1509,13 +1529,15 @@ static void free_one_page(struct zone *zone, unsigned int order, int migratetype, fpi_t fpi_flags) { - spin_lock(&zone->lock); + unsigned long flags; + + spin_lock_irqsave(&zone->lock, flags); if (unlikely(has_isolate_pageblock(zone) || is_migrate_isolate(migratetype))) { migratetype = get_pfnblock_migratetype(page, pfn); } __free_one_page(page, pfn, zone, order, migratetype, fpi_flags); - spin_unlock(&zone->lock); + spin_unlock_irqrestore(&zone->lock, flags); } static void __meminit __init_single_page(struct page *page, unsigned long pfn, @@ -3104,52 +3126,54 @@ static struct list_head *get_populated_pcp_list(struct zone *zone, * Called from the vmstat counter updater to drain pagesets of this * currently executing processor on remote nodes after they have * expired. - * - * Note that this function must be called with the thread pinned to - * a single processor. */ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) { - unsigned long flags; int to_drain, batch; - local_irq_save(flags); batch = READ_ONCE(pcp->batch); to_drain = min(pcp->count, batch); - if (to_drain > 0) + if (to_drain > 0) { + unsigned long flags; + struct per_cpu_pageset_ext *ps_ext = pcp_to_pageset_ext(pcp); + + /* + * free_pcppages_bulk expects IRQs disabled for zone->lock + * so even though pcp->lock is not intended to be IRQ-safe, + * it's needed in this context. + */ + spin_lock_irqsave(&ps_ext->lock, flags); free_pcppages_bulk(zone, to_drain, pcp); - local_irq_restore(flags); + spin_unlock_irqrestore(&ps_ext->lock, flags); + } } #endif /* * Drain pcplists of the indicated processor and zone. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. */ static void drain_pages_zone(unsigned int cpu, struct zone *zone) { - unsigned long flags; struct per_cpu_pageset *pset; + struct per_cpu_pageset_ext *ps_ext; struct per_cpu_pages *pcp; - local_irq_save(flags); pset = per_cpu_ptr(zone->pageset, cpu); + ps_ext = pageset_to_pageset_ext(pset); pcp = &pset->pcp; - if (pcp->count) + if (pcp->count) { + unsigned long flags; + + /* See drain_zone_pages on why this is disabling IRQs */ + spin_lock_irqsave(&ps_ext->lock, flags); free_pcppages_bulk(zone, pcp->count, pcp); - local_irq_restore(flags); + spin_unlock_irqrestore(&ps_ext->lock, flags); + } } /* * Drain pcplists of all zones on the indicated processor. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. */ static void drain_pages(unsigned int cpu) { @@ -3162,9 +3186,6 @@ static void drain_pages(unsigned int cpu) /* * Spill all of this CPU's per-cpu pages back into the buddy allocator. - * - * The CPU has to be pinned. When zone parameter is non-NULL, spill just - * the single zone's pages. */ void drain_local_pages(struct zone *zone) { @@ -3176,30 +3197,10 @@ void drain_local_pages(struct zone *zone) drain_pages(cpu); } -static void drain_local_pages_wq(struct work_struct *work) -{ - struct pcpu_drain *drain; - - drain = container_of(work, struct pcpu_drain, work); - - /* - * drain_all_pages doesn't use proper cpu hotplug protection so - * we can race with cpu offline when the WQ can move this from - * a cpu pinned worker to an unbound one. We can operate on a different - * cpu which is allright but we also have to make sure to not move to - * a different one. - */ - preempt_disable(); - drain_local_pages(drain->zone); - preempt_enable(); -} - /* * Spill all the per-cpu pages from all CPUs back into the buddy allocator. * * When zone parameter is non-NULL, spill just the single zone's pages. - * - * Note that this can be extremely slow as the draining happens in a workqueue. */ void drain_all_pages(struct zone *zone) { @@ -3211,13 +3212,6 @@ void drain_all_pages(struct zone *zone) */ static cpumask_t cpus_with_pcps; - /* - * Make sure nobody triggers this path before mm_percpu_wq is fully - * initialized. - */ - if (WARN_ON_ONCE(!mm_percpu_wq)) - return; - /* * Do not drain if one is already in progress unless it's specific to * a zone. Such callers are primarily CMA and memory hotplug and need @@ -3261,14 +3255,12 @@ void drain_all_pages(struct zone *zone) } for_each_cpu(cpu, &cpus_with_pcps) { - struct pcpu_drain *drain = per_cpu_ptr(&pcpu_drain, cpu); - - drain->zone = zone; - INIT_WORK(&drain->work, drain_local_pages_wq); - queue_work_on(cpu, mm_percpu_wq, &drain->work); + if (zone) { + drain_pages_zone(cpu, zone); + } else { + drain_pages(cpu); + } } - for_each_cpu(cpu, &cpus_with_pcps) - flush_work(&per_cpu_ptr(&pcpu_drain, cpu)->work); mutex_unlock(&pcpu_drain_mutex); } @@ -3340,38 +3332,41 @@ static bool free_unref_page_prepare(struct page *page, unsigned long pfn) return true; } -static void free_unref_page_commit(struct page *page, unsigned long pfn) +/* Returns true if the page was committed to the per-cpu list. */ +static bool free_unref_page_commit(struct page *page, int migratetype, + bool locked) { struct zone *zone = page_zone(page); struct per_cpu_pages *pcp; - int migratetype; + struct per_cpu_pageset_ext *ps_ext; + unsigned long __maybe_unused UP_flags; - migratetype = get_pcppage_migratetype(page); __count_vm_event(PGFREE); + pcp = &this_cpu_ptr(zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); - /* - * We only track unmovable, reclaimable and movable on pcp lists. - * Free ISOLATE pages back to the allocator because they are being - * offlined but treat HIGHATOMIC as movable pages so we can get those - * areas back if necessary. Otherwise, we may have to free - * excessively into the page allocator - */ - if (migratetype >= MIGRATE_PCPTYPES) { - if (unlikely(is_migrate_isolate(migratetype))) { - free_one_page(zone, page, pfn, 0, migratetype, - FPI_NONE); - return; + if (!locked) { + /* Protect against a parallel drain. */ + pcp_trylock_prepare(UP_flags); + if (!spin_trylock(&ps_ext->lock)) { + pcp_trylock_finish(UP_flags); + return false; } - migratetype = MIGRATE_MOVABLE; } - pcp = &this_cpu_ptr(zone->pageset)->pcp; list_add(&page->lru, &pcp->lists[migratetype]); pcp->count++; if (pcp->count >= pcp->high) { unsigned long batch = READ_ONCE(pcp->batch); free_pcppages_bulk(zone, batch, pcp); } + + if (!locked) { + spin_unlock(&ps_ext->lock); + pcp_trylock_finish(UP_flags); + } + + return true; } /* @@ -3381,13 +3376,36 @@ void free_unref_page(struct page *page) { unsigned long flags; unsigned long pfn = page_to_pfn(page); + int migratetype; + bool freed_pcp = false; if (!free_unref_page_prepare(page, pfn)) return; + /* + * We only track unmovable, reclaimable, movable and cma on pcp lists. + * Place ISOLATE pages on the isolated list because they are being + * offlined but treat HIGHATOMIC as movable pages so we can get those + * areas back if necessary. Otherwise, we may have to free + * excessively into the page allocator + */ + migratetype = get_pcppage_migratetype(page); + if (unlikely(migratetype > MIGRATE_RECLAIMABLE)) { + if (unlikely(is_migrate_isolate(migratetype))) { + free_one_page(page_zone(page), page, pfn, 0, migratetype, FPI_NONE); + return; + } + if (migratetype == MIGRATE_HIGHATOMIC) + migratetype = MIGRATE_MOVABLE; + } + local_irq_save(flags); - free_unref_page_commit(page, pfn); + freed_pcp = free_unref_page_commit(page, migratetype, false); local_irq_restore(flags); + + if (unlikely(!freed_pcp)) + free_one_page(page_zone(page), page, pfn, 0, migratetype, + FPI_NONE); } /* @@ -3396,35 +3414,107 @@ void free_unref_page(struct page *page) void free_unref_page_list(struct list_head *list) { struct page *page, *next; - unsigned long flags, pfn; + struct per_cpu_pageset_ext *ps_ext; + struct per_cpu_pages *pcp; + struct zone *locked_zone; + unsigned long flags; int batch_count = 0; + int migratetype; + + /* + * An empty list is possible. Check early so that the later + * lru_to_page() does not potentially read garbage. + */ + if (list_empty(list)) + return; /* Prepare pages for freeing */ list_for_each_entry_safe(page, next, list, lru) { - pfn = page_to_pfn(page); - if (!free_unref_page_prepare(page, pfn)) + unsigned long pfn = page_to_pfn(page); + if (!free_unref_page_prepare(page, pfn)) { list_del(&page->lru); - set_page_private(page, pfn); + continue; + } + + /* + * Free isolated pages directly to the allocator, see + * comment in free_unref_page. + */ + migratetype = get_pcppage_migratetype(page); + if (unlikely(migratetype > MIGRATE_RECLAIMABLE)) { + if (unlikely(is_migrate_isolate(migratetype))) { + list_del(&page->lru); + free_one_page(page_zone(page), page, pfn, 0, + migratetype, FPI_NONE); + continue; + } + + /* + * Non-isolated types over MIGRATE_RECLAIMABLE get added + * to the MIGRATE_MOVABLE pcp list. + */ + if (migratetype == MIGRATE_HIGHATOMIC) + set_pcppage_migratetype(page, MIGRATE_MOVABLE); + } } + /* + * Preparation could have drained the list due to failing to prepare + * or all pages are being isolated. + */ + if (list_empty(list)) + return; + + VM_BUG_ON(in_irq()); + local_irq_save(flags); + + page = lru_to_page(list); + locked_zone = page_zone(page); + pcp = &this_cpu_ptr(locked_zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); + list_for_each_entry_safe(page, next, list, lru) { - unsigned long pfn = page_private(page); + struct zone *zone = page_zone(page); - set_page_private(page, 0); + /* Different zone, different pcp lock. */ + if (zone != locked_zone) { + spin_unlock(&ps_ext->lock); + locked_zone = zone; + pcp = &this_cpu_ptr(zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); + } + + migratetype = get_pcppage_migratetype(page); trace_mm_page_free_batched(page); - free_unref_page_commit(page, pfn); + + /* + * If there is a parallel drain in progress, free to the buddy + * allocator directly. This is expensive as the zone lock will + * be acquired multiple times but if a drain is in progress + * then an expensive operation is already taking place. + */ + if (!free_unref_page_commit(page, migratetype, true)) + free_one_page(page_zone(page), page, page_to_pfn(page), + 0, migratetype, FPI_NONE); /* * Guard against excessive IRQ disabled times when we get * a large list of pages to free. */ if (++batch_count == SWAP_CLUSTER_MAX) { + spin_unlock(&ps_ext->lock); local_irq_restore(flags); batch_count = 0; local_irq_save(flags); + pcp = &this_cpu_ptr(locked_zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); } } + spin_unlock(&ps_ext->lock); local_irq_restore(flags); } @@ -3546,14 +3636,79 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z) #endif } +static __always_inline +struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone, + unsigned int order, unsigned int alloc_flags, + int migratetype) +{ + struct page *page; + unsigned long flags; + + do { + page = NULL; + spin_lock_irqsave(&zone->lock, flags); + /* + * order-0 request can reach here when the pcplist is skipped + * due to non-CMA allocation context. HIGHATOMIC area is + * reserved for high-order atomic allocation, so order-0 + * request should skip it. + */ + if (order > 0 && alloc_flags & ALLOC_HARDER) { + page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); + if (page) + trace_mm_page_alloc_zone_locked(page, order, migratetype); + } + if (!page) { + if (migratetype == MIGRATE_MOVABLE && + alloc_flags & ALLOC_CMA) + page = __rmqueue_cma(zone, order, migratetype, + alloc_flags); + if (!page) + page = __rmqueue(zone, order, migratetype, + alloc_flags); + } + if (!page) { + spin_unlock_irqrestore(&zone->lock, flags); + return NULL; + } + + __mod_zone_freepage_state(zone, -(1 << order), + get_pcppage_migratetype(page)); + spin_unlock_irqrestore(&zone->lock, flags); + } while (check_new_pages(page, order)); + + __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); + zone_statistics(preferred_zone, zone); + + return page; +} + /* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, unsigned int alloc_flags, struct per_cpu_pages *pcp, - gfp_t gfp_flags) + gfp_t gfp_flags, bool locked) { struct page *page = NULL; + unsigned long __maybe_unused UP_flags; struct list_head *list = NULL; + struct per_cpu_pageset_ext *ps_ext = pcp_to_pageset_ext(pcp); + + /* + * spin_trylock is not necessary right now due to due to + * local_lock_irqsave and is a preparation step for + * a conversion to local_lock using the trylock to prevent + * IRQ re-entrancy. If pcp->lock cannot be acquired, the caller + * uses rmqueue_buddy. + * TODO: Convert local_lock_irqsave to local_lock. + */ + if (unlikely(!locked)) { + pcp_trylock_prepare(UP_flags); + if (!spin_trylock(&ps_ext->lock)) { + pcp_trylock_finish(UP_flags); + return NULL; + } + } do { /* First try to get CMA pages */ @@ -3571,8 +3726,10 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, list = get_populated_pcp_list(zone, 0, pcp, migratetype, alloc_flags); if (unlikely(list == NULL) || - unlikely(list_empty(list))) - return NULL; + unlikely(list_empty(list))) { + page = NULL; + goto out; + } } page = list_first_entry(list, struct page, lru); @@ -3580,6 +3737,12 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, pcp->count--; } while (check_new_pcp(page)); +out: + if (!locked) { + spin_unlock(&ps_ext->lock); + pcp_trylock_finish(UP_flags); + } + return page; } @@ -3595,7 +3758,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, local_irq_save(flags); pcp = &this_cpu_ptr(zone->pageset)->pcp; page = __rmqueue_pcplist(zone, migratetype, alloc_flags, pcp, - gfp_flags); + gfp_flags, false); if (page) { __count_zid_vm_events(PGALLOC, page_zonenum(page), 1); zone_statistics(preferred_zone, zone); @@ -3613,13 +3776,13 @@ struct page *rmqueue(struct zone *preferred_zone, gfp_t gfp_flags, unsigned int alloc_flags, int migratetype) { - unsigned long flags; struct page *page; if (likely(order == 0)) { page = rmqueue_pcplist(preferred_zone, zone, gfp_flags, migratetype, alloc_flags); - goto out; + if (page) + goto out; } /* @@ -3627,42 +3790,14 @@ struct page *rmqueue(struct zone *preferred_zone, * allocate greater than order-1 page units with __GFP_NOFAIL. */ WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1)); - spin_lock_irqsave(&zone->lock, flags); - do { - page = NULL; - /* - * order-0 request can reach here when the pcplist is skipped - * due to non-CMA allocation context. HIGHATOMIC area is - * reserved for high-order atomic allocation, so order-0 - * request should skip it. - */ - if (order > 0 && alloc_flags & ALLOC_HARDER) { - page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); - if (page) - trace_mm_page_alloc_zone_locked(page, order, migratetype); - } - if (!page) { - if (migratetype == MIGRATE_MOVABLE && - alloc_flags & ALLOC_CMA) - page = __rmqueue_cma(zone, order, migratetype, - alloc_flags); - if (!page) - page = __rmqueue(zone, order, migratetype, - alloc_flags); - } - } while (page && check_new_pages(page, order)); - spin_unlock(&zone->lock); - if (!page) - goto failed; - __mod_zone_freepage_state(zone, -(1 << order), - get_pcppage_migratetype(page)); + page = rmqueue_buddy(preferred_zone, zone, order, alloc_flags, + migratetype); + if (unlikely(!page)) + return NULL; - __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); - zone_statistics(preferred_zone, zone); trace_android_vh_rmqueue(preferred_zone, zone, order, gfp_flags, alloc_flags, migratetype); - local_irq_restore(flags); out: /* Separate test+clear to avoid unnecessary atomics */ @@ -3673,10 +3808,6 @@ out: VM_BUG_ON_PAGE(page && bad_range(zone, page), page); return page; - -failed: - local_irq_restore(flags); - return NULL; } #ifdef CONFIG_FAIL_PAGE_ALLOC @@ -6113,7 +6244,7 @@ static void build_zonelists(pg_data_t *pgdat) * Other parts of the kernel may not check if the zone is available. */ static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch); -static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset); +static DEFINE_PER_CPU(struct per_cpu_pageset_ext, boot_pageset); static DEFINE_PER_CPU(struct per_cpu_nodestat, boot_nodestats); static void __build_all_zonelists(void *data) @@ -6180,7 +6311,7 @@ build_all_zonelists_init(void) * (a chicken-egg dilemma). */ for_each_possible_cpu(cpu) - setup_pageset(&per_cpu(boot_pageset, cpu), 0); + setup_pageset(&per_cpu(boot_pageset, cpu).pageset, 0); mminit_verify_zonelist(); cpuset_init_current_mems_allowed(); @@ -6599,11 +6730,14 @@ static void pageset_set_batch(struct per_cpu_pageset *p, unsigned long batch) static void pageset_init(struct per_cpu_pageset *p) { struct per_cpu_pages *pcp; + struct per_cpu_pageset_ext *ps_ext; int migratetype; memset(p, 0, sizeof(*p)); + ps_ext = pageset_to_pageset_ext(p); pcp = &p->pcp; + spin_lock_init(&ps_ext->lock); for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++) INIT_LIST_HEAD(&pcp->lists[migratetype]); } @@ -6650,7 +6784,10 @@ static void __meminit zone_pageset_init(struct zone *zone, int cpu) void __meminit setup_zone_pageset(struct zone *zone) { int cpu; - zone->pageset = alloc_percpu(struct per_cpu_pageset); + struct per_cpu_pageset_ext *ps_ext; + + ps_ext = alloc_percpu(struct per_cpu_pageset_ext); + zone->pageset = &ps_ext->pageset; for_each_possible_cpu(cpu) zone_pageset_init(zone, cpu); } @@ -6676,7 +6813,7 @@ void __init setup_per_cpu_pageset(void) * the nodes these zones are associated with. */ for_each_possible_cpu(cpu) { - struct per_cpu_pageset *pcp = &per_cpu(boot_pageset, cpu); + struct per_cpu_pageset *pcp = &per_cpu(boot_pageset, cpu).pageset; memset(pcp->vm_numa_stat_diff, 0, sizeof(pcp->vm_numa_stat_diff)); } @@ -6694,7 +6831,7 @@ static __meminit void zone_pcp_init(struct zone *zone) * relies on the ability of the linker to provide the * offset of a (static) per cpu variable into the per cpu area. */ - zone->pageset = &boot_pageset; + zone->pageset = &boot_pageset.pageset; if (populated_zone(zone)) printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%u\n", @@ -7603,17 +7740,10 @@ restart: out2: /* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */ - for (nid = 0; nid < MAX_NUMNODES; nid++) { - unsigned long start_pfn, end_pfn; - + for (nid = 0; nid < MAX_NUMNODES; nid++) zone_movable_pfn[nid] = roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES); - get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); - if (zone_movable_pfn[nid] >= end_pfn) - zone_movable_pfn[nid] = 0; - } - out: /* restore the node_state */ node_states[N_MEMORY] = saved_node_state; @@ -8722,7 +8852,12 @@ static int __alloc_contig_migrate_range(struct compact_control *cc, if (ret < 0) { if (ret == -EBUSY) { alloc_contig_dump_pages(&cc->migratepages); - page_pinner_mark_migration_failed_pages(&cc->migratepages); + list_for_each_entry(page, &cc->migratepages, lru) { + /* The page will be freed by putback_movable_pages soon */ + if (page_count(page) == 1) + continue; + page_pinner_failure_detect(page); + } } if (!list_empty(&cc->migratepages)) { @@ -9032,13 +9167,13 @@ void zone_pcp_reset(struct zone *zone) /* avoid races with drain_pages() */ local_irq_save(flags); - if (zone->pageset != &boot_pageset) { + if (zone->pageset != &boot_pageset.pageset) { for_each_online_cpu(cpu) { pset = per_cpu_ptr(zone->pageset, cpu); drain_zonestat(zone, pset); } free_percpu(zone->pageset); - zone->pageset = &boot_pageset; + zone->pageset = &boot_pageset.pageset; } local_irq_restore(flags); } diff --git a/mm/page_ext.c b/mm/page_ext.c index 7e44726b35495..e5e31ff1adba5 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -58,11 +58,21 @@ * can utilize this callback to initialize the state of it correctly. */ +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) +static bool need_page_idle(void) +{ + return true; +} +struct page_ext_operations page_idle_ops = { + .need = need_page_idle, +}; +#endif + static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_PAGE_OWNER &page_owner_ops, #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) &page_idle_ops, #endif #ifdef CONFIG_PAGE_PINNER diff --git a/mm/page_idle.c b/mm/page_idle.c index 057c61df12dba..144fb4ed961d7 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -211,16 +211,6 @@ static const struct attribute_group page_idle_attr_group = { .name = "page_idle", }; -#ifndef CONFIG_64BIT -static bool need_page_idle(void) -{ - return true; -} -struct page_ext_operations page_idle_ops = { - .need = need_page_idle, -}; -#endif - static int __init page_idle_init(void) { int err; diff --git a/mm/page_io.c b/mm/page_io.c index f2900cf6c5b4f..d5efe9558b8a0 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -69,54 +69,6 @@ void end_swap_bio_write(struct bio *bio) bio_put(bio); } -static void swap_slot_free_notify(struct page *page) -{ - struct swap_info_struct *sis; - struct gendisk *disk; - swp_entry_t entry; - - /* - * There is no guarantee that the page is in swap cache - the software - * suspend code (at least) uses end_swap_bio_read() against a non- - * swapcache page. So we must check PG_swapcache before proceeding with - * this optimization. - */ - if (unlikely(!PageSwapCache(page))) - return; - - sis = page_swap_info(page); - if (data_race(!(sis->flags & SWP_BLKDEV))) - return; - - /* - * The swap subsystem performs lazy swap slot freeing, - * expecting that the page will be swapped out again. - * So we can avoid an unnecessary write if the page - * isn't redirtied. - * This is good for real swap storage because we can - * reduce unnecessary I/O and enhance wear-leveling - * if an SSD is used as the as swap device. - * But if in-memory swap device (eg zram) is used, - * this causes a duplicated copy between uncompressed - * data in VM-owned memory and compressed data in - * zram-owned memory. So let's free zram-owned memory - * and make the VM-owned decompressed page *dirty*, - * so the page should be swapped out somewhere again if - * we again wish to reclaim it. - */ - disk = sis->bdev->bd_disk; - entry.val = page_private(page); - if (disk->fops->swap_slot_free_notify && __swap_count(entry) == 1) { - unsigned long offset; - - offset = swp_offset(entry); - - SetPageDirty(page); - disk->fops->swap_slot_free_notify(sis->bdev, - offset); - } -} - static void end_swap_bio_read(struct bio *bio) { struct page *page = bio_first_page_all(bio); @@ -132,7 +84,6 @@ static void end_swap_bio_read(struct bio *bio) } SetPageUptodate(page); - swap_slot_free_notify(page); out: unlock_page(page); WRITE_ONCE(bio->bi_private, NULL); @@ -409,11 +360,6 @@ int swap_readpage(struct page *page, bool synchronous) if (sis->flags & SWP_SYNCHRONOUS_IO) { ret = bdev_read_page(sis->bdev, swap_page_sector(page), page); if (!ret) { - if (trylock_page(page)) { - swap_slot_free_notify(page); - unlock_page(page); - } - count_vm_event(PSWPIN); goto out; } diff --git a/mm/page_pinner.c b/mm/page_pinner.c index 12d545c44a666..b81d48fa65fdb 100644 --- a/mm/page_pinner.c +++ b/mm/page_pinner.c @@ -15,19 +15,25 @@ #include "internal.h" #define PAGE_PINNER_STACK_DEPTH 16 -#define LONGTERM_PIN_BUCKETS 4096 +static unsigned long pp_buf_size = 4096; struct page_pinner { depot_stack_handle_t handle; - s64 ts_usec; + u64 ts_usec; atomic_t count; }; +enum pp_state { + PP_PUT, + PP_FREE, + PP_FAIL_DETECTED, +}; + struct captured_pinner { depot_stack_handle_t handle; union { - s64 ts_usec; - s64 elapsed; + u64 ts_usec; + u64 elapsed; }; /* struct page fields */ @@ -36,24 +42,17 @@ struct captured_pinner { int mapcount; struct address_space *mapping; unsigned long flags; + enum pp_state state; }; -struct longterm_pinner { +struct page_pinner_buffer { spinlock_t lock; - unsigned int index; - struct captured_pinner pinner[LONGTERM_PIN_BUCKETS]; + unsigned long index; + struct captured_pinner *buffer; }; -static struct longterm_pinner lt_pinner = { - .lock = __SPIN_LOCK_UNLOCKED(lt_pinner.lock), -}; - -static s64 threshold_usec = 300000; - /* alloc_contig failed pinner */ -static struct longterm_pinner acf_pinner = { - .lock = __SPIN_LOCK_UNLOCKED(acf_pinner.lock), -}; +static struct page_pinner_buffer pp_buffer; static bool page_pinner_enabled; DEFINE_STATIC_KEY_FALSE(page_pinner_inited); @@ -128,96 +127,61 @@ static void capture_page_state(struct page *page, record->mapcount = page_mapcount(page); } -static void check_longterm_pin(struct page_pinner *page_pinner, - struct page *page) +static void add_record(struct page_pinner_buffer *pp_buf, + struct captured_pinner *record) { - s64 now, delta = 0; unsigned long flags; unsigned int idx; - struct captured_pinner record; - - now = ktime_to_us(ktime_get_boottime()); - - /* get/put_page can be raced. Ignore that case */ - if (page_pinner->ts_usec < now) - delta = now - page_pinner->ts_usec; - if (delta <= threshold_usec) - return; - - record.handle = page_pinner->handle; - record.elapsed = delta; - capture_page_state(page, &record); - - spin_lock_irqsave(<_pinner.lock, flags); - idx = lt_pinner.index++; - lt_pinner.index %= LONGTERM_PIN_BUCKETS; - lt_pinner.pinner[idx] = record; - spin_unlock_irqrestore(<_pinner.lock, flags); + spin_lock_irqsave(&pp_buf->lock, flags); + idx = pp_buf->index++; + pp_buf->index %= pp_buf_size; + pp_buf->buffer[idx] = *record; + spin_unlock_irqrestore(&pp_buf->lock, flags); } -void __reset_page_pinner(struct page *page, unsigned int order, bool free) +void __free_page_pinner(struct page *page, unsigned int order) { struct page_pinner *page_pinner; struct page_ext *page_ext; int i; + /* free_page could be called before buffer is initialized */ + if (!pp_buffer.buffer) + return; + page_ext = lookup_page_ext(page); if (unlikely(!page_ext)) return; for (i = 0; i < (1 << order); i++) { - if (!test_bit(PAGE_EXT_GET, &page_ext->flags) && - !test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, - &page_ext->flags)) + struct captured_pinner record; + + if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) continue; page_pinner = get_page_pinner(page_ext); - if (free) { - /* record page free call path */ - __page_pinner_migration_failed(page); - atomic_set(&page_pinner->count, 0); - __clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); - } else { - check_longterm_pin(page_pinner, page); - } - clear_bit(PAGE_EXT_GET, &page_ext->flags); - page_ext = page_ext_next(page_ext); - } -} + /* record page free call path */ + page_ext = lookup_page_ext(page); + if (unlikely(!page_ext)) + continue; -static inline void __set_page_pinner_handle(struct page *page, - struct page_ext *page_ext, depot_stack_handle_t handle, - unsigned int order) -{ - struct page_pinner *page_pinner; - int i; - s64 usec = ktime_to_us(ktime_get_boottime()); + record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); + record.ts_usec = (u64)ktime_to_us(ktime_get_boottime()); + record.state = PP_FREE; + capture_page_state(page, &record); - for (i = 0; i < (1 << order); i++) { - page_pinner = get_page_pinner(page_ext); - page_pinner->handle = handle; - page_pinner->ts_usec = usec; - set_bit(PAGE_EXT_GET, &page_ext->flags); - atomic_inc(&page_pinner->count); + add_record(&pp_buffer, &record); + + atomic_set(&page_pinner->count, 0); + page_pinner->ts_usec = 0; + clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); page_ext = page_ext_next(page_ext); } } -noinline void __set_page_pinner(struct page *page, unsigned int order) -{ - struct page_ext *page_ext = lookup_page_ext(page); - depot_stack_handle_t handle; - - if (unlikely(!page_ext)) - return; - - handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); - __set_page_pinner_handle(page, page_ext, handle, order); -} - static ssize_t -print_page_pinner(bool longterm, char __user *buf, size_t count, struct captured_pinner *record) +print_page_pinner(char __user *buf, size_t count, struct captured_pinner *record) { int ret; unsigned long *entries; @@ -229,15 +193,17 @@ print_page_pinner(bool longterm, char __user *buf, size_t count, struct captured if (!kbuf) return -ENOMEM; - if (longterm) { - ret = snprintf(kbuf, count, "Page pinned for %lld us\n", + if (record->state == PP_PUT) { + ret = snprintf(kbuf, count, "At least, pinned for %llu us\n", record->elapsed); } else { - s64 ts_usec = record->ts_usec; + u64 ts_usec = record->ts_usec; unsigned long rem_usec = do_div(ts_usec, 1000000); ret = snprintf(kbuf, count, - "Page pinned ts [%5lu.%06lu]\n", + "%s [%5lu.%06lu]\n", + record->state == PP_FREE ? "Freed at" : + "Failure detected at", (unsigned long)ts_usec, rem_usec); } @@ -277,60 +243,39 @@ err: return -ENOMEM; } -void __dump_page_pinner(struct page *page) +void __page_pinner_failure_detect(struct page *page) { struct page_ext *page_ext = lookup_page_ext(page); struct page_pinner *page_pinner; - depot_stack_handle_t handle; - unsigned long *entries; - unsigned int nr_entries; - int pageblock_mt; - unsigned long pfn; - int count; - unsigned long rem_usec; - s64 ts_usec; + struct captured_pinner record; + u64 now; - if (unlikely(!page_ext)) { - pr_alert("There is not page extension available.\n"); + if (unlikely(!page_ext)) return; - } - page_pinner = get_page_pinner(page_ext); - - count = atomic_read(&page_pinner->count); - if (!count) { - pr_alert("page_pinner info is not present (never set?)\n"); + if (test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) return; - } - pfn = page_to_pfn(page); - ts_usec = page_pinner->ts_usec; - rem_usec = do_div(ts_usec, 1000000); - pr_alert("page last pinned %5lu.%06lu] count %d\n", - (unsigned long)ts_usec, rem_usec, count); - - pageblock_mt = get_pageblock_migratetype(page); - pr_alert("PFN %lu Block %lu type %s Flags %#lx(%pGp)\n", - pfn, - pfn >> pageblock_order, - migratetype_names[pageblock_mt], - page->flags, &page->flags); - - handle = READ_ONCE(page_pinner->handle); - if (!handle) { - pr_alert("page_pinner allocation stack trace missing\n"); - } else { - nr_entries = stack_depot_fetch(handle, &entries); - stack_trace_print(entries, nr_entries, 0); - } + now = (u64)ktime_to_us(ktime_get_boottime()); + page_pinner = get_page_pinner(page_ext); + if (!page_pinner->ts_usec) + page_pinner->ts_usec = now; + set_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); + record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); + record.ts_usec = now; + record.state = PP_FAIL_DETECTED; + capture_page_state(page, &record); + + add_record(&pp_buffer, &record); } +EXPORT_SYMBOL_GPL(__page_pinner_failure_detect); -void __page_pinner_migration_failed(struct page *page) +void __page_pinner_put_page(struct page *page) { struct page_ext *page_ext = lookup_page_ext(page); + struct page_pinner *page_pinner; struct captured_pinner record; - unsigned long flags; - unsigned int idx; + u64 now, ts_usec; if (unlikely(!page_ext)) return; @@ -338,74 +283,26 @@ void __page_pinner_migration_failed(struct page *page) if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) return; + page_pinner = get_page_pinner(page_ext); record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); - record.ts_usec = ktime_to_us(ktime_get_boottime()); - capture_page_state(page, &record); - - spin_lock_irqsave(&acf_pinner.lock, flags); - idx = acf_pinner.index++; - acf_pinner.index %= LONGTERM_PIN_BUCKETS; - acf_pinner.pinner[idx] = record; - spin_unlock_irqrestore(&acf_pinner.lock, flags); -} -EXPORT_SYMBOL_GPL(__page_pinner_migration_failed); - -void __page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ - struct page *page; - struct page_ext *page_ext; - - list_for_each_entry(page, page_list, lru) { - /* The page will be freed by putback_movable_pages soon */ - if (page_count(page) == 1) - continue; - page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - continue; - __set_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); - __page_pinner_migration_failed(page); - } -} - -static ssize_t -read_longterm_page_pinner(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - loff_t i, idx; - struct captured_pinner record; - unsigned long flags; - - if (!static_branch_unlikely(&page_pinner_inited)) - return -EINVAL; - - if (*ppos >= LONGTERM_PIN_BUCKETS) - return 0; - - i = *ppos; - *ppos = i + 1; + now = (u64)ktime_to_us(ktime_get_boottime()); + ts_usec = page_pinner->ts_usec; - /* - * reading the records in the reverse order with newest one - * being read first followed by older ones - */ - idx = (lt_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) % - LONGTERM_PIN_BUCKETS; - spin_lock_irqsave(<_pinner.lock, flags); - record = lt_pinner.pinner[idx]; - spin_unlock_irqrestore(<_pinner.lock, flags); - if (!record.handle) - return 0; + if (now > ts_usec) + record.elapsed = now - ts_usec; + else + record.elapsed = 0; + record.state = PP_PUT; + capture_page_state(page, &record); - return print_page_pinner(true, buf, count, &record); + add_record(&pp_buffer, &record); } +EXPORT_SYMBOL_GPL(__page_pinner_put_page); -static const struct file_operations proc_longterm_pinner_operations = { - .read = read_longterm_page_pinner, -}; - -static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, +static ssize_t read_buffer(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + u64 tmp; loff_t i, idx; struct captured_pinner record; unsigned long flags; @@ -413,7 +310,7 @@ static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, if (!static_branch_unlikely(&failure_tracking)) return -EINVAL; - if (*ppos >= LONGTERM_PIN_BUCKETS) + if (*ppos >= pp_buf_size) return 0; i = *ppos; @@ -423,45 +320,22 @@ static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, * reading the records in the reverse order with newest one * being read first followed by older ones */ - idx = (acf_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) % - LONGTERM_PIN_BUCKETS; + tmp = pp_buffer.index - 1 - i + pp_buf_size; + idx = do_div(tmp, pp_buf_size); - spin_lock_irqsave(&acf_pinner.lock, flags); - record = acf_pinner.pinner[idx]; - spin_unlock_irqrestore(&acf_pinner.lock, flags); + spin_lock_irqsave(&pp_buffer.lock, flags); + record = pp_buffer.buffer[idx]; + spin_unlock_irqrestore(&pp_buffer.lock, flags); if (!record.handle) return 0; - return print_page_pinner(false, buf, count, &record); + return print_page_pinner(buf, count, &record); } -static const struct file_operations proc_alloc_contig_failed_operations = { - .read = read_alloc_contig_failed, +static const struct file_operations proc_buffer_operations = { + .read = read_buffer, }; -static int pp_threshold_set(void *data, unsigned long long val) -{ - unsigned long flags; - - threshold_usec = (s64)val; - - spin_lock_irqsave(<_pinner.lock, flags); - memset(lt_pinner.pinner, 0, - sizeof(struct captured_pinner) * LONGTERM_PIN_BUCKETS); - lt_pinner.index = 0; - spin_unlock_irqrestore(<_pinner.lock, flags); - return 0; -} - -static int pp_threshold_get(void *data, unsigned long long *val) -{ - *val = (unsigned long long)threshold_usec; - - return 0; -} -DEFINE_DEBUGFS_ATTRIBUTE(pp_threshold_fops, pp_threshold_get, - pp_threshold_set, "%lld\n"); - static int failure_tracking_set(void *data, u64 val) { bool on; @@ -483,6 +357,35 @@ DEFINE_DEBUGFS_ATTRIBUTE(failure_tracking_fops, failure_tracking_get, failure_tracking_set, "%llu\n"); +static int buffer_size_set(void *data, u64 val) +{ + unsigned long flags; + struct captured_pinner *new, *old; + + new = kvmalloc_array(val, sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + spin_lock_irqsave(&pp_buffer.lock, flags); + old = pp_buffer.buffer; + pp_buffer.buffer = new; + pp_buffer.index = 0; + pp_buf_size = val; + spin_unlock_irqrestore(&pp_buffer.lock, flags); + kvfree(old); + + return 0; +} + +static int buffer_size_get(void *data, u64 *val) +{ + *val = pp_buf_size; + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(buffer_size_fops, + buffer_size_get, + buffer_size_set, "%llu\n"); + static int __init page_pinner_init(void) { struct dentry *pp_debugfs_root; @@ -490,23 +393,31 @@ static int __init page_pinner_init(void) if (!static_branch_unlikely(&page_pinner_inited)) return 0; - pr_info("page_pinner enabled\n"); + pp_buffer.buffer = kvmalloc_array(pp_buf_size, sizeof(*pp_buffer.buffer), + GFP_KERNEL); + if (!pp_buffer.buffer) { + pr_info("page_pinner disabled due to \n"); + return 1; + } - pp_debugfs_root = debugfs_create_dir("page_pinner", NULL); + spin_lock_init(&pp_buffer.lock); + pp_buffer.index = 0; - debugfs_create_file("longterm_pinner", 0444, pp_debugfs_root, NULL, - &proc_longterm_pinner_operations); + pr_info("page_pinner enabled\n"); - debugfs_create_file("threshold", 0644, pp_debugfs_root, NULL, - &pp_threshold_fops); + pp_debugfs_root = debugfs_create_dir("page_pinner", NULL); - debugfs_create_file("alloc_contig_failed", 0444, + debugfs_create_file("buffer", 0444, pp_debugfs_root, NULL, - &proc_alloc_contig_failed_operations); + &proc_buffer_operations); debugfs_create_file("failure_tracking", 0644, pp_debugfs_root, NULL, &failure_tracking_fops); + + debugfs_create_file("buffer_size", 0644, + pp_debugfs_root, NULL, + &buffer_size_fops); return 0; } late_initcall(page_pinner_init) diff --git a/mm/rmap.c b/mm/rmap.c index 4fdbda090c2c2..52291f59b0b45 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -72,6 +72,7 @@ #include #include #include +#include #include @@ -782,6 +783,12 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, } if (pvmw.pte) { + if (lru_gen_enabled() && pte_young(*pvmw.pte) && + !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { + lru_gen_look_around(&pvmw); + referenced++; + } + if (ptep_clear_flush_young_notify(vma, address, pvmw.pte)) { /* diff --git a/mm/swap.c b/mm/swap.c index 8d5c61de5a6eb..2f69e44ca7374 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -87,9 +87,8 @@ static void __page_cache_release(struct page *page) spin_lock_irqsave(&pgdat->lru_lock, flags); lruvec = mem_cgroup_page_lruvec(page, pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); spin_unlock_irqrestore(&pgdat->lru_lock, flags); } __ClearPageWaiters(page); @@ -240,9 +239,9 @@ static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec, int *pgmoved = arg; if (PageLRU(page) && !PageUnevictable(page)) { - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); - add_page_to_lru_list_tail(page, lruvec, page_lru(page)); + add_page_to_lru_list_tail(page, lruvec); (*pgmoved) += thp_nr_pages(page); } } @@ -333,13 +332,11 @@ static void __activate_page(struct page *page, struct lruvec *lruvec, void *arg) { if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - int lru = page_lru_base_type(page); int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); SetPageActive(page); - lru += LRU_ACTIVE; - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); trace_mm_lru_activate(page); __count_vm_events(PGACTIVATE, nr_pages); @@ -362,7 +359,7 @@ static bool need_activate_page_drain(int cpu) return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; } -static void activate_page(struct page *page) +void activate_page(struct page *page) { page = compound_head(page); if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { @@ -382,7 +379,7 @@ static inline void activate_page_drain(int cpu) { } -static void activate_page(struct page *page) +void activate_page(struct page *page) { pg_data_t *pgdat = page_pgdat(page); @@ -423,6 +420,43 @@ static void __lru_cache_activate_page(struct page *page) local_unlock(&lru_pvecs.lock); } +#ifdef CONFIG_LRU_GEN +static void page_inc_refs(struct page *page) +{ + unsigned long refs; + unsigned long old_flags, new_flags; + + if (PageUnevictable(page)) + return; + + /* see the comment on MAX_NR_TIERS */ + do { + new_flags = old_flags = READ_ONCE(page->flags); + + if (!(new_flags & BIT(PG_referenced))) { + new_flags |= BIT(PG_referenced); + continue; + } + + if (!(new_flags & BIT(PG_workingset))) { + new_flags |= BIT(PG_workingset); + continue; + } + + refs = new_flags & LRU_REFS_MASK; + refs = min(refs + BIT(LRU_REFS_PGOFF), LRU_REFS_MASK); + + new_flags &= ~LRU_REFS_MASK; + new_flags |= refs; + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); +} +#else +static void page_inc_refs(struct page *page) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Mark a page as having seen activity. * @@ -437,6 +471,11 @@ void mark_page_accessed(struct page *page) { page = compound_head(page); + if (lru_gen_enabled()) { + page_inc_refs(page); + return; + } + if (!PageReferenced(page)) { SetPageReferenced(page); } else if (PageUnevictable(page)) { @@ -480,6 +519,11 @@ void lru_cache_add(struct page *page) VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); VM_BUG_ON_PAGE(PageLRU(page), page); + /* see the comment in lru_gen_add_page() */ + if (lru_gen_enabled() && !PageUnevictable(page) && + lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) + SetPageActive(page); + get_page(page); local_lock(&lru_pvecs.lock); pvec = this_cpu_ptr(&lru_pvecs.lru_add); @@ -542,8 +586,7 @@ void __lru_cache_add_inactive_or_unevictable(struct page *page, static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, void *arg) { - int lru; - bool active; + bool active = PageActive(page); int nr_pages = thp_nr_pages(page); if (!PageLRU(page)) @@ -556,10 +599,7 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, if (page_mapped(page)) return; - active = PageActive(page); - lru = page_lru_base_type(page); - - del_page_from_lru_list(page, lruvec, lru + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); @@ -569,14 +609,14 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, * It can make readahead confusing. But race window * is _really_ small and it's non-critical problem. */ - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); SetPageReclaim(page); } else { /* * The page's writeback ends up during pagevec * We moves tha page into tail of inactive. */ - add_page_to_lru_list_tail(page, lruvec, lru); + add_page_to_lru_list_tail(page, lruvec); __count_vm_events(PGROTATED, nr_pages); } @@ -590,14 +630,13 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, void *arg) { - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { - int lru = page_lru_base_type(page); + if (PageLRU(page) && !PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, lru + LRU_ACTIVE); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); __count_vm_events(PGDEACTIVATE, nr_pages); __count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE, @@ -610,11 +649,9 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, { if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page) && !PageUnevictable(page)) { - bool active = PageActive(page); int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, - LRU_INACTIVE_ANON + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); /* @@ -623,7 +660,7 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, * anonymous pages */ ClearPageSwapBacked(page); - add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list(page, lruvec); __count_vm_events(PGLAZYFREE, nr_pages); __count_memcg_events(lruvec_memcg(lruvec), PGLAZYFREE, @@ -638,16 +675,13 @@ static void lru_lazyfree_movetail_fn(struct page *page, struct lruvec *lruvec, if (PageLRU(page) && !PageUnevictable(page) && PageSwapBacked(page) && !PageSwapCache(page)) { - bool active = PageActive(page); - - del_page_from_lru_list(page, lruvec, - LRU_INACTIVE_ANON + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); if (add_to_tail && *add_to_tail) - add_page_to_lru_list_tail(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list_tail(page, lruvec); else - add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list(page, lruvec); } } @@ -733,7 +767,7 @@ void deactivate_file_page(struct page *page) */ void deactivate_page(struct page *page) { - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { + if (PageLRU(page) && !PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { struct pagevec *pvec; local_lock(&lru_pvecs.lock); @@ -1052,9 +1086,8 @@ void release_pages(struct page **pages, int nr) } lruvec = mem_cgroup_page_lruvec(page, locked_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); } __ClearPageWaiters(page); @@ -1117,8 +1150,7 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, * Put page_tail on the list at the correct position * so they all end up in order. */ - add_page_to_lru_list_tail(page_tail, lruvec, - page_lru(page_tail)); + add_page_to_lru_list_tail(page_tail, lruvec); } } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ @@ -1126,7 +1158,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, void *arg) { - enum lru_list lru; int was_unevictable = TestClearPageUnevictable(page); int nr_pages = thp_nr_pages(page); @@ -1162,19 +1193,17 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, smp_mb__after_atomic(); if (page_evictable(page)) { - lru = page_lru(page); if (was_unevictable) __count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages); } else { - lru = LRU_UNEVICTABLE; ClearPageActive(page); SetPageUnevictable(page); if (!was_unevictable) __count_vm_events(UNEVICTABLE_PGCULLED, nr_pages); } - add_page_to_lru_list(page, lruvec, lru); - trace_mm_lru_insertion(page, lru); + add_page_to_lru_list(page, lruvec); + trace_mm_lru_insertion(page); } /* diff --git a/mm/swap_state.c b/mm/swap_state.c index a8a98bf7c894e..d13d58fe48c1f 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -513,7 +513,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * __read_swap_cache_async(), which has set SWAP_HAS_CACHE * in swap_map, but not yet added its page to swap cache. */ - schedule_timeout_uninterruptible(1); + cond_resched(); } /* @@ -538,7 +538,6 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, workingset_refault(page, shadow); /* Caller will initiate read into locked page */ - SetPageWorkingset(page); lru_cache_add(page); *new_page_allocated = true; return page; diff --git a/mm/usercopy.c b/mm/usercopy.c index 540968b481e7e..b3de3c4eefba7 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -294,10 +294,7 @@ static bool enable_checks __initdata = true; static int __init parse_hardened_usercopy(char *str) { - if (strtobool(str, &enable_checks)) - pr_warn("Invalid option string for hardened_usercopy: '%s'\n", - str); - return 1; + return strtobool(str, &enable_checks); } __setup("hardened_usercopy=", parse_hardened_usercopy); diff --git a/mm/vmscan.c b/mm/vmscan.c index d49cd9cb79e0e..cb1a9b5b0729a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -51,6 +51,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -129,6 +133,13 @@ struct scan_control { /* The file pages on the current node are dangerously low */ unsigned int file_is_tiny:1; +#ifdef CONFIG_LRU_GEN + /* help make better choices when multiple memcgs are available */ + unsigned int memcgs_need_aging:1; + unsigned int memcgs_need_swapping:1; + unsigned int memcgs_avoid_swapping:1; +#endif + /* Allocation order */ s8 order; @@ -931,9 +942,11 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, if (PageSwapCache(page)) { swp_entry_t swap = { .val = page_private(page) }; - mem_cgroup_swapout(page, swap); + + /* get a shadow entry before mem_cgroup_swapout() clears page_memcg() */ if (reclaimed && !mapping_exiting(mapping)) shadow = workingset_eviction(page, target_memcg); + mem_cgroup_swapout(page, swap); __delete_from_swap_cache(page, swap, shadow); xa_unlock_irqrestore(&mapping->i_pages, flags); put_swap_page(page, swap); @@ -1144,6 +1157,11 @@ static unsigned int shrink_page_list(struct list_head *page_list, if (!sc->may_unmap && page_mapped(page)) goto keep_locked; + /* page_update_gen() tried to promote this page? */ + if (lru_gen_enabled() && !ignore_references && + page_mapped(page) && PageReferenced(page)) + goto keep_locked; + may_enter_fs = (sc->gfp_mask & __GFP_FS) || (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); @@ -1837,10 +1855,9 @@ int isolate_lru_page(struct page *page) spin_lock_irq(&pgdat->lru_lock); lruvec = mem_cgroup_page_lruvec(page, pgdat); if (PageLRU(page)) { - int lru = page_lru(page); get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); ret = 0; } spin_unlock_irq(&pgdat->lru_lock); @@ -1912,13 +1929,12 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, int nr_pages, nr_moved = 0; LIST_HEAD(pages_to_free); struct page *page; - enum lru_list lru; while (!list_empty(list)) { page = lru_to_page(list); VM_BUG_ON_PAGE(PageLRU(page), page); + list_del(&page->lru); if (unlikely(!page_evictable(page))) { - list_del(&page->lru); spin_unlock_irq(&pgdat->lru_lock); putback_lru_page(page); spin_lock_irq(&pgdat->lru_lock); @@ -1927,16 +1943,11 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, lruvec = mem_cgroup_page_lruvec(page, pgdat); SetPageLRU(page); - lru = page_lru(page); - - nr_pages = thp_nr_pages(page); - update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); - list_move(&page->lru, &lruvec->lists[lru]); + add_page_to_lru_list(page, lruvec); if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); if (unlikely(PageCompound(page))) { spin_unlock_irq(&pgdat->lru_lock); @@ -1945,6 +1956,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, } else list_add(&page->lru, &pages_to_free); } else { + nr_pages = thp_nr_pages(page); nr_moved += nr_pages; if (PageActive(page)) workingset_age_nonresident(lruvec, nr_pages); @@ -2288,6 +2300,106 @@ enum scan_balance { SCAN_FILE, }; +static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) +{ + unsigned long file; + struct lruvec *target_lruvec; + + if (lru_gen_enabled()) + return; + + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + /* + * Determine the scan balance between anon and file LRUs. + */ + spin_lock_irq(&pgdat->lru_lock); + sc->anon_cost = target_lruvec->anon_cost; + sc->file_cost = target_lruvec->file_cost; + spin_unlock_irq(&pgdat->lru_lock); + + /* + * Target desirable inactive:active list ratios for the anon + * and file LRU lists. + */ + if (!sc->force_deactivate) { + unsigned long refaults; + + refaults = lruvec_page_state(target_lruvec, + WORKINGSET_ACTIVATE_ANON); + if (refaults != target_lruvec->refaults[0] || + inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) + sc->may_deactivate |= DEACTIVATE_ANON; + else + sc->may_deactivate &= ~DEACTIVATE_ANON; + + /* + * When refaults are being observed, it means a new + * workingset is being established. Deactivate to get + * rid of any stale active pages quickly. + */ + refaults = lruvec_page_state(target_lruvec, + WORKINGSET_ACTIVATE_FILE); + if (refaults != target_lruvec->refaults[1] || + inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) + sc->may_deactivate |= DEACTIVATE_FILE; + else + sc->may_deactivate &= ~DEACTIVATE_FILE; + } else + sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; + + /* + * If we have plenty of inactive file pages that aren't + * thrashing, try to reclaim those first before touching + * anonymous pages. + */ + file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); + if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) + sc->cache_trim_mode = 1; + else + sc->cache_trim_mode = 0; + + /* + * Prevent the reclaimer from falling into the cache trap: as + * cache pages start out inactive, every cache fault will tip + * the scan balance towards the file LRU. And as the file LRU + * shrinks, so does the window for rotation from references. + * This means we have a runaway feedback loop where a tiny + * thrashing file LRU becomes infinitely more attractive than + * anon pages. Try to detect this based on file LRU size. + */ + if (!cgroup_reclaim(sc)) { + unsigned long total_high_wmark = 0; + unsigned long free, anon; + int z; + + free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); + file = node_page_state(pgdat, NR_ACTIVE_FILE) + + node_page_state(pgdat, NR_INACTIVE_FILE); + + for (z = 0; z < MAX_NR_ZONES; z++) { + struct zone *zone = &pgdat->node_zones[z]; + + if (!managed_zone(zone)) + continue; + + total_high_wmark += high_wmark_pages(zone); + } + + /* + * Consider anon: if that's low too, this isn't a + * runaway file reclaim problem, but rather just + * extreme pressure. Reclaim as per usual then. + */ + anon = node_page_state(pgdat, NR_INACTIVE_ANON); + + sc->file_is_tiny = + file + free <= total_high_wmark && + !(sc->may_deactivate & DEACTIVATE_ANON) && + anon >> sc->priority; + } +} + /* * Determine how aggressively the anon and file LRU lists should be * scanned. The relative value of each set of LRU lists is determined @@ -2500,158 +2612,2793 @@ out: } } -static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -{ - unsigned long nr[NR_LRU_LISTS]; - unsigned long targets[NR_LRU_LISTS]; - unsigned long nr_to_scan; - enum lru_list lru; - unsigned long nr_reclaimed = 0; - unsigned long nr_to_reclaim = sc->nr_to_reclaim; - struct blk_plug plug; - bool scan_adjusted; +#ifdef CONFIG_LRU_GEN - get_scan_count(lruvec, sc, nr); +#ifdef CONFIG_LRU_GEN_ENABLED +DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); +#else +DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); +#endif - /* Record the original scan target for proportional adjustments later */ - memcpy(targets, nr, sizeof(nr)); +/****************************************************************************** + * shorthand helpers + ******************************************************************************/ - /* - * Global reclaiming within direct reclaim at DEF_PRIORITY is a normal - * event that can occur when there is little memory pressure e.g. - * multiple streaming readers/writers. Hence, we do not abort scanning - * when the requested number of pages are reclaimed when scanning at - * DEF_PRIORITY on the assumption that the fact we are direct - * reclaiming implies that kswapd is not keeping up and it is best to - * do a batch of work at once. For memcg reclaim one check is made to - * abort proportional reclaim if either the file or anon lru has already - * dropped to zero at the first pass. - */ - scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() && - sc->priority == DEF_PRIORITY); +#define DEFINE_MAX_SEQ(lruvec) \ + unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) - blk_start_plug(&plug); - while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || - nr[LRU_INACTIVE_FILE]) { - unsigned long nr_anon, nr_file, percentage; - unsigned long nr_scanned; +#define DEFINE_MIN_SEQ(lruvec) \ + unsigned long min_seq[ANON_AND_FILE] = { \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ + } - for_each_evictable_lru(lru) { - if (nr[lru]) { - nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX); - nr[lru] -= nr_to_scan; +#define for_each_gen_type_zone(gen, type, zone) \ + for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) - nr_reclaimed += shrink_list(lru, nr_to_scan, - lruvec, sc); - } - } +static int page_lru_gen(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); - cond_resched(); + return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} - if (nr_reclaimed < nr_to_reclaim || scan_adjusted) - continue; +static int page_lru_tier(struct page *page) +{ + int refs; + unsigned long flags = READ_ONCE(page->flags); - /* - * For kswapd and memcg, reclaim at least the number of pages - * requested. Ensure that the anon and file LRUs are scanned - * proportionally what was requested by get_scan_count(). We - * stop reclaiming one LRU and reduce the amount scanning - * proportional to the original scan target. - */ - nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; - nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; + refs = (flags & LRU_REFS_FLAGS) == LRU_REFS_FLAGS ? + ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + 1 : 0; - /* - * It's just vindictive to attack the larger once the smaller - * has gone to zero. And given the way we stop scanning the - * smaller below, this makes sure that we only make one nudge - * towards proportionality once we've got nr_to_reclaim. - */ - if (!nr_file || !nr_anon) - break; + return lru_tier_from_refs(refs); +} - if (nr_file > nr_anon) { - unsigned long scan_target = targets[LRU_INACTIVE_ANON] + - targets[LRU_ACTIVE_ANON] + 1; - lru = LRU_BASE; - percentage = nr_anon * 100 / scan_target; - } else { - unsigned long scan_target = targets[LRU_INACTIVE_FILE] + - targets[LRU_ACTIVE_FILE] + 1; - lru = LRU_FILE; - percentage = nr_file * 100 / scan_target; - } +static bool get_cap(int cap) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + return static_branch_likely(&lru_gen_caps[cap]); +#else + return static_branch_unlikely(&lru_gen_caps[cap]); +#endif +} - /* Stop scanning the smaller of the LRU */ - nr[lru] = 0; - nr[lru + LRU_ACTIVE] = 0; +static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) +{ + struct pglist_data *pgdat = NODE_DATA(nid); - /* - * Recalculate the other LRU scan count based on its original - * scan target and the percentage scanning already complete - */ - lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); +#ifdef CONFIG_MEMCG + if (memcg) { + struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; - lru += LRU_ACTIVE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); + /* for hotadd_new_pgdat() */ + if (!lruvec->pgdat) + lruvec->pgdat = pgdat; - scan_adjusted = true; + return lruvec; } - blk_finish_plug(&plug); - sc->nr_reclaimed += nr_reclaimed; +#endif + VM_BUG_ON(!mem_cgroup_disabled()); - /* - * Even if we did not try to evict anon pages at all, we want to - * rebalance the anon lru active/inactive ratio. - */ - if (total_swap_pages && inactive_is_low(lruvec, LRU_INACTIVE_ANON)) - shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); + return pgdat ? &pgdat->__lruvec : NULL; } -/* Use reclaim/compaction for costly allocs or under memory pressure */ -static bool in_reclaim_compaction(struct scan_control *sc) +static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) { - if (IS_ENABLED(CONFIG_COMPACTION) && sc->order && - (sc->order > PAGE_ALLOC_COSTLY_ORDER || - sc->priority < DEF_PRIORITY - 2)) - return true; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); - return false; + if (mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + return 0; + + return mem_cgroup_swappiness(memcg); } -/* - * Reclaim/compaction is used for high-order allocation requests. It reclaims - * order-0 pages before compacting the zone. should_continue_reclaim() returns - * true if more pages should be reclaimed such that when the page allocator - * calls try_to_compact_pages() that it will have enough free pages to succeed. - * It will give up earlier than that if there is difficulty reclaiming pages. - */ -static inline bool should_continue_reclaim(struct pglist_data *pgdat, - unsigned long nr_reclaimed, - struct scan_control *sc) +static int get_nr_gens(struct lruvec *lruvec, int type) { - unsigned long pages_for_compaction; - unsigned long inactive_lru_pages; - int z; + return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; +} - /* If not in reclaim/compaction mode, stop */ - if (!in_reclaim_compaction(sc)) - return false; +static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) +{ + /* see the comment on lru_gen_struct */ + return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && + get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +} - /* - * Stop if we failed to reclaim any pages from the last SWAP_CLUSTER_MAX - * number of pages that were scanned. This will return to the caller - * with the risk reclaim/compaction and the resulting allocation attempt - * fails. In the past we have tried harder for __GFP_RETRY_MAYFAIL - * allocations through requiring that the full LRU list has been scanned - * first, by assuming that zero delta of sc->nr_scanned means full LRU - * scan, but that approximation was wrong, and there were corner cases +/****************************************************************************** + * mm_struct list + ******************************************************************************/ + +static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) +{ + static struct lru_gen_mm_list mm_list = { + .fifo = LIST_HEAD_INIT(mm_list.fifo), + .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), + }; + +#ifdef CONFIG_MEMCG + if (memcg) + return &memcg->mm_list; +#endif + VM_BUG_ON(!mem_cgroup_disabled()); + + return &mm_list; +} + +void lru_gen_add_mm(struct mm_struct *mm) +{ + int nid; + struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + + VM_BUG_ON_MM(!list_empty(&mm->lru_gen.list), mm); +#ifdef CONFIG_MEMCG + VM_BUG_ON_MM(mm->lru_gen.memcg, mm); + mm->lru_gen.memcg = memcg; +#endif + spin_lock(&mm_list->lock); + + for_each_node_state(nid, N_MEMORY) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm_list->fifo) + lruvec->mm_state.tail = &mm->lru_gen.list; + } + + list_add_tail(&mm->lru_gen.list, &mm_list->fifo); + + spin_unlock(&mm_list->lock); +} + +void lru_gen_del_mm(struct mm_struct *mm) +{ + int nid; + struct lru_gen_mm_list *mm_list; + struct mem_cgroup *memcg = NULL; + + if (list_empty(&mm->lru_gen.list)) + return; + +#ifdef CONFIG_MEMCG + memcg = mm->lru_gen.memcg; +#endif + mm_list = get_mm_list(memcg); + + spin_lock(&mm_list->lock); + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm->lru_gen.list) + lruvec->mm_state.tail = lruvec->mm_state.tail->next; + + if (lruvec->mm_state.head != &mm->lru_gen.list) + continue; + + lruvec->mm_state.head = lruvec->mm_state.head->next; + if (lruvec->mm_state.head == &mm_list->fifo) + WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); + } + + list_del_init(&mm->lru_gen.list); + + spin_unlock(&mm_list->lock); + +#ifdef CONFIG_MEMCG + mem_cgroup_put(mm->lru_gen.memcg); + mm->lru_gen.memcg = NULL; +#endif +} + +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm) +{ + struct mem_cgroup *memcg; + + lockdep_assert_held(&mm->owner->alloc_lock); + + /* for mm_update_next_owner() */ + if (mem_cgroup_disabled()) + return; + + rcu_read_lock(); + memcg = mem_cgroup_from_task(mm->owner); + rcu_read_unlock(); + if (memcg == mm->lru_gen.memcg) + return; + + VM_BUG_ON_MM(!mm->lru_gen.memcg, mm); + VM_BUG_ON_MM(list_empty(&mm->lru_gen.list), mm); + + lru_gen_del_mm(mm); + lru_gen_add_mm(mm); +} +#endif + +/* + * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when + * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of + * bits in a bitmap, k is the number of hash functions and n is the number of + * inserted items. + * + * Page table walkers use one of the two filters to reduce their search space. + * To get rid of non-leaf entries that no longer have enough leaf entries, the + * aging uses the double-buffering technique to flip to the other filter each + * time it produces a new generation. For non-leaf entries that have enough + * leaf entries, the aging carries them over to the next generation in + * walk_pmd_range(); the eviction also report them when walking the rmap + * in lru_gen_look_around(). + * + * For future optimizations: + * 1. It's not necessary to keep both filters all the time. The spare one can be + * freed after the RCU grace period and reallocated if needed again. + * 2. And when reallocating, it's worth scaling its size according to the number + * of inserted entries in the other filter, to reduce the memory overhead on + * small systems and false positives on large systems. + * 3. Jenkins' hash function is an alternative to Knuth's. + */ +#define BLOOM_FILTER_SHIFT 15 + +static inline int filter_gen_from_seq(unsigned long seq) +{ + return seq % NR_BLOOM_FILTERS; +} + +static void get_item_key(void *item, int *key) +{ + u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); + + BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); + + key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); + key[1] = hash >> BLOOM_FILTER_SHIFT; +} + +static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) +{ + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + filter = lruvec->mm_state.filters[gen]; + if (filter) { + bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); + return; + } + + filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), GFP_ATOMIC); + WRITE_ONCE(lruvec->mm_state.filters[gen], filter); +} + +static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return; + + get_item_key(item, key); + + if (!test_bit(key[0], filter)) + set_bit(key[0], filter); + if (!test_bit(key[1], filter)) + set_bit(key[1], filter); +} + +static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return true; + + get_item_key(item, key); + + return test_bit(key[0], filter) && test_bit(key[1], filter); +} + +static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) +{ + int i; + int hist; + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + if (walk) { + hist = lru_hist_from_seq(walk->max_seq); + + for (i = 0; i < NR_MM_STATS; i++) { + WRITE_ONCE(lruvec->mm_state.stats[hist][i], + lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); + walk->mm_stats[i] = 0; + } + } + + if (NR_HIST_GENS > 1 && last) { + hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); + + for (i = 0; i < NR_MM_STATS; i++) + WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); + } +} + +static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + int type; + unsigned long size = 0; + struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); + + if (!walk->full_scan && cpumask_empty(mm_cpumask(mm)) && + !node_isset(pgdat->node_id, mm->lru_gen.nodes)) + return true; + + node_clear(pgdat->node_id, mm->lru_gen.nodes); + + for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { + size += type ? get_mm_counter(mm, MM_FILEPAGES) : + get_mm_counter(mm, MM_ANONPAGES) + + get_mm_counter(mm, MM_SHMEMPAGES); + } + + if (size < MIN_LRU_BATCH) + return true; + + if (mm_is_oom_victim(mm)) + return true; + + return !mmget_not_zero(mm); +} + +static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, + struct mm_struct **iter) +{ + bool first = false; + bool last = true; + struct mm_struct *mm = NULL; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + /* + * There are four interesting cases for this page table walker: + * 1. It tries to start a new iteration of mm_list with a stale max_seq; + * there is nothing to be done. + * 2. It's the first of the current generation, and it needs to reset + * the Bloom filter for the next generation. + * 3. It reaches the end of mm_list, and it needs to increment + * mm_state->seq; the iteration is done. + * 4. It's the last of the current generation, and it needs to reset the + * mm stats counters for the next generation. + */ + if (*iter) + mmput_async(*iter); + else if (walk->max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < walk->max_seq); + VM_BUG_ON(*iter && mm_state->seq > walk->max_seq); + VM_BUG_ON(*iter && !mm_state->nr_walkers); + + if (walk->max_seq <= mm_state->seq) { + if (!*iter) + last = false; + goto done; + } + + if (!mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + mm_state->head = mm_list->fifo.next; + first = true; + } + + while (!mm && mm_state->head != &mm_list->fifo) { + mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + + mm_state->head = mm_state->head->next; + + /* full scan for those added after the last iteration */ + if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { + mm_state->tail = mm_state->head; + walk->full_scan = true; + } + + if (should_skip_mm(mm, walk)) + mm = NULL; + } + + if (mm_state->head == &mm_list->fifo) + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); +done: + if (*iter && !mm) + mm_state->nr_walkers--; + if (!*iter && mm) + mm_state->nr_walkers++; + + if (mm_state->nr_walkers) + last = false; + + if (mm && first) + reset_bloom_filter(lruvec, walk->max_seq + 1); + + if (*iter || last) + reset_mm_stats(lruvec, walk, last); + + spin_unlock(&mm_list->lock); + + *iter = mm; + + return last; +} + +static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) +{ + bool success = false; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + if (max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < max_seq); + + if (max_seq > mm_state->seq && !mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); + reset_mm_stats(lruvec, NULL, true); + success = true; + } + + spin_unlock(&mm_list->lock); + + return success; +} + +/****************************************************************************** + * refault feedback loop + ******************************************************************************/ + +/* + * A feedback loop based on Proportional-Integral-Derivative (PID) controller. + * + * The P term is refaulted/(evicted+protected) from a tier in the generation + * currently being evicted; the I term is the exponential moving average of the + * P term over the generations previously evicted, using the smoothing factor + * 1/2; the D term isn't supported. + * + * The setpoint (SP) is always the first tier of one type; the process variable + * (PV) is either any tier of the other type or any other tier of the same + * type. + * + * The error is the difference between the SP and the PV; the correction is + * turn off protection when SP>PV or turn on protection when SPlrugen; + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + pos->refaulted = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + pos->total = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + pos->total += lrugen->protected[hist][type][tier - 1]; + pos->gain = gain; +} + +static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) +{ + int hist, tier; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; + unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; + + lockdep_assert_held(&lruvec_pgdat(lruvec)->lru_lock); + + if (!carryover && !clear) + return; + + hist = lru_hist_from_seq(seq); + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + if (carryover) { + unsigned long sum; + + sum = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); + + sum = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + sum += lrugen->protected[hist][type][tier - 1]; + WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); + } + + if (clear) { + atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); + atomic_long_set(&lrugen->evicted[hist][type][tier], 0); + if (tier) + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); + } + } +} + +static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) +{ + /* + * Return true if the PV has a limited number of refaults or a lower + * refaulted/total than the SP. + */ + return pv->refaulted < MIN_LRU_BATCH || + pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= + (sp->refaulted + 1) * pv->total * pv->gain; +} + +/****************************************************************************** + * the aging + ******************************************************************************/ + +static int page_update_gen(struct page *page, int gen) +{ + unsigned long old_flags, new_flags; + + VM_BUG_ON(gen >= MAX_NR_GENS); + VM_BUG_ON(!rcu_read_lock_held()); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + + /* for shrink_page_list() */ + if (!(new_flags & LRU_GEN_MASK)) { + new_flags |= BIT(PG_referenced); + continue; + } + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} + +static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + unsigned long old_flags, new_flags; + int type = page_is_file_lru(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(!(new_flags & LRU_GEN_MASK), page); + + new_gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + /* page_update_gen() has promoted this page? */ + if (new_gen >= 0 && new_gen != old_gen) + return new_gen; + + new_gen = (old_gen + 1) % MAX_NR_GENS; + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for end_page_writeback() */ + if (reclaiming) + new_flags |= BIT(PG_reclaim); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, old_gen, new_gen); + + return new_gen; +} + +static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + + VM_BUG_ON(old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen >= MAX_NR_GENS); + + walk->batched++; + + walk->nr_pages[old_gen][type][zone] -= delta; + walk->nr_pages[new_gen][type][zone] += delta; +} + +static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) +{ + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + walk->batched = 0; + + for_each_gen_type_zone(gen, type, zone) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + int delta = walk->nr_pages[gen][type][zone]; + + if (!delta) + continue; + + walk->nr_pages[gen][type][zone] = 0; + WRITE_ONCE(lrugen->nr_pages[gen][type][zone], + lrugen->nr_pages[gen][type][zone] + delta); + + if (lru_gen_is_active(lruvec, gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, delta); + } +} + +static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *walk) +{ + struct address_space *mapping; + struct vm_area_struct *vma = walk->vma; + struct lru_gen_mm_walk *priv = walk->private; + + if (!vma_is_accessible(vma) || is_vm_hugetlb_page(vma) || + (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) || + vma == get_gate_vma(vma->vm_mm)) + return true; + + if (vma_is_anonymous(vma)) + return !priv->can_swap; + + if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) + return true; + + mapping = vma->vm_file->f_mapping; + if (mapping_unevictable(mapping)) + return true; + + /* check readpage to exclude special mappings like dax, etc. */ + return shmem_mapping(mapping) ? !priv->can_swap : !mapping->a_ops->readpage; +} + +/* + * Some userspace memory allocators map many single-page VMAs. Instead of + * returning back to the PGD table for each of such VMAs, finish an entire PMD + * table to reduce zigzags and improve cache performance. + */ +static bool get_next_vma(struct mm_walk *walk, unsigned long mask, unsigned long size, + unsigned long *start, unsigned long *end) +{ + unsigned long next = round_up(*end, size); + + VM_BUG_ON(mask & size); + VM_BUG_ON(*start >= *end); + VM_BUG_ON((next & mask) != (*start & mask)); + + while (walk->vma) { + if (next >= walk->vma->vm_end) { + walk->vma = walk->vma->vm_next; + continue; + } + + if ((next & mask) != (walk->vma->vm_start & mask)) + return false; + + if (should_skip_vma(walk->vma->vm_start, walk->vma->vm_end, walk)) { + walk->vma = walk->vma->vm_next; + continue; + } + + *start = max(next, walk->vma->vm_start); + next = (next | ~mask) + 1; + /* rounded-up boundaries can wrap to 0 */ + *end = next && next < walk->vma->vm_end ? next : walk->vma->vm_end; + + return true; + } + + return false; +} + +static bool suitable_to_scan(int total, int young) +{ + int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); + + /* suitable if the average number of young PTEs per cacheline is >=1 */ + return young * n >= total; +} + +static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pte_t *pte; + spinlock_t *ptl; + unsigned long addr; + int total = 0; + int young = 0; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pmd_leaf(*pmd)); + + ptl = pte_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + return false; + + arch_enter_lazy_mmu_mode(); + + pte = pte_offset_map(pmd, start & PMD_MASK); +restart: + for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { + struct page *page; + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < walk->vma->vm_start || addr >= walk->vma->vm_end); + + total++; + priv->mm_stats[MM_PTE_TOTAL]++; + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(walk->vma, addr, pte + i)) + continue; + + young++; + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); + } + + if (i < PTRS_PER_PTE && get_next_vma(walk, PMD_MASK, PAGE_SIZE, &start, &end)) + goto restart; + + pte_unmap(pte); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); + + return suitable_to_scan(total, young); +} + +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ + int i; + pmd_t *pmd; + spinlock_t *ptl; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pud_leaf(*pud)); + + /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ + if (*start == -1) { + *start = next; + return; + } + + i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); + if (i && i <= MIN_LRU_BATCH) { + __set_bit(i - 1, priv->bitmap); + return; + } + + pmd = pmd_offset(pud, *start); + + ptl = pmd_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + goto done; + + arch_enter_lazy_mmu_mode(); + + do { + struct page *page; + unsigned long pfn = pmd_pfn(pmd[i]); + unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; + + VM_BUG_ON(addr < vma->vm_start || addr >= vma->vm_end); + + if (!pmd_present(pmd[i]) || is_huge_zero_pmd(pmd[i])) + goto next; + + if (WARN_ON_ONCE(pmd_devmap(pmd[i]))) + goto next; + + if (!pmd_trans_huge(pmd[i])) { + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && + get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + goto next; + + page = pfn_to_page(pfn); + VM_BUG_ON_PAGE(PageTail(page), page); + if (page_to_nid(page) != pgdat->node_id) + goto next; + + if (page_memcg_rcu(page) != memcg) + goto next; + + if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) + goto next; + + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pmd_dirty(pmd[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); +next: + i = i > MIN_LRU_BATCH ? 0 : + find_next_bit(priv->bitmap, MIN_LRU_BATCH, i) + 1; + } while (i <= MIN_LRU_BATCH); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); +done: + *start = -1; + bitmap_zero(priv->bitmap, MIN_LRU_BATCH); +} +#else +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ +} +#endif + +static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pmd_t *pmd; + unsigned long next; + unsigned long addr; + struct vm_area_struct *vma; + unsigned long pos = -1; + struct lru_gen_mm_walk *priv = walk->private; + + VM_BUG_ON(pud_leaf(*pud)); + + /* + * Finish an entire PMD in two passes: the first only reaches to PTE + * tables to avoid taking the PMD lock; the second, if necessary, takes + * the PMD lock to clear the accessed bit in PMD entries. + */ + pmd = pmd_offset(pud, start & PUD_MASK); +restart: + /* walk_pte_range() may call get_next_vma() */ + vma = walk->vma; + for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { + pmd_t val = pmd_read_atomic(pmd + i); + + /* for pmd_read_atomic() */ + barrier(); + + next = pmd_addr_end(addr, end); + + if (!pmd_present(val)) { + priv->mm_stats[MM_PTE_TOTAL]++; + continue; + } + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_trans_huge(val)) { + unsigned long pfn = pmd_pfn(val); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + + priv->mm_stats[MM_PTE_TOTAL]++; + + if (is_huge_zero_pmd(val)) + continue; + + if (!pmd_young(val)) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + continue; + } +#endif + priv->mm_stats[MM_PMD_TOTAL]++; + +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG + if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + } +#endif + if (!priv->full_scan && !test_bloom_filter(priv->lruvec, priv->max_seq, pmd + i)) + continue; + + priv->mm_stats[MM_PMD_FOUND]++; + + if (!walk_pte_range(&val, addr, next, walk)) + continue; + + priv->mm_stats[MM_PMD_ADDED]++; + + /* carry over to the next generation */ + update_bloom_filter(priv->lruvec, priv->max_seq + 1, pmd + i); + } + + walk_pmd_range_locked(pud, -1, vma, walk, &pos); + + if (i < PTRS_PER_PMD && get_next_vma(walk, PUD_MASK, PMD_SIZE, &start, &end)) + goto restart; +} + +static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pud_t *pud; + unsigned long addr; + unsigned long next; + struct lru_gen_mm_walk *priv = walk->private; + + VM_BUG_ON(p4d_leaf(*p4d)); + + pud = pud_offset(p4d, start & P4D_MASK); +restart: + for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { + pud_t val = READ_ONCE(pud[i]); + + next = pud_addr_end(addr, end); + + if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) + continue; + + walk_pmd_range(&val, addr, next, walk); + + if (priv->batched >= MAX_LRU_BATCH) { + end = (addr | ~PUD_MASK) + 1; + goto done; + } + } + + if (i < PTRS_PER_PUD && get_next_vma(walk, P4D_MASK, PUD_SIZE, &start, &end)) + goto restart; + + end = round_up(end, P4D_SIZE); +done: + /* rounded-up boundaries can wrap to 0 */ + priv->next_addr = end && walk->vma ? max(end, walk->vma->vm_start) : 0; + + return -EAGAIN; +} + +static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + static const struct mm_walk_ops mm_walk_ops = { + .test_walk = should_skip_vma, + .p4d_entry = walk_pud_range, + }; + + int err; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + walk->next_addr = FIRST_USER_ADDRESS; + + do { + err = -EBUSY; + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + break; + + /* the caller might be holding the lock for write */ + if (mmap_read_trylock(mm)) { + unsigned long start = walk->next_addr; + unsigned long end = mm->highest_vm_end; + + err = walk_page_range(mm, start, end, &mm_walk_ops, walk); + + mmap_read_unlock(mm); + + if (walk->batched) { + spin_lock_irq(&pgdat->lru_lock); + reset_batch_size(lruvec, walk); + spin_unlock_irq(&pgdat->lru_lock); + } + } + + mem_cgroup_unlock_pages(); + + cond_resched(); + } while (err == -EAGAIN && walk->next_addr && !mm_is_oom_victim(mm)); +} + +static struct lru_gen_mm_walk *alloc_mm_walk(void) +{ + if (current->reclaim_state && current->reclaim_state->mm_walk) + return current->reclaim_state->mm_walk; + + return kzalloc(sizeof(struct lru_gen_mm_walk), + __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +} + +static void free_mm_walk(struct lru_gen_mm_walk *walk) +{ + if (!current->reclaim_state || !current->reclaim_state->mm_walk) + kfree(walk); +} + +static void inc_min_seq(struct lruvec *lruvec) +{ + int type; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = 0; type < ANON_AND_FILE; type++) { + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); + } +} + +static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +{ + int gen, type, zone; + bool success = false; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { + gen = lru_gen_from_seq(min_seq[type]); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + goto next; + } + + min_seq[type]++; + } +next: + ; + } + + /* see the comment on lru_gen_struct */ + if (can_swap) { + min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); + min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); + } + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + if (min_seq[type] == lrugen->min_seq[type]) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); + success = true; + } + + return success; +} + +static void inc_max_seq(struct lruvec *lruvec) +{ + int prev, next; + int type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + inc_min_seq(lruvec); + + /* + * Update the active/inactive LRU sizes for compatibility. Both sides of + * the current max_seq need to be covered, since max_seq+1 can overlap + * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do + * overlap, cold/hot inversion happens. This can be solved by moving + * pages from min_seq to min_seq+1 but is omitted for simplicity. + */ + prev = lru_gen_from_seq(lrugen->max_seq - 1); + next = lru_gen_from_seq(lrugen->max_seq + 1); + + for (type = 0; type < ANON_AND_FILE; type++) { + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + long delta = lrugen->nr_pages[prev][type][zone] - + lrugen->nr_pages[next][type][zone]; + + if (!delta) + continue; + + WARN_ON_ONCE(delta != (int)delta); + + __update_lru_size(lruvec, lru, zone, delta); + __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); + } + } + + for (type = 0; type < ANON_AND_FILE; type++) + reset_ctrl_pos(lruvec, type, false); + + WRITE_ONCE(lrugen->timestamps[next], jiffies); + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); + + spin_unlock_irq(&pgdat->lru_lock); +} + +static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + struct scan_control *sc, bool can_swap, bool full_scan) +{ + bool success; + struct lru_gen_mm_walk *walk; + struct mm_struct *mm = NULL; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(max_seq > READ_ONCE(lrugen->max_seq)); + + /* + * If the hardware doesn't automatically set the accessed bit, fallback + * to lru_gen_look_around(), which only clears the accessed bit in a + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ + if (!full_scan && (!arch_has_hw_pte_young() || !get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk = alloc_mm_walk(); + if (!walk) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk->lruvec = lruvec; + walk->max_seq = max_seq; + walk->can_swap = can_swap; + walk->full_scan = full_scan; + + do { + success = iterate_mm_list(lruvec, walk, &mm); + if (mm) + walk_mm(lruvec, mm, walk); + + cond_resched(); + } while (mm); + + free_mm_walk(walk); +done: + if (!success) { + if (!current_is_kswapd() && !sc->priority) + wait_event_killable(lruvec->mm_state.wait, + max_seq < READ_ONCE(lrugen->max_seq)); + + return max_seq < READ_ONCE(lrugen->max_seq); + } + + VM_BUG_ON(max_seq != READ_ONCE(lrugen->max_seq)); + + inc_max_seq(lruvec); + /* either this sees any waiters or they will see updated max_seq */ + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); + + wakeup_flusher_threads(WB_REASON_VMSCAN); + + return true; +} + +static long get_nr_evictable(struct lruvec *lruvec, unsigned long max_seq, + unsigned long *min_seq, bool can_swap, bool *need_aging) +{ + int gen, type, zone; + long old = 0; + long young = 0; + long total = 0; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + unsigned long seq; + + for (seq = min_seq[type]; seq <= max_seq; seq++) { + long size = 0; + + gen = lru_gen_from_seq(seq); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + total += size; + if (seq == max_seq) + young += size; + if (seq + MIN_NR_GENS == max_seq) + old += size; + } + } + + /* + * The aging and the eviction is a typical producer-consumer model. The + * aging tries to be lazy to reduce the unnecessary overhead. On the + * other hand, the eviction stalls when the number of generations + * reaches MIN_NR_GENS. So ideally, there should be MIN_NR_GENS+1 + * generations, hence the first two if's. + * + * In addition, it's ideal to spread pages out evenly, meaning + * 1/(MIN_NR_GENS+1) of the total number of pages for each generation. A + * reasonable range for this average portion would [1/MIN_NR_GENS, + * 1/(MIN_NR_GENS+2)]. From the consumer's POV, the eviction only cares + * about the lower bound of cold pages, i.e., 1/(MIN_NR_GENS+2), whereas + * from the producer's POV, the aging only cares about the upper bound + * of hot pages, i.e., 1/MIN_NR_GENS. + */ + if (min_seq[LRU_GEN_FILE] + MIN_NR_GENS > max_seq) + *need_aging = true; + else if (min_seq[LRU_GEN_FILE] + MIN_NR_GENS < max_seq) + *need_aging = false; + else if (young * MIN_NR_GENS > total) + *need_aging = true; + else if (old * (MIN_NR_GENS + 2) < total) + *need_aging = true; + else + *need_aging = false; + + return total > 0 ? total : 0; +} + +static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, + unsigned long min_ttl) +{ + bool need_aging; + long nr_to_scan; + int swappiness = get_swappiness(lruvec, sc); + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (min_ttl) { + int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + if (time_is_after_jiffies(birth + min_ttl)) + return false; + } + + mem_cgroup_calculate_protection(NULL, memcg); + + if (mem_cgroup_below_min(memcg)) + return false; + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, swappiness, &need_aging); + if (!nr_to_scan) + return false; + + nr_to_scan >>= sc->priority; + + if (!mem_cgroup_online(memcg)) + nr_to_scan++; + + if (nr_to_scan && need_aging && (!mem_cgroup_below_low(memcg) || sc->memcg_low_reclaim)) + try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); + + return true; +} + +/* to protect the working set of the last N jiffies */ +static unsigned long lru_gen_min_ttl __read_mostly; + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ + struct mem_cgroup *memcg; + bool success = false; + unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_BUG_ON(!current_is_kswapd()); + + /* + * To reduce the chance of going into the aging path or swapping, which + * can be costly, optimistically skip them unless their corresponding + * flags were cleared in the eviction path. This improves the overall + * performance when multiple memcgs are available. + */ + if (!sc->memcgs_need_aging) { + sc->memcgs_need_aging = true; + sc->memcgs_avoid_swapping = !sc->memcgs_need_swapping; + sc->memcgs_need_swapping = true; + return; + } + + sc->memcgs_need_swapping = true; + sc->memcgs_avoid_swapping = true; + + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + + if (age_lruvec(lruvec, sc, min_ttl)) + success = true; + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + current->reclaim_state->mm_walk = NULL; + + /* + * The main goal is to OOM kill if every generation from all memcgs is + * younger than min_ttl. However, another theoretical possibility is all + * memcgs are either below min or empty. + */ + if (!success && mutex_trylock(&oom_lock)) { + struct oom_control oc = { + .gfp_mask = sc->gfp_mask, + .order = sc->order, + }; + + out_of_memory(&oc); + + mutex_unlock(&oom_lock); + } +} + +/* + * This function exploits spatial locality when shrink_page_list() walks the + * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. + * If the scan was done cacheline efficiently, it adds the PMD entry pointing + * to the PTE table to the Bloom filter. This process is a feedback loop from + * the eviction to the aging. + */ +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ + int i; + pte_t *pte; + unsigned long start; + unsigned long end; + unsigned long addr; + struct page *page; + struct lru_gen_mm_walk *walk; + int young = 0; + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + struct mem_cgroup *memcg = page_memcg(pvmw->page); + struct pglist_data *pgdat = page_pgdat(pvmw->page); + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + DEFINE_MAX_SEQ(lruvec); + int old_gen, new_gen = lru_gen_from_seq(max_seq); + + lockdep_assert_held(pvmw->ptl); + VM_BUG_ON_PAGE(PageLRU(pvmw->page), pvmw->page); + + if (spin_is_contended(pvmw->ptl)) + return; + + start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); + end = pmd_addr_end(pvmw->address, pvmw->vma->vm_end); + + if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { + if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) + end = start + MIN_LRU_BATCH * PAGE_SIZE; + else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) + start = end - MIN_LRU_BATCH * PAGE_SIZE; + else { + start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; + end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; + } + } + + pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; + + rcu_read_lock(); + arch_enter_lazy_mmu_mode(); + + for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < pvmw->vma->vm_start || addr >= pvmw->vma->vm_end); + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) + continue; + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) + continue; + + young++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_lru_gen(page); + if (old_gen < 0) + SetPageReferenced(page); + else if (old_gen != new_gen) + __set_bit(i, bitmap); + } + + arch_leave_lazy_mmu_mode(); + rcu_read_unlock(); + + /* feedback from rmap walkers to page table walkers */ + if (suitable_to_scan(i, young)) + update_bloom_filter(lruvec, max_seq, pvmw->pmd); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + + if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) + activate_page(pte_page(pte[i])); + return; + } + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + return; + + if (!walk) { + spin_lock_irq(&pgdat->lru_lock); + new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); + } + + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = compound_head(pte_page(pte[i])); + if (page_memcg_rcu(page) != memcg) + continue; + + old_gen = page_update_gen(page, new_gen); + if (old_gen < 0 || old_gen == new_gen) + continue; + + if (walk) + update_batch_size(walk, page, old_gen, new_gen); + else + lru_gen_update_size(lruvec, page, old_gen, new_gen); + } + + if (!walk) + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_unlock_pages(); +} + +/****************************************************************************** + * the eviction + ******************************************************************************/ + +static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +{ + bool success; + int gen = page_lru_gen(page); + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int tier = page_lru_tier(page); + int delta = thp_nr_pages(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON_PAGE(gen >= MAX_NR_GENS, page); + + if (!page_evictable(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageUnevictable(page); + add_page_to_lru_list(page, lruvec); + __count_vm_events(UNEVICTABLE_PGCULLED, delta); + return true; + } + + if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageSwapBacked(page); + add_page_to_lru_list_tail(page, lruvec); + return true; + } + + if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + if (tier > tier_idx) { + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + gen = page_inc_gen(lruvec, page, false); + list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); + + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], + lrugen->protected[hist][type][tier - 1] + delta); + __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); + return true; + } + + if (PageLocked(page) || PageWriteback(page) || + (type == LRU_GEN_FILE && PageDirty(page))) { + gen = page_inc_gen(lruvec, page, true); + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + return false; +} + +static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) +{ + bool success; + + if (!sc->may_unmap && page_mapped(page)) + return false; + + if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && + (PageDirty(page) || (PageAnon(page) && !PageSwapCache(page)))) + return false; + + if (!get_page_unless_zero(page)) + return false; + + ClearPageLRU(page); + + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + + return true; +} + +static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + int type, int tier, struct list_head *list) +{ + int gen, zone; + enum vm_event_item item; + int sorted = 0; + int scanned = 0; + int isolated = 0; + int remaining = MAX_LRU_BATCH; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + VM_BUG_ON(!list_empty(list)); + + if (get_nr_gens(lruvec, type) == MIN_NR_GENS) + return 0; + + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + for (zone = sc->reclaim_idx; zone >= 0; zone--) { + LIST_HEAD(moved); + int skipped = 0; + struct list_head *head = &lrugen->lists[gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); + int delta = thp_nr_pages(page); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + scanned += delta; + + if (sort_page(lruvec, page, tier)) + sorted += delta; + else if (isolate_page(lruvec, page, sc)) { + list_add(&page->lru, list); + isolated += delta; + } else { + list_move(&page->lru, &moved); + skipped += delta; + } + + if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) + break; + } + + if (skipped) { + list_splice(&moved, head); + __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); + } + + if (!remaining || isolated >= MIN_LRU_BATCH) + break; + } + + item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; + if (!cgroup_reclaim(sc)) { + __count_vm_events(item, isolated); + __count_vm_events(PGREFILL, sorted); + } + __count_memcg_events(memcg, item, isolated); + __count_memcg_events(memcg, PGREFILL, sorted); + __count_vm_events(PGSCAN_ANON + type, isolated); + + /* + * There might not be eligible pages due to reclaim_idx, may_unmap and + * may_writepage. Check the remaining to prevent livelock if there is no + * progress. + */ + return isolated || !remaining ? scanned : 0; +} + +static int get_tier_idx(struct lruvec *lruvec, int type) +{ + int tier; + struct ctrl_pos sp, pv; + + /* + * To leave a margin for fluctuations, use a larger gain factor (1:2). + * This value is chosen because any other tier would have at least twice + * as many refaults as the first tier. + */ + read_ctrl_pos(lruvec, type, 0, 1, &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, 2, &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + return tier - 1; +} + +static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) +{ + int type, tier; + struct ctrl_pos sp, pv; + int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; + + /* + * Compare the first tier of anon with that of file to determine which + * type to scan. Also need to compare other tiers of the selected type + * with the first tier of the other type to determine the last tier (of + * the selected type) to evict. + */ + read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); + read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); + type = positive_ctrl_err(&sp, &pv); + + read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, gain[type], &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + *tier_idx = tier - 1; + + return type; +} + +static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + int *type_scanned, struct list_head *list) +{ + int i; + int type; + int scanned; + int tier = -1; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + /* + * Try to make the obvious choice first. When anon and file are both + * available from the same generation, interpret swappiness 1 as file + * first and 200 as anon first. + */ + if (!swappiness) + type = LRU_GEN_FILE; + else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) + type = LRU_GEN_ANON; + else if (swappiness == 1) + type = LRU_GEN_FILE; + else if (swappiness == 200) + type = LRU_GEN_ANON; + else + type = get_type_to_scan(lruvec, swappiness, &tier); + + for (i = !swappiness; i < ANON_AND_FILE; i++) { + if (tier < 0) + tier = get_tier_idx(lruvec, type); + + scanned = scan_pages(lruvec, sc, type, tier, list); + if (scanned) + break; + + type = !type; + tier = -1; + } + + *type_scanned = type; + + return scanned; +} + +static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + bool *swapped) +{ + int type; + int scanned; + int reclaimed; + LIST_HEAD(list); + struct page *page; + enum vm_event_item item; + struct reclaim_stat stat; + struct lru_gen_mm_walk *walk; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); + + if (try_to_inc_min_seq(lruvec, swappiness)) + scanned++; + + if (get_nr_gens(lruvec, LRU_GEN_FILE) == MIN_NR_GENS) + scanned = 0; + + spin_unlock_irq(&pgdat->lru_lock); + + if (list_empty(&list)) + return scanned; + + reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); + + /* + * To avoid livelock, don't add rejected pages back to the same lists + * they were isolated from. See lru_gen_add_page(). + */ + list_for_each_entry(page, &list, lru) { + ClearPageReferenced(page); + ClearPageWorkingset(page); + + if (PageReclaim(page) && (PageDirty(page) || PageWriteback(page))) + ClearPageActive(page); + else + SetPageActive(page); + } + + spin_lock_irq(&pgdat->lru_lock); + + move_pages_to_lru(lruvec, &list); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + if (walk && walk->batched) + reset_batch_size(lruvec, walk); + + item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; + if (!cgroup_reclaim(sc)) + __count_vm_events(item, reclaimed); + __count_memcg_events(memcg, item, reclaimed); + __count_vm_events(PGSTEAL_ANON + type, reclaimed); + + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_uncharge_list(&list); + free_unref_page_list(&list); + + sc->nr_reclaimed += reclaimed; + + if (type == LRU_GEN_ANON && swapped) + *swapped = true; + + return scanned; +} + +static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap) +{ + bool need_aging; + long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (mem_cgroup_below_min(memcg) || + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, can_swap, &need_aging); + if (!nr_to_scan) + return 0; + + /* reset the priority if the target has been met */ + nr_to_scan >>= sc->nr_reclaimed < sc->nr_to_reclaim ? sc->priority : DEF_PRIORITY; + + if (!mem_cgroup_online(memcg)) + nr_to_scan++; + + if (!nr_to_scan) + return 0; + + if (!need_aging) { + sc->memcgs_need_aging = false; + return nr_to_scan; + } + + /* leave the work to lru_gen_age_node() */ + if (current_is_kswapd()) + return 0; + + /* try other memcgs before going to the aging path */ + if (!cgroup_reclaim(sc) && !sc->force_deactivate) { + sc->skipped_deactivate = true; + return 0; + } + + if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) + return nr_to_scan; + + return min_seq[LRU_GEN_FILE] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ + struct blk_plug plug; + long scanned = 0; + bool swapped = false; + unsigned long reclaimed = sc->nr_reclaimed; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + lru_add_drain(); + + blk_start_plug(&plug); + + if (current_is_kswapd()) + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + while (true) { + int delta; + int swappiness; + long nr_to_scan; + + if (sc->may_swap) + swappiness = get_swappiness(lruvec, sc); + else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) + swappiness = 1; + else + swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (!nr_to_scan) + break; + + delta = evict_pages(lruvec, sc, swappiness, &swapped); + if (!delta) + break; + + if (sc->memcgs_avoid_swapping && swappiness < 200 && swapped) + break; + + scanned += delta; + if (scanned >= nr_to_scan) { + if (!swapped && sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH) + sc->memcgs_need_swapping = false; + break; + } + + cond_resched(); + } + + if (current_is_kswapd()) + current->reclaim_state->mm_walk = NULL; + + blk_finish_plug(&plug); +} + +/****************************************************************************** + * state change + ******************************************************************************/ + +static bool __maybe_unused state_is_valid(struct lruvec *lruvec) +{ + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (lrugen->enabled) { + enum lru_list lru; + + for_each_evictable_lru(lru) { + if (!list_empty(&lruvec->lists[lru])) + return false; + } + } else { + int gen, type, zone; + + for_each_gen_type_zone(gen, type, zone) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + return false; + + /* unlikely but not a bug when reset_batch_size() is pending */ + VM_WARN_ON(lrugen->nr_pages[gen][type][zone]); + } + } + + return true; +} + +static bool fill_evictable(struct lruvec *lruvec) +{ + enum lru_list lru; + int remaining = MAX_LRU_BATCH; + + for_each_evictable_lru(lru) { + int type = is_file_lru(lru); + bool active = is_active_lru(lru); + struct list_head *head = &lruvec->lists[lru]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page) != active, page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_lru_gen(page) < MAX_NR_GENS, page); + + prefetchw_prev_lru_page(page, head, flags); + + del_page_from_lru_list(page, lruvec); + success = lru_gen_add_page(lruvec, page, false); + VM_BUG_ON(!success); + + if (!--remaining) + return false; + } + } + + return true; +} + +static bool drain_evictable(struct lruvec *lruvec) +{ + int gen, type, zone; + int remaining = MAX_LRU_BATCH; + + for_each_gen_type_zone(gen, type, zone) { + struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + success = lru_gen_del_page(lruvec, page, false); + VM_BUG_ON(!success); + add_page_to_lru_list(page, lruvec); + + if (!--remaining) + return false; + } + } + + return true; +} + +static void lru_gen_change_state(bool enable) +{ + static DEFINE_MUTEX(state_mutex); + + struct mem_cgroup *memcg; + + cgroup_lock(); + cpus_read_lock(); + get_online_mems(); + mutex_lock(&state_mutex); + + if (enable == lru_gen_enabled()) + goto unlock; + + if (enable) + static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + else + static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node(nid) { + struct pglist_data *pgdat = NODE_DATA(nid); + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (!pgdat) { + lruvec->lrugen.enabled = enable; + continue; + } + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + VM_BUG_ON(!state_is_valid(lruvec)); + + lruvec->lrugen.enabled = enable; + + while (!(enable ? fill_evictable(lruvec) : drain_evictable(lruvec))) { + spin_unlock_irq(&pgdat->lru_lock); + cond_resched(); + spin_lock_irq(&pgdat->lru_lock); + } + + spin_unlock_irq(&pgdat->lru_lock); + } + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); +unlock: + mutex_unlock(&state_mutex); + put_online_mems(); + cpus_read_unlock(); + cgroup_unlock(); +} + +/****************************************************************************** + * sysfs interface + ******************************************************************************/ + +static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); +} + +static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + unsigned int msecs; + + if (kstrtouint(buf, 0, &msecs)) + return -EINVAL; + + WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); + + return len; +} + +static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( + min_ttl_ms, 0644, show_min_ttl, store_min_ttl +); + +static ssize_t show_enable(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + unsigned int caps = 0; + + if (get_cap(LRU_GEN_CORE)) + caps |= BIT(LRU_GEN_CORE); + + if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) + caps |= BIT(LRU_GEN_MM_WALK); + + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) + caps |= BIT(LRU_GEN_NONLEAF_YOUNG); + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); +} + +static ssize_t store_enable(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + int i; + unsigned int caps; + + if (tolower(*buf) == 'n') + caps = 0; + else if (tolower(*buf) == 'y') + caps = -1; + else if (kstrtouint(buf, 0, &caps)) + return -EINVAL; + + for (i = 0; i < NR_LRU_GEN_CAPS; i++) { + bool enable = caps & BIT(i); + + if (i == LRU_GEN_CORE) + lru_gen_change_state(enable); + else if (enable) + static_branch_enable(&lru_gen_caps[i]); + else + static_branch_disable(&lru_gen_caps[i]); + } + + return len; +} + +static struct kobj_attribute lru_gen_enabled_attr = __ATTR( + enabled, 0644, show_enable, store_enable +); + +static struct attribute *lru_gen_attrs[] = { + &lru_gen_min_ttl_attr.attr, + &lru_gen_enabled_attr.attr, + NULL +}; + +static struct attribute_group lru_gen_attr_group = { + .name = "lru_gen", + .attrs = lru_gen_attrs, +}; + +/****************************************************************************** + * debugfs interface + ******************************************************************************/ + +static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) +{ + struct mem_cgroup *memcg; + loff_t nr_to_skip = *pos; + + m->private = kvmalloc(PATH_MAX, GFP_KERNEL); + if (!m->private) + return ERR_PTR(-ENOMEM); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node_state(nid, N_MEMORY) { + if (!nr_to_skip--) + return get_lruvec(memcg, nid); + } + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + return NULL; +} + +static void lru_gen_seq_stop(struct seq_file *m, void *v) +{ + if (!IS_ERR_OR_NULL(v)) + mem_cgroup_iter_break(NULL, lruvec_memcg(v)); + + kvfree(m->private); + m->private = NULL; +} + +static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + int nid = lruvec_pgdat(v)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(v); + + ++*pos; + + nid = next_memory_node(nid); + if (nid == MAX_NUMNODES) { + memcg = mem_cgroup_iter(NULL, memcg, NULL); + if (!memcg) + return NULL; + + nid = first_memory_node; + } + + return get_lruvec(memcg, nid); +} + +static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, + unsigned long max_seq, unsigned long *min_seq, + unsigned long seq) +{ + int i; + int type, tier; + int hist = lru_hist_from_seq(seq); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + seq_printf(m, " %10d", tier); + for (type = 0; type < ANON_AND_FILE; type++) { + unsigned long n[3] = {}; + + if (seq == max_seq) { + n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); + n[1] = READ_ONCE(lrugen->avg_total[type][tier]); + + seq_printf(m, " %10luR %10luT %10lu ", n[0], n[1], n[2]); + } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { + n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); + n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); + + seq_printf(m, " %10lur %10lue %10lup", n[0], n[1], n[2]); + } else + seq_puts(m, " 0 0 0 "); + } + seq_putc(m, '\n'); + } + + seq_puts(m, " "); + for (i = 0; i < NR_MM_STATS; i++) { + if (seq == max_seq && NR_HIST_GENS == 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + toupper(MM_STAT_CODES[i])); + else if (seq != max_seq && NR_HIST_GENS > 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + MM_STAT_CODES[i]); + else + seq_puts(m, " 0 "); + } + seq_putc(m, '\n'); +} + +static int lru_gen_seq_show(struct seq_file *m, void *v) +{ + unsigned long seq; + bool full = !debugfs_real_fops(m->file)->write; + struct lruvec *lruvec = v; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int nid = lruvec_pgdat(lruvec)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (nid == first_memory_node) { + const char *path = memcg ? m->private : ""; + +#ifdef CONFIG_MEMCG + if (memcg) + cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); +#endif + seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); + } + + seq_printf(m, " node %5d\n", nid); + + if (!full) + seq = min_seq[LRU_GEN_ANON]; + else if (max_seq >= MAX_NR_GENS) + seq = max_seq - MAX_NR_GENS + 1; + else + seq = 0; + + for (; seq <= max_seq; seq++) { + int type, zone; + int gen = lru_gen_from_seq(seq); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); + + for (type = 0; type < ANON_AND_FILE; type++) { + long size = 0; + char mark = full && seq < min_seq[type] ? 'x' : ' '; + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + seq_printf(m, " %10lu%c", max(size, 0L), mark); + } + + seq_putc(m, '\n'); + + if (full) + lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); + } + + return 0; +} + +static const struct seq_operations lru_gen_seq_ops = { + .start = lru_gen_seq_start, + .stop = lru_gen_seq_stop, + .next = lru_gen_seq_next, + .show = lru_gen_seq_show, +}; + +static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + bool can_swap, bool full_scan) +{ + DEFINE_MAX_SEQ(lruvec); + + if (seq == max_seq) + try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, full_scan); + + return seq > max_seq ? -EINVAL : 0; +} + +static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + int swappiness, unsigned long nr_to_reclaim) +{ + struct blk_plug plug; + int err = -EINTR; + DEFINE_MAX_SEQ(lruvec); + + if (seq + MIN_NR_GENS > max_seq) + return -EINVAL; + + sc->nr_reclaimed = 0; + + blk_start_plug(&plug); + + while (!signal_pending(current)) { + DEFINE_MIN_SEQ(lruvec); + + if (seq < min_seq[!swappiness] || sc->nr_reclaimed >= nr_to_reclaim || + !evict_pages(lruvec, sc, swappiness, NULL)) { + err = 0; + break; + } + + cond_resched(); + } + + blk_finish_plug(&plug); + + return err; +} + +static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, + struct scan_control *sc, int swappiness, unsigned long opt) +{ + struct lruvec *lruvec; + int err = -EINVAL; + struct mem_cgroup *memcg = NULL; + + if (!mem_cgroup_disabled()) { + rcu_read_lock(); + memcg = mem_cgroup_from_id(memcg_id); +#ifdef CONFIG_MEMCG + if (memcg && !css_tryget(&memcg->css)) + memcg = NULL; +#endif + rcu_read_unlock(); + + if (!memcg) + goto done; + } + if (memcg_id != mem_cgroup_id(memcg)) + goto done; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) + goto done; + + lruvec = get_lruvec(memcg, nid); + + if (swappiness < 0) + swappiness = get_swappiness(lruvec, sc); + else if (swappiness > 200) + goto done; + + switch (cmd) { + case '+': + err = run_aging(lruvec, seq, sc, swappiness, opt); + break; + case '-': + err = run_eviction(lruvec, seq, sc, swappiness, opt); + break; + } +done: + mem_cgroup_put(memcg); + + return err; +} + +static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, + size_t len, loff_t *pos) +{ + void *buf; + char *cur, *next; + unsigned int flags; + int err = 0; + struct scan_control sc = { + .may_writepage = true, + .may_unmap = true, + .may_swap = true, + .reclaim_idx = MAX_NR_ZONES - 1, + .gfp_mask = GFP_KERNEL, + }; + + buf = kvmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, src, len)) { + kvfree(buf); + return -EFAULT; + } + + next = buf; + next[len] = '\0'; + + sc.reclaim_state.mm_walk = alloc_mm_walk(); + if (!sc.reclaim_state.mm_walk) { + kvfree(buf); + return -ENOMEM; + } + + set_task_reclaim_state(current, &sc.reclaim_state); + flags = memalloc_noreclaim_save(); + + while ((cur = strsep(&next, ",;\n"))) { + int n; + int end; + char cmd; + unsigned int memcg_id; + unsigned int nid; + unsigned long seq; + unsigned int swappiness = -1; + unsigned long opt = -1; + + cur = skip_spaces(cur); + if (!*cur) + continue; + + n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, + &seq, &end, &swappiness, &end, &opt, &end); + if (n < 4 || cur[end]) { + err = -EINVAL; + break; + } + + err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); + if (err) + break; + } + + memalloc_noreclaim_restore(flags); + set_task_reclaim_state(current, NULL); + + free_mm_walk(sc.reclaim_state.mm_walk); + kvfree(buf); + + return err ? : len; +} + +static int lru_gen_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &lru_gen_seq_ops); +} + +static const struct file_operations lru_gen_rw_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .write = lru_gen_seq_write, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations lru_gen_ro_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/****************************************************************************** + * initialization + ******************************************************************************/ + +void lru_gen_init_lruvec(struct lruvec *lruvec) +{ + int i; + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); + + for (i = 0; i <= MIN_NR_GENS + 1; i++) + lrugen->timestamps[i] = jiffies; + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; + init_waitqueue_head(&lruvec->mm_state.wait); +} + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ + INIT_LIST_HEAD(&memcg->mm_list.fifo); + spin_lock_init(&memcg->mm_list.lock); +} + +void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ + int i; + int nid; + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + VM_BUG_ON(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); + + for (i = 0; i < NR_BLOOM_FILTERS; i++) { + bitmap_free(lruvec->mm_state.filters[i]); + lruvec->mm_state.filters[i] = NULL; + } + } +} +#endif + +static int __init init_lru_gen(void) +{ + BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); + BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); + BUILD_BUG_ON(sizeof(MM_STAT_CODES) != NR_MM_STATS + 1); + + if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) + pr_err("lru_gen: failed to create sysfs group\n"); + + debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); + debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); + + return 0; +}; +late_initcall(init_lru_gen); + +#else + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ +} + +#endif /* CONFIG_LRU_GEN */ + +static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ + unsigned long nr[NR_LRU_LISTS]; + unsigned long targets[NR_LRU_LISTS]; + unsigned long nr_to_scan; + enum lru_list lru; + unsigned long nr_reclaimed = 0; + unsigned long nr_to_reclaim = sc->nr_to_reclaim; + struct blk_plug plug; + bool scan_adjusted; + + if (lru_gen_enabled()) { + lru_gen_shrink_lruvec(lruvec, sc); + return; + } + + get_scan_count(lruvec, sc, nr); + + /* Record the original scan target for proportional adjustments later */ + memcpy(targets, nr, sizeof(nr)); + + /* + * Global reclaiming within direct reclaim at DEF_PRIORITY is a normal + * event that can occur when there is little memory pressure e.g. + * multiple streaming readers/writers. Hence, we do not abort scanning + * when the requested number of pages are reclaimed when scanning at + * DEF_PRIORITY on the assumption that the fact we are direct + * reclaiming implies that kswapd is not keeping up and it is best to + * do a batch of work at once. For memcg reclaim one check is made to + * abort proportional reclaim if either the file or anon lru has already + * dropped to zero at the first pass. + */ + scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() && + sc->priority == DEF_PRIORITY); + + blk_start_plug(&plug); + while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || + nr[LRU_INACTIVE_FILE]) { + unsigned long nr_anon, nr_file, percentage; + unsigned long nr_scanned; + + for_each_evictable_lru(lru) { + if (nr[lru]) { + nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX); + nr[lru] -= nr_to_scan; + + nr_reclaimed += shrink_list(lru, nr_to_scan, + lruvec, sc); + } + } + + cond_resched(); + + if (nr_reclaimed < nr_to_reclaim || scan_adjusted) + continue; + + /* + * For kswapd and memcg, reclaim at least the number of pages + * requested. Ensure that the anon and file LRUs are scanned + * proportionally what was requested by get_scan_count(). We + * stop reclaiming one LRU and reduce the amount scanning + * proportional to the original scan target. + */ + nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; + nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; + + /* + * It's just vindictive to attack the larger once the smaller + * has gone to zero. And given the way we stop scanning the + * smaller below, this makes sure that we only make one nudge + * towards proportionality once we've got nr_to_reclaim. + */ + if (!nr_file || !nr_anon) + break; + + if (nr_file > nr_anon) { + unsigned long scan_target = targets[LRU_INACTIVE_ANON] + + targets[LRU_ACTIVE_ANON] + 1; + lru = LRU_BASE; + percentage = nr_anon * 100 / scan_target; + } else { + unsigned long scan_target = targets[LRU_INACTIVE_FILE] + + targets[LRU_ACTIVE_FILE] + 1; + lru = LRU_FILE; + percentage = nr_file * 100 / scan_target; + } + + /* Stop scanning the smaller of the LRU */ + nr[lru] = 0; + nr[lru + LRU_ACTIVE] = 0; + + /* + * Recalculate the other LRU scan count based on its original + * scan target and the percentage scanning already complete + */ + lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; + nr_scanned = targets[lru] - nr[lru]; + nr[lru] = targets[lru] * (100 - percentage) / 100; + nr[lru] -= min(nr[lru], nr_scanned); + + lru += LRU_ACTIVE; + nr_scanned = targets[lru] - nr[lru]; + nr[lru] = targets[lru] * (100 - percentage) / 100; + nr[lru] -= min(nr[lru], nr_scanned); + + scan_adjusted = true; + } + blk_finish_plug(&plug); + sc->nr_reclaimed += nr_reclaimed; + + /* + * Even if we did not try to evict anon pages at all, we want to + * rebalance the anon lru active/inactive ratio. + */ + if (total_swap_pages && inactive_is_low(lruvec, LRU_INACTIVE_ANON)) + shrink_active_list(SWAP_CLUSTER_MAX, lruvec, + sc, LRU_ACTIVE_ANON); +} + +/* Use reclaim/compaction for costly allocs or under memory pressure */ +static bool in_reclaim_compaction(struct scan_control *sc) +{ + if (IS_ENABLED(CONFIG_COMPACTION) && sc->order && + (sc->order > PAGE_ALLOC_COSTLY_ORDER || + sc->priority < DEF_PRIORITY - 2)) + return true; + + return false; +} + +/* + * Reclaim/compaction is used for high-order allocation requests. It reclaims + * order-0 pages before compacting the zone. should_continue_reclaim() returns + * true if more pages should be reclaimed such that when the page allocator + * calls try_to_compact_pages() that it will have enough free pages to succeed. + * It will give up earlier than that if there is difficulty reclaiming pages. + */ +static inline bool should_continue_reclaim(struct pglist_data *pgdat, + unsigned long nr_reclaimed, + struct scan_control *sc) +{ + unsigned long pages_for_compaction; + unsigned long inactive_lru_pages; + int z; + + /* If not in reclaim/compaction mode, stop */ + if (!in_reclaim_compaction(sc)) + return false; + + /* + * Stop if we failed to reclaim any pages from the last SWAP_CLUSTER_MAX + * number of pages that were scanned. This will return to the caller + * with the risk reclaim/compaction and the resulting allocation attempt + * fails. In the past we have tried harder for __GFP_RETRY_MAYFAIL + * allocations through requiring that the full LRU list has been scanned + * first, by assuming that zero delta of sc->nr_scanned means full LRU + * scan, but that approximation was wrong, and there were corner cases * where always a non-zero amount of pages were scanned. */ if (!nr_reclaimed) @@ -2748,7 +5495,6 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) unsigned long nr_reclaimed, nr_scanned; struct lruvec *target_lruvec; bool reclaimable = false; - unsigned long file; target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); @@ -2758,93 +5504,7 @@ again: nr_reclaimed = sc->nr_reclaimed; nr_scanned = sc->nr_scanned; - /* - * Determine the scan balance between anon and file LRUs. - */ - spin_lock_irq(&pgdat->lru_lock); - sc->anon_cost = target_lruvec->anon_cost; - sc->file_cost = target_lruvec->file_cost; - spin_unlock_irq(&pgdat->lru_lock); - - /* - * Target desirable inactive:active list ratios for the anon - * and file LRU lists. - */ - if (!sc->force_deactivate) { - unsigned long refaults; - - refaults = lruvec_page_state(target_lruvec, - WORKINGSET_ACTIVATE_ANON); - if (refaults != target_lruvec->refaults[0] || - inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) - sc->may_deactivate |= DEACTIVATE_ANON; - else - sc->may_deactivate &= ~DEACTIVATE_ANON; - - /* - * When refaults are being observed, it means a new - * workingset is being established. Deactivate to get - * rid of any stale active pages quickly. - */ - refaults = lruvec_page_state(target_lruvec, - WORKINGSET_ACTIVATE_FILE); - if (refaults != target_lruvec->refaults[1] || - inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) - sc->may_deactivate |= DEACTIVATE_FILE; - else - sc->may_deactivate &= ~DEACTIVATE_FILE; - } else - sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; - - /* - * If we have plenty of inactive file pages that aren't - * thrashing, try to reclaim those first before touching - * anonymous pages. - */ - file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); - if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) - sc->cache_trim_mode = 1; - else - sc->cache_trim_mode = 0; - - /* - * Prevent the reclaimer from falling into the cache trap: as - * cache pages start out inactive, every cache fault will tip - * the scan balance towards the file LRU. And as the file LRU - * shrinks, so does the window for rotation from references. - * This means we have a runaway feedback loop where a tiny - * thrashing file LRU becomes infinitely more attractive than - * anon pages. Try to detect this based on file LRU size. - */ - if (!cgroup_reclaim(sc)) { - unsigned long total_high_wmark = 0; - unsigned long free, anon; - int z; - - free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); - file = node_page_state(pgdat, NR_ACTIVE_FILE) + - node_page_state(pgdat, NR_INACTIVE_FILE); - - for (z = 0; z < MAX_NR_ZONES; z++) { - struct zone *zone = &pgdat->node_zones[z]; - if (!managed_zone(zone)) - continue; - - total_high_wmark += high_wmark_pages(zone); - } - - /* - * Consider anon: if that's low too, this isn't a - * runaway file reclaim problem, but rather just - * extreme pressure. Reclaim as per usual then. - */ - anon = node_page_state(pgdat, NR_INACTIVE_ANON); - - sc->file_is_tiny = - file + free <= total_high_wmark && - !(sc->may_deactivate & DEACTIVATE_ANON) && - anon >> sc->priority; - } + prepare_scan_count(pgdat, sc); shrink_node_memcgs(pgdat, sc); @@ -3064,6 +5724,9 @@ static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat) struct lruvec *target_lruvec; unsigned long refaults; + if (lru_gen_enabled()) + return; + target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); target_lruvec->refaults[0] = refaults; @@ -3439,6 +6102,11 @@ static void age_active_anon(struct pglist_data *pgdat, struct mem_cgroup *memcg; struct lruvec *lruvec; + if (lru_gen_enabled()) { + lru_gen_age_node(pgdat, sc); + return; + } + if (!total_swap_pages) return; @@ -4423,12 +7091,9 @@ void check_move_unevictable_pages(struct pagevec *pvec) continue; if (page_evictable(page)) { - enum lru_list lru = page_lru_base_type(page); - - VM_BUG_ON_PAGE(PageActive(page), page); + del_page_from_lru_list(page, lruvec); ClearPageUnevictable(page); - del_page_from_lru_list(page, lruvec, LRU_UNEVICTABLE); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); pgrescued += nr_pages; } } diff --git a/mm/workingset.c b/mm/workingset.c index 975a4d2dd02ee..25eaab8811927 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -185,7 +185,6 @@ static unsigned int bucket_order __read_mostly; static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, bool workingset) { - eviction >>= bucket_order; eviction &= EVICTION_MASK; eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; eviction = (eviction << NODES_SHIFT) | pgdat->node_id; @@ -210,10 +209,116 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, *memcgidp = memcgid; *pgdat = NODE_DATA(nid); - *evictionp = entry << bucket_order; + *evictionp = entry; *workingsetp = workingset; } +#ifdef CONFIG_LRU_GEN + +static int page_lru_refs(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); + + BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); + + /* see the comment on MAX_NR_TIERS */ + return flags & BIT(PG_workingset) ? (flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF : 0; +} + +static void *lru_gen_eviction(struct page *page) +{ + int hist, tier; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + int type = page_is_file_lru(page); + int refs = page_lru_refs(page); + int delta = thp_nr_pages(page); + bool workingset = PageWorkingset(page); + struct mem_cgroup *memcg = page_memcg(page); + struct pglist_data *pgdat = page_pgdat(page); + + lruvec = mem_cgroup_lruvec(memcg, pgdat); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + token = (min_seq << LRU_REFS_WIDTH) | refs; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); + + return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset); +} + +static void lru_gen_refault(struct page *page, void *shadow) +{ + int hist, tier, refs; + int memcg_id; + bool workingset; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + struct mem_cgroup *memcg; + struct pglist_data *pgdat; + int type = page_is_file_lru(page); + int delta = thp_nr_pages(page); + + unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); + + refs = token & (BIT(LRU_REFS_WIDTH) - 1); + if (refs && !workingset) + return; + + if (page_pgdat(page) != pgdat) + return; + + rcu_read_lock(); + memcg = page_memcg_rcu(page); + if (mem_cgroup_id(memcg) != memcg_id) + goto unlock; + + token >>= LRU_REFS_WIDTH; + lruvec = mem_cgroup_lruvec(memcg, pgdat); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + if (token != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) + goto unlock; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); + mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); + + /* + * Count the following two cases as stalls: + * 1. For pages accessed through page tables, hotter pages pushed out + * hot pages which refaulted immediately. + * 2. For pages accessed through file descriptors, numbers of accesses + * might have been beyond the limit. + */ + if (lru_gen_in_fault() || refs + workingset == BIT(LRU_REFS_WIDTH)) { + SetPageWorkingset(page); + mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); + } +unlock: + rcu_read_unlock(); +} + +#else + +static void *lru_gen_eviction(struct page *page) +{ + return NULL; +} + +static void lru_gen_refault(struct page *page, void *shadow) +{ +} + +#endif /* CONFIG_LRU_GEN */ + /** * workingset_age_nonresident - age non-resident entries as LRU ages * @lruvec: the lruvec that was aged @@ -262,11 +367,15 @@ void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg) VM_BUG_ON_PAGE(page_count(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page); + if (lru_gen_enabled()) + return lru_gen_eviction(page); + lruvec = mem_cgroup_lruvec(target_memcg, pgdat); workingset_age_nonresident(lruvec, thp_nr_pages(page)); /* XXX: target_memcg can be NULL, go through lruvec */ memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); eviction = atomic_long_read(&lruvec->nonresident_age); + eviction >>= bucket_order; return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); } @@ -294,7 +403,13 @@ void workingset_refault(struct page *page, void *shadow) bool workingset; int memcgid; + if (lru_gen_enabled()) { + lru_gen_refault(page, shadow); + return; + } + unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); + eviction <<= bucket_order; rcu_read_lock(); /* diff --git a/net/9p/mod.c b/net/9p/mod.c index 5126566850bd0..94cd2d132fd7f 100644 --- a/net/9p/mod.c +++ b/net/9p/mod.c @@ -189,4 +189,5 @@ MODULE_AUTHOR("Latchesar Ionkov "); MODULE_AUTHOR("Eric Van Hensbergen "); MODULE_AUTHOR("Ron Minnich "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_DESCRIPTION("Plan 9 Resource Sharing Support (9P2000)"); diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 986f707e7d973..ee9cead765450 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -164,9 +164,6 @@ static void batadv_backbone_gw_release(struct kref *ref) */ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) { - if (!backbone_gw) - return; - kref_put(&backbone_gw->refcount, batadv_backbone_gw_release); } @@ -202,9 +199,6 @@ static void batadv_claim_release(struct kref *ref) */ static void batadv_claim_put(struct batadv_bla_claim *claim) { - if (!claim) - return; - kref_put(&claim->refcount, batadv_claim_release); } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 338e4e9c33b8a..0e6e53e9b5f35 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -128,9 +128,6 @@ static void batadv_dat_entry_release(struct kref *ref) */ static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry) { - if (!dat_entry) - return; - kref_put(&dat_entry->refcount, batadv_dat_entry_release); } diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 62f6f13f89ffd..ef3f85b576c4c 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -60,7 +60,7 @@ * after rcu grace period * @ref: kref pointer of the gw_node */ -void batadv_gw_node_release(struct kref *ref) +static void batadv_gw_node_release(struct kref *ref) { struct batadv_gw_node *gw_node; @@ -70,6 +70,16 @@ void batadv_gw_node_release(struct kref *ref) kfree_rcu(gw_node, rcu); } +/** + * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release + * it + * @gw_node: gateway node to free + */ +void batadv_gw_node_put(struct batadv_gw_node *gw_node) +{ + kref_put(&gw_node->refcount, batadv_gw_node_release); +} + /** * batadv_gw_get_selected_gw_node() - Get currently selected gateway * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index c5b1de586fde0..88b5dba843547 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -29,7 +28,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); void batadv_gw_node_free(struct batadv_priv *bat_priv); -void batadv_gw_node_release(struct kref *ref); +void batadv_gw_node_put(struct batadv_gw_node *gw_node); struct batadv_gw_node * batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); @@ -41,17 +40,4 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); -/** - * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release - * it - * @gw_node: gateway node to free - */ -static inline void batadv_gw_node_put(struct batadv_gw_node *gw_node) -{ - if (!gw_node) - return; - - kref_put(&gw_node->refcount, batadv_gw_node_release); -} - #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index ba5850cfb2774..b1855d9d0b062 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -113,9 +113,6 @@ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, */ static inline void batadv_hardif_put(struct batadv_hard_iface *hard_iface) { - if (!hard_iface) - return; - kref_put(&hard_iface->refcount, batadv_hardif_release); } diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 1481b80395689..35b3e03c07774 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -222,9 +222,6 @@ static void batadv_nc_node_release(struct kref *ref) */ static void batadv_nc_node_put(struct batadv_nc_node *nc_node) { - if (!nc_node) - return; - kref_put(&nc_node->refcount, batadv_nc_node_release); } @@ -249,9 +246,6 @@ static void batadv_nc_path_release(struct kref *ref) */ static void batadv_nc_path_put(struct batadv_nc_path *nc_path) { - if (!nc_path) - return; - kref_put(&nc_path->refcount, batadv_nc_path_release); } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 2d38a09459bb5..805d8969bdfbc 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -178,7 +178,7 @@ out: * and queue for free after rcu grace period * @ref: kref pointer of the originator-vlan object */ -void batadv_orig_node_vlan_release(struct kref *ref) +static void batadv_orig_node_vlan_release(struct kref *ref) { struct batadv_orig_node_vlan *orig_vlan; @@ -187,6 +187,16 @@ void batadv_orig_node_vlan_release(struct kref *ref) kfree_rcu(orig_vlan, rcu); } +/** + * batadv_orig_node_vlan_put() - decrement the refcounter and possibly release + * the originator-vlan object + * @orig_vlan: the originator-vlan object to release + */ +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan) +{ + kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release); +} + /** * batadv_originator_init() - Initialize all originator structures * @bat_priv: the bat priv with all the soft interface information @@ -222,7 +232,7 @@ err: * free after rcu grace period * @ref: kref pointer of the neigh_ifinfo */ -void batadv_neigh_ifinfo_release(struct kref *ref) +static void batadv_neigh_ifinfo_release(struct kref *ref) { struct batadv_neigh_ifinfo *neigh_ifinfo; @@ -234,12 +244,22 @@ void batadv_neigh_ifinfo_release(struct kref *ref) kfree_rcu(neigh_ifinfo, rcu); } +/** + * batadv_neigh_ifinfo_put() - decrement the refcounter and possibly release + * the neigh_ifinfo + * @neigh_ifinfo: the neigh_ifinfo object to release + */ +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo) +{ + kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release); +} + /** * batadv_hardif_neigh_release() - release hardif neigh node from lists and * queue for free after rcu grace period * @ref: kref pointer of the neigh_node */ -void batadv_hardif_neigh_release(struct kref *ref) +static void batadv_hardif_neigh_release(struct kref *ref) { struct batadv_hardif_neigh_node *hardif_neigh; @@ -254,12 +274,22 @@ void batadv_hardif_neigh_release(struct kref *ref) kfree_rcu(hardif_neigh, rcu); } +/** + * batadv_hardif_neigh_put() - decrement the hardif neighbors refcounter + * and possibly release it + * @hardif_neigh: hardif neigh neighbor to free + */ +void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) +{ + kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release); +} + /** * batadv_neigh_node_release() - release neigh_node from lists and queue for * free after rcu grace period * @ref: kref pointer of the neigh_node */ -void batadv_neigh_node_release(struct kref *ref) +static void batadv_neigh_node_release(struct kref *ref) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; @@ -279,6 +309,16 @@ void batadv_neigh_node_release(struct kref *ref) kfree_rcu(neigh_node, rcu); } +/** + * batadv_neigh_node_put() - decrement the neighbors refcounter and possibly + * release it + * @neigh_node: neigh neighbor to free + */ +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node) +{ + kref_put(&neigh_node->refcount, batadv_neigh_node_release); +} + /** * batadv_orig_router_get() - router to the originator depending on iface * @orig_node: the orig node for the router @@ -811,7 +851,7 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) * free after rcu grace period * @ref: kref pointer of the orig_ifinfo */ -void batadv_orig_ifinfo_release(struct kref *ref) +static void batadv_orig_ifinfo_release(struct kref *ref) { struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *router; @@ -829,6 +869,16 @@ void batadv_orig_ifinfo_release(struct kref *ref) kfree_rcu(orig_ifinfo, rcu); } +/** + * batadv_orig_ifinfo_put() - decrement the refcounter and possibly release + * the orig_ifinfo + * @orig_ifinfo: the orig_ifinfo object to release + */ +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) +{ + kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); +} + /** * batadv_orig_node_free_rcu() - free the orig_node * @rcu: rcu pointer of the orig_node @@ -852,7 +902,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) * free after rcu grace period * @ref: kref pointer of the orig_node */ -void batadv_orig_node_release(struct kref *ref) +static void batadv_orig_node_release(struct kref *ref) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; @@ -898,6 +948,16 @@ void batadv_orig_node_release(struct kref *ref) call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); } +/** + * batadv_orig_node_put() - decrement the orig node refcounter and possibly + * release it + * @orig_node: the orig node to free + */ +void batadv_orig_node_put(struct batadv_orig_node *orig_node) +{ + kref_put(&orig_node->refcount, batadv_orig_node_release); +} + /** * batadv_originator_free() - Free all originator structures * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 3b824a79743a2..7bc01c138b3ab 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -22,18 +21,19 @@ bool batadv_compare_orig(const struct hlist_node *node, const void *data2); int batadv_originator_init(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_purge_orig_ref(struct batadv_priv *bat_priv); -void batadv_orig_node_release(struct kref *ref); +void batadv_orig_node_put(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_hardif_neigh_node * batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -void batadv_hardif_neigh_release(struct kref *ref); +void +batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh); struct batadv_neigh_node * batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -void batadv_neigh_node_release(struct kref *ref); +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, const struct batadv_hard_iface *if_outgoing); @@ -43,7 +43,7 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); -void batadv_neigh_ifinfo_release(struct kref *ref); +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo); int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset); @@ -54,7 +54,7 @@ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, struct batadv_orig_ifinfo * batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing); -void batadv_orig_ifinfo_release(struct kref *ref); +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo); int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); @@ -65,7 +65,7 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, struct batadv_orig_node_vlan * batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, unsigned short vid); -void batadv_orig_node_vlan_release(struct kref *ref); +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan); /** * batadv_choose_orig() - Return the index of the orig entry in the hash table @@ -86,86 +86,4 @@ static inline u32 batadv_choose_orig(const void *data, u32 size) struct batadv_orig_node * batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data); -/** - * batadv_orig_node_vlan_put() - decrement the refcounter and possibly release - * the originator-vlan object - * @orig_vlan: the originator-vlan object to release - */ -static inline void -batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan) -{ - if (!orig_vlan) - return; - - kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release); -} - -/** - * batadv_neigh_ifinfo_put() - decrement the refcounter and possibly release - * the neigh_ifinfo - * @neigh_ifinfo: the neigh_ifinfo object to release - */ -static inline void -batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo) -{ - if (!neigh_ifinfo) - return; - - kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release); -} - -/** - * batadv_hardif_neigh_put() - decrement the hardif neighbors refcounter - * and possibly release it - * @hardif_neigh: hardif neigh neighbor to free - */ -static inline void -batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) -{ - if (!hardif_neigh) - return; - - kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release); -} - -/** - * batadv_neigh_node_put() - decrement the neighbors refcounter and possibly - * release it - * @neigh_node: neigh neighbor to free - */ -static inline void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node) -{ - if (!neigh_node) - return; - - kref_put(&neigh_node->refcount, batadv_neigh_node_release); -} - -/** - * batadv_orig_ifinfo_put() - decrement the refcounter and possibly release - * the orig_ifinfo - * @orig_ifinfo: the orig_ifinfo object to release - */ -static inline void -batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) -{ - if (!orig_ifinfo) - return; - - kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); -} - -/** - * batadv_orig_node_put() - decrement the orig node refcounter and possibly - * release it - * @orig_node: the orig node to free - */ -static inline void batadv_orig_node_put(struct batadv_orig_node *orig_node) -{ - if (!orig_node) - return; - - kref_put(&orig_node->refcount, batadv_orig_node_release); -} - #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 8f7c778255fba..7496047b318a4 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -512,7 +512,7 @@ out: * after rcu grace period * @ref: kref pointer of the vlan object */ -void batadv_softif_vlan_release(struct kref *ref) +static void batadv_softif_vlan_release(struct kref *ref) { struct batadv_softif_vlan *vlan; @@ -525,6 +525,19 @@ void batadv_softif_vlan_release(struct kref *ref) kfree_rcu(vlan, rcu); } +/** + * batadv_softif_vlan_put() - decrease the vlan object refcounter and + * possibly release it + * @vlan: the vlan object to release + */ +void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan) +{ + if (!vlan) + return; + + kref_put(&vlan->refcount, batadv_softif_vlan_release); +} + /** * batadv_softif_vlan_get() - get the vlan object for a specific vid * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 53aba17b90688..534e08d6ad919 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -25,21 +24,8 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface); bool batadv_softif_is_valid(const struct net_device *net_dev); extern struct rtnl_link_ops batadv_link_ops; int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); -void batadv_softif_vlan_release(struct kref *ref); +void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan); struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid); -/** - * batadv_softif_vlan_put() - decrease the vlan object refcounter and - * possibly release it - * @vlan: the vlan object to release - */ -static inline void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan) -{ - if (!vlan) - return; - - kref_put(&vlan->refcount, batadv_softif_vlan_release); -} - #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index 00d62a6c5e0ef..db7e3774825b5 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -357,9 +357,6 @@ static void batadv_tp_vars_release(struct kref *ref) */ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars) { - if (!tp_vars) - return; - kref_put(&tp_vars->refcount, batadv_tp_vars_release); } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5f990a2061072..de946ea8f13c8 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -248,9 +248,6 @@ static void batadv_tt_local_entry_release(struct kref *ref) static void batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) { - if (!tt_local_entry) - return; - kref_put(&tt_local_entry->common.refcount, batadv_tt_local_entry_release); } @@ -274,7 +271,7 @@ static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu) * queue for free after rcu grace period * @ref: kref pointer of the nc_node */ -void batadv_tt_global_entry_release(struct kref *ref) +static void batadv_tt_global_entry_release(struct kref *ref) { struct batadv_tt_global_entry *tt_global_entry; @@ -286,6 +283,17 @@ void batadv_tt_global_entry_release(struct kref *ref) call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu); } +/** + * batadv_tt_global_entry_put() - decrement the tt_global_entry refcounter and + * possibly release it + * @tt_global_entry: tt_global_entry to be free'd + */ +void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) +{ + kref_put(&tt_global_entry->common.refcount, + batadv_tt_global_entry_release); +} + /** * batadv_tt_global_hash_count() - count the number of orig entries * @bat_priv: the bat priv with all the soft interface information @@ -445,9 +453,6 @@ static void batadv_tt_orig_list_entry_release(struct kref *ref) static void batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) { - if (!orig_entry) - return; - kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); } @@ -2813,9 +2818,6 @@ static void batadv_tt_req_node_release(struct kref *ref) */ static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node) { - if (!tt_req_node) - return; - kref_put(&tt_req_node->refcount, batadv_tt_req_node_release); } diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 63cc8fd3ff66a..b24d35b9226a1 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -32,7 +31,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_tt_global_entry * batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid); -void batadv_tt_global_entry_release(struct kref *ref); +void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry); int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid); struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, @@ -59,19 +58,4 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, int batadv_tt_cache_init(void); void batadv_tt_cache_destroy(void); -/** - * batadv_tt_global_entry_put() - decrement the tt_global_entry refcounter and - * possibly release it - * @tt_global_entry: tt_global_entry to be free'd - */ -static inline void -batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) -{ - if (!tt_global_entry) - return; - - kref_put(&tt_global_entry->common.refcount, - batadv_tt_global_entry_release); -} - #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index 99fc48efde543..6a23a566cde17 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -50,9 +50,6 @@ static void batadv_tvlv_handler_release(struct kref *ref) */ static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) { - if (!tvlv_handler) - return; - kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release); } @@ -109,9 +106,6 @@ static void batadv_tvlv_container_release(struct kref *ref) */ static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv) { - if (!tvlv) - return; - kref_put(&tvlv->refcount, batadv_tvlv_container_release); } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ecd2ffcf2ba28..1c5a0a60292d2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -508,9 +508,7 @@ static void le_conn_timeout(struct work_struct *work) if (conn->role == HCI_ROLE_SLAVE) { /* Disable LE Advertising */ le_disable_advertising(hdev); - hci_dev_lock(hdev); hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); - hci_dev_unlock(hdev); return; } diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index 51a941b56ec3a..4dfcd0d7ff3f7 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -134,3 +134,4 @@ static void __exit fini_umh(void) module_init(load_umh); module_exit(fini_umh); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/net/can/isotp.c b/net/can/isotp.c index 63e6e8923200b..d0581dc6a65fd 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1003,29 +1003,26 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, { struct sock *sk = sock->sk; struct sk_buff *skb; - struct isotp_sock *so = isotp_sk(sk); - int noblock = flags & MSG_DONTWAIT; - int ret = 0; - - if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK)) - return -EINVAL; - - if (!so->bound) - return -EADDRNOTAVAIL; + int err = 0; + int noblock; + noblock = flags & MSG_DONTWAIT; flags &= ~MSG_DONTWAIT; - skb = skb_recv_datagram(sk, flags, noblock, &ret); + + skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) - return ret; + return err; if (size < skb->len) msg->msg_flags |= MSG_TRUNC; else size = skb->len; - ret = memcpy_to_msg(msg, skb->data, size); - if (ret < 0) - goto out_err; + err = memcpy_to_msg(msg, skb->data, size); + if (err < 0) { + skb_free_datagram(sk, skb); + return err; + } sock_recv_timestamp(msg, sk, skb); @@ -1035,13 +1032,9 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, memcpy(msg->msg_name, skb->cb, msg->msg_namelen); } - /* set length of return value */ - ret = (flags & MSG_TRUNC) ? skb->len : size; - -out_err: skb_free_datagram(sk, skb); - return ret; + return size; } static int isotp_release(struct socket *sock) @@ -1109,7 +1102,6 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) struct net *net = sock_net(sk); int ifindex; struct net_device *dev; - canid_t tx_id, rx_id; int err = 0; int notify_enetdown = 0; int do_rx_reg = 1; @@ -1117,18 +1109,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (len < ISOTP_MIN_NAMELEN) return -EINVAL; - /* sanitize tx/rx CAN identifiers */ - tx_id = addr->can_addr.tp.tx_id; - if (tx_id & CAN_EFF_FLAG) - tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); - else - tx_id &= CAN_SFF_MASK; - - rx_id = addr->can_addr.tp.rx_id; - if (rx_id & CAN_EFF_FLAG) - rx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); - else - rx_id &= CAN_SFF_MASK; + if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) + return -EADDRNOTAVAIL; if (!addr->can_ifindex) return -ENODEV; @@ -1140,13 +1122,21 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) do_rx_reg = 0; /* do not validate rx address for functional addressing */ - if (do_rx_reg && rx_id == tx_id) { - err = -EADDRNOTAVAIL; - goto out; + if (do_rx_reg) { + if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) { + err = -EADDRNOTAVAIL; + goto out; + } + + if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + err = -EADDRNOTAVAIL; + goto out; + } } if (so->bound && addr->can_ifindex == so->ifindex && - rx_id == so->rxid && tx_id == so->txid) + addr->can_addr.tp.rx_id == so->rxid && + addr->can_addr.tp.tx_id == so->txid) goto out; dev = dev_get_by_index(net, addr->can_ifindex); @@ -1170,7 +1160,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) ifindex = dev->ifindex; if (do_rx_reg) - can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id), + can_rx_register(net, dev, addr->can_addr.tp.rx_id, + SINGLE_MASK(addr->can_addr.tp.rx_id), isotp_rcv, sk, "isotp", sk); dev_put(dev); @@ -1190,8 +1181,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) /* switch to new settings */ so->ifindex = ifindex; - so->rxid = rx_id; - so->txid = tx_id; + so->rxid = addr->can_addr.tp.rx_id; + so->txid = addr->can_addr.tp.tx_id; so->bound = 1; out: diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0c3c0c9cbe23a..fc36c8eddbf72 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3669,7 +3669,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, unsigned int delta_len = 0; struct sk_buff *tail = NULL; struct sk_buff *nskb, *tmp; - int err; + int len_diff, err; skb_push(skb, -skb_network_offset(skb) + offset); @@ -3709,9 +3709,11 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, skb_push(nskb, -skb_network_offset(nskb) + offset); skb_release_head_state(nskb); + len_diff = skb_network_header_len(nskb) - skb_network_header_len(skb); __copy_skb_header(nskb, skb); skb_headers_offset_update(nskb, skb_headroom(nskb) - skb_headroom(skb)); + nskb->transport_header += len_diff; skb_copy_from_linear_data_offset(skb, -tnl_hlen, nskb->data - tnl_hlen, offset + tnl_hlen); diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 545181a1ae043..e4bb89599b44b 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -27,7 +27,6 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, int elem_first_coalesce) { struct page_frag *pfrag = sk_page_frag(sk); - u32 osize = msg->sg.size; int ret = 0; len -= msg->sg.size; @@ -36,17 +35,13 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, u32 orig_offset; int use, i; - if (!sk_page_frag_refill(sk, pfrag)) { - ret = -ENOMEM; - goto msg_trim; - } + if (!sk_page_frag_refill(sk, pfrag)) + return -ENOMEM; orig_offset = pfrag->offset; use = min_t(int, len, pfrag->size - orig_offset); - if (!sk_wmem_schedule(sk, use)) { - ret = -ENOMEM; - goto msg_trim; - } + if (!sk_wmem_schedule(sk, use)) + return -ENOMEM; i = msg->sg.end; sk_msg_iter_var_prev(i); @@ -76,10 +71,6 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, } return ret; - -msg_trim: - sk_msg_trim(sk, msg, osize); - return ret; } EXPORT_SYMBOL_GPL(sk_msg_alloc); diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index f543fca6dfcbf..71c8ef7d40870 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -766,7 +766,6 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) struct net_device *master; master = of_find_net_device_by_node(ethernet); - of_node_put(ethernet); if (!master) return -EPROBE_DEFER; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index d76af5ba5cc20..a3271ec3e1627 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -448,7 +448,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; - unsigned int allocsz; /* this is non-NULL only with TCP/UDP Encapsulation */ if (x->encap) { @@ -458,10 +457,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * return err; } - allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); - if (allocsz > ESP_SKB_FRAG_MAXSIZE) - goto cow; - if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c72d0de8bf714..ce787c3867938 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -529,15 +529,6 @@ void __ip_select_ident(struct net *net, struct iphdr *iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); -static void ip_rt_fix_tos(struct flowi4 *fl4) -{ - __u8 tos = RT_FL_TOS(fl4); - - fl4->flowi4_tos = tos & IPTOS_RT_MASK; - fl4->flowi4_scope = tos & RTO_ONLINK ? - RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; -} - static void __build_flow_key(const struct net *net, struct flowi4 *fl4, const struct sock *sk, const struct iphdr *iph, @@ -862,7 +853,6 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf rt = (struct rtable *) dst; __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0); - ip_rt_fix_tos(&fl4); __ip_do_redirect(rt, skb, &fl4, true); } @@ -1087,7 +1077,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct flowi4 fl4; ip_rt_build_flow_key(&fl4, sk, skb); - ip_rt_fix_tos(&fl4); /* Don't make lookup fail for bridged encapsulations */ if (skb && netif_is_any_bridge_port(skb->dev)) @@ -1162,8 +1151,6 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) goto out; new = true; - } else { - ip_rt_fix_tos(&fl4); } __ip_rt_update_pmtu((struct rtable *)xfrm_dst_path(&rt->dst), &fl4, mtu); @@ -2537,6 +2524,7 @@ add: struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, const struct sk_buff *skb) { + __u8 tos = RT_FL_TOS(fl4); struct fib_result res = { .type = RTN_UNSPEC, .fi = NULL, @@ -2546,7 +2534,9 @@ struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, struct rtable *rth; fl4->flowi4_iif = LOOPBACK_IFINDEX; - ip_rt_fix_tos(fl4); + fl4->flowi4_tos = tos & IPTOS_RT_MASK; + fl4->flowi4_scope = ((tos & RTO_ONLINK) ? + RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); rcu_read_lock(); rth = ip_route_output_key_hash_rcu(net, fl4, &res, skb); diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index eaf2308c355a6..6b745ce4108c8 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -218,9 +218,10 @@ int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, struct sk_psock *psock = sk_psock_get(sk); int ret; - if (unlikely(!psock)) - return -EPIPE; - + if (unlikely(!psock)) { + sk_msg_free(sk, msg); + return 0; + } ret = ingress ? bpf_tcp_ingress(sk, psock, msg, bytes, flags) : tcp_bpf_push_locked(sk, msg, bytes, flags, false); sk_psock_put(sk, psock); @@ -370,7 +371,7 @@ more_data: cork = true; psock->cork = NULL; } - sk_msg_return(sk, msg, msg->sg.size); + sk_msg_return(sk, msg, tosend); release_sock(sk); ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags); @@ -410,11 +411,8 @@ more_data: } if (msg && msg->sg.data[msg->sg.start].page_link && - msg->sg.data[msg->sg.start].length) { - if (eval == __SK_REDIRECT) - sk_mem_charge(sk, msg->sg.size); + msg->sg.data[msg->sg.start].length) goto more_data; - } } return ret; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7fce54a298025..37e70cd46feaf 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3733,7 +3733,6 @@ static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) */ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) { - struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_request *fo = tp->fastopen_req; int space, err = 0; @@ -3748,10 +3747,8 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) * private TCP options. The cost is reduced data space in SYN :( */ tp->rx_opt.mss_clamp = tcp_mss_clamp(tp, tp->rx_opt.mss_clamp); - /* Sync mss_cache after updating the mss_clamp */ - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - space = __tcp_mtu_to_mss(sk, icsk->icsk_pmtu_cookie) - + space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - MAX_TCP_OPTION_SPACE; space = min_t(size_t, space, fo->size); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e97a2dd206e14..ef2068a60d4ad 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -598,12 +598,6 @@ void udp_encap_enable(void) } EXPORT_SYMBOL(udp_encap_enable); -void udp_encap_disable(void) -{ - static_branch_dec(&udp_encap_needed_key); -} -EXPORT_SYMBOL(udp_encap_disable); - /* Handler for tunnels with arbitrary destination ports: no socket lookup, go * through error handlers in encapsulations looking for a match. */ diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 61c913b75c9e1..0158b0163ca8e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -483,7 +483,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; - unsigned int allocsz; if (x->encap) { int err = esp6_output_encap(x, skb, esp); @@ -492,10 +491,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info return err; } - allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); - if (allocsz > ESP_SKB_FRAG_MAXSIZE) - goto cow; - if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; @@ -813,7 +808,8 @@ int esp6_input_done2(struct sk_buff *skb, int err) struct tcphdr *th; offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); - if (offset == -1) { + + if (offset < 0) { err = -EINVAL; goto out; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2aa39ce7093df..d6f2126f46184 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1500,8 +1500,8 @@ static int __ip6_append_data(struct sock *sk, sizeof(struct frag_hdr) : 0) + rt->rt6i_nfheader_len; - if (mtu <= fragheaderlen || - ((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr)) + if (mtu < fragheaderlen || + ((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr)) goto emsgsize; maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 10760164a80f4..069551a04369e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1610,10 +1610,8 @@ void udpv6_destroy_sock(struct sock *sk) if (encap_destroy) encap_destroy(sk); } - if (up->encap_enabled) { + if (up->encap_enabled) static_branch_dec(&udpv6_encap_needed_key); - udp_encap_disable(); - } } inet6_destroy_sock(sk); diff --git a/net/key/af_key.c b/net/key/af_key.c index bd9b5c573b5a4..d1364b858fdf0 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1703,7 +1703,7 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad xfrm_probe_algs(); - supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); if (!supp_skb) { if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) pfk->registered &= ~(1<sadb_msg_satype); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 99a37c411323e..ac5cadd02cfa8 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -276,7 +276,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -288,14 +287,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) goto out; rc = -ENODEV; if (sk->sk_bound_dev_if) { - dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); - if (dev && addr->sllc_arphrd != dev->type) { - dev_put(dev); - dev = NULL; + llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + if (llc->dev && addr->sllc_arphrd != llc->dev->type) { + dev_put(llc->dev); + llc->dev = NULL; } } else - dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); - if (!dev) + llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); + if (!llc->dev) goto out; rc = -EUSERS; llc->laddr.lsap = llc_ui_autoport(); @@ -305,11 +304,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sap = llc_sap_open(llc->laddr.lsap, NULL); if (!sap) goto out; - - /* Note: We do not expect errors from this point. */ - llc->dev = dev; - dev = NULL; - memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); /* assign new connection to its SAP */ @@ -317,7 +311,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; out: - dev_put(dev); return rc; } @@ -340,7 +333,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -356,26 +348,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) rc = -ENODEV; rcu_read_lock(); if (sk->sk_bound_dev_if) { - dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); - if (dev) { + llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); + if (llc->dev) { if (is_zero_ether_addr(addr->sllc_mac)) - memcpy(addr->sllc_mac, dev->dev_addr, + memcpy(addr->sllc_mac, llc->dev->dev_addr, IFHWADDRLEN); - if (addr->sllc_arphrd != dev->type || + if (addr->sllc_arphrd != llc->dev->type || !ether_addr_equal(addr->sllc_mac, - dev->dev_addr)) { + llc->dev->dev_addr)) { rc = -EINVAL; - dev = NULL; + llc->dev = NULL; } } - } else { - dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, + } else + llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, addr->sllc_mac); - } - if (dev) - dev_hold(dev); + if (llc->dev) + dev_hold(llc->dev); rcu_read_unlock(); - if (!dev) + if (!llc->dev) goto out; if (!addr->sllc_sap) { rc = -EUSERS; @@ -408,11 +399,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out_put; } } - - /* Note: We do not expect errors from this point. */ - llc->dev = dev; - dev = NULL; - llc->laddr.lsap = addr->sllc_sap; memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); @@ -423,7 +409,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) out_put: llc_sap_put(sap); out: - dev_put(dev); release_sock(sk); return rc; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8010967a68741..d46ed4cbe7717 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2076,12 +2076,14 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, const struct mesh_setup *setup) { u8 *new_ie; + const u8 *old_ie; struct ieee80211_sub_if_data *sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); int i; /* allocate information elements */ new_ie = NULL; + old_ie = ifmsh->ie; if (setup->ie_len) { new_ie = kmemdup(setup->ie, setup->ie_len, @@ -2091,6 +2093,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, } ifmsh->ie_len = setup->ie_len; ifmsh->ie = new_ie; + kfree(old_ie); /* now copy the rest of the setup parameters */ ifmsh->mesh_id_len = setup->mesh_id_len; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 3f785bdfa942d..c8fb2187ad4b2 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -354,8 +354,8 @@ static void tcp_options(const struct sk_buff *skb, length, buff); BUG_ON(ptr == NULL); - state->td_scale = 0; - state->flags &= IP_CT_TCP_FLAG_BE_LIBERAL; + state->td_scale = + state->flags = 0; while (length > 0) { int opcode=*ptr++; @@ -840,16 +840,6 @@ static bool nf_conntrack_tcp_established(const struct nf_conn *ct) test_bit(IPS_ASSURED_BIT, &ct->status); } -static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state) -{ - state->td_end = 0; - state->td_maxend = 0; - state->td_maxwin = 0; - state->td_maxack = 0; - state->td_scale = 0; - state->flags &= IP_CT_TCP_FLAG_BE_LIBERAL; -} - /* Returns verdict for packet, or -1 for invalid. */ int nf_conntrack_tcp_packet(struct nf_conn *ct, struct sk_buff *skb, @@ -956,7 +946,8 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = ct->proto.tcp.last_flags; - nf_ct_tcp_state_reset(&ct->proto.tcp.seen[dir]); + memset(&ct->proto.tcp.seen[dir], 0, + sizeof(struct ip_ct_tcp_state)); break; } ct->proto.tcp.last_index = index; diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index a61b5bf5aa0fb..dbc2e945c98eb 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -162,7 +162,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv) struct nft_rule *const *rules; const struct nft_rule *rule; const struct nft_expr *expr, *last; - struct nft_regs regs = {}; + struct nft_regs regs; unsigned int stackptr = 0; struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; bool genbit = READ_ONCE(net->nft.gencursor); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f37916156ca52..e55af5c078ac0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -149,8 +149,6 @@ static const struct rhashtable_params netlink_rhashtable_params; static inline u32 netlink_group_mask(u32 group) { - if (group > 32) - return 0; return group ? 1 << (group - 1) : 0; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 7ff98d39ec942..a11b558813c10 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -730,57 +730,6 @@ static bool skb_nfct_cached(struct net *net, } #if IS_ENABLED(CONFIG_NF_NAT) -static void ovs_nat_update_key(struct sw_flow_key *key, - const struct sk_buff *skb, - enum nf_nat_manip_type maniptype) -{ - if (maniptype == NF_NAT_MANIP_SRC) { - __be16 src; - - key->ct_state |= OVS_CS_F_SRC_NAT; - if (key->eth.type == htons(ETH_P_IP)) - key->ipv4.addr.src = ip_hdr(skb)->saddr; - else if (key->eth.type == htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, - sizeof(key->ipv6.addr.src)); - else - return; - - if (key->ip.proto == IPPROTO_UDP) - src = udp_hdr(skb)->source; - else if (key->ip.proto == IPPROTO_TCP) - src = tcp_hdr(skb)->source; - else if (key->ip.proto == IPPROTO_SCTP) - src = sctp_hdr(skb)->source; - else - return; - - key->tp.src = src; - } else { - __be16 dst; - - key->ct_state |= OVS_CS_F_DST_NAT; - if (key->eth.type == htons(ETH_P_IP)) - key->ipv4.addr.dst = ip_hdr(skb)->daddr; - else if (key->eth.type == htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, - sizeof(key->ipv6.addr.dst)); - else - return; - - if (key->ip.proto == IPPROTO_UDP) - dst = udp_hdr(skb)->dest; - else if (key->ip.proto == IPPROTO_TCP) - dst = tcp_hdr(skb)->dest; - else if (key->ip.proto == IPPROTO_SCTP) - dst = sctp_hdr(skb)->dest; - else - return; - - key->tp.dst = dst; - } -} - /* Modelled after nf_nat_ipv[46]_fn(). * range is only used for new, uninitialized NAT state. * Returns either NF_ACCEPT or NF_DROP. @@ -788,7 +737,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key, static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_nat_range2 *range, - enum nf_nat_manip_type maniptype, struct sw_flow_key *key) + enum nf_nat_manip_type maniptype) { int hooknum, nh_off, err = NF_ACCEPT; @@ -861,13 +810,60 @@ push: skb_push(skb, nh_off); skb_postpush_rcsum(skb, skb->data, nh_off); - /* Update the flow key if NAT successful. */ - if (err == NF_ACCEPT) - ovs_nat_update_key(key, skb, maniptype); - return err; } +static void ovs_nat_update_key(struct sw_flow_key *key, + const struct sk_buff *skb, + enum nf_nat_manip_type maniptype) +{ + if (maniptype == NF_NAT_MANIP_SRC) { + __be16 src; + + key->ct_state |= OVS_CS_F_SRC_NAT; + if (key->eth.type == htons(ETH_P_IP)) + key->ipv4.addr.src = ip_hdr(skb)->saddr; + else if (key->eth.type == htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, + sizeof(key->ipv6.addr.src)); + else + return; + + if (key->ip.proto == IPPROTO_UDP) + src = udp_hdr(skb)->source; + else if (key->ip.proto == IPPROTO_TCP) + src = tcp_hdr(skb)->source; + else if (key->ip.proto == IPPROTO_SCTP) + src = sctp_hdr(skb)->source; + else + return; + + key->tp.src = src; + } else { + __be16 dst; + + key->ct_state |= OVS_CS_F_DST_NAT; + if (key->eth.type == htons(ETH_P_IP)) + key->ipv4.addr.dst = ip_hdr(skb)->daddr; + else if (key->eth.type == htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, + sizeof(key->ipv6.addr.dst)); + else + return; + + if (key->ip.proto == IPPROTO_UDP) + dst = udp_hdr(skb)->dest; + else if (key->ip.proto == IPPROTO_TCP) + dst = tcp_hdr(skb)->dest; + else if (key->ip.proto == IPPROTO_SCTP) + dst = sctp_hdr(skb)->dest; + else + return; + + key->tp.dst = dst; + } +} + /* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, @@ -907,7 +903,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, } else { return NF_ACCEPT; /* Connection is not NATed. */ } - err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key); + err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { if (ct->status & IPS_SRC_NAT) { @@ -917,13 +913,17 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, maniptype = NF_NAT_MANIP_SRC; err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, - maniptype, key); + maniptype); } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL, - NF_NAT_MANIP_SRC, key); + NF_NAT_MANIP_SRC); } } + /* Mark NAT done if successful and update the flow key. */ + if (err == NF_ACCEPT) + ovs_nat_update_key(key, skb, maniptype); + return err; } #else /* !CONFIG_NF_NAT */ diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 8c4bdfa627ca9..4c5c2331e7648 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2201,8 +2201,8 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, icmpv6_key->icmpv6_type = ntohs(output->tp.src); icmpv6_key->icmpv6_code = ntohs(output->tp.dst); - if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) || - swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { + if (icmpv6_key->icmpv6_type == NDISC_NEIGHBOUR_SOLICITATION || + icmpv6_key->icmpv6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { struct ovs_key_nd *nd_key; nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key)); diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 3bad9f5f91023..dce48162f6c27 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -760,12 +760,14 @@ void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool, bool, enum rxrpc_propose_ack_trace); void rxrpc_process_call(struct work_struct *); -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why); - -void rxrpc_delete_call_timer(struct rxrpc_call *call); +static inline void rxrpc_reduce_call_timer(struct rxrpc_call *call, + unsigned long expire_at, + unsigned long now, + enum rxrpc_timer_trace why) +{ + trace_rxrpc_timer(call, why, now); + timer_reduce(&call->timer, expire_at); +} /* * call_object.c @@ -789,7 +791,6 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *); bool __rxrpc_queue_call(struct rxrpc_call *); bool rxrpc_queue_call(struct rxrpc_call *); void rxrpc_see_call(struct rxrpc_call *); -bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op); void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_cleanup_call(struct rxrpc_call *); diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 22e05de5d1ca9..df864e6922679 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -310,7 +310,7 @@ recheck_state: } if (call->state == RXRPC_CALL_COMPLETE) { - rxrpc_delete_call_timer(call); + del_timer_sync(&call->timer); goto out_put; } diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 043508fd8d8a5..4eb91d958a48d 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -53,30 +53,10 @@ static void rxrpc_call_timer_expired(struct timer_list *t) if (call->state < RXRPC_CALL_COMPLETE) { trace_rxrpc_timer(call, rxrpc_timer_expired, jiffies); - __rxrpc_queue_call(call); - } else { - rxrpc_put_call(call, rxrpc_call_put); - } -} - -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why) -{ - if (rxrpc_try_get_call(call, rxrpc_call_got_timer)) { - trace_rxrpc_timer(call, why, now); - if (timer_reduce(&call->timer, expire_at)) - rxrpc_put_call(call, rxrpc_call_put_notimer); + rxrpc_queue_call(call); } } -void rxrpc_delete_call_timer(struct rxrpc_call *call) -{ - if (del_timer_sync(&call->timer)) - rxrpc_put_call(call, rxrpc_call_put_timer); -} - static struct lock_class_key rxrpc_call_user_mutex_lock_class_key; /* @@ -483,17 +463,6 @@ void rxrpc_see_call(struct rxrpc_call *call) } } -bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) -{ - const void *here = __builtin_return_address(0); - int n = atomic_fetch_add_unless(&call->usage, 1, 0); - - if (n == 0) - return false; - trace_rxrpc_call(call->debug_id, op, n, here, NULL); - return true; -} - /* * Note the addition of a ref on a call. */ @@ -541,7 +510,8 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) spin_unlock_bh(&call->lock); rxrpc_put_call_slot(call); - rxrpc_delete_call_timer(call); + + del_timer_sync(&call->timer); /* Make sure we don't get any more notifications */ write_lock_bh(&rx->recvmsg_lock); @@ -648,8 +618,6 @@ static void rxrpc_destroy_call(struct work_struct *work) struct rxrpc_call *call = container_of(work, struct rxrpc_call, processor); struct rxrpc_net *rxnet = call->rxnet; - rxrpc_delete_call_timer(call); - rxrpc_put_connection(call->conn); rxrpc_put_peer(call->peer); kfree(call->rxtx_buffer); @@ -684,6 +652,8 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) memset(&call->sock_node, 0xcd, sizeof(call->sock_node)); + del_timer_sync(&call->timer); + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 236fadc4a4399..6c320623cdcd7 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -139,5 +139,6 @@ cleanup_sunrpc(void) rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); fs_initcall(init_sunrpc); /* Ensure we're initialised before nfs */ module_exit(cleanup_sunrpc); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 46304e647c492..04aaca4b8bf93 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -2037,14 +2037,7 @@ static void xprt_destroy(struct rpc_xprt *xprt) */ wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE); - /* - * xprt_schedule_autodisconnect() can run after XPRT_LOCKED - * is cleared. We use ->transport_lock to ensure the mod_timer() - * can only run *before* del_time_sync(), never after. - */ - spin_lock(&xprt->transport_lock); del_timer_sync(&xprt->timer); - spin_unlock(&xprt->transport_lock); /* * Destroy sockets etc from the system workqueue so they can diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 42283dc6c5b7c..8d2c98531af45 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2846,8 +2846,7 @@ static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) /* Try again later if dest link is congested */ if (tsk->cong_link_cnt) { - sk_reset_timer(sk, &sk->sk_timer, - jiffies + msecs_to_jiffies(100)); + sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); return; } /* Prepare SYN for retransmit */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b7edca89e0ba9..fa99fe5bcf6ce 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -3008,4 +3008,5 @@ fs_initcall(af_unix_init); module_exit(af_unix_exit); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_ALIAS_NETPROTO(PF_UNIX); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index c59806253a65a..005aa701f4d52 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -333,8 +333,7 @@ void vsock_remove_sock(struct vsock_sock *vsk) } EXPORT_SYMBOL_GPL(vsock_remove_sock); -void vsock_for_each_connected_socket(struct vsock_transport *transport, - void (*fn)(struct sock *sk)) +void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) { int i; @@ -343,12 +342,8 @@ void vsock_for_each_connected_socket(struct vsock_transport *transport, for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) { struct vsock_sock *vsk; list_for_each_entry(vsk, &vsock_connected_table[i], - connected_table) { - if (vsk->transport != transport) - continue; - + connected_table) fn(sk_vsock(vsk)); - } } spin_unlock_bh(&vsock_table_lock); diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index e131121533ad9..3a056f8affd1d 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -24,7 +24,6 @@ static struct workqueue_struct *virtio_vsock_workqueue; static struct virtio_vsock __rcu *the_virtio_vsock; static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */ -static struct virtio_transport virtio_transport; /* forward declaration */ struct virtio_vsock { struct virtio_device *vdev; @@ -384,8 +383,7 @@ static void virtio_vsock_event_handle(struct virtio_vsock *vsock, switch (le32_to_cpu(event->id)) { case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: virtio_vsock_update_guest_cid(vsock); - vsock_for_each_connected_socket(&virtio_transport.transport, - virtio_vsock_reset_sock); + vsock_for_each_connected_socket(virtio_vsock_reset_sock); break; } } @@ -637,8 +635,7 @@ static void virtio_vsock_remove(struct virtio_device *vdev) synchronize_rcu(); /* Reset all connected sockets when the device disappear */ - vsock_for_each_connected_socket(&virtio_transport.transport, - virtio_vsock_reset_sock); + vsock_for_each_connected_socket(virtio_vsock_reset_sock); /* Stop all work handlers to make sure no one is accessing the device, * so we can safely call vdev->config->reset(). diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index a9ca95a0fcdda..1c9ecb18b8e64 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -75,8 +75,6 @@ static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; static int PROTOCOL_OVERRIDE = -1; -static struct vsock_transport vmci_transport; /* forward declaration */ - /* Helper function to convert from a VMCI error code to a VSock error code. */ static s32 vmci_transport_error_to_vsock_error(s32 vmci_error) @@ -884,8 +882,7 @@ static void vmci_transport_qp_resumed_cb(u32 sub_id, const struct vmci_event_data *e_data, void *client_data) { - vsock_for_each_connected_socket(&vmci_transport, - vmci_transport_handle_detach); + vsock_for_each_connected_socket(vmci_transport_handle_detach); } static void vmci_transport_recv_pkt_work(struct work_struct *work) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ed99f0bcae99..5d8959a5e7608 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -475,7 +475,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .len = IEEE80211_MAX_MESH_ID_LEN }, [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT, - [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, + /* allow 3 for NUL-termination, we used to declare this NLA_STRING */ + [NL80211_ATTR_REG_ALPHA2] = NLA_POLICY_RANGE(NLA_BINARY, 2, 3), [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index d231d4620c38f..03ed170b8125e 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1775,15 +1775,10 @@ void x25_kill_by_neigh(struct x25_neigh *nb) write_lock_bh(&x25_list_lock); - sk_for_each(s, &x25_list) { - if (x25_sk(s)->neighbour == nb) { - write_unlock_bh(&x25_list_lock); - lock_sock(s); + sk_for_each(s, &x25_list) + if (x25_sk(s)->neighbour == nb) x25_disconnect(s, ENETUNREACH, 0, 0); - release_sock(s); - write_lock_bh(&x25_list_lock); - } - } + write_unlock_bh(&x25_list_lock); /* Remove any related forwards */ diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index cf5b0a8952254..2e4508a6cb3a7 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -1520,15 +1520,14 @@ int main(int argc, char **argv) setlocale(LC_ALL, ""); - prev_time = get_nsecs(); - start_time = prev_time; - if (!opt_quiet) { ret = pthread_create(&pt, NULL, poller, NULL); if (ret) exit_with_error(ret); } + prev_time = get_nsecs(); + start_time = prev_time; if (opt_bench == BENCH_RXDROP) rx_drop_all(); diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index f1d201782346f..4852bf44e913e 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -22,7 +22,7 @@ dtc-objs += yamltree.o # To include installed in a non-default path HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1) # To link libyaml installed in a non-default path -HOSTLDLIBS_dtc := $(shell pkg-config --libs yaml-0.1) +HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs) endif # Generated files need one more search path to include headers in source tree diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index dacd697ffd383..48e141e079562 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -431,23 +431,6 @@ static unsigned int stackleak_cleanup_execute(void) return 0; } -/* - * STRING_CST may or may not be NUL terminated: - * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html - */ -static inline bool string_equal(tree node, const char *string, int length) -{ - if (TREE_STRING_LENGTH(node) < length) - return false; - if (TREE_STRING_LENGTH(node) > length + 1) - return false; - if (TREE_STRING_LENGTH(node) == length + 1 && - TREE_STRING_POINTER(node)[length] != '\0') - return false; - return !memcmp(TREE_STRING_POINTER(node), string, length); -} -#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str)) - static bool stackleak_gate(void) { tree section; @@ -457,13 +440,13 @@ static bool stackleak_gate(void) if (section && TREE_VALUE(section)) { section = TREE_VALUE(TREE_VALUE(section)); - if (STRING_EQUAL(section, ".init.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) return false; - if (STRING_EQUAL(section, ".devinit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) return false; - if (STRING_EQUAL(section, ".cpuinit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) return false; - if (STRING_EQUAL(section, ".meminit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) return false; } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index c4e9a70a0be7a..fab2dc30b5f47 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -62,7 +62,7 @@ static int __init evm_set_fixmode(char *str) else pr_err("invalid \"%s\" mode", str); - return 1; + return 0; } __setup("evm=", evm_set_fixmode); diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c index 63e5c646f7620..931d8dfb4a7f4 100644 --- a/security/keys/keyctl_pkey.c +++ b/security/keys/keyctl_pkey.c @@ -135,23 +135,15 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par switch (op) { case KEYCTL_PKEY_ENCRYPT: - if (uparams.in_len > info.max_dec_size || - uparams.out_len > info.max_enc_size) - return -EINVAL; - break; case KEYCTL_PKEY_DECRYPT: if (uparams.in_len > info.max_enc_size || uparams.out_len > info.max_dec_size) return -EINVAL; break; case KEYCTL_PKEY_SIGN: - if (uparams.in_len > info.max_data_size || - uparams.out_len > info.max_sig_size) - return -EINVAL; - break; case KEYCTL_PKEY_VERIFY: - if (uparams.in_len > info.max_data_size || - uparams.in2_len > info.max_sig_size) + if (uparams.in_len > info.max_sig_size || + uparams.out_len > info.max_data_size) return -EINVAL; break; default: @@ -159,7 +151,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par } params->in_len = uparams.in_len; - params->out_len = uparams.out_len; /* Note: same as in2_len */ + params->out_len = uparams.out_len; return 0; } diff --git a/security/security.c b/security/security.c index baa63edb53e29..1e0f79c665a34 100644 --- a/security/security.c +++ b/security/security.c @@ -826,22 +826,9 @@ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) return call_int_hook(fs_context_dup, 0, fc, src_fc); } -int security_fs_context_parse_param(struct fs_context *fc, - struct fs_parameter *param) +int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct security_hook_list *hp; - int trc; - int rc = -ENOPARAM; - - hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param, - list) { - trc = hp->hook.fs_context_parse_param(fc, param); - if (trc == 0) - rc = 0; - else if (trc != -ENOPARAM) - return trc; - } - return rc; + return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param); } int security_sb_alloc(struct super_block *sb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3024b84e68710..56a6a7056388f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2823,9 +2823,10 @@ static int selinux_fs_context_parse_param(struct fs_context *fc, return opt; rc = selinux_add_opt(opt, param->string, &fc->security); - if (!rc) + if (!rc) { param->string = NULL; - + rc = 1; + } return rc; } @@ -3706,12 +3707,6 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, CAP_OPT_NONE, true); break; - case FIOCLEX: - case FIONCLEX: - if (!selinux_policycap_ioctl_skip_cloexec()) - error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); - break; - /* default case assumes that the command will go * to the file's ioctl() function. */ diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h index a9e572ca4fd96..2ec038efbb03c 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -11,7 +11,6 @@ enum { POLICYDB_CAPABILITY_CGROUPSECLABEL, POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION, POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS, - POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h index ebd64afe1defd..b89289f092c93 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -12,8 +12,7 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { "always_check_network", "cgroup_seclabel", "nnp_nosuid_transition", - "genfs_seclabel_symlinks", - "ioctl_skip_cloexec" + "genfs_seclabel_symlinks" }; #endif /* _SELINUX_POLICYCAP_NAMES_H_ */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index cefd6e2a5ea88..a2c0cf6293cad 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -221,13 +221,6 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void) return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]); } -static inline bool selinux_policycap_ioctl_skip_cloexec(void) -{ - struct selinux_state *state = &selinux_state; - - return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC]); -} - static inline bool selinux_android_nlroute_getlink(void) { struct selinux_state *state = &selinux_state; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d893c2280f595..2b745ae8cb981 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -2124,8 +2124,6 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) } ret = sel_make_avc_files(dentry); - if (ret) - goto err; dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino); if (IS_ERR(dentry)) { diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 00e95f8bd7c73..7314196185d15 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -346,7 +346,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, int rc; struct xfrm_sec_ctx *ctx; char *ctx_str = NULL; - u32 str_len; + int str_len; if (!polsec) return 0; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d24b9700ebf92..fe8d33b287f5c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2507,7 +2507,7 @@ static int smk_ipv6_check(struct smack_known *subject, #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = PF_INET6; - ad.a.u.net->dport = address->sin6_port; + ad.a.u.net->dport = ntohs(address->sin6_port); if (act == SMK_RECEIVING) ad.a.u.net->v6info.saddr = address->sin6_addr; else diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 363b65be87ab7..3445ae6fd4794 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c @@ -24,7 +24,7 @@ static const char *tomoyo_loader; static int __init tomoyo_loader_setup(char *str) { tomoyo_loader = str; - return 1; + return 0; } __setup("TOMOYO_loader=", tomoyo_loader_setup); @@ -64,7 +64,7 @@ static const char *tomoyo_trigger; static int __init tomoyo_trigger_setup(char *str) { tomoyo_trigger = str; - return 1; + return 0; } __setup("TOMOYO_trigger=", tomoyo_trigger_setup); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f88de74da1eb3..d79febeebf0c5 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -774,11 +774,6 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, if (oss_period_size < 16) return -EINVAL; - - /* don't allocate too large period; 1MB period must be enough */ - if (oss_period_size > 1024 * 1024) - return -ENOMEM; - runtime->oss.period_bytes = oss_period_size; runtime->oss.period_frames = 1; runtime->oss.periods = oss_periods; @@ -1047,9 +1042,10 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) goto failure; } #endif - oss_period_size = array_size(oss_period_size, oss_frame_size); - oss_buffer_size = array_size(oss_period_size, runtime->oss.periods); - if (oss_buffer_size <= 0) { + oss_period_size *= oss_frame_size; + + oss_buffer_size = oss_period_size * runtime->oss.periods; + if (oss_buffer_size < 0) { err = -EINVAL; goto failure; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 1e2d1b35c1946..d5ca161d588c5 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -61,10 +61,7 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t } if ((width = snd_pcm_format_physical_width(format->format)) < 0) return width; - size = array3_size(frames, format->channels, width); - /* check for too large period size once again */ - if (size > 1024 * 1024) - return -ENOMEM; + size = frames * format->channels * width; if (snd_BUG_ON(size % 8)) return -ENXIO; size /= 8; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 59d222446d777..a8ae5928decda 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -969,8 +969,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, init_waitqueue_head(&runtime->tsleep); runtime->status->state = SNDRV_PCM_STATE_OPEN; - mutex_init(&runtime->buffer_mutex); - atomic_set(&runtime->buffer_accessing, 0); substream->runtime = runtime; substream->private_data = pcm->private_data; @@ -1004,7 +1002,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) } else { substream->runtime = NULL; } - mutex_destroy(&runtime->buffer_mutex); kfree(runtime); put_pid(substream->pid); substream->pid = NULL; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 289f52af15b96..5e04c4b9e0239 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2221,15 +2221,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, err = -EINVAL; goto _end_unlock; } - if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) { - err = -EBUSY; - goto _end_unlock; - } snd_pcm_stream_unlock_irq(substream); err = writer(substream, appl_ofs, data, offset, frames, transfer); snd_pcm_stream_lock_irq(substream); - atomic_dec(&runtime->buffer_accessing); if (err < 0) goto _end_unlock; err = pcm_accessible_state(runtime); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index a9a0d74f31656..4f03ba8ed0ae5 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -164,20 +164,19 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, size_t size; struct snd_dma_buffer new_dmab; - mutex_lock(&substream->pcm->open_mutex); if (substream->runtime) { buffer->error = -EBUSY; - goto unlock; + return; } if (!snd_info_get_line(buffer, line, sizeof(line))) { snd_info_get_str(str, line, sizeof(str)); size = simple_strtoul(str, NULL, 10) * 1024; if ((size != 0 && size < 8192) || size > substream->dma_max) { buffer->error = -EINVAL; - goto unlock; + return; } if (substream->dma_buffer.bytes == size) - goto unlock; + return; memset(&new_dmab, 0, sizeof(new_dmab)); new_dmab.dev = substream->dma_buffer.dev; if (size > 0) { @@ -186,7 +185,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; - goto unlock; + return; } substream->buffer_bytes_max = size; } else { @@ -198,8 +197,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, } else { buffer->error = -EINVAL; } - unlock: - mutex_unlock(&substream->pcm->open_mutex); } static inline void preallocate_info_init(struct snd_pcm_substream *substream) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 6cc7c2a9fe732..c5ef5182fcf19 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -667,30 +667,6 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, return 0; } -/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise - * block the further r/w operations - */ -static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime) -{ - if (!atomic_dec_unless_positive(&runtime->buffer_accessing)) - return -EBUSY; - mutex_lock(&runtime->buffer_mutex); - return 0; /* keep buffer_mutex, unlocked by below */ -} - -/* release buffer_mutex and clear r/w access flag */ -static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) -{ - mutex_unlock(&runtime->buffer_mutex); - atomic_inc(&runtime->buffer_accessing); -} - -#if IS_ENABLED(CONFIG_SND_PCM_OSS) -#define is_oss_stream(substream) ((substream)->oss.oss) -#else -#define is_oss_stream(substream) false -#endif - static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -702,25 +678,22 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - err = snd_pcm_buffer_access_lock(runtime); - if (err < 0) - return err; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: - if (!is_oss_stream(substream) && - atomic_read(&substream->mmap_count)) - err = -EBADFD; break; default: - err = -EBADFD; - break; + snd_pcm_stream_unlock_irq(substream); + return -EBADFD; } snd_pcm_stream_unlock_irq(substream); - if (err) - goto unlock; +#if IS_ENABLED(CONFIG_SND_PCM_OSS) + if (!substream->oss.oss) +#endif + if (atomic_read(&substream->mmap_count)) + return -EBADFD; snd_pcm_sync_stop(substream, true); @@ -807,21 +780,16 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if ((usecs = period_to_usecs(runtime)) >= 0) cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs); - err = 0; + return 0; _error: - if (err) { - /* hardware might be unusable from this time, - * so we force application to retry to set - * the correct hardware parameter settings - */ - snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); - if (substream->ops->hw_free != NULL) - substream->ops->hw_free(substream); - if (substream->managed_buffer_alloc) - snd_pcm_lib_free_pages(substream); - } - unlock: - snd_pcm_buffer_access_unlock(runtime); + /* hardware might be unusable from this time, + so we force application to retry to set + the correct hardware parameter settings */ + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + if (substream->ops->hw_free != NULL) + substream->ops->hw_free(substream); + if (substream->managed_buffer_alloc) + snd_pcm_lib_free_pages(substream); return err; } @@ -861,33 +829,26 @@ static int do_hw_free(struct snd_pcm_substream *substream) static int snd_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - int result = 0; + int result; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - result = snd_pcm_buffer_access_lock(runtime); - if (result < 0) - return result; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: - if (atomic_read(&substream->mmap_count)) - result = -EBADFD; break; default: - result = -EBADFD; - break; + snd_pcm_stream_unlock_irq(substream); + return -EBADFD; } snd_pcm_stream_unlock_irq(substream); - if (result) - goto unlock; + if (atomic_read(&substream->mmap_count)) + return -EBADFD; result = do_hw_free(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); - unlock: - snd_pcm_buffer_access_unlock(runtime); return result; } @@ -1193,17 +1154,15 @@ struct action_ops { static int snd_pcm_action_group(const struct action_ops *ops, struct snd_pcm_substream *substream, snd_pcm_state_t state, - bool stream_lock) + bool do_lock) { struct snd_pcm_substream *s = NULL; struct snd_pcm_substream *s1; int res = 0, depth = 1; snd_pcm_group_for_each_entry(s, substream) { - if (s != substream) { - if (!stream_lock) - mutex_lock_nested(&s->runtime->buffer_mutex, depth); - else if (s->pcm->nonatomic) + if (do_lock && s != substream) { + if (s->pcm->nonatomic) mutex_lock_nested(&s->self_group.mutex, depth); else spin_lock_nested(&s->self_group.lock, depth); @@ -1231,18 +1190,18 @@ static int snd_pcm_action_group(const struct action_ops *ops, ops->post_action(s, state); } _unlock: - /* unlock streams */ - snd_pcm_group_for_each_entry(s1, substream) { - if (s1 != substream) { - if (!stream_lock) - mutex_unlock(&s1->runtime->buffer_mutex); - else if (s1->pcm->nonatomic) - mutex_unlock(&s1->self_group.mutex); - else - spin_unlock(&s1->self_group.lock); + if (do_lock) { + /* unlock streams */ + snd_pcm_group_for_each_entry(s1, substream) { + if (s1 != substream) { + if (s1->pcm->nonatomic) + mutex_unlock(&s1->self_group.mutex); + else + spin_unlock(&s1->self_group.lock); + } + if (s1 == s) /* end */ + break; } - if (s1 == s) /* end */ - break; } return res; } @@ -1372,15 +1331,10 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, /* Guarantee the group members won't change during non-atomic action */ down_read(&snd_pcm_link_rwsem); - res = snd_pcm_buffer_access_lock(substream->runtime); - if (res < 0) - goto unlock; if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, false); else res = snd_pcm_action_single(ops, substream, state); - snd_pcm_buffer_access_unlock(substream->runtime); - unlock: up_read(&snd_pcm_link_rwsem); return res; } @@ -1875,13 +1829,11 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); if (err < 0) return err; - snd_pcm_stream_lock_irq(substream); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; - snd_pcm_stream_unlock_irq(substream); return 0; } @@ -1889,12 +1841,10 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); runtime->control->appl_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - snd_pcm_stream_unlock_irq(substream); } static const struct action_ops snd_pcm_action_reset = { diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index df44dd5dc4b22..bbfbebf4affbc 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c @@ -240,7 +240,9 @@ int fcp_avc_transaction(struct fw_unit *unit, t.response_match_bytes = response_match_bytes; t.state = STATE_PENDING; init_waitqueue_head(&t.wait); - t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03); + + if (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03) + t.deferrable = true; spin_lock_irq(&transactions_lock); list_add_tail(&t.list, &transactions); diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 9ee3a312c6793..fa3c39cff5f85 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -544,7 +544,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, static int dev; int err; struct snd_card *card; - struct pnp_dev *cdev, *iter; + struct pnp_dev *cdev; char cid[PNP_ID_LEN]; if (pnp_device_is_isapnp(pdev)) @@ -560,11 +560,9 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, strcpy(cid, pdev->id[0].id); cid[5] = '1'; cdev = NULL; - list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) { - if (!strcmp(iter->id[0].id, cid)) { - cdev = iter; + list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) { + if (!strcmp(cdev->id[0].id, cid)) break; - } } err = snd_cs423x_card_new(&pdev->dev, dev, &card); if (err < 0) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 963731cf0d8c8..012a7ee849e8a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -938,8 +938,8 @@ static int snd_ac97_ad18xx_pcm_get_volume(struct snd_kcontrol *kcontrol, struct int codec = kcontrol->private_value & 3; mutex_lock(&ac97->page_mutex); - ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); - ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); + ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); + ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); mutex_unlock(&ac97->page_mutex); return 0; } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 120dd8b33ac81..7363d61eaec23 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -302,6 +302,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_MICGAINZ 0x01 /* mic boost */ #define CM_MICGAINZ_SHIFT 0 +#define CM_REG_MIXER3 0x24 #define CM_REG_AUX_VOL 0x26 #define CM_VAUXL_MASK 0xf0 #define CM_VAUXR_MASK 0x0f @@ -3290,7 +3291,7 @@ static void snd_cmipci_remove(struct pci_dev *pci) */ static const unsigned char saved_regs[] = { CM_REG_FUNCTRL1, CM_REG_CHFORMAT, CM_REG_LEGACY_CTRL, CM_REG_MISC_CTRL, - CM_REG_MIXER0, CM_REG_MIXER1, CM_REG_MIXER2, CM_REG_AUX_VOL, CM_REG_PLL, + CM_REG_MIXER0, CM_REG_MIXER1, CM_REG_MIXER2, CM_REG_MIXER3, CM_REG_PLL, CM_REG_CH0_FRAME1, CM_REG_CH0_FRAME2, CM_REG_CH1_FRAME1, CM_REG_CH1_FRAME2, CM_REG_EXT_MISC, CM_REG_INT_STATUS, CM_REG_INT_HLDCLR, CM_REG_FUNCTRL0, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71e11481ba41c..fe725f0f09312 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1608,7 +1608,6 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, struct hda_codec *codec = per_pin->codec; struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; - struct device *dev = hda_codec_dev(codec); hda_nid_t pin_nid = per_pin->pin_nid; int dev_id = per_pin->dev_id; /* @@ -1622,13 +1621,8 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, int present; int ret; -#ifdef CONFIG_PM - if (dev->power.runtime_status == RPM_SUSPENDING) - return; -#endif - ret = snd_hda_power_up_pm(codec); - if (ret < 0 && pm_runtime_suspended(dev)) + if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) goto out; present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b886326ce9b96..ed0cfcb05ef0d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3615,8 +3615,8 @@ static void alc256_shutup(struct hda_codec *codec) /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly * when booting with headset plugged. So skip setting it for the codec alc257 */ - if (codec->core.vendor_id != 0x10ec0236 && - codec->core.vendor_id != 0x10ec0257) + if (spec->codec_variant != ALC269_TYPE_ALC257 && + spec->codec_variant != ALC269_TYPE_ALC256) alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (!spec->no_shutup_pins) @@ -6762,7 +6762,6 @@ enum { ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, - ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS, ALC269VC_FIXUP_ACER_HEADSET_MIC, @@ -8084,14 +8083,6 @@ static const struct hda_fixup alc269_fixups[] = { { } }, }, - [ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x08}, - { 0x20, AC_VERB_SET_PROC_COEF, 0x2fcf}, - { } - }, - }, [ALC295_FIXUP_ASUS_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8810,7 +8801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), @@ -8844,7 +8834,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), @@ -8895,8 +8884,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[5|7][0-9]RZ[Q]", ALC269_FIXUP_DMIC), SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x866d, "Clevo NP5[05]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x867d, "Clevo NP7[01]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME), SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -9187,7 +9174,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, - {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"}, @@ -10853,7 +10839,6 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 97533412ce11e..6a63e8797a0b6 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -280,10 +280,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); - ret = clk_enable(ssc_p->ssc->clk); - if (ret) - return ret; - + clk_enable(ssc_p->ssc->clk); ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC unless initialized to keep it in a clean state */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 8a55d59a6c2aa..ed1f69b570244 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -214,7 +214,6 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "dai and pcm info missing\n"); - of_node_put(codec_np); return -EINVAL; } at91sam9g20ek_dai.cpus->of_node = cpu_np; diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index 529604a06c532..9fbc3c1113cc5 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -142,7 +142,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) if (!cpu_np) { dev_err(&pdev->dev, "atmel,ssc-controller node missing\n"); ret = -EINVAL; - goto out_put_codec_np; + goto out; } dai->cpus->of_node = cpu_np; dai->platforms->of_node = cpu_np; @@ -153,10 +153,13 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "Failed to set SSC %d for audio: %d\n", ret, priv->ssc_id); - goto out_put_cpu_np; + goto out; } - ret = devm_snd_soc_register_card(&pdev->dev, card); + of_node_put(codec_np); + of_node_put(cpu_np); + + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "Platform device allocation failed\n"); goto out_put_audio; @@ -164,14 +167,10 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s ok\n", __func__); - goto out_put_cpu_np; + return ret; out_put_audio: atmel_ssc_put_audio(priv->ssc_id); -out_put_cpu_np: - of_node_put(cpu_np); -out_put_codec_np: - of_node_put(codec_np); out: return ret; } @@ -181,6 +180,7 @@ static int sam9x5_wm8731_driver_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct sam9x5_drvdata *priv = card->drvdata; + snd_soc_unregister_card(card); atmel_ssc_put_audio(priv->ssc_id); return 0; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 52c89a6f54e9a..34c6dd04b85a3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -659,7 +659,6 @@ config SND_SOC_CS4349 config SND_SOC_CS47L15 tristate - depends on MFD_CS47L15 config SND_SOC_CS47L24 tristate @@ -667,19 +666,15 @@ config SND_SOC_CS47L24 config SND_SOC_CS47L35 tristate - depends on MFD_CS47L35 config SND_SOC_CS47L85 tristate - depends on MFD_CS47L85 config SND_SOC_CS47L90 tristate - depends on MFD_CS47L90 config SND_SOC_CS47L92 tristate - depends on MFD_CS47L92 # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 971b8360b5b1b..3ddd822240e3a 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1221,10 +1221,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1236,10 +1234,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1250,10 +1246,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, @@ -1270,10 +1264,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); - -err_disable_clk: - clk_disable_unprepare(priv->mclk); - return ret; } static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 9ad7fc0baf072..fcc10c8bc6259 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1201,7 +1201,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->mclk); if (ret < 0) { dev_err(dev, "failed to enable mclk %d\n", ret); - goto err_clk; + return ret; } dev_set_drvdata(dev, priv); @@ -1209,9 +1209,6 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &msm8916_wcd_digital, msm8916_wcd_digital_dai, ARRAY_SIZE(msm8916_wcd_digital_dai)); -err_clk: - clk_disable_unprepare(priv->ahbclk); - return ret; } static int msm8916_wcd_digital_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 456d9b24d0249..1f39d5998cf67 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -107,7 +107,6 @@ int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, priv->mtkaif_protocol = mtkaif_protocol; return 0; } -EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol); static void playback_gpio_set(struct mt6358_priv *priv) { @@ -274,7 +273,6 @@ int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); return 0; } -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) { @@ -298,7 +296,6 @@ int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) capture_gpio_reset(priv); return 0; } -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, int phase_1, int phase_2) @@ -313,7 +310,6 @@ int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); return 0; } -EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); /* dl pga gain */ enum { diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 4423e61bf1abf..db8a41aaa3859 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3478,8 +3478,6 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) table_size = sizeof(struct impedance_mapping_table) * rt5663->pdata.impedance_sensing_num; rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL); - if (!rt5663->imp_table) - return -ENOMEM; ret = device_property_read_u32_array(dev, "realtek,impedance_sensing_table", (u32 *)rt5663->imp_table, table_size); diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 8540ac230d0ed..01df3f4e045a9 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2522,16 +2522,13 @@ static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc, mode_val = ucontrol->value.enumerated.item[0]; - if (mode_val == wcd->hph_mode) - return 0; - if (mode_val == 0) { dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); mode_val = CLS_H_LOHIFI; } wcd->hph_mode = mode_val; - return 1; + return 0; } static int slim_rx_mux_get(struct snd_kcontrol *kc, @@ -5047,7 +5044,6 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) } wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np); - of_node_put(ifc_dev_np); if (!wcd->sidev) { dev_err(dev, "Unable to get SLIM Interface device\n"); return -EINVAL; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index ec5d997725b9c..a6aa212fa0c89 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1536,38 +1536,18 @@ static int wm8350_component_probe(struct snd_soc_component *component) wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, wm8350_hpl_jack_handler, 0, "Left jack detect", priv); - if (ret != 0) - goto err; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, wm8350_hpr_jack_handler, 0, "Right jack detect", priv); - if (ret != 0) - goto free_jck_det_l; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, wm8350_mic_handler, 0, "Microphone short", priv); - if (ret != 0) - goto free_jck_det_r; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, wm8350_mic_handler, 0, "Microphone detect", priv); - if (ret != 0) - goto free_micscd; return 0; - -free_micscd: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv); -free_jck_det_r: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); -free_jck_det_l: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); -err: - return ret; } static void wm8350_component_remove(struct snd_soc_component *component) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 36da0f01571a1..fd4160289faca 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -403,13 +403,9 @@ static int dw_i2s_runtime_suspend(struct device *dev) static int dw_i2s_runtime_resume(struct device *dev) { struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); - int ret; - if (dw_dev->capability & DW_I2S_MASTER) { - ret = clk_enable(dw_dev->clk); - if (ret) - return ret; - } + if (dw_dev->capability & DW_I2S_MASTER) + clk_enable(dw_dev->clk); return 0; } @@ -426,13 +422,10 @@ static int dw_i2s_resume(struct snd_soc_component *component) { struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); struct snd_soc_dai *dai; - int stream, ret; + int stream; - if (dev->capability & DW_I2S_MASTER) { - ret = clk_enable(dev->clk); - if (ret) - return ret; - } + if (dev->capability & DW_I2S_MASTER) + clk_enable(dev->clk); for_each_component_dais(component, dai) { for_each_pcm_streams(stream) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index d01e8d516df1f..15bcb0f38ec9e 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -544,8 +544,6 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - /* Disable TX clock */ - regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0); } else { scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 9e602c3456196..fad1eb6253d53 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -87,7 +87,6 @@ static int imx_es8328_probe(struct platform_device *pdev) if (int_port > MUX_PORT_MAX || int_port == 0) { dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", MUX_PORT_MAX); - ret = -EINVAL; goto fail; } diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d0d79f47bfdd5..6cada4c1e283b 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -255,7 +255,7 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream, struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; - int ret; + int ret = 0; if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index f2eda81985e27..07f8cf9980e31 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -455,10 +455,7 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, * basic clock which should be fast enough for the internal * logic. */ - ret = clk_enable(saif->clk); - if (ret) - return ret; - + clk_enable(saif->clk); ret = clk_set_rate(saif->clk, 24000000); clk_disable(saif->clk); if (ret) diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index fb721bc499496..a6407f4388de7 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -118,9 +118,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) codec_np = of_parse_phandle(np, "audio-codec", 0); if (!saif_np[0] || !saif_np[1] || !codec_np) { dev_err(&pdev->dev, "phandle missing or invalid\n"); - of_node_put(codec_np); - of_node_put(saif_np[0]); - of_node_put(saif_np[1]); return -EINVAL; } diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 785baf98f9da2..fa84ec695b525 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -624,23 +624,20 @@ static int rockchip_i2s_probe(struct platform_device *pdev) i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); if (IS_ERR(i2s->mclk)) { dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); - ret = PTR_ERR(i2s->mclk); - goto err_clk; + return PTR_ERR(i2s->mclk); } - regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - goto err_clk; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &rockchip_i2s_regmap_config); if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "Failed to initialise managed register map\n"); - ret = PTR_ERR(i2s->regmap); - goto err_clk; + return PTR_ERR(i2s->regmap); } i2s->playback_dma_data.addr = res->start + I2S_TXDR; @@ -699,8 +696,7 @@ err_suspend: i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk: - clk_disable_unprepare(i2s->hclk); + return ret; } diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0fa72907d5bf1..3c574792231bc 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -816,27 +816,14 @@ static int fsi_clk_enable(struct device *dev, return ret; } - ret = clk_enable(clock->xck); - if (ret) - goto err; - ret = clk_enable(clock->ick); - if (ret) - goto disable_xck; - ret = clk_enable(clock->div); - if (ret) - goto disable_ick; + clk_enable(clock->xck); + clk_enable(clock->ick); + clk_enable(clock->div); clock->count++; } return ret; - -disable_ick: - clk_disable(clock->ick); -disable_xck: - clk_disable(clock->xck); -err: - return ret; } static int fsi_clk_disable(struct device *dev, diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d0f3ff8edd904..3a6a60215e815 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -766,11 +766,6 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) return -EINVAL; } - if (!codec_dai) { - dev_err(rtd->card->dev, "Missing codec\n"); - return -EINVAL; - } - /* check client and interface hw capabilities */ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ea145eedcb68d..19f6ff047cddc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3053,7 +3053,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, for_each_component(pos) { component_of_node = soc_component_to_node(pos); - if (component_of_node != args->np || !pos->num_dai) + if (component_of_node != args->np) continue; ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 0d100b4e43f7e..9ef80a48707eb 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -83,10 +83,10 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component, memset(&slave_config, 0, sizeof(slave_config)); - if (pcm->config && pcm->config->prepare_slave_config) - prepare_slave_config = pcm->config->prepare_slave_config; - else + if (!pcm->config) prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; + else + prepare_slave_config = pcm->config->prepare_slave_config; if (prepare_slave_config) { ret = prepare_slave_config(substream, params, &slave_config); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 23a5f9a52da0f..4d24ac255d253 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -578,8 +578,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, if (le32_to_cpu(hdr->ops.info) == SND_SOC_TPLG_CTL_BYTES && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER - && (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ - || k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) + && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { struct soc_bytes_ext *sbe; struct snd_soc_tplg_bytes_control *be; diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 6943c05273ae7..cb822d9537678 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -191,7 +191,6 @@ static int imx8m_probe(struct snd_sof_dev *sdev) } ret = of_address_to_resource(res_node, 0, &res); - of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); goto exit_pdev_unregister; diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 347636a80b487..2707a16c6a4d3 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -47,7 +47,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); if (ret < 0) { dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret); - goto out_put; + goto error; } hstream->period_bytes = 0;/* initialize period_bytes */ @@ -58,23 +58,22 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret); - goto out_free; + goto error; } } else { ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); - goto out_free; + goto error; } hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); } return dsp_stream; -out_free: - snd_dma_free_pages(dmab); -out_put: +error: hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + snd_dma_free_pages(dmab); return ERR_PTR(ret); } diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index dd9013c476649..2ed92c990b97c 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -91,7 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); } ret = IRQ_HANDLED; @@ -105,7 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); ret = IRQ_HANDLED; } @@ -138,7 +138,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); ret = IRQ_HANDLED; } diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 065c5f0d1f5f0..136059331211d 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -65,7 +65,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { dev_err(reader->dev, "FIFO error detected\n"); - snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(reader->substream); ret = IRQ_HANDLED; } diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 4895bcee1f557..dd34504c09ba8 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -708,9 +708,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return -ENODEV; - ret = clk_enable(dev->clk); - if (ret) - goto err_put_clk; + clk_enable(dev->clk); dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); @@ -732,7 +730,6 @@ err_unregister_component: snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); -err_put_clk: clk_put(dev->clk); return ret; } diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 5c4158069a5a8..ce19a6058b279 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -84,7 +84,6 @@ struct xlnx_pcm_drv_data { struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; struct clk *axi_clk; - unsigned int sysclk; }; /* @@ -315,15 +314,6 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) return IRQ_NONE; } -static int xlnx_formatter_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir) -{ - struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); - - adata->sysclk = freq; - return 0; -} - static int xlnx_formatter_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -460,25 +450,11 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component, u64 size; struct snd_pcm_runtime *runtime = substream->runtime; struct xlnx_pcm_stream_param *stream_data = runtime->private_data; - struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); active_ch = params_channels(params); if (active_ch > stream_data->ch_limit) return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - adata->sysclk) { - unsigned int mclk_fs = adata->sysclk / params_rate(params); - - if (adata->sysclk % params_rate(params) != 0) { - dev_warn(component->dev, "sysclk %u not divisible by rate %u\n", - adata->sysclk, params_rate(params)); - return -EINVAL; - } - - writel(mclk_fs, stream_data->mmio + XLNX_AUD_FS_MULTIPLIER); - } - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && stream_data->xfer_mode == AES_TO_PCM) { val = readl(stream_data->mmio + XLNX_AUD_STS); @@ -576,7 +552,6 @@ static int xlnx_formatter_pcm_new(struct snd_soc_component *component, static const struct snd_soc_component_driver xlnx_asoc_component = { .name = DRV_NAME, - .set_sysclk = xlnx_formatter_set_sysclk, .open = xlnx_formatter_pcm_open, .close = xlnx_formatter_pcm_close, .hw_params = xlnx_formatter_pcm_hw_params, diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 8a2da6b1012eb..76c0e37a838cf 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -218,9 +218,7 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) runtime->hw = snd_at73c213_playback_hw; chip->substream = substream; - err = clk_enable(chip->ssc->clk); - if (err) - return err; + clk_enable(chip->ssc->clk); return 0; } @@ -778,9 +776,7 @@ static int snd_at73c213_chip_init(struct snd_at73c213 *chip) goto out; /* Enable DAC master clock. */ - retval = clk_enable(chip->board->dac_clk); - if (retval) - goto out; + clk_enable(chip->board->dac_clk); /* Initialize at73c213 on SPI bus. */ retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); @@ -893,9 +889,7 @@ static int snd_at73c213_dev_init(struct snd_card *card, chip->card = card; chip->irq = -1; - retval = clk_enable(chip->ssc->clk); - if (retval) - return retval; + clk_enable(chip->ssc->clk); retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); if (retval) { @@ -1014,9 +1008,7 @@ static int snd_at73c213_remove(struct spi_device *spi) int retval; /* Stop playback. */ - retval = clk_enable(chip->ssc->clk); - if (retval) - goto out; + clk_enable(chip->ssc->clk); ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); clk_disable(chip->ssc->clk); @@ -1096,16 +1088,9 @@ static int snd_at73c213_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_at73c213 *chip = card->private_data; - int retval; - retval = clk_enable(chip->board->dac_clk); - if (retval) - return retval; - retval = clk_enable(chip->ssc->clk); - if (retval) { - clk_disable(chip->board->dac_clk); - return retval; - } + clk_enable(chip->board->dac_clk); + clk_enable(chip->ssc->clk); ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); return 0; diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 81ace832d7e42..8f6823df944ff 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -542,16 +542,6 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x25c4, 0x0003), .map = scms_usb3318_map, }, - { - /* Corsair Virtuoso SE Latest (wired mode) */ - .id = USB_ID(0x1b1c, 0x0a3f), - .map = corsair_virtuoso_map, - }, - { - /* Corsair Virtuoso SE Latest (wireless mode) */ - .id = USB_ID(0x1b1c, 0x0a40), - .map = corsair_virtuoso_map, - }, { .id = USB_ID(0x30be, 0x0101), /* Schiit Hel */ .ignore_ctl_error = 1, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 99f2203bf51f1..86fdd669f3fd7 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3135,10 +3135,9 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, if (unitid == 7 && cval->control == UAC_FU_VOLUME) snd_dragonfly_quirk_db_scale(mixer, cval, kctl); break; - /* lowest playback value is muted on some devices */ - case USB_ID(0x0d8c, 0x000c): /* C-Media */ - case USB_ID(0x0d8c, 0x0014): /* C-Media */ - case USB_ID(0x19f7, 0x0003): /* RODE NT-USB */ + /* lowest playback value is muted on C-Media devices */ + case USB_ID(0x0d8c, 0x000c): + case USB_ID(0x0d8c, 0x0014): if (strstr(kctl->id.name, "Playback")) cval->min_mute = 1; break; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f3571fb3e65e1..26b6bee72039a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1491,8 +1491,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 1, if current task belongs to the cgroup2. - * * 0, if current task does not belong to the cgroup2. + * * 0, if current task belongs to the cgroup2. + * * 1, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index bd22853be4a6b..0911aea4cdbe5 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -1416,11 +1416,6 @@ static const char *btf_dump_resolve_name(struct btf_dump *d, __u32 id, if (s->name_resolved) return *cached_name ? *cached_name : orig_name; - if (btf_is_fwd(t) || (btf_is_enum(t) && btf_vlen(t) == 0)) { - s->name_resolved = 1; - return orig_name; - } - dup_cnt = btf_dump_name_dups(d, name_map, orig_name); if (dup_cnt > 1) { const size_t max_len = 256; diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 61df26f048d91..b337d6f29098b 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -10923,9 +10923,6 @@ void bpf_object__detach_skeleton(struct bpf_object_skeleton *s) void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s) { - if (!s) - return; - if (s->progs) bpf_object__detach_skeleton(s); if (s->obj) diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index c4390ef98b192..3028f932e10c0 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -895,23 +895,12 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, int xsk_umem__delete(struct xsk_umem *umem) { - struct xdp_mmap_offsets off; - int err; - if (!umem) return 0; if (umem->refcount) return -EBUSY; - err = xsk_get_mmap_offsets(umem->fd, &off); - if (!err && umem->fill_save && umem->comp_save) { - munmap(umem->fill_save->ring - off.fr.desc, - off.fr.desc + umem->config.fill_size * sizeof(__u64)); - munmap(umem->comp_save->ring - off.cr.desc, - off.cr.desc + umem->config.comp_size * sizeof(__u64)); - } - close(umem->fd); free(umem); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3609da7cce0ab..4d569ad7db02d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -231,7 +231,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols) prev = curr; curr = rb_entry(nd, struct symbol, rb_node); - if (prev->end == prev->start || prev->end != curr->start) + if (prev->end == prev->start && prev->end != curr->start) arch__symbols__fixup_end(prev, curr); } diff --git a/tools/testing/selftests/bpf/prog_tests/timer_crash.c b/tools/testing/selftests/bpf/prog_tests/timer_crash.c new file mode 100644 index 0000000000000..f74b82305da8c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/timer_crash.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "timer_crash.skel.h" + +enum { + MODE_ARRAY, + MODE_HASH, +}; + +static void test_timer_crash_mode(int mode) +{ + struct timer_crash *skel; + + skel = timer_crash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "timer_crash__open_and_load")) + return; + skel->bss->pid = getpid(); + skel->bss->crash_map = mode; + if (!ASSERT_OK(timer_crash__attach(skel), "timer_crash__attach")) + goto end; + usleep(1); +end: + timer_crash__destroy(skel); +} + +void test_timer_crash(void) +{ + if (test__start_subtest("array")) + test_timer_crash_mode(MODE_ARRAY); + if (test__start_subtest("hash")) + test_timer_crash_mode(MODE_HASH); +} diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/testing/selftests/bpf/progs/test_sock_fields.c index 7967348b11af6..81b57b9aaaeae 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -113,7 +113,7 @@ static void tpcpy(struct bpf_tcp_sock *dst, #define RET_LOG() ({ \ linum = __LINE__; \ - bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_ANY); \ + bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_NOEXIST); \ return CG_OK; \ }) diff --git a/tools/testing/selftests/bpf/progs/timer_crash.c b/tools/testing/selftests/bpf/progs/timer_crash.c new file mode 100644 index 0000000000000..f8f7944e70dae --- /dev/null +++ b/tools/testing/selftests/bpf/progs/timer_crash.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +struct map_elem { + struct bpf_timer timer; + struct bpf_spin_lock lock; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct map_elem); +} amap SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct map_elem); +} hmap SEC(".maps"); + +int pid = 0; +int crash_map = 0; /* 0 for amap, 1 for hmap */ + +SEC("fentry/do_nanosleep") +int sys_enter(void *ctx) +{ + struct map_elem *e, value = {}; + void *map = crash_map ? (void *)&hmap : (void *)&amap; + + if (bpf_get_current_task_btf()->tgid != pid) + return 0; + + *(void **)&value = (void *)0xdeadcaf3; + + bpf_map_update_elem(map, &(int){0}, &value, 0); + /* For array map, doing bpf_map_update_elem will do a + * check_and_free_timer_in_array, which will trigger the crash if timer + * pointer was overwritten, for hmap we need to use bpf_timer_cancel. + */ + if (crash_map == 1) { + e = bpf_map_lookup_elem(map, &(int){0}); + if (!e) + return 0; + bpf_timer_cancel(&e->timer); + } + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing/selftests/bpf/test_lirc_mode2.sh index 5252b91f48a18..ec4e15948e406 100755 --- a/tools/testing/selftests/bpf/test_lirc_mode2.sh +++ b/tools/testing/selftests/bpf/test_lirc_mode2.sh @@ -3,7 +3,6 @@ # Kselftest framework requirement - SKIP code is 4. ksft_skip=4 -ret=$ksft_skip msg="skip all tests:" if [ $UID != 0 ]; then @@ -26,7 +25,7 @@ do fi done -if [ -n "$LIRCDEV" ]; +if [ -n $LIRCDEV ]; then TYPE=lirc_mode2 ./test_lirc_mode2_user $LIRCDEV $INPUTDEV @@ -37,5 +36,3 @@ then echo -e ${GREEN}"PASS: $TYPE"${NC} fi fi - -exit $ret diff --git a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh index 6c69c42b1d607..b497bb85b667f 100755 --- a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh +++ b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh @@ -120,14 +120,6 @@ setup() ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=0 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=0 - # disable IPv6 DAD because it sometimes takes too long and fails tests - ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip link add veth1 type veth peer name veth2 ip link add veth3 type veth peer name veth4 ip link add veth5 type veth peer name veth6 @@ -297,7 +289,7 @@ test_ping() ip netns exec ${NS1} ping -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null RET=$? elif [ "${PROTO}" == "IPv6" ] ; then - ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/null + ip netns exec ${NS1} ping6 -c 1 -W 6 -I veth1 ${IPv6_DST} 2>&1 > /dev/null RET=$? else echo " test_ping: unknown PROTO: ${PROTO}" diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile new file mode 100644 index 0000000000000..8a3f2cd9fec0c --- /dev/null +++ b/tools/testing/selftests/damon/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for damon selftests + +TEST_FILES = _chk_dependency.sh +TEST_PROGS = debugfs_attrs.sh + +include ../lib.mk diff --git a/tools/testing/selftests/damon/_chk_dependency.sh b/tools/testing/selftests/damon/_chk_dependency.sh new file mode 100644 index 0000000000000..0189db81550be --- /dev/null +++ b/tools/testing/selftests/damon/_chk_dependency.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +DBGFS=/sys/kernel/debug/damon + +if [ $EUID -ne 0 ]; +then + echo "Run as root" + exit $ksft_skip +fi + +if [ ! -d "$DBGFS" ] +then + echo "$DBGFS not found" + exit $ksft_skip +fi + +for f in attrs target_ids monitor_on +do + if [ ! -f "$DBGFS/$f" ] + then + echo "$f not found" + exit 1 + fi +done diff --git a/tools/testing/selftests/damon/debugfs_attrs.sh b/tools/testing/selftests/damon/debugfs_attrs.sh new file mode 100644 index 0000000000000..196b6640bf378 --- /dev/null +++ b/tools/testing/selftests/damon/debugfs_attrs.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +test_write_result() { + file=$1 + content=$2 + orig_content=$3 + expect_reason=$4 + expected=$5 + + echo "$content" > "$file" + if [ $? -ne "$expected" ] + then + echo "writing $content to $file doesn't return $expected" + echo "expected because: $expect_reason" + echo "$orig_content" > "$file" + exit 1 + fi +} + +test_write_succ() { + test_write_result "$1" "$2" "$3" "$4" 0 +} + +test_write_fail() { + test_write_result "$1" "$2" "$3" "$4" 1 +} + +test_content() { + file=$1 + orig_content=$2 + expected=$3 + expect_reason=$4 + + content=$(cat "$file") + if [ "$content" != "$expected" ] + then + echo "reading $file expected $expected but $content" + echo "expected because: $expect_reason" + echo "$orig_content" > "$file" + exit 1 + fi +} + +source ./_chk_dependency.sh + +# Test attrs file +# =============== + +file="$DBGFS/attrs" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4 5" "$orig_content" "valid input" +test_write_fail "$file" "1 2 3 4" "$orig_content" "no enough fields" +test_write_fail "$file" "1 2 3 5 4" "$orig_content" \ + "min_nr_regions > max_nr_regions" +test_content "$file" "$orig_content" "1 2 3 4 5" "successfully written" +echo "$orig_content" > "$file" + +# Test schemes file +# ================= + +file="$DBGFS/schemes" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \ + "$orig_content" "valid input" +test_write_fail "$file" "1 2 +3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines" +test_write_succ "$file" "" "$orig_content" "disabling" +echo "$orig_content" > "$file" + +# Test target_ids file +# ==================== + +file="$DBGFS/target_ids" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input" +test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input" +test_content "$file" "$orig_content" "1 2" "non-integer was there" +test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input" +test_content "$file" "$orig_content" "" "wrong input written" +test_write_succ "$file" "" "$orig_content" "empty input" +test_content "$file" "$orig_content" "" "empty input written" +echo "$orig_content" > "$file" + +echo "PASS" diff --git a/tools/testing/selftests/filesystems/fuse/fd_bpf.c b/tools/testing/selftests/filesystems/fuse/fd_bpf.c index f9102058515ff..ebf5c92c92972 100644 --- a/tools/testing/selftests/filesystems/fuse/fd_bpf.c +++ b/tools/testing/selftests/filesystems/fuse/fd_bpf.c @@ -74,7 +74,7 @@ SEC("maps") struct fuse_bpf_map test_map2 = { SEC("test_daemon") -int trace_daemon(struct fuse_args *fa) +int trace_daemon(struct fuse_bpf_args *fa) { uint64_t uid_gid = bpf_get_current_uid_gid(); uint32_t uid = uid_gid & 0xffffffff; diff --git a/tools/testing/selftests/filesystems/fuse/fuse_test.c b/tools/testing/selftests/filesystems/fuse/fuse_test.c index 857484b90ae71..7adc6bdb22416 100644 --- a/tools/testing/selftests/filesystems/fuse/fuse_test.c +++ b/tools/testing/selftests/filesystems/fuse/fuse_test.c @@ -485,7 +485,7 @@ static int bpf_test_redact_readdir(const char *mount_dir) TESTSYSCALL(closedir(dir)); dir = NULL; FUSE_DAEMON - bool skip = true; + bool skip = true; for (int i = 0; i < ARRAY_SIZE(names) + 1; i++) { uint8_t bytes_in[FUSE_MIN_READ_BUFFER]; uint8_t bytes_out[FUSE_MIN_READ_BUFFER]; diff --git a/tools/testing/selftests/filesystems/fuse/test_bpf.c b/tools/testing/selftests/filesystems/fuse/test_bpf.c index 8afef42b4657a..3f4a9e727b683 100644 --- a/tools/testing/selftests/filesystems/fuse/test_bpf.c +++ b/tools/testing/selftests/filesystems/fuse/test_bpf.c @@ -35,7 +35,7 @@ inline int strcmp(const char *a, const char *b) } SEC("test_readdir_redact") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int readdir_test(struct fuse_args *fa) +int readdir_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_READDIR | FUSE_PREFILTER: { @@ -60,7 +60,7 @@ int readdir_test(struct fuse_args *fa) SEC("test_trace") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int trace_test(struct fuse_args *fa) +int trace_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -361,7 +361,7 @@ int trace_test(struct fuse_args *fa) SEC("test_hidden") -int trace_hidden(struct fuse_args *fa) +int trace_hidden(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -418,7 +418,7 @@ int trace_hidden(struct fuse_args *fa) } SEC("test_simple") -int trace_simple(struct fuse_args *fa) +int trace_simple(struct fuse_bpf_args *fa) { if (fa->opcode & FUSE_PREFILTER) bpf_printk("prefilter opcode: %d", @@ -432,7 +432,7 @@ int trace_simple(struct fuse_args *fa) } SEC("test_passthrough") -int trace_daemon(struct fuse_args *fa) +int trace_daemon(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -468,7 +468,7 @@ int trace_daemon(struct fuse_args *fa) SEC("test_error") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int error_test(struct fuse_args *fa) +int error_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_MKDIR | FUSE_PREFILTER: { diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile index f3798029247a3..5a2f6301c4b27 100644 --- a/tools/testing/selftests/filesystems/incfs/Makefile +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -I../.. -I../../../../.. -LDLIBS := -llz4 -lzstd -lcrypto -lpthread +CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -I../.. -I../../../../.. -fno-omit-frame-pointer -fsanitize=address -g +LDLIBS := -llz4 -lzstd -lcrypto -lpthread -fsanitize=address TEST_GEN_PROGS := incfs_test incfs_stress incfs_perf include ../../lib.mk diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index e3ba304f39cad..b3773bd1df91f 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #define FS_IOC_GETFLAGS _IOR('f', 1, long) #define FS_VERITY_FL 0x00100000 /* Verity protected inode */ +#define TEST_SKIP 2 #define TEST_FAILURE 1 #define TEST_SUCCESS 0 @@ -2793,14 +2795,16 @@ failure: return TEST_FAILURE; } +#define THREE_GB (3LL * 1024 * 1024 * 1024) +#define FOUR_GB (4LL * 1024 * 1024 * 1024) /* Have 1GB of margin */ static int large_file_test(const char *mount_dir) { char *backing_dir; int cmd_fd = -1; int i; - int result = TEST_FAILURE; + int result = TEST_FAILURE, ret; uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; - int block_count = 3LL * 1024 * 1024 * 1024 / INCFS_DATA_FILE_BLOCK_SIZE; + int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE; struct incfs_fill_block *block_buf = calloc(block_count, sizeof(struct incfs_fill_block)); struct incfs_fill_blocks fill_blocks = { @@ -2809,6 +2813,22 @@ static int large_file_test(const char *mount_dir) }; incfs_uuid_t id; int fd = -1; + struct statvfs svfs; + unsigned long long free_disksz; + + ret = statvfs(mount_dir, &svfs); + if (ret) { + ksft_print_msg("Can't get disk size. Skipping %s...\n", __func__); + return TEST_SKIP; + } + + free_disksz = (unsigned long long)svfs.f_bavail * svfs.f_bsize; + + if (FOUR_GB > free_disksz) { + ksft_print_msg("Not enough free disk space (%lldMB). Skipping %s...\n", + free_disksz >> 20, __func__); + return TEST_SKIP; + } backing_dir = create_backing_dir(mount_dir); if (!backing_dir) @@ -2849,6 +2869,7 @@ static int large_file_test(const char *mount_dir) failure: close(fd); close(cmd_fd); + unlink("very_large_file"); umount(mount_dir); free(backing_dir); return result; @@ -4688,9 +4709,15 @@ struct test_case { void run_one_test(const char *mount_dir, struct test_case *test_case) { + int ret; + ksft_print_msg("Running %s\n", test_case->name); - if (test_case->pfunc(mount_dir) == TEST_SUCCESS) + ret = test_case->pfunc(mount_dir); + + if (ret == TEST_SUCCESS) ksft_test_result_pass("%s\n", test_case->name); + else if (ret == TEST_SKIP) + ksft_test_result_skip("%s\n", test_case->name); else ksft_test_result_fail("%s\n", test_case->name); } diff --git a/tools/testing/selftests/filesystems/incfs/utils.c b/tools/testing/selftests/filesystems/incfs/utils.c index e60b0d36f49df..d7deb5321c3e2 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.c +++ b/tools/testing/selftests/filesystems/incfs/utils.c @@ -81,6 +81,16 @@ int mount_fs(const char *mount_dir, const char *backing_dir, return result; } +int umount_fs(const char *mount_dir) +{ + int result; + + result = umount(mount_dir); + if (result != 0) + perror("Error unmounting fs."); + return result; +} + int mount_fs_opt(const char *mount_dir, const char *backing_dir, const char *opt, bool remount) { @@ -116,6 +126,9 @@ size_t format_signature(void **buf, const char *root_hash, const char *add_data) size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1; struct signature_blob *sb = malloc(size); + if (!sb) + return 0; + *sb = (struct signature_blob){ .version = INCFS_SIGNATURE_VERSION, .hash_section_size = sizeof(struct hash_section), @@ -126,7 +139,7 @@ size_t format_signature(void **buf, const char *root_hash, const char *add_data) .salt_size = 0, .hash_size = SHA256_DIGEST_SIZE, }, - .signing_section_size = sizeof(uint32_t) + strlen(add_data) + 1, + .signing_section_size = strlen(add_data) + 1, }; memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE); diff --git a/tools/testing/selftests/filesystems/incfs/utils.h b/tools/testing/selftests/filesystems/incfs/utils.h index f5ed8dc5f0ff2..17a1ac5eef7d8 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.h +++ b/tools/testing/selftests/filesystems/incfs/utils.h @@ -29,6 +29,8 @@ int drop_caches(void); int mount_fs(const char *mount_dir, const char *backing_dir, int read_timeout_ms); +int umount_fs(const char *mount_dir); + int mount_fs_opt(const char *mount_dir, const char *backing_dir, const char *opt, bool remount); diff --git a/tools/testing/selftests/net/test_vxlan_under_vrf.sh b/tools/testing/selftests/net/test_vxlan_under_vrf.sh index a44b9aca74272..09f9ed92cbe4c 100755 --- a/tools/testing/selftests/net/test_vxlan_under_vrf.sh +++ b/tools/testing/selftests/net/test_vxlan_under_vrf.sh @@ -118,11 +118,11 @@ echo "[ OK ]" # Move the underlay to a non-default VRF ip -netns hv-1 link set veth0 vrf vrf-underlay -ip -netns hv-1 link set vxlan0 down -ip -netns hv-1 link set vxlan0 up +ip -netns hv-1 link set veth0 down +ip -netns hv-1 link set veth0 up ip -netns hv-2 link set veth0 vrf vrf-underlay -ip -netns hv-2 link set vxlan0 down -ip -netns hv-2 link set vxlan0 up +ip -netns hv-2 link set veth0 down +ip -netns hv-2 link set veth0 up echo -n "Check VM connectivity through VXLAN (underlay in a VRF) " ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 01ec6876e8f58..2cf32e6b376e1 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -40,9 +40,9 @@ TEST_GEN_FILES += userfaultfd TEST_GEN_FILES += khugepaged ifeq ($(MACHINE),x86_64) -CAN_BUILD_I386 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_32bit_program.c -m32) -CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_64bit_program.c) -CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_program.c -no-pie) +CAN_BUILD_I386 := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_64bit_program.c) +CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_program.c -no-pie) TARGETS := protection_keys BINARIES_32 := $(TARGETS:%=%_32) diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index f1b675a4040b7..6703c7906b714 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -6,9 +6,9 @@ include ../lib.mk .PHONY: all all_32 all_64 warn_32bit_failure clean UNAME_M := $(shell uname -m) -CAN_BUILD_I386 := $(shell ./check_cc.sh "$(CC)" trivial_32bit_program.c -m32) -CAN_BUILD_X86_64 := $(shell ./check_cc.sh "$(CC)" trivial_64bit_program.c) -CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie) +CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) +CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selftests/x86/check_cc.sh index 8c669c0d662ee..3e2089c8cf549 100755 --- a/tools/testing/selftests/x86/check_cc.sh +++ b/tools/testing/selftests/x86/check_cc.sh @@ -7,7 +7,7 @@ CC="$1" TESTPROG="$2" shift 2 -if [ -n "$CC" ] && $CC -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then +if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then echo 1 else echo 0 diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 23f142af544ad..cb3f29c09aff3 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -130,7 +130,6 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features) memset(dev, 0, sizeof *dev); dev->vdev.features = features; INIT_LIST_HEAD(&dev->vdev.vqs); - spin_lock_init(&dev->vdev.vqs_list_lock); dev->buf_size = 1024; dev->buf = malloc(dev->buf_size); assert(dev->buf); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f30ae932efb5a..a07bfa9beda3c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -114,8 +114,6 @@ EXPORT_SYMBOL_GPL(kvm_debugfs_dir); static int kvm_debugfs_num_entries; static const struct file_operations stat_fops_per_vm; -static struct file_operations kvm_chardev_ops; - static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, unsigned long arg); #ifdef CONFIG_KVM_COMPAT @@ -810,16 +808,6 @@ static struct kvm *kvm_create_vm(unsigned long type) preempt_notifier_inc(); - /* - * When the fd passed to this ioctl() is opened it pins the module, - * but try_module_get() also prevents getting a reference if the module - * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait"). - */ - if (!try_module_get(kvm_chardev_ops.owner)) { - r = -ENODEV; - goto out_err; - } - return kvm; out_err: @@ -898,7 +886,6 @@ static void kvm_destroy_vm(struct kvm *kvm) preempt_notifier_dec(); hardware_disable_all(); mmdrop(mm); - module_put(kvm_chardev_ops.owner); } void kvm_get_kvm(struct kvm *kvm) -- GitLab