mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
* remotes/origin/tmp-4716ccc :
UPSTREAM: media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
ANDROID: incremental fs: Evict inodes before freeing mount data
UPSTREAM: ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
UPSTREAM: hid: bigben_probe(): validate report count
UPSTREAM: HID: bigben: use spinlock to safely schedule workers
BACKPORT: of: base: Skip CPU nodes with "fail"/"fail-..." status
UPSTREAM: HID: bigben_worker() remove unneeded check on report_field
UPSTREAM: HID: bigben: use spinlock to protect concurrent accesses
UPSTREAM: hwrng: virtio - add an internal buffer
UPSTREAM: ext4: fix another off-by-one fsmap error on 1k block filesystems
UPSTREAM: ext4: refuse to create ea block when umounted
UPSTREAM: ext4: optimize ea_inode block expansion
UPSTREAM: ext4: allocate extended attribute value in vmalloc area
BACKPORT: FROMGIT: cgroup: Use separate src/dst nodes when preloading css_sets for migration
ANDROID: fs/f2fs: fixup __f2fs_cluster_blocks with F2FS_FS_COMPRESSION
UPSTREAM: usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
UPSTREAM: KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
Revert "iommu: Add gfp parameter to iommu_ops::map"
Revert "iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()"
Revert "RDMA/usnic: use iommu_map_atomic() under spin_lock()"
Linux 5.4.233
bpf: add missing header file include
Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child qdiscs"
ext4: Fix function prototype mismatch for ext4_feat_ktype
wifi: mwifiex: Add missing compatible string for SD8787
uaccess: Add speculation barrier to copy_from_user()
mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
drm/i915/gvt: fix double free bug in split_2MB_gtt_entry
alarmtimer: Prevent starvation by small intervals and SIG_IGN
powerpc: dts: t208x: Disable 10G on MAC1 and MAC2
can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len
KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception
random: always mix cycle counter in add_latent_entropy()
powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G
wifi: rtl8xxxu: gen2: Turn on the rate control
drm/etnaviv: don't truncate physical page address
drm: etnaviv: fix common struct sg_table related issues
scatterlist: add generic wrappers for iterating over sgtable objects
dma-mapping: add generic helpers for mapping sgtable objects
Linux 5.4.232
iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()
net: sched: sch: Fix off by one in htb_activate_prios()
ASoC: SOF: Intel: hda-dai: fix possible stream_tag leak
nilfs2: fix underflow in second superblock position calculations
kvm: initialize all of the kvm_debugregs structure before sending it to userspace
i40e: Add checking for null for nlmsg_find_attr()
ipv6: Fix tcp socket connection with DSCP.
ipv6: Fix datagram socket connection with DSCP.
ixgbe: add double of VLAN header when computing the max MTU
net: mpls: fix stale pointer if allocation fails during device rename
net: stmmac: Restrict warning on disabling DMA store and fwd mode
bnxt_en: Fix mqprio and XDP ring checking logic
net: stmmac: fix order of dwmac5 FlexPPS parametrization sequence
net/usb: kalmia: Don't pass act_len in usb_bulk_msg error path
dccp/tcp: Avoid negative sk_forward_alloc by ipv6_pinfo.pktoptions.
sctp: sctp_sock_filter(): avoid list_entry() on possibly empty list
net: bgmac: fix BCM5358 support by setting correct flags
i40e: add double of VLAN header when computing the max MTU
ixgbe: allow to increase MTU to 3K with XDP enabled
revert "squashfs: harden sanity check in squashfs_read_xattr_id_table"
net: Fix unwanted sign extension in netdev_stats_to_stats64()
Revert "mm: Always release pages to the buddy allocator in memblock_free_late()."
hugetlb: check for undefined shift on 32 bit architectures
sched/psi: Fix use-after-free in ep_remove_wait_queue()
ALSA: hda/realtek - fixed wrong gpio assigned
ALSA: hda/conexant: add a new hda codec SN6180
mmc: mmc_spi: fix error handling in mmc_spi_probe()
mmc: sdio: fix possible resource leaks in some error paths
ipv4: Fix incorrect route flushing when source address is deleted
Revert "ipv4: Fix incorrect route flushing when source address is deleted"
xfs: sync lazy sb accounting on quiesce of read-only mounts
xfs: prevent UAF in xfs_log_item_in_current_chkpt
xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks
xfs: ensure inobt record walks always make forward progress
xfs: fix missing CoW blocks writeback conversion retry
xfs: only relog deferred intent items if free space in the log gets low
xfs: expose the log push threshold
xfs: periodically relog deferred intent items
xfs: change the order in which child and parent defer ops are finished
xfs: fix an incore inode UAF in xfs_bui_recover
xfs: clean up xfs_bui_item_recover iget/trans_alloc/ilock ordering
xfs: clean up bmap intent item recovery checking
xfs: xfs_defer_capture should absorb remaining transaction reservation
xfs: xfs_defer_capture should absorb remaining block reservations
xfs: proper replay of deferred ops queued during log recovery
xfs: fix finobt btree block recovery ordering
xfs: log new intent items created as part of finishing recovered intent items
xfs: refactor xfs_defer_finish_noroll
xfs: turn dfp_intent into a xfs_log_item
xfs: merge the ->diff_items defer op into ->create_intent
xfs: merge the ->log_item defer op into ->create_intent
xfs: factor out a xfs_defer_create_intent helper
xfs: remove the xfs_inode_log_item_t typedef
xfs: remove the xfs_efd_log_item_t typedef
xfs: remove the xfs_efi_log_item_t typedef
netfilter: nft_tproxy: restrict to prerouting hook
btrfs: free device in btrfs_close_devices for a single device filesystem
aio: fix mremap after fork null-deref
nvme-fc: fix a missing queue put in nvmet_fc_ls_create_association
s390/decompressor: specify __decompress() buf len to avoid overflow
net: sched: sch: Bounds check priority
net: stmmac: do not stop RX_CLK in Rx LPI state for qcs404 SoC
net/rose: Fix to not accept on connected socket
tools/virtio: fix the vringh test for virtio ring changes
ASoC: cs42l56: fix DT probe
selftests/bpf: Verify copy_register_state() preserves parent/live fields
migrate: hugetlb: check for hugetlb shared PMD in node migration
bpf: Always return target ifindex in bpf_fib_lookup
nvme-pci: Move enumeration by class to be last in the table
arm64: dts: meson-axg: Make mmc host controller interrupts level-sensitive
arm64: dts: meson-g12-common: Make mmc host controller interrupts level-sensitive
arm64: dts: meson-gx: Make mmc host controller interrupts level-sensitive
riscv: Fixup race condition on PG_dcache_clean in flush_icache_pte
ceph: flush cap releases when the session is flushed
usb: typec: altmodes/displayport: Fix probe pin assign check
usb: core: add quirk for Alcor Link AK9563 smartcard reader
net: USB: Fix wrong-direction WARNING in plusb.c
pinctrl: intel: Restore the pins that used to be in Direct IRQ mode
pinctrl: single: fix potential NULL dereference
pinctrl: aspeed: Fix confusing types in return value
ALSA: pci: lx6464es: fix a debug loop
selftests: forwarding: lib: quote the sysctl values
rds: rds_rm_zerocopy_callback() use list_first_entry()
ice: Do not use WQ_MEM_RECLAIM flag for workqueue
ionic: clean interrupt before enabling queue to avoid credit race
net: phy: meson-gxl: use MMD access dummy stubs for GXL, internal PHY
bonding: fix error checking in bond_debug_reregister()
xfrm: fix bug with DSCP copy to v6 from v4 tunnel
RDMA/usnic: use iommu_map_atomic() under spin_lock()
iommu: Add gfp parameter to iommu_ops::map
IB/IPoIB: Fix legacy IPoIB due to wrong number of queues
IB/hfi1: Restore allocated resources on failed copyout
can: j1939: do not wait 250 ms if the same addr was already claimed
tracing: Fix poll() and select() do not work on per_cpu trace_pipe and trace_pipe_raw
ALSA: emux: Avoid potential array out-of-bound in snd_emux_xg_control()
btrfs: zlib: zero-initialize zlib workspace
btrfs: limit device extents to the device size
iio:adc:twl6030: Enable measurement of VAC
wifi: brcmfmac: Check the count value of channel spec to prevent out-of-bounds reads
f2fs: fix to do sanity check on i_extra_isize in is_alive()
fbdev: smscufx: fix error handling code in ufx_usb_probe
powerpc/imc-pmu: Revert nest_init_lock to being a mutex
serial: 8250_dma: Fix DMA Rx rearm race
serial: 8250_dma: Fix DMA Rx completion race
xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
mm: swap: properly update readahead statistics in unuse_pte_range()
nvmem: core: fix cell removal on error
Squashfs: fix handling and sanity checking of xattr_ids count
mm/swapfile: add cond_resched() in get_swap_pages()
fpga: stratix10-soc: Fix return value check in s10_ops_write_init()
mm: hugetlb: proc: check for hugetlb shared PMD in /proc/PID/smaps
riscv: disable generation of unwind tables
parisc: Wire up PTRACE_GETREGS/PTRACE_SETREGS for compat case
parisc: Fix return code of pdc_iodc_print()
iio:adc:twl6030: Enable measurements of VUSB, VBAT and others
iio: adc: berlin2-adc: Add missing of_node_put() in error path
iio: hid: fix the retval in accel_3d_capture_sample
efi: Accept version 2 of memory attributes table
watchdog: diag288_wdt: fix __diag288() inline assembly
watchdog: diag288_wdt: do not use stack buffers for hardware data
fbcon: Check font dimension limits
Input: i8042 - add Clevo PCX0DX to i8042 quirk table
Input: i8042 - add TUXEDO devices to i8042 quirk tables
Input: i8042 - merge quirk tables
Input: i8042 - move __initconst to fix code styling warning
vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
usb: gadget: f_fs: Fix unbalanced spinlock in __ffs_ep0_queue_wait
usb: dwc3: qcom: enable vbus override when in OTG dr-mode
usb: dwc3: dwc3-qcom: Fix typo in the dwc3 vbus override API
iio: adc: stm32-dfsdm: fill module aliases
net/x25: Fix to not accept on connected socket
i2c: rk3x: fix a bunch of kernel-doc warnings
scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
scsi: target: core: Fix warning on RT kernels
efi: fix potential NULL deref in efi_mem_reserve_persistent
net: openvswitch: fix flow memory leak in ovs_flow_cmd_new
virtio-net: Keep stop() to follow mirror sequence of open()
selftests: net: udpgso_bench_tx: Cater for pending datagrams zerocopy benchmarking
selftests: net: udpgso_bench: Fix racing bug between the rx/tx programs
selftests: net: udpgso_bench_rx/tx: Stop when wrong CLI args are provided
selftests: net: udpgso_bench_rx: Fix 'used uninitialized' compiler warning
ata: libata: Fix sata_down_spd_limit() when no link speed is reported
can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
net: phy: meson-gxl: Add generic dummy stubs for MMD register access
squashfs: harden sanity check in squashfs_read_xattr_id_table
netfilter: br_netfilter: disable sabotage_in hook after first suppression
netrom: Fix use-after-free caused by accept on already connected socket
fix "direction" argument of iov_iter_kvec()
fix iov_iter_bvec() "direction" argument
WRITE is "data source", not destination...
scsi: Revert "scsi: core: map PQ=1, PDT=other values to SCSI_SCAN_TARGET_PRESENT"
arm64: dts: imx8mm: Fix pad control for UART1_DTE_RX
ALSA: hda/via: Avoid potential array out-of-bound in add_secret_dac_path()
ASoC: Intel: bytcr_rt5651: Drop reference count of ACPI device after use
bus: sunxi-rsb: Fix error handling in sunxi_rsb_init()
firewire: fix memory leak for payload of request subaction to IEC 61883-1 FCP region
Linux 5.4.231
Revert "xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()"
usb: host: xhci-plat: add wakeup entry at sysfs
Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt
ipv6: ensure sane device mtu in tunnels
exit: Use READ_ONCE() for all oops/warn limit reads
docs: Fix path paste-o for /sys/kernel/warn_count
panic: Expose "warn_count" to sysfs
panic: Introduce warn_limit
panic: Consolidate open-coded panic_on_warn checks
exit: Allow oops_limit to be disabled
exit: Expose "oops_count" to sysfs
exit: Put an upper limit on how often we can oops
ia64: make IA64_MCA_RECOVERY bool instead of tristate
csky: Fix function name in csky_alignment() and die()
h8300: Fix build errors from do_exit() to make_task_dead() transition
hexagon: Fix function name in die()
objtool: Add a missing comma to avoid string concatenation
exit: Add and use make_task_dead.
mm: kasan: do not panic if both panic_on_warn and kasan_multishot set
panic: unset panic_on_warn inside panic()
sysctl: add a new register_sysctl_init() interface
dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init
blk-cgroup: fix missing pd_online_fn() while activating policy
bpf: Skip task with pid=1 in send_signal_common()
ARM: dts: imx: Fix pca9547 i2c-mux node name
x86/asm: Fix an assembler warning with current binutils
clk: Fix pointer casting to prevent oops in devm_clk_release()
perf/x86/amd: fix potential integer overflow on shift of a int
netfilter: conntrack: unify established states for SCTP paths
x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
block: fix and cleanup bio_check_ro
nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted
Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode"
net: mdio-mux-meson-g12a: force internal PHY off on mux switch
net: xgene: Move shared header file into include/linux
net/phy/mdio-i2c: Move header file to include/linux/mdio
net/tg3: resolve deadlock in tg3_reset_task() during EEH
thermal: intel: int340x: Add locking to int340x_thermal_get_trip_type()
net: ravb: Fix possible hang if RIS2_QFF1 happen
sctp: fail if no bound addresses can be used for a given scope
net/sched: sch_taprio: do not schedule in taprio_reset()
netrom: Fix use-after-free of a listening socket.
netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE
ipv4: prevent potential spectre v1 gadget in fib_metrics_match()
ipv4: prevent potential spectre v1 gadget in ip_metrics_convert()
netlink: annotate data races around sk_state
netlink: annotate data races around dst_portid and dst_group
netlink: annotate data races around nlk->portid
netfilter: nft_set_rbtree: skip elements in transaction from garbage collection
net: fix UaF in netns ops registration error path
netlink: prevent potential spectre v1 gadgets
EDAC/qcom: Do not pass llcc_driv_data as edac_device_ctl_info's pvt_info
EDAC/device: Respect any driver-supplied workqueue polling value
ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment
thermal: intel: int340x: Protect trip temperature from concurrent updates
KVM: x86/vmx: Do not skip segment attributes if unusable bit is set
cifs: Fix oops due to uncleared server->smbd_conn in reconnect
ftrace/scripts: Update the instructions for ftrace-bisect.sh
trace_events_hist: add check for return value of 'create_hist_field'
tracing: Make sure trace_printk() can output as soon as it can be used
module: Don't wait for GOING modules
scsi: hpsa: Fix allocation size for scsi_host_alloc()
Bluetooth: hci_sync: cancel cmd_timer if hci_open failed
Revert "Revert "xhci: Set HCD flag to defer primary roothub registration""
fs: reiserfs: remove useless new_opts in reiserfs_remount
netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state
Revert "selftests/bpf: check null propagation only neither reg is PTR_TO_BTF_ID"
mmc: sdhci-esdhc-imx: correct the tuning start tap and step setting
mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
lockref: stop doing cpu_relax in the cmpxchg loop
platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK
platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD
scsi: hisi_sas: Set a port invalid only if there are no devices attached when refreshing port id
KVM: s390: interrupt: use READ_ONCE() before cmpxchg()
spi: spidev: remove debug messages that access spidev->spi without locking
ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
cpufreq: armada-37xx: stop using 0 as NULL pointer
s390/debug: add _ASM_S390_ prefix to header guard
drm: Add orientation quirk for Lenovo ideapad D330-10IGL
ASoC: fsl_micfil: Correct the number of steps on SX controls
cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist
tcp: fix rate_app_limited to default to 1
net: dsa: microchip: ksz9477: port map correction in ALU table entry register
driver core: Fix test_async_probe_init saves device in wrong array
w1: fix WARNING after calling w1_process()
w1: fix deadloop in __w1_remove_master_device()
tcp: avoid the lookup process failing to get sk in ehash table
dmaengine: xilinx_dma: call of_node_put() when breaking out of for_each_child_of_node()
dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling
dmaengine: xilinx_dma: use devm_platform_ioremap_resource()
HID: betop: check shape of output reports
net: macb: fix PTP TX timestamp failure due to packet padding
dmaengine: Fix double increment of client_count in dma_chan_get()
drm/panfrost: fix GENERIC_ATOMIC64 dependency
net: mlx5: eliminate anonymous module_init & module_exit
usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
HID: revert CHERRY_MOUSE_000C quirk
net: stmmac: fix invalid call to mdiobus_get_phy()
HID: check empty report_list in bigben_probe()
HID: check empty report_list in hid_validate_values()
net: mdio: validate parameter addr in mdiobus_get_phy()
net: usb: sr9700: Handle negative len
l2tp: Don't sleep and disable BH under writer-side sk_callback_lock
l2tp: Serialize access to sk_user_data with sk_callback_lock
net: fix a concurrency bug in l2tp_tunnel_register()
net/sched: sch_taprio: fix possible use-after-free
wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
gpio: mxc: Always set GPIOs used as interrupt source to INPUT mode
net: wan: Add checks for NULL for utdm in undo_uhdlc_init and unmap_si_regs
net: nfc: Fix use-after-free in local_cleanup()
phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in rockchip_usb2phy_power_on()
bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation
amd-xgbe: Delay AN timeout during KR training
amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent
affs: initialize fsdata in affs_truncate()
IB/hfi1: Fix expected receive setup error exit issues
IB/hfi1: Reserve user expected TIDs
IB/hfi1: Reject a zero-length user expected buffer
RDMA/core: Fix ib block iterator counter overflow
tomoyo: fix broken dependency on *.conf.default
EDAC/highbank: Fix memory leak in highbank_mc_probe()
HID: intel_ish-hid: Add check for ishtp_dma_tx_map
ARM: imx: add missing of_node_put()
ARM: imx35: Retrieve the IIM base address from devicetree
ARM: imx31: Retrieve the IIM base address from devicetree
ARM: imx27: Retrieve the SYSCTRL base address from devicetree
ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts'
memory: mvebu-devbus: Fix missing clk_disable_unprepare in mvebu_devbus_probe()
memory: atmel-sdramc: Fix missing clk_disable_unprepare in atmel_ramc_probe()
clk: Provide new devm_clk helpers for prepared and enabled clocks
clk: generalize devm_clk_get() a bit
Linux 5.4.230
mm/khugepaged: fix collapse_pte_mapped_thp() to allow anon_vma
x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix
drm/amd/display: Fix set scaling doesn's work
drm/i915: re-disable RC6p on Sandy Bridge
gsmi: fix null-deref in gsmi_get_variable
serial: atmel: fix incorrect baudrate setup
dmaengine: tegra210-adma: fix global intr clear
serial: pch_uart: Pass correct sg to dma_unmap_sg()
dt-bindings: phy: g12a-usb3-pcie-phy: fix compatible string documentation
usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210
usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
usb: gadget: g_webcam: Send color matching descriptor per frame
usb: typec: altmodes/displayport: Fix pin assignment calculation
usb: typec: altmodes/displayport: Add pin assignment helper
usb: host: ehci-fsl: Fix module alias
USB: serial: cp210x: add SCALANCE LPE-9000 device id
USB: gadgetfs: Fix race between mounting and unmounting
cifs: do not include page data when checking signature
btrfs: fix race between quota rescan and disable leading to NULL pointer deref
mmc: sunxi-mmc: Fix clock refcount imbalance during unbind
comedi: adv_pci1760: Fix PWM instruction handling
usb: core: hub: disable autosuspend for TI TUSB8041
misc: fastrpc: Fix use-after-free race condition for maps
misc: fastrpc: Don't remove map on creater_process and device_release
USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
USB: serial: option: add Quectel EM05CN modem
USB: serial: option: add Quectel EM05CN (SG) modem
USB: serial: option: add Quectel EC200U modem
USB: serial: option: add Quectel EM05-G (RS) modem
USB: serial: option: add Quectel EM05-G (CS) modem
USB: serial: option: add Quectel EM05-G (GR) modem
prlimit: do_prlimit needs to have a speculation check
xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
usb: acpi: add helper to check port lpm capability using acpi _DSM
xhci: Add a flag to disable USB3 lpm on a xhci root port level.
xhci: Add update_hub_device override for PCI xHCI hosts
xhci: Fix null pointer dereference when host dies
usb: xhci: Check endpoint is valid before dereferencing it
xhci-pci: set the dma max_seg_size
ALSA: hda/realtek - Turn on power early
drm/i915/gt: Reset twice
efi: fix userspace infinite retry read efivars after EFI runtime services page fault
nilfs2: fix general protection fault in nilfs_btree_insert()
Add exception protection processing for vd in axi_chan_handle_err function
wifi: brcmfmac: fix regression for Broadcom PCIe wifi devices
f2fs: let's avoid panic if extent_tree is not created
RDMA/srp: Move large values to a new enum for gcc13
net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats
selftests/bpf: check null propagation only neither reg is PTR_TO_BTF_ID
pNFS/filelayout: Fix coalescing test for single DS
Revert "net: add atomic_long_t to net_device_stats fields"
Revert "PM/devfreq: governor: Add a private governor_data for governor"
Linux 5.4.229
tipc: call tipc_lxc_xmit without holding node_read_lock
ocfs2: fix freeing uninitialized resource on ocfs2_dlm_shutdown
tipc: Add a missing case of TIPC_DIRECT_MSG type
tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
tipc: fix use-after-free in tipc_disc_rcv()
Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout"
mm: Always release pages to the buddy allocator in memblock_free_late().
efi: fix NULL-deref in init error path
arm64: cmpxchg_double*: hazard against entire exchange variable
arm64: atomics: remove LL/SC trampolines
arm64: atomics: format whitespace consistently
drm/virtio: Fix GEM handle creation UAF
x86/resctrl: Fix task CLOSID/RMID update race
x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent unnecessary IPI
iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
iommu/mediatek-v1: Add error handle for mtk_iommu_probe
net/mlx5: Fix ptp max frequency adjustment range
net/mlx5: Rename ptp clock info
net/sched: act_mpls: Fix warning during failed attribute validation
nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
hvc/xen: lock console list traversal
tipc: fix unexpected link reset due to discovery messages
tipc: eliminate checking netns if node established
tipc: improve throughput between nodes in netns
regulator: da9211: Use irq handler when ready
EDAC/device: Fix period calculation in edac_device_reset_delay_period()
x86/boot: Avoid using Intel mnemonics in AT&T syntax asm
powerpc/imc-pmu: Fix use of mutex in IRQs disabled section
netfilter: ipset: Fix overflow before widen in the bitmap_ip_create() function.
ext4: fix uninititialized value in 'ext4_evict_inode'
ext4: fix use-after-free in ext4_orphan_cleanup
ext4: lost matching-pair of trace in ext4_truncate
ext4: fix bug_on in __es_tree_search caused by bad quota inode
quota: Factor out setup of quota inode
jbd2: use the correct print format
usb: ulpi: defer ulpi_register on ulpi_read_id timeout
wifi: wilc1000: sdio: fix module autoloading
ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
ixgbe: fix pci device refcount leak
platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during probe
drm/msm/adreno: Make adreno quirks not overwrite each other
cifs: Fix uninitialized memory read for smb311 posix symlink create
ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
net/ulp: prevent ULP without clone op from entering the LISTEN status
s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple()
s390/kexec: fix ipl report address for kdump
perf auxtrace: Fix address filter duplicate symbol selection
docs: Fix the docs build with Sphinx 6.0
efi: tpm: Avoid READ_ONCE() for accessing the event log
KVM: arm64: Fix S1PTW handling on RO memslots
net: sched: disallow noqueue for qdisc classes
driver core: Fix bus_type.match() error handling in __driver_attach()
selftests: set the BUILD variable to absolute path
selftests: Fix kselftest O=objdir build from cluttering top level objdir
parisc: Align parisc MADV_XXX constants with all other architectures
mbcache: Avoid nesting of cache->c_list_lock under bit locks
hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
hfs/hfsplus: use WARN_ON for sanity check
ext4: don't allow journal inode to have encrypt flag
riscv: uaccess: fix type of 0 variable on error in get_user()
nfsd: fix handling of readdir in v4root vs. mount upcall timeout
x86/bugs: Flush IBP in ib_prctl_set()
ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
udf: Fix extension of the last extent in the file
caif: fix memory leak in cfctrl_linkup_request()
drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
usb: rndis_host: Secure rndis_query check against int overflow
drivers/net/bonding/bond_3ad: return when there's no aggregator
perf tools: Fix resources leak in perf_data__open_dir()
net: sched: cbq: dont intepret cls results when asked to drop
net: sched: atm: dont intepret cls results when asked to drop
RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
RDMA/uverbs: Silence shiftTooManyBitsSigned warning
net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
net: amd-xgbe: add missed tasklet_kill
vhost: fix range used in translate_desc()
nfc: Fix potential resource leaks
qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
net: sched: fix memory leak in tcindex_set_parms
net: hns3: add interrupts re-initialization while doing VF FLR
nfsd: shut down the NFSv4 state objects before the filecache
bpf: pull before calling skb_postpull_rcsum()
SUNRPC: ensure the matching upcall is in-flight upon downcall
ext4: fix deadlock due to mbcache entry corruption
mbcache: automatically delete entries from cache on freeing
ext4: fix race when reusing xattr blocks
ext4: unindent codeblock in ext4_xattr_block_set()
ext4: remove EA inode entry from mbcache on inode eviction
mbcache: add functions to delete entry if unused
mbcache: don't reclaim used entries
ext4: use kmemdup() to replace kmalloc + memcpy
fs: ext4: initialize fsdata in pagecache_write()
ext4: use memcpy_to_page() in pagecache_write()
mm/highmem: Lift memcpy_[to|from]_page to core
ext4: correct inconsistent error msg in nojournal mode
ext4: goto right label 'failed_mount3a'
ravb: Fix "failed to switch device to config mode" message during unbind
KVM: nVMX: Properly expose ENABLE_USR_WAIT_PAUSE control to L1
KVM: VMX: Fix the spelling of CPU_BASED_USE_TSC_OFFSETTING
KVM: VMX: Rename NMI_PENDING to NMI_WINDOW
KVM: VMX: Rename INTERRUPT_PENDING to INTERRUPT_WINDOW
KVM: retpolines: x86: eliminate retpoline from vmx.c exit handlers
KVM: x86: optimize more exit handlers in vmx.c
perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data
perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
dm thin: resume even if in FAIL mode
media: s5p-mfc: Fix in register read and write for H264
media: s5p-mfc: Clear workbit to handle error condition
media: s5p-mfc: Fix to handle reference queue during finishing
PM/devfreq: governor: Add a private governor_data for governor
btrfs: replace strncpy() with strscpy()
ext4: allocate extended attribute value in vmalloc area
ext4: avoid unaccounted block allocation when expanding inode
ext4: initialize quota before expanding inode in setproject ioctl
ext4: fix inode leak in ext4_xattr_inode_create() on an error path
ext4: avoid BUG_ON when creating xattrs
ext4: fix error code return to user-space in ext4_get_branch()
ext4: fix corruption when online resizing a 1K bigalloc fs
ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
ext4: init quota for 'old.inode' in 'ext4_rename'
ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
ext4: fix reserved cluster accounting in __es_remove_extent()
ext4: add helper to check quota inums
ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
ext4: fix undefined behavior in bit shift for ext4_check_flag_values
ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop
drm/vmwgfx: Validate the box size for the snooped cursor
drm/connector: send hotplug uevent on connector cleanup
device_cgroup: Roll back to original exceptions after copy failure
parisc: led: Fix potential null-ptr-deref in start_task()
iommu/amd: Fix ivrs_acpihid cmdline parsing code
crypto: n2 - add missing hash statesize
PCI/sysfs: Fix double free in error path
PCI: Fix pci_device_is_present() for VFs by checking PF
ipmi: fix use after free in _ipmi_destroy_user()
ima: Fix a potential NULL pointer access in ima_restore_measurement_list
mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
ipmi: fix long wait in unload when IPMI disconnect
efi: Add iMac Pro 2017 to uefi skip cert quirk
md/bitmap: Fix bitmap chunk size overflow issues
cifs: fix missing display of three mount options
cifs: fix confusing debug message
media: dvb-core: Fix UAF due to refcount races at releasing
media: dvb-core: Fix double free in dvb_register_device()
ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line
tracing/hist: Fix wrong return value in parse_action_params()
x86/microcode/intel: Do not retry microcode reloading on the APs
tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
dm cache: set needs_check flag after aborting metadata
dm cache: Fix UAF in destroy()
dm clone: Fix UAF in clone_dtr()
dm integrity: Fix UAF in dm_integrity_dtr()
dm thin: Fix UAF in run_timer_softirq()
dm thin: Use last transaction's pmd->root when commit failed
dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
binfmt: Fix error return code in load_elf_fdpic_binary()
binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf
cpufreq: Init completion before kobject_init_and_add()
selftests: Use optional USERCFLAGS and USERLDFLAGS
arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
ARM: ux500: do not directly dereference __iomem
btrfs: fix resolving backrefs for inline extent followed by prealloc
mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
ktest.pl minconfig: Unset configs instead of just removing them
kest.pl: Fix grub2 menu handling for rebooting
soc: qcom: Select REMAP_MMIO for LLCC driver
media: stv0288: use explicitly signed char
net/af_packet: make sure to pull mac header
net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
f2fs: should put a page when checking the summary info
mm, compaction: fix fast_isolate_around() to stay within boundaries
md: fix a crash in mempool_free
pnode: terminate at peers of source
ALSA: line6: fix stack overflow in line6_midi_transmit
ALSA: line6: correct midi status byte when receiving data from podxt
ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
hfsplus: fix bug causing custom uid and gid being unable to be assigned with mount
HID: plantronics: Additional PIDs for double volume key presses quirk
HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
powerpc/rtas: avoid scheduling in rtas_os_term()
powerpc/rtas: avoid device tree lookups in rtas_os_term()
objtool: Fix SEGFAULT
nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
nvme: resync include/linux/nvme.h with nvmecli
ata: ahci: Fix PCS quirk application for suspend
nvme-pci: fix doorbell buffer value endianness
cifs: fix oops during encryption
media: dvbdev: fix refcnt bug
media: dvbdev: fix build warning due to comments
gcov: add support for checksum field
regulator: core: fix deadlock on regulator enable
iio: adc128s052: add proper .data members in adc128_of_match table
iio: adc: ad_sigma_delta: do not use internal iio_dev lock
reiserfs: Add missing calls to reiserfs_security_free()
HID: wacom: Ensure bootloader PID is usable in hidraw mode
usb: dwc3: core: defer probe on ulpi_read_id timeout
ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
ASoC: rt5670: Remove unbalanced pm_runtime_put()
ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()
ASoC: wm8994: Fix potential deadlock
ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
ASoC: Intel: Skylake: Fix driver hang during shutdown
ALSA: hda: add snd_hdac_stop_streams() helper
ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
clk: st: Fix memory leak in st_of_quadfs_setup()
media: si470x: Fix use-after-free in si470x_int_in_callback()
mmc: f-sdh30: Add quirks for broken timeout clock capability
regulator: core: fix use_count leakage when handling boot-on
blk-mq: fix possible memleak when register 'hctx' failed
media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
media: dvbdev: adopts refcnt to avoid UAF
media: dvb-frontends: fix leak of memory fw
bpf: Prevent decl_tag from being referenced in func_proto arg
ppp: associate skb with a device at tx
mrp: introduce active flags to prevent UAF when applicant uninit
net: add atomic_long_t to net_device_stats fields
md/raid1: stop mdx_raid1 thread when raid1 array run failed
drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
drm/sti: Use drm_mode_copy()
drm/rockchip: Use drm_mode_copy()
s390/lcs: Fix return type of lcs_start_xmit()
s390/netiucv: Fix return type of netiucv_tx()
s390/ctcm: Fix return type of ctc{mp,}m_tx()
igb: Do not free q_vector unless new one was allocated
wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()
hamradio: baycom_epp: Fix return type of baycom_send_packet()
net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
bpf: make sure skb->len != 0 when redirecting to a tunneling device
ipmi: fix memleak when unload ipmi driver
ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
wifi: ath9k: verify the expected usb_endpoints are present
brcmfmac: return error when getting invalid max_flowrings from dongle
drm/etnaviv: add missing quirks for GC300
hfs: fix OOB Read in __hfs_brec_find
acct: fix potential integer overflow in encode_comp_t()
nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
ACPICA: Fix error code path in acpi_ds_call_control_method()
fs: jfs: fix shift-out-of-bounds in dbDiscardAG
udf: Avoid double brelse() in udf_rename()
fs: jfs: fix shift-out-of-bounds in dbAllocAG
binfmt_misc: fix shift-out-of-bounds in check_special_flags
rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
net: stream: purge sk_error_queue in sk_stream_kill_queues()
myri10ge: Fix an error handling path in myri10ge_probe()
rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
net_sched: reject TCF_EM_SIMPLE case for complex ematch module
mailbox: zynq-ipi: fix error handling while device_register() fails
skbuff: Account for tail adjustment during pull operations
openvswitch: Fix flow lookup to use unmasked key
rtc: mxc_v2: Add missing clk_disable_unprepare()
r6040: Fix kmemleak in probe and remove
nfc: pn533: Clear nfc_target before being used
mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
NFSD: Add tracepoints to NFSD's duplicate reply cache
nfsd: Define the file access mode enum for tracing
rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
selftests/powerpc: Fix resource leaks
powerpc/hv-gpci: Fix hv_gpci event list
powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
powerpc/perf: callchain validate kernel stack pointer bounds
powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
cxl: Fix refcount leak in cxl_calc_capp_routing
powerpc/52xx: Fix a resource leak in an error handling path
macintosh/macio-adb: check the return value of ioremap()
macintosh: fix possible memory leak in macio_add_one_device()
iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
iommu/amd: Fix pci device refcount leak in ppr_notifier()
rtc: pcf85063: Fix reading alarm
rtc: snvs: Allow a time difference on clock register read
include/uapi/linux/swab: Fix potentially missing __always_inline
RDMA/siw: Fix pointer cast warning
power: supply: fix null pointer dereferencing in power_supply_get_battery_info
HSI: omap_ssi_core: Fix error handling in ssi_init()
perf symbol: correction while adjusting symbol
perf trace: Handle failure when trace point folder is missed
perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
perf trace: Add a strtoul() method to 'struct syscall_arg_fmt'
perf trace: Allow associating scnprintf routines with well known arg names
perf trace: Add the syscall_arg_fmt pointer to syscall_arg
perf trace: Factor out the initialization of syscal_arg_fmt->scnprintf
perf trace: Separate 'struct syscall_fmt' definition from syscall_fmts variable
perf trace: Return error if a system call doesn't exist
power: supply: fix residue sysfs file in error handle route of __power_supply_register()
HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
fbdev: vermilion: decrease reference count in error path
fbdev: via: Fix error in via_core_init()
fbdev: pm2fb: fix missing pci_disable_device()
fbdev: ssd1307fb: Drop optional dependency
samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
tracing/hist: Fix issue of losting command info in error_log
usb: storage: Add check for kcalloc
i2c: ismt: Fix an out-of-bounds bug in ismt_access()
vme: Fix error not catched in fake_init()
staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
staging: rtl8192u: Fix use after free in ieee80211_rx()
i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
chardev: fix error handling in cdev_device_add()
mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
drivers: mcb: fix resource leak in mcb_probe()
usb: gadget: f_hid: fix refcount leak on error path
usb: gadget: f_hid: fix f_hidg lifetime vs cdev
usb: gadget: f_hid: optional SETUP/SET_REPORT mode
usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os
misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
misc: ocxl: fix possible name leak in ocxl_file_register_afu()
test_firmware: fix memory leak in test_firmware_init()
serial: sunsab: Fix error handling in sunsab_init()
serial: altera_uart: fix locking in polling mode
tty: serial: altera_uart_{r,t}x_chars() need only uart_port
tty: serial: clean up stop-tx part in altera_uart_tx_chars()
serial: pch: Fix PCI device refcount leak in pch_request_dma()
serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
serial: amba-pl011: avoid SBSA UART accessing DMACR register
usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
staging: vme_user: Fix possible UAF in tsi148_dma_list_add
usb: fotg210-udc: Fix ages old endianness issues
uio: uio_dmem_genirq: Fix deadlock between irq config and handling
uio: uio_dmem_genirq: Fix missing unlock in irq configuration
vfio: platform: Do not pass return buffer to ACPI _RST method
class: fix possible memory leak in __class_register()
serial: tegra: Read DMA status before terminating
tty: serial: tegra: Activate RX DMA transfer by request
drivers: dio: fix possible memory leak in dio_init()
IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
hwrng: geode - Fix PCI device refcount leak
hwrng: amd - Fix PCI device refcount leak
crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
orangefs: Fix sysfs not cleanup when dev init failed
RDMA/hfi1: Fix error return code in parse_platform_config()
crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
f2fs: avoid victim selection from previous victim section
RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
scsi: snic: Fix possible UAF in snic_tgt_create()
scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
scsi: ipr: Fix WARNING in ipr_init()
scsi: fcoe: Fix possible name leak when device_register() fails
scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
scsi: hpsa: Fix error handling in hpsa_add_sas_host()
scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
scsi: hpsa: Fix possible memory leak in hpsa_init_one()
RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
crypto: ccree - Make cc_debugfs_global_fini() available for module init function
RDMA/hfi: Decrease PCI device reference count in error path
PCI: Check for alloc failure in pci_request_irq()
crypto: ccree - Remove debugfs when platform_driver_register failed
crypto: ccree - swap SHA384 and SHA512 larval hashes at build time
scsi: scsi_debug: Fix a warning in resp_write_scat()
RDMA/siw: Set defined status for work completion with undefined status
RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
RDMA/siw: Fix immediate work request flush to completion queue
f2fs: fix normal discard process
RDMA/core: Fix order of nldev_exit call
apparmor: Use pointer to struct aa_label for lbs_cred
apparmor: Fix abi check to include v8 abi
apparmor: fix lockdep warning when removing a namespace
apparmor: fix a memleak in multi_transaction_new()
stmmac: fix potential division by 0
Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
ntb_netdev: Use dev_kfree_skb_any() in interrupt context
net: lan9303: Fix read error execution path
can: tcan4x5x: Remove invalid write in clear_interrupts
net: amd-xgbe: Check only the minimum speed for active/passive cables
net: amd-xgbe: Fix logic around active and passive cables
net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
net/tunnel: wait until all sk_user_data reader finish before releasing the sock
net: farsync: Fix kmemleak when rmmods farsync
ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
net: defxx: Fix missing err handling in dfx_init()
net: vmw_vsock: vmci: Check memcpy_from_msg()
clk: socfpga: Fix memory leak in socfpga_gate_init()
clk: socfpga: use clk_hw_register for a5/c5
clk: socfpga: clk-pll: Remove unused variable 'rc'
blktrace: Fix output non-blktrace event when blk_classic option enabled
wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
clk: samsung: Fix memory leak in _samsung_clk_register_pll()
media: coda: Add check for kmalloc
media: coda: Add check for dcoda_iram_alloc
media: c8sectpfe: Add of_node_put() when breaking out of loop
mmc: mmci: fix return value check of mmc_add_host()
mmc: wbsd: fix return value check of mmc_add_host()
mmc: via-sdmmc: fix return value check of mmc_add_host()
mmc: meson-gx: fix return value check of mmc_add_host()
mmc: omap_hsmmc: fix return value check of mmc_add_host()
mmc: atmel-mci: fix return value check of mmc_add_host()
mmc: wmt-sdmmc: fix return value check of mmc_add_host()
mmc: vub300: fix return value check of mmc_add_host()
mmc: toshsd: fix return value check of mmc_add_host()
mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
mmc: pxamci: fix return value check of mmc_add_host()
mmc: mxcmmc: fix return value check of mmc_add_host()
mmc: moxart: fix return value check of mmc_add_host()
mmc: alcor: fix return value check of mmc_add_host()
NFSv4.x: Fail client initialisation if state manager thread can't run
SUNRPC: Fix missing release socket in rpc_sockname()
xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
media: saa7164: fix missing pci_disable_device()
bpf, sockmap: fix race in sock_map_free()
regulator: core: fix resource leak in regulator_register()
configfs: fix possible memory leak in configfs_create_dir()
hsr: Avoid double remove of a node.
clk: qcom: clk-krait: fix wrong div2 functions
regulator: core: fix module refcount leak in set_supply()
wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
bonding: uninitialized variable in bond_miimon_inspect()
bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
netfilter: conntrack: set icmpv6 redirects as RELATED
ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
wifi: iwlwifi: mvm: fix double free on tx path.
ALSA: asihpi: fix missing pci_disable_device()
NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
NFSv4.2: Fix initialisation of struct nfs4_label
NFSv4.2: Fix a memory stomp in decode_attr_security_label
NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
ASoC: dt-bindings: wcd9335: fix reset line polarity in example
drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
media: dvb-core: Fix ignored return value in dvb_register_frontend()
pinctrl: pinconf-generic: add missing of_node_put()
clk: imx: replace osc_hdmi with dummy
clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
media: imon: fix a race condition in send_packet()
mtd: maps: pxa2xx-flash: fix memory leak in probe
bonding: fix link recovery in mode 2 when updelay is nonzero
bonding: Rename slave_arr to usable_slaves
bonding: Export skip slave logic to function
clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
regulator: core: use kfree_const() to free space conditionally
ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
HID: hid-sensor-custom: set fixed size for custom attributes
bpf: Move skb->len == 0 checks into __bpf_redirect
media: videobuf-dma-contig: use dma_mmap_coherent
media: platform: exynos4-is: Fix error handling in fimc_md_init()
media: solo6x10: fix possible memory leak in solo_sysfs_init()
Input: elants_i2c - properly handle the reset GPIO when power is off
mtd: lpddr2_nvm: Fix possible null-ptr-deref
wifi: ath10k: Fix return value in ath10k_pci_init()
ima: Fix misuse of dereference of pointer in template_desc_init_fields()
integrity: Fix memory leakage in keyring allocation error path
amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
ASoC: pxa: fix null-pointer dereference in filter()
drm/mediatek: Modify dpi power on/off sequence.
drm/radeon: Add the missed acpi_put_table() to fix memory leak
rxrpc: Fix ack.bufferSize to be 0 when generating an ack
net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
media: camss: Clean up received buffers on failed start of streaming
wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
mtd: Fix device name leak when register device failed in add_mtd_device()
bpf: propagate precision in ALU/ALU64 operations
media: vivid: fix compose size exceed boundary
ima: Handle -ESTALE returned by ima_filter_rule_match()
ima: Fix fall-through warnings for Clang
ima: Rename internal filter rule functions
drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
spi: Update reference to struct spi_controller
clk: renesas: r9a06g032: Repair grave increment error
can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming
can: kvaser_usb: Add struct kvaser_usb_busparams
can: kvaser_usb_leaf: Fix bogus restart events
can: kvaser_usb_leaf: Fix wrong CAN state after stopping
can: kvaser_usb_leaf: Fix improved state not being reported
can: kvaser_usb_leaf: Set Warning state even without bus errors
can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event
can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
can: kvaser_usb: do not increase tx statistics when sending error message frames
media: i2c: ad5820: Fix error path
pata_ipx4xx_cf: Fix unsigned comparison with less than zero
wifi: rtl8xxxu: Fix reading the vendor of combo chips
wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
rapidio: devices: fix missing put_device in mport_cdev_open
hfs: Fix OOB Write in hfs_asc2mac
relay: fix type mismatch when allocating memory in relay_create_buf()
eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
rapidio: fix possible UAF when kfifo_alloc() fails
fs: sysv: Fix sysv_nblocks() returns wrong value
MIPS: OCTEON: warn only once if deprecated link status is being used
MIPS: BCM63xx: Add check for NULL for clk in clk_enable
platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
PM: runtime: Do not call __rpm_callback() from rpm_idle()
PM: runtime: Improve path in rpm_idle() when no callback
xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
x86/xen: Fix memory leak in xen_init_lock_cpu()
x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
xen/events: only register debug interrupt for 2-level events
uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
rapidio: rio: fix possible name leak in rio_register_mport()
rapidio: fix possible name leaks when rio_add_device() fails
ocfs2: fix memory leak in ocfs2_mount_volume()
ocfs2: rewrite error handling of ocfs2_fill_super
ocfs2: ocfs2_mount_volume does cleanup job before return error
debugfs: fix error when writing negative value to atomic_t debugfs file
docs: fault-injection: fix non-working usage of negative values
lib/notifier-error-inject: fix error when writing -errno to debugfs file
libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
genirq/irqdesc: Don't try to remove non-existing sysfs files
nfsd: don't call nfsd_file_put from client states seqfile display
EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
PNP: fix name memory leak in pnp_alloc_dev()
selftests/efivarfs: Add checking of the test return value
MIPS: vpe-cmp: fix possible memory leak while module exiting
MIPS: vpe-mt: fix possible memory leak while module exiting
ocfs2: fix memory leak in ocfs2_stack_glue_init()
lib/fonts: fix undefined behavior in bit shift for get_default_font
proc: fixup uptime selftest
timerqueue: Use rb_entry_safe() in timerqueue_getnext()
perf: Fix possible memleak in pmu_dev_alloc()
selftests/ftrace: event_triggers: wait longer for test_event_enable
fs: don't audit the capability check in simple_xattr_list()
PM: hibernate: Fix mistake in kerneldoc comment
alpha: fix syscall entry in !AUDUT_SYSCALL case
cpuidle: dt: Return the correct numbers of parsed idle states
tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
ARM: mmp: fix timer_read delay
pstore/ram: Fix error return code in ramoops_probe()
arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
ARM: dts: turris-omnia: Add switch port 6 node
ARM: dts: turris-omnia: Add ethernet aliases
ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
arm64: dts: mt2712e: Fix unit address for pinctrl node
arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of pm_runtime_get_sync
arm: dts: spear600: Fix clcd interrupt
drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
ARM: dts: qcom: apq8064: fix coresight compatible
usb: musb: remove extra check in musb_gadget_vbus_draw
net: loopback: use NET_NAME_PREDICTABLE for name_assign_type
Bluetooth: L2CAP: Fix u8 overflow
HID: uclogic: Add HID_QUIRK_HIDINPUT_FORCE quirk
HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch V 10
HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch 10E
HID: ite: Add support for Acer S1002 keyboard-dock
xen-netback: move removal of "hotplug-status" to the right place
igb: Initialize mailbox message for VF reset
USB: serial: f81534: fix division by zero on line-speed change
USB: serial: f81232: fix division by zero on line-speed change
USB: serial: cp210x: add Kamstrup RF sniffer PIDs
USB: serial: option: add Quectel EM05-G modem
usb: gadget: uvc: Prevent buffer overflow in setup handler
udf: Fix extending file within last block
udf: Do not bother looking for prealloc extents if i_lenExtents matches i_size
udf: Fix preallocation discarding at indirect extent boundary
udf: Discard preallocation before extending file with a hole
tracing/ring-buffer: Only do full wait when cpu != RING_BUFFER_ALL_CPUS
ANDROID: Add more hvc devices for virtio-console.
Revert "can: af_can: fix NULL pointer dereference in can_rcv_filter"
ANDROID: Revert "tracing/ring-buffer: Have polling block on watermark"
Linux 5.4.228
ASoC: ops: Correct bounds check for second channel on SX controls
can: mcba_usb: Fix termination command argument
can: sja1000: fix size of OCR_MODE_MASK define
pinctrl: meditatek: Startup with the IRQs disabled
ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx()
nfp: fix use-after-free in area_cache_get()
block: unhash blkdev part inode when the part is deleted
mm/hugetlb: fix races when looking up a CONT-PTE/PMD size hugetlb page
x86/smpboot: Move rcu_cpu_starting() earlier
net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
Linux 5.4.227
can: esd_usb: Allow REC and TEC to return to zero
net: mvneta: Fix an out of bounds check
ipv6: avoid use-after-free in ip6_fragment()
net: plip: don't call kfree_skb/dev_kfree_skb() under spin_lock_irq()
xen/netback: fix build warning
ethernet: aeroflex: fix potential skb leak in greth_init_rings()
ipv4: Fix incorrect route flushing when table ID 0 is used
ipv4: Fix incorrect route flushing when source address is deleted
tipc: Fix potential OOB in tipc_link_proto_rcv()
net: hisilicon: Fix potential use-after-free in hix5hd2_rx()
net: hisilicon: Fix potential use-after-free in hisi_femac_rx()
net: thunderx: Fix missing destroy_workqueue of nicvf_rx_mode_wq
net: stmmac: fix "snps,axi-config" node property parsing
nvme initialize core quirks before calling nvme_init_subsystem
NFC: nci: Bounds check struct nfc_target arrays
i40e: Disallow ip4 and ip6 l4_4_bytes
i40e: Fix for VF MAC address 0
i40e: Fix not setting default xps_cpus after reset
net: mvneta: Prevent out of bounds read in mvneta_config_rss()
xen-netfront: Fix NULL sring after live migration
net: encx24j600: Fix invalid logic in reading of MISTAT register
net: encx24j600: Add parentheses to fix precedence
mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add()
selftests: rtnetlink: correct xfrm policy rule in kci_test_ipsec_offload
net: dsa: ksz: Check return value
Bluetooth: Fix not cleanup led when bt_init fails
Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn()
af_unix: Get user_ns from in_skb in unix_diag_get_exact().
igb: Allocate MSI-X vector when testing
e1000e: Fix TX dispatch condition
gpio: amd8111: Fix PCI device reference count leak
drm/bridge: ti-sn65dsi86: Fix output polarity setting bug
ca8210: Fix crash by zero initializing data
ieee802154: cc2520: Fix error return code in cc2520_hw_init()
can: af_can: fix NULL pointer dereference in can_rcv_filter
HID: core: fix shift-out-of-bounds in hid_report_raw_event
HID: hid-lg4ff: Add check for empty lbuf
HID: usbhid: Add ALWAYS_POLL quirk for some mice
drm/shmem-helper: Remove errant put in error path
KVM: s390: vsie: Fix the initialization of the epoch extension (epdx) field
mm/gup: fix gup_pud_range() for dax
memcg: fix possible use-after-free in memcg_write_event_control()
media: v4l2-dv-timings.c: fix too strict blanking sanity checks
Revert "net: dsa: b53: Fix valid setting for MDB entries"
xen/netback: don't call kfree_skb() with interrupts disabled
xen/netback: do some code cleanup
xen/netback: Ensure protocol headers don't fall in the non-linear area
mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths
mm/khugepaged: fix GUP-fast interaction by sending IPI
mm/khugepaged: take the right locks for page table retraction
net: usb: qmi_wwan: add u-blox 0x1342 composition
9p/xen: check logical size for buffer size
fbcon: Use kzalloc() in fbcon_prepare_logo()
regulator: twl6030: fix get status of twl6032 regulators
ASoC: soc-pcm: Add NULL check in BE reparenting
btrfs: send: avoid unaligned encoded writes when attempting to clone range
ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
regulator: slg51000: Wait after asserting CS pin
9p/fd: Use P9_HDRSZ for header size
ARM: dts: rockchip: disable arm_global_timer on rk3066 and rk3188
ARM: 9266/1: mm: fix no-MMU ZERO_PAGE() implementation
ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels
ARM: dts: rockchip: rk3188: fix lcdc1-rgb24 node name
ARM: dts: rockchip: fix ir-receiver node names
arm: dts: rockchip: fix node name for hym8563 rtc
arm64: dts: rockchip: keep I2S1 disabled for GPIO function on ROCK Pi 4 series
Change-Id: I6a643eaa2ee55257328d881f5b860200719e981e
Signed-off-by: kamasali Satyanarayan <[email protected]>
2264 lines
57 KiB
C
2264 lines
57 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/mm.h>
|
|
#include <linux/sched/coredump.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/rmap.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/mm_inline.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/khugepaged.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/hashtable.h>
|
|
#include <linux/userfaultfd_k.h>
|
|
#include <linux/page_idle.h>
|
|
#include <linux/swapops.h>
|
|
#include <linux/shmem_fs.h>
|
|
|
|
#include <asm/tlb.h>
|
|
#include <asm/pgalloc.h>
|
|
#include "internal.h"
|
|
|
|
enum scan_result {
|
|
SCAN_FAIL,
|
|
SCAN_SUCCEED,
|
|
SCAN_PMD_NULL,
|
|
SCAN_EXCEED_NONE_PTE,
|
|
SCAN_PTE_NON_PRESENT,
|
|
SCAN_PAGE_RO,
|
|
SCAN_LACK_REFERENCED_PAGE,
|
|
SCAN_PAGE_NULL,
|
|
SCAN_SCAN_ABORT,
|
|
SCAN_PAGE_COUNT,
|
|
SCAN_PAGE_LRU,
|
|
SCAN_PAGE_LOCK,
|
|
SCAN_PAGE_ANON,
|
|
SCAN_PAGE_COMPOUND,
|
|
SCAN_ANY_PROCESS,
|
|
SCAN_VMA_NULL,
|
|
SCAN_VMA_CHECK,
|
|
SCAN_ADDRESS_RANGE,
|
|
SCAN_SWAP_CACHE_PAGE,
|
|
SCAN_DEL_PAGE_LRU,
|
|
SCAN_ALLOC_HUGE_PAGE_FAIL,
|
|
SCAN_CGROUP_CHARGE_FAIL,
|
|
SCAN_EXCEED_SWAP_PTE,
|
|
SCAN_TRUNCATED,
|
|
SCAN_PAGE_HAS_PRIVATE,
|
|
};
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/huge_memory.h>
|
|
|
|
static struct task_struct *khugepaged_thread __read_mostly;
|
|
static DEFINE_MUTEX(khugepaged_mutex);
|
|
|
|
/* default scan 8*512 pte (or vmas) every 30 second */
|
|
static unsigned int khugepaged_pages_to_scan __read_mostly;
|
|
static unsigned int khugepaged_pages_collapsed;
|
|
static unsigned int khugepaged_full_scans;
|
|
static unsigned int khugepaged_scan_sleep_millisecs __read_mostly = 10000;
|
|
/* during fragmentation poll the hugepage allocator once every minute */
|
|
static unsigned int khugepaged_alloc_sleep_millisecs __read_mostly = 60000;
|
|
static unsigned long khugepaged_sleep_expire;
|
|
static DEFINE_SPINLOCK(khugepaged_mm_lock);
|
|
static DECLARE_WAIT_QUEUE_HEAD(khugepaged_wait);
|
|
/*
|
|
* default collapse hugepages if there is at least one pte mapped like
|
|
* it would have happened if the vma was large enough during page
|
|
* fault.
|
|
*/
|
|
static unsigned int khugepaged_max_ptes_none __read_mostly;
|
|
static unsigned int khugepaged_max_ptes_swap __read_mostly;
|
|
|
|
#define MM_SLOTS_HASH_BITS 10
|
|
static __read_mostly DEFINE_HASHTABLE(mm_slots_hash, MM_SLOTS_HASH_BITS);
|
|
|
|
static struct kmem_cache *mm_slot_cache __read_mostly;
|
|
|
|
#define MAX_PTE_MAPPED_THP 8
|
|
|
|
/**
|
|
* struct mm_slot - hash lookup from mm to mm_slot
|
|
* @hash: hash collision list
|
|
* @mm_node: khugepaged scan list headed in khugepaged_scan.mm_head
|
|
* @mm: the mm that this information is valid for
|
|
*/
|
|
struct mm_slot {
|
|
struct hlist_node hash;
|
|
struct list_head mm_node;
|
|
struct mm_struct *mm;
|
|
|
|
/* pte-mapped THP in this mm */
|
|
int nr_pte_mapped_thp;
|
|
unsigned long pte_mapped_thp[MAX_PTE_MAPPED_THP];
|
|
};
|
|
|
|
/**
|
|
* struct khugepaged_scan - cursor for scanning
|
|
* @mm_head: the head of the mm list to scan
|
|
* @mm_slot: the current mm_slot we are scanning
|
|
* @address: the next address inside that to be scanned
|
|
*
|
|
* There is only the one khugepaged_scan instance of this cursor structure.
|
|
*/
|
|
struct khugepaged_scan {
|
|
struct list_head mm_head;
|
|
struct mm_slot *mm_slot;
|
|
unsigned long address;
|
|
};
|
|
|
|
static struct khugepaged_scan khugepaged_scan = {
|
|
.mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head),
|
|
};
|
|
|
|
#ifdef CONFIG_SYSFS
|
|
static ssize_t scan_sleep_millisecs_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_scan_sleep_millisecs);
|
|
}
|
|
|
|
static ssize_t scan_sleep_millisecs_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long msecs;
|
|
int err;
|
|
|
|
err = kstrtoul(buf, 10, &msecs);
|
|
if (err || msecs > UINT_MAX)
|
|
return -EINVAL;
|
|
|
|
khugepaged_scan_sleep_millisecs = msecs;
|
|
khugepaged_sleep_expire = 0;
|
|
wake_up_interruptible(&khugepaged_wait);
|
|
|
|
return count;
|
|
}
|
|
static struct kobj_attribute scan_sleep_millisecs_attr =
|
|
__ATTR(scan_sleep_millisecs, 0644, scan_sleep_millisecs_show,
|
|
scan_sleep_millisecs_store);
|
|
|
|
static ssize_t alloc_sleep_millisecs_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_alloc_sleep_millisecs);
|
|
}
|
|
|
|
static ssize_t alloc_sleep_millisecs_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
unsigned long msecs;
|
|
int err;
|
|
|
|
err = kstrtoul(buf, 10, &msecs);
|
|
if (err || msecs > UINT_MAX)
|
|
return -EINVAL;
|
|
|
|
khugepaged_alloc_sleep_millisecs = msecs;
|
|
khugepaged_sleep_expire = 0;
|
|
wake_up_interruptible(&khugepaged_wait);
|
|
|
|
return count;
|
|
}
|
|
static struct kobj_attribute alloc_sleep_millisecs_attr =
|
|
__ATTR(alloc_sleep_millisecs, 0644, alloc_sleep_millisecs_show,
|
|
alloc_sleep_millisecs_store);
|
|
|
|
static ssize_t pages_to_scan_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_pages_to_scan);
|
|
}
|
|
static ssize_t pages_to_scan_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err;
|
|
unsigned long pages;
|
|
|
|
err = kstrtoul(buf, 10, &pages);
|
|
if (err || !pages || pages > UINT_MAX)
|
|
return -EINVAL;
|
|
|
|
khugepaged_pages_to_scan = pages;
|
|
|
|
return count;
|
|
}
|
|
static struct kobj_attribute pages_to_scan_attr =
|
|
__ATTR(pages_to_scan, 0644, pages_to_scan_show,
|
|
pages_to_scan_store);
|
|
|
|
static ssize_t pages_collapsed_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_pages_collapsed);
|
|
}
|
|
static struct kobj_attribute pages_collapsed_attr =
|
|
__ATTR_RO(pages_collapsed);
|
|
|
|
static ssize_t full_scans_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_full_scans);
|
|
}
|
|
static struct kobj_attribute full_scans_attr =
|
|
__ATTR_RO(full_scans);
|
|
|
|
static ssize_t khugepaged_defrag_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
return single_hugepage_flag_show(kobj, attr, buf,
|
|
TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG);
|
|
}
|
|
static ssize_t khugepaged_defrag_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return single_hugepage_flag_store(kobj, attr, buf, count,
|
|
TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG);
|
|
}
|
|
static struct kobj_attribute khugepaged_defrag_attr =
|
|
__ATTR(defrag, 0644, khugepaged_defrag_show,
|
|
khugepaged_defrag_store);
|
|
|
|
/*
|
|
* max_ptes_none controls if khugepaged should collapse hugepages over
|
|
* any unmapped ptes in turn potentially increasing the memory
|
|
* footprint of the vmas. When max_ptes_none is 0 khugepaged will not
|
|
* reduce the available free memory in the system as it
|
|
* runs. Increasing max_ptes_none will instead potentially reduce the
|
|
* free memory in the system during the khugepaged scan.
|
|
*/
|
|
static ssize_t khugepaged_max_ptes_none_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_max_ptes_none);
|
|
}
|
|
static ssize_t khugepaged_max_ptes_none_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err;
|
|
unsigned long max_ptes_none;
|
|
|
|
err = kstrtoul(buf, 10, &max_ptes_none);
|
|
if (err || max_ptes_none > HPAGE_PMD_NR-1)
|
|
return -EINVAL;
|
|
|
|
khugepaged_max_ptes_none = max_ptes_none;
|
|
|
|
return count;
|
|
}
|
|
static struct kobj_attribute khugepaged_max_ptes_none_attr =
|
|
__ATTR(max_ptes_none, 0644, khugepaged_max_ptes_none_show,
|
|
khugepaged_max_ptes_none_store);
|
|
|
|
static ssize_t khugepaged_max_ptes_swap_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%u\n", khugepaged_max_ptes_swap);
|
|
}
|
|
|
|
static ssize_t khugepaged_max_ptes_swap_store(struct kobject *kobj,
|
|
struct kobj_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int err;
|
|
unsigned long max_ptes_swap;
|
|
|
|
err = kstrtoul(buf, 10, &max_ptes_swap);
|
|
if (err || max_ptes_swap > HPAGE_PMD_NR-1)
|
|
return -EINVAL;
|
|
|
|
khugepaged_max_ptes_swap = max_ptes_swap;
|
|
|
|
return count;
|
|
}
|
|
|
|
static struct kobj_attribute khugepaged_max_ptes_swap_attr =
|
|
__ATTR(max_ptes_swap, 0644, khugepaged_max_ptes_swap_show,
|
|
khugepaged_max_ptes_swap_store);
|
|
|
|
static struct attribute *khugepaged_attr[] = {
|
|
&khugepaged_defrag_attr.attr,
|
|
&khugepaged_max_ptes_none_attr.attr,
|
|
&pages_to_scan_attr.attr,
|
|
&pages_collapsed_attr.attr,
|
|
&full_scans_attr.attr,
|
|
&scan_sleep_millisecs_attr.attr,
|
|
&alloc_sleep_millisecs_attr.attr,
|
|
&khugepaged_max_ptes_swap_attr.attr,
|
|
NULL,
|
|
};
|
|
|
|
struct attribute_group khugepaged_attr_group = {
|
|
.attrs = khugepaged_attr,
|
|
.name = "khugepaged",
|
|
};
|
|
#endif /* CONFIG_SYSFS */
|
|
|
|
#define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB)
|
|
|
|
int hugepage_madvise(struct vm_area_struct *vma,
|
|
unsigned long *vm_flags, int advice)
|
|
{
|
|
switch (advice) {
|
|
case MADV_HUGEPAGE:
|
|
#ifdef CONFIG_S390
|
|
/*
|
|
* qemu blindly sets MADV_HUGEPAGE on all allocations, but s390
|
|
* can't handle this properly after s390_enable_sie, so we simply
|
|
* ignore the madvise to prevent qemu from causing a SIGSEGV.
|
|
*/
|
|
if (mm_has_pgste(vma->vm_mm))
|
|
return 0;
|
|
#endif
|
|
*vm_flags &= ~VM_NOHUGEPAGE;
|
|
*vm_flags |= VM_HUGEPAGE;
|
|
/*
|
|
* If the vma become good for khugepaged to scan,
|
|
* register it here without waiting a page fault that
|
|
* may not happen any time soon.
|
|
*/
|
|
if (!(*vm_flags & VM_NO_KHUGEPAGED) &&
|
|
khugepaged_enter_vma_merge(vma, *vm_flags))
|
|
return -ENOMEM;
|
|
break;
|
|
case MADV_NOHUGEPAGE:
|
|
*vm_flags &= ~VM_HUGEPAGE;
|
|
*vm_flags |= VM_NOHUGEPAGE;
|
|
/*
|
|
* Setting VM_NOHUGEPAGE will prevent khugepaged from scanning
|
|
* this vma even if we leave the mm registered in khugepaged if
|
|
* it got registered before VM_NOHUGEPAGE was set.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int __init khugepaged_init(void)
|
|
{
|
|
mm_slot_cache = kmem_cache_create("khugepaged_mm_slot",
|
|
sizeof(struct mm_slot),
|
|
__alignof__(struct mm_slot), 0, NULL);
|
|
if (!mm_slot_cache)
|
|
return -ENOMEM;
|
|
|
|
khugepaged_pages_to_scan = HPAGE_PMD_NR * 8;
|
|
khugepaged_max_ptes_none = HPAGE_PMD_NR - 1;
|
|
khugepaged_max_ptes_swap = HPAGE_PMD_NR / 8;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init khugepaged_destroy(void)
|
|
{
|
|
kmem_cache_destroy(mm_slot_cache);
|
|
}
|
|
|
|
static inline struct mm_slot *alloc_mm_slot(void)
|
|
{
|
|
if (!mm_slot_cache) /* initialization failed */
|
|
return NULL;
|
|
return kmem_cache_zalloc(mm_slot_cache, GFP_KERNEL);
|
|
}
|
|
|
|
static inline void free_mm_slot(struct mm_slot *mm_slot)
|
|
{
|
|
kmem_cache_free(mm_slot_cache, mm_slot);
|
|
}
|
|
|
|
static struct mm_slot *get_mm_slot(struct mm_struct *mm)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
|
|
hash_for_each_possible(mm_slots_hash, mm_slot, hash, (unsigned long)mm)
|
|
if (mm == mm_slot->mm)
|
|
return mm_slot;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void insert_to_mm_slots_hash(struct mm_struct *mm,
|
|
struct mm_slot *mm_slot)
|
|
{
|
|
mm_slot->mm = mm;
|
|
hash_add(mm_slots_hash, &mm_slot->hash, (long)mm);
|
|
}
|
|
|
|
static inline int khugepaged_test_exit(struct mm_struct *mm)
|
|
{
|
|
return atomic_read(&mm->mm_users) == 0 || !mmget_still_valid(mm);
|
|
}
|
|
|
|
static bool hugepage_vma_check(struct vm_area_struct *vma,
|
|
unsigned long vm_flags)
|
|
{
|
|
if ((!(vm_flags & VM_HUGEPAGE) && !khugepaged_always()) ||
|
|
(vm_flags & VM_NOHUGEPAGE) ||
|
|
test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags))
|
|
return false;
|
|
|
|
if (shmem_file(vma->vm_file) ||
|
|
(IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) &&
|
|
vma->vm_file &&
|
|
(vm_flags & VM_DENYWRITE))) {
|
|
if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
|
|
return false;
|
|
return IS_ALIGNED((vma->vm_start >> PAGE_SHIFT) - vma->vm_pgoff,
|
|
HPAGE_PMD_NR);
|
|
}
|
|
if (!vma->anon_vma || vma->vm_ops)
|
|
return false;
|
|
if (is_vma_temporary_stack(vma))
|
|
return false;
|
|
return !(vm_flags & VM_NO_KHUGEPAGED);
|
|
}
|
|
|
|
int __khugepaged_enter(struct mm_struct *mm)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
int wakeup;
|
|
|
|
mm_slot = alloc_mm_slot();
|
|
if (!mm_slot)
|
|
return -ENOMEM;
|
|
|
|
/* __khugepaged_exit() must not run from under us */
|
|
VM_BUG_ON_MM(atomic_read(&mm->mm_users) == 0, mm);
|
|
if (unlikely(test_and_set_bit(MMF_VM_HUGEPAGE, &mm->flags))) {
|
|
free_mm_slot(mm_slot);
|
|
return 0;
|
|
}
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
insert_to_mm_slots_hash(mm, mm_slot);
|
|
/*
|
|
* Insert just behind the scanning cursor, to let the area settle
|
|
* down a little.
|
|
*/
|
|
wakeup = list_empty(&khugepaged_scan.mm_head);
|
|
list_add_tail(&mm_slot->mm_node, &khugepaged_scan.mm_head);
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
|
|
mmgrab(mm);
|
|
if (wakeup)
|
|
wake_up_interruptible(&khugepaged_wait);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
|
|
unsigned long vm_flags)
|
|
{
|
|
unsigned long hstart, hend;
|
|
|
|
/*
|
|
* khugepaged only supports read-only files for non-shmem files.
|
|
* khugepaged does not yet work on special mappings. And
|
|
* file-private shmem THP is not supported.
|
|
*/
|
|
if (!hugepage_vma_check(vma, vm_flags))
|
|
return 0;
|
|
|
|
hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
|
|
hend = vma->vm_end & HPAGE_PMD_MASK;
|
|
if (hstart < hend)
|
|
return khugepaged_enter(vma, vm_flags);
|
|
return 0;
|
|
}
|
|
|
|
void __khugepaged_exit(struct mm_struct *mm)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
int free = 0;
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
mm_slot = get_mm_slot(mm);
|
|
if (mm_slot && khugepaged_scan.mm_slot != mm_slot) {
|
|
hash_del(&mm_slot->hash);
|
|
list_del(&mm_slot->mm_node);
|
|
free = 1;
|
|
}
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
|
|
if (free) {
|
|
clear_bit(MMF_VM_HUGEPAGE, &mm->flags);
|
|
free_mm_slot(mm_slot);
|
|
mmdrop(mm);
|
|
} else if (mm_slot) {
|
|
/*
|
|
* This is required to serialize against
|
|
* khugepaged_test_exit() (which is guaranteed to run
|
|
* under mmap sem read mode). Stop here (after we
|
|
* return all pagetables will be destroyed) until
|
|
* khugepaged has finished working on the pagetables
|
|
* under the mmap_sem.
|
|
*/
|
|
down_write(&mm->mmap_sem);
|
|
up_write(&mm->mmap_sem);
|
|
}
|
|
}
|
|
|
|
static void release_pte_page(struct page *page)
|
|
{
|
|
dec_node_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page));
|
|
unlock_page(page);
|
|
putback_lru_page(page);
|
|
}
|
|
|
|
static void release_pte_pages(pte_t *pte, pte_t *_pte)
|
|
{
|
|
while (--_pte >= pte) {
|
|
pte_t pteval = *_pte;
|
|
if (!pte_none(pteval) && !is_zero_pfn(pte_pfn(pteval)))
|
|
release_pte_page(pte_page(pteval));
|
|
}
|
|
}
|
|
|
|
static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
|
|
unsigned long address,
|
|
pte_t *pte)
|
|
{
|
|
struct page *page = NULL;
|
|
pte_t *_pte;
|
|
int none_or_zero = 0, result = 0, referenced = 0;
|
|
bool writable = false;
|
|
|
|
for (_pte = pte; _pte < pte+HPAGE_PMD_NR;
|
|
_pte++, address += PAGE_SIZE) {
|
|
pte_t pteval = *_pte;
|
|
if (pte_none(pteval) || (pte_present(pteval) &&
|
|
is_zero_pfn(pte_pfn(pteval)))) {
|
|
if (!userfaultfd_armed(vma) &&
|
|
++none_or_zero <= khugepaged_max_ptes_none) {
|
|
continue;
|
|
} else {
|
|
result = SCAN_EXCEED_NONE_PTE;
|
|
goto out;
|
|
}
|
|
}
|
|
if (!pte_present(pteval)) {
|
|
result = SCAN_PTE_NON_PRESENT;
|
|
goto out;
|
|
}
|
|
page = vm_normal_page(vma, address, pteval);
|
|
if (unlikely(!page)) {
|
|
result = SCAN_PAGE_NULL;
|
|
goto out;
|
|
}
|
|
|
|
/* TODO: teach khugepaged to collapse THP mapped with pte */
|
|
if (PageCompound(page)) {
|
|
result = SCAN_PAGE_COMPOUND;
|
|
goto out;
|
|
}
|
|
|
|
VM_BUG_ON_PAGE(!PageAnon(page), page);
|
|
|
|
/*
|
|
* We can do it before isolate_lru_page because the
|
|
* page can't be freed from under us. NOTE: PG_lock
|
|
* is needed to serialize against split_huge_page
|
|
* when invoked from the VM.
|
|
*/
|
|
if (!trylock_page(page)) {
|
|
result = SCAN_PAGE_LOCK;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* cannot use mapcount: can't collapse if there's a gup pin.
|
|
* The page must only be referenced by the scanned process
|
|
* and page swap cache.
|
|
*/
|
|
if (page_count(page) != 1 + PageSwapCache(page)) {
|
|
unlock_page(page);
|
|
result = SCAN_PAGE_COUNT;
|
|
goto out;
|
|
}
|
|
if (pte_write(pteval)) {
|
|
writable = true;
|
|
} else {
|
|
if (PageSwapCache(page) &&
|
|
!reuse_swap_page(page, NULL)) {
|
|
unlock_page(page);
|
|
result = SCAN_SWAP_CACHE_PAGE;
|
|
goto out;
|
|
}
|
|
/*
|
|
* Page is not in the swap cache. It can be collapsed
|
|
* into a THP.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Isolate the page to avoid collapsing an hugepage
|
|
* currently in use by the VM.
|
|
*/
|
|
if (isolate_lru_page(page)) {
|
|
unlock_page(page);
|
|
result = SCAN_DEL_PAGE_LRU;
|
|
goto out;
|
|
}
|
|
inc_node_page_state(page,
|
|
NR_ISOLATED_ANON + page_is_file_cache(page));
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
VM_BUG_ON_PAGE(PageLRU(page), page);
|
|
|
|
/* There should be enough young pte to collapse the page */
|
|
if (pte_young(pteval) ||
|
|
page_is_young(page) || PageReferenced(page) ||
|
|
mmu_notifier_test_young(vma->vm_mm, address))
|
|
referenced++;
|
|
}
|
|
|
|
if (unlikely(!writable)) {
|
|
result = SCAN_PAGE_RO;
|
|
} else if (unlikely(!referenced)) {
|
|
result = SCAN_LACK_REFERENCED_PAGE;
|
|
} else {
|
|
result = SCAN_SUCCEED;
|
|
trace_mm_collapse_huge_page_isolate(page, none_or_zero,
|
|
referenced, writable, result);
|
|
return 1;
|
|
}
|
|
out:
|
|
release_pte_pages(pte, _pte);
|
|
trace_mm_collapse_huge_page_isolate(page, none_or_zero,
|
|
referenced, writable, result);
|
|
return 0;
|
|
}
|
|
|
|
static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
|
|
struct vm_area_struct *vma,
|
|
unsigned long address,
|
|
spinlock_t *ptl)
|
|
{
|
|
pte_t *_pte;
|
|
for (_pte = pte; _pte < pte + HPAGE_PMD_NR;
|
|
_pte++, page++, address += PAGE_SIZE) {
|
|
pte_t pteval = *_pte;
|
|
struct page *src_page;
|
|
|
|
if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) {
|
|
clear_user_highpage(page, address);
|
|
add_mm_counter(vma->vm_mm, MM_ANONPAGES, 1);
|
|
if (is_zero_pfn(pte_pfn(pteval))) {
|
|
/*
|
|
* ptl mostly unnecessary.
|
|
*/
|
|
spin_lock(ptl);
|
|
/*
|
|
* paravirt calls inside pte_clear here are
|
|
* superfluous.
|
|
*/
|
|
pte_clear(vma->vm_mm, address, _pte);
|
|
spin_unlock(ptl);
|
|
}
|
|
} else {
|
|
src_page = pte_page(pteval);
|
|
copy_user_highpage(page, src_page, address, vma);
|
|
VM_BUG_ON_PAGE(page_mapcount(src_page) != 1, src_page);
|
|
release_pte_page(src_page);
|
|
/*
|
|
* ptl mostly unnecessary, but preempt has to
|
|
* be disabled to update the per-cpu stats
|
|
* inside page_remove_rmap().
|
|
*/
|
|
spin_lock(ptl);
|
|
/*
|
|
* paravirt calls inside pte_clear here are
|
|
* superfluous.
|
|
*/
|
|
pte_clear(vma->vm_mm, address, _pte);
|
|
page_remove_rmap(src_page, false);
|
|
spin_unlock(ptl);
|
|
free_page_and_swap_cache(src_page);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void khugepaged_alloc_sleep(void)
|
|
{
|
|
DEFINE_WAIT(wait);
|
|
|
|
add_wait_queue(&khugepaged_wait, &wait);
|
|
freezable_schedule_timeout_interruptible(
|
|
msecs_to_jiffies(khugepaged_alloc_sleep_millisecs));
|
|
remove_wait_queue(&khugepaged_wait, &wait);
|
|
}
|
|
|
|
static int khugepaged_node_load[MAX_NUMNODES];
|
|
|
|
static bool khugepaged_scan_abort(int nid)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* If node_reclaim_mode is disabled, then no extra effort is made to
|
|
* allocate memory locally.
|
|
*/
|
|
if (!node_reclaim_mode)
|
|
return false;
|
|
|
|
/* If there is a count for this node already, it must be acceptable */
|
|
if (khugepaged_node_load[nid])
|
|
return false;
|
|
|
|
for (i = 0; i < MAX_NUMNODES; i++) {
|
|
if (!khugepaged_node_load[i])
|
|
continue;
|
|
if (node_distance(nid, i) > node_reclaim_distance)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Defrag for khugepaged will enter direct reclaim/compaction if necessary */
|
|
static inline gfp_t alloc_hugepage_khugepaged_gfpmask(void)
|
|
{
|
|
return khugepaged_defrag() ? GFP_TRANSHUGE : GFP_TRANSHUGE_LIGHT;
|
|
}
|
|
|
|
#ifdef CONFIG_NUMA
|
|
static int khugepaged_find_target_node(void)
|
|
{
|
|
static int last_khugepaged_target_node = NUMA_NO_NODE;
|
|
int nid, target_node = 0, max_value = 0;
|
|
|
|
/* find first node with max normal pages hit */
|
|
for (nid = 0; nid < MAX_NUMNODES; nid++)
|
|
if (khugepaged_node_load[nid] > max_value) {
|
|
max_value = khugepaged_node_load[nid];
|
|
target_node = nid;
|
|
}
|
|
|
|
/* do some balance if several nodes have the same hit record */
|
|
if (target_node <= last_khugepaged_target_node)
|
|
for (nid = last_khugepaged_target_node + 1; nid < MAX_NUMNODES;
|
|
nid++)
|
|
if (max_value == khugepaged_node_load[nid]) {
|
|
target_node = nid;
|
|
break;
|
|
}
|
|
|
|
last_khugepaged_target_node = target_node;
|
|
return target_node;
|
|
}
|
|
|
|
static bool khugepaged_prealloc_page(struct page **hpage, bool *wait)
|
|
{
|
|
if (IS_ERR(*hpage)) {
|
|
if (!*wait)
|
|
return false;
|
|
|
|
*wait = false;
|
|
*hpage = NULL;
|
|
khugepaged_alloc_sleep();
|
|
} else if (*hpage) {
|
|
put_page(*hpage);
|
|
*hpage = NULL;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static struct page *
|
|
khugepaged_alloc_page(struct page **hpage, gfp_t gfp, int node)
|
|
{
|
|
VM_BUG_ON_PAGE(*hpage, *hpage);
|
|
|
|
*hpage = __alloc_pages_node(node, gfp, HPAGE_PMD_ORDER);
|
|
if (unlikely(!*hpage)) {
|
|
count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
|
|
*hpage = ERR_PTR(-ENOMEM);
|
|
return NULL;
|
|
}
|
|
|
|
prep_transhuge_page(*hpage);
|
|
count_vm_event(THP_COLLAPSE_ALLOC);
|
|
return *hpage;
|
|
}
|
|
#else
|
|
static int khugepaged_find_target_node(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline struct page *alloc_khugepaged_hugepage(void)
|
|
{
|
|
struct page *page;
|
|
|
|
page = alloc_pages(alloc_hugepage_khugepaged_gfpmask(),
|
|
HPAGE_PMD_ORDER);
|
|
if (page)
|
|
prep_transhuge_page(page);
|
|
return page;
|
|
}
|
|
|
|
static struct page *khugepaged_alloc_hugepage(bool *wait)
|
|
{
|
|
struct page *hpage;
|
|
|
|
do {
|
|
hpage = alloc_khugepaged_hugepage();
|
|
if (!hpage) {
|
|
count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
|
|
if (!*wait)
|
|
return NULL;
|
|
|
|
*wait = false;
|
|
khugepaged_alloc_sleep();
|
|
} else
|
|
count_vm_event(THP_COLLAPSE_ALLOC);
|
|
} while (unlikely(!hpage) && likely(khugepaged_enabled()));
|
|
|
|
return hpage;
|
|
}
|
|
|
|
static bool khugepaged_prealloc_page(struct page **hpage, bool *wait)
|
|
{
|
|
/*
|
|
* If the hpage allocated earlier was briefly exposed in page cache
|
|
* before collapse_file() failed, it is possible that racing lookups
|
|
* have not yet completed, and would then be unpleasantly surprised by
|
|
* finding the hpage reused for the same mapping at a different offset.
|
|
* Just release the previous allocation if there is any danger of that.
|
|
*/
|
|
if (*hpage && page_count(*hpage) > 1) {
|
|
put_page(*hpage);
|
|
*hpage = NULL;
|
|
}
|
|
|
|
if (!*hpage)
|
|
*hpage = khugepaged_alloc_hugepage(wait);
|
|
|
|
if (unlikely(!*hpage))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static struct page *
|
|
khugepaged_alloc_page(struct page **hpage, gfp_t gfp, int node)
|
|
{
|
|
VM_BUG_ON(!*hpage);
|
|
|
|
return *hpage;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* If mmap_sem temporarily dropped, revalidate vma
|
|
* before taking mmap_sem.
|
|
* Return 0 if succeeds, otherwise return none-zero
|
|
* value (scan code).
|
|
*/
|
|
|
|
static int hugepage_vma_revalidate(struct mm_struct *mm, unsigned long address,
|
|
struct vm_area_struct **vmap)
|
|
{
|
|
struct vm_area_struct *vma;
|
|
unsigned long hstart, hend;
|
|
|
|
if (unlikely(khugepaged_test_exit(mm)))
|
|
return SCAN_ANY_PROCESS;
|
|
|
|
*vmap = vma = find_vma(mm, address);
|
|
if (!vma)
|
|
return SCAN_VMA_NULL;
|
|
|
|
hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
|
|
hend = vma->vm_end & HPAGE_PMD_MASK;
|
|
if (address < hstart || address + HPAGE_PMD_SIZE > hend)
|
|
return SCAN_ADDRESS_RANGE;
|
|
if (!hugepage_vma_check(vma, vma->vm_flags))
|
|
return SCAN_VMA_CHECK;
|
|
/* Anon VMA expected */
|
|
if (!vma->anon_vma || vma->vm_ops)
|
|
return SCAN_VMA_CHECK;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Bring missing pages in from swap, to complete THP collapse.
|
|
* Only done if khugepaged_scan_pmd believes it is worthwhile.
|
|
*
|
|
* Called and returns without pte mapped or spinlocks held,
|
|
* but with mmap_sem held to protect against vma changes.
|
|
*/
|
|
|
|
static bool __collapse_huge_page_swapin(struct mm_struct *mm,
|
|
struct vm_area_struct *vma,
|
|
unsigned long address, pmd_t *pmd,
|
|
int referenced)
|
|
{
|
|
int swapped_in = 0;
|
|
vm_fault_t ret = 0;
|
|
struct vm_fault vmf = {
|
|
.vma = vma,
|
|
.address = address,
|
|
.flags = FAULT_FLAG_ALLOW_RETRY,
|
|
.pmd = pmd,
|
|
.pgoff = linear_page_index(vma, address),
|
|
.vma_flags = vma->vm_flags,
|
|
.vma_page_prot = vma->vm_page_prot,
|
|
};
|
|
|
|
/* we only decide to swapin, if there is enough young ptes */
|
|
if (referenced < HPAGE_PMD_NR/2) {
|
|
trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 0);
|
|
return false;
|
|
}
|
|
vmf.pte = pte_offset_map(pmd, address);
|
|
for (; vmf.address < address + HPAGE_PMD_NR*PAGE_SIZE;
|
|
vmf.pte++, vmf.address += PAGE_SIZE) {
|
|
vmf.orig_pte = *vmf.pte;
|
|
if (!is_swap_pte(vmf.orig_pte))
|
|
continue;
|
|
swapped_in++;
|
|
ret = do_swap_page(&vmf);
|
|
|
|
/* do_swap_page returns VM_FAULT_RETRY with released mmap_sem */
|
|
if (ret & VM_FAULT_RETRY) {
|
|
down_read(&mm->mmap_sem);
|
|
if (hugepage_vma_revalidate(mm, address, &vmf.vma)) {
|
|
/* vma is no longer available, don't continue to swapin */
|
|
trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 0);
|
|
return false;
|
|
}
|
|
/* check if the pmd is still valid */
|
|
if (mm_find_pmd(mm, address) != pmd) {
|
|
trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 0);
|
|
return false;
|
|
}
|
|
}
|
|
if (ret & VM_FAULT_ERROR) {
|
|
trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 0);
|
|
return false;
|
|
}
|
|
/* pte is unmapped now, we need to map it */
|
|
vmf.pte = pte_offset_map(pmd, vmf.address);
|
|
}
|
|
vmf.pte--;
|
|
pte_unmap(vmf.pte);
|
|
trace_mm_collapse_huge_page_swapin(mm, swapped_in, referenced, 1);
|
|
return true;
|
|
}
|
|
|
|
static void collapse_huge_page(struct mm_struct *mm,
|
|
unsigned long address,
|
|
struct page **hpage,
|
|
int node, int referenced)
|
|
{
|
|
pmd_t *pmd, _pmd;
|
|
pte_t *pte;
|
|
pgtable_t pgtable;
|
|
struct page *new_page;
|
|
spinlock_t *pmd_ptl, *pte_ptl;
|
|
int isolated = 0, result = 0;
|
|
struct mem_cgroup *memcg;
|
|
struct vm_area_struct *vma;
|
|
struct mmu_notifier_range range;
|
|
gfp_t gfp;
|
|
|
|
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
|
|
|
/* Only allocate from the target node */
|
|
gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
|
|
|
|
/*
|
|
* Before allocating the hugepage, release the mmap_sem read lock.
|
|
* The allocation can take potentially a long time if it involves
|
|
* sync compaction, and we do not need to hold the mmap_sem during
|
|
* that. We will recheck the vma after taking it again in write mode.
|
|
*/
|
|
up_read(&mm->mmap_sem);
|
|
new_page = khugepaged_alloc_page(hpage, gfp, node);
|
|
if (!new_page) {
|
|
result = SCAN_ALLOC_HUGE_PAGE_FAIL;
|
|
goto out_nolock;
|
|
}
|
|
|
|
if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
|
|
result = SCAN_CGROUP_CHARGE_FAIL;
|
|
goto out_nolock;
|
|
}
|
|
|
|
down_read(&mm->mmap_sem);
|
|
result = hugepage_vma_revalidate(mm, address, &vma);
|
|
if (result) {
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
up_read(&mm->mmap_sem);
|
|
goto out_nolock;
|
|
}
|
|
|
|
pmd = mm_find_pmd(mm, address);
|
|
if (!pmd) {
|
|
result = SCAN_PMD_NULL;
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
up_read(&mm->mmap_sem);
|
|
goto out_nolock;
|
|
}
|
|
|
|
/*
|
|
* __collapse_huge_page_swapin always returns with mmap_sem locked.
|
|
* If it fails, we release mmap_sem and jump out_nolock.
|
|
* Continuing to collapse causes inconsistency.
|
|
*/
|
|
if (!__collapse_huge_page_swapin(mm, vma, address, pmd, referenced)) {
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
up_read(&mm->mmap_sem);
|
|
goto out_nolock;
|
|
}
|
|
|
|
up_read(&mm->mmap_sem);
|
|
/*
|
|
* Prevent all access to pagetables with the exception of
|
|
* gup_fast later handled by the ptep_clear_flush and the VM
|
|
* handled by the anon_vma lock + PG_lock.
|
|
*/
|
|
down_write(&mm->mmap_sem);
|
|
result = hugepage_vma_revalidate(mm, address, &vma);
|
|
if (result)
|
|
goto out;
|
|
/* check if the pmd is still valid */
|
|
if (mm_find_pmd(mm, address) != pmd)
|
|
goto out;
|
|
|
|
vm_write_begin(vma);
|
|
anon_vma_lock_write(vma->anon_vma);
|
|
|
|
mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, NULL, mm,
|
|
address, address + HPAGE_PMD_SIZE);
|
|
mmu_notifier_invalidate_range_start(&range);
|
|
|
|
pte = pte_offset_map(pmd, address);
|
|
pte_ptl = pte_lockptr(mm, pmd);
|
|
|
|
pmd_ptl = pmd_lock(mm, pmd); /* probably unnecessary */
|
|
/*
|
|
* After this gup_fast can't run anymore. This also removes
|
|
* any huge TLB entry from the CPU so we won't allow
|
|
* huge and small TLB entries for the same virtual address
|
|
* to avoid the risk of CPU bugs in that area.
|
|
*/
|
|
_pmd = pmdp_collapse_flush(vma, address, pmd);
|
|
spin_unlock(pmd_ptl);
|
|
mmu_notifier_invalidate_range_end(&range);
|
|
tlb_remove_table_sync_one();
|
|
|
|
spin_lock(pte_ptl);
|
|
isolated = __collapse_huge_page_isolate(vma, address, pte);
|
|
spin_unlock(pte_ptl);
|
|
|
|
if (unlikely(!isolated)) {
|
|
pte_unmap(pte);
|
|
spin_lock(pmd_ptl);
|
|
BUG_ON(!pmd_none(*pmd));
|
|
/*
|
|
* We can only use set_pmd_at when establishing
|
|
* hugepmds and never for establishing regular pmds that
|
|
* points to regular pagetables. Use pmd_populate for that
|
|
*/
|
|
pmd_populate(mm, pmd, pmd_pgtable(_pmd));
|
|
spin_unlock(pmd_ptl);
|
|
anon_vma_unlock_write(vma->anon_vma);
|
|
vm_write_end(vma);
|
|
result = SCAN_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* All pages are isolated and locked so anon_vma rmap
|
|
* can't run anymore.
|
|
*/
|
|
anon_vma_unlock_write(vma->anon_vma);
|
|
|
|
__collapse_huge_page_copy(pte, new_page, vma, address, pte_ptl);
|
|
pte_unmap(pte);
|
|
__SetPageUptodate(new_page);
|
|
pgtable = pmd_pgtable(_pmd);
|
|
|
|
_pmd = mk_huge_pmd(new_page, vma->vm_page_prot);
|
|
_pmd = maybe_pmd_mkwrite(pmd_mkdirty(_pmd), vma);
|
|
|
|
/*
|
|
* spin_lock() below is not the equivalent of smp_wmb(), so
|
|
* this is needed to avoid the copy_huge_page writes to become
|
|
* visible after the set_pmd_at() write.
|
|
*/
|
|
smp_wmb();
|
|
|
|
spin_lock(pmd_ptl);
|
|
BUG_ON(!pmd_none(*pmd));
|
|
page_add_new_anon_rmap(new_page, vma, address, true);
|
|
mem_cgroup_commit_charge(new_page, memcg, false, true);
|
|
count_memcg_events(memcg, THP_COLLAPSE_ALLOC, 1);
|
|
lru_cache_add_active_or_unevictable(new_page, vma);
|
|
pgtable_trans_huge_deposit(mm, pmd, pgtable);
|
|
set_pmd_at(mm, address, pmd, _pmd);
|
|
update_mmu_cache_pmd(vma, address, pmd);
|
|
spin_unlock(pmd_ptl);
|
|
vm_write_end(vma);
|
|
|
|
*hpage = NULL;
|
|
|
|
khugepaged_pages_collapsed++;
|
|
result = SCAN_SUCCEED;
|
|
out_up_write:
|
|
up_write(&mm->mmap_sem);
|
|
out_nolock:
|
|
trace_mm_collapse_huge_page(mm, isolated, result);
|
|
return;
|
|
out:
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
goto out_up_write;
|
|
}
|
|
|
|
static int khugepaged_scan_pmd(struct mm_struct *mm,
|
|
struct vm_area_struct *vma,
|
|
unsigned long address,
|
|
struct page **hpage)
|
|
{
|
|
pmd_t *pmd;
|
|
pte_t *pte, *_pte;
|
|
int ret = 0, none_or_zero = 0, result = 0, referenced = 0;
|
|
struct page *page = NULL;
|
|
unsigned long _address;
|
|
spinlock_t *ptl;
|
|
int node = NUMA_NO_NODE, unmapped = 0;
|
|
bool writable = false;
|
|
|
|
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
|
|
|
pmd = mm_find_pmd(mm, address);
|
|
if (!pmd) {
|
|
result = SCAN_PMD_NULL;
|
|
goto out;
|
|
}
|
|
|
|
memset(khugepaged_node_load, 0, sizeof(khugepaged_node_load));
|
|
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
|
|
for (_address = address, _pte = pte; _pte < pte+HPAGE_PMD_NR;
|
|
_pte++, _address += PAGE_SIZE) {
|
|
pte_t pteval = *_pte;
|
|
if (is_swap_pte(pteval)) {
|
|
if (++unmapped <= khugepaged_max_ptes_swap) {
|
|
continue;
|
|
} else {
|
|
result = SCAN_EXCEED_SWAP_PTE;
|
|
goto out_unmap;
|
|
}
|
|
}
|
|
if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) {
|
|
if (!userfaultfd_armed(vma) &&
|
|
++none_or_zero <= khugepaged_max_ptes_none) {
|
|
continue;
|
|
} else {
|
|
result = SCAN_EXCEED_NONE_PTE;
|
|
goto out_unmap;
|
|
}
|
|
}
|
|
if (!pte_present(pteval)) {
|
|
result = SCAN_PTE_NON_PRESENT;
|
|
goto out_unmap;
|
|
}
|
|
if (pte_write(pteval))
|
|
writable = true;
|
|
|
|
page = vm_normal_page(vma, _address, pteval);
|
|
if (unlikely(!page)) {
|
|
result = SCAN_PAGE_NULL;
|
|
goto out_unmap;
|
|
}
|
|
|
|
/* TODO: teach khugepaged to collapse THP mapped with pte */
|
|
if (PageCompound(page)) {
|
|
result = SCAN_PAGE_COMPOUND;
|
|
goto out_unmap;
|
|
}
|
|
|
|
/*
|
|
* Record which node the original page is from and save this
|
|
* information to khugepaged_node_load[].
|
|
* Khupaged will allocate hugepage from the node has the max
|
|
* hit record.
|
|
*/
|
|
node = page_to_nid(page);
|
|
if (khugepaged_scan_abort(node)) {
|
|
result = SCAN_SCAN_ABORT;
|
|
goto out_unmap;
|
|
}
|
|
khugepaged_node_load[node]++;
|
|
if (!PageLRU(page)) {
|
|
result = SCAN_PAGE_LRU;
|
|
goto out_unmap;
|
|
}
|
|
if (PageLocked(page)) {
|
|
result = SCAN_PAGE_LOCK;
|
|
goto out_unmap;
|
|
}
|
|
if (!PageAnon(page)) {
|
|
result = SCAN_PAGE_ANON;
|
|
goto out_unmap;
|
|
}
|
|
|
|
/*
|
|
* cannot use mapcount: can't collapse if there's a gup pin.
|
|
* The page must only be referenced by the scanned process
|
|
* and page swap cache.
|
|
*/
|
|
if (page_count(page) != 1 + PageSwapCache(page)) {
|
|
result = SCAN_PAGE_COUNT;
|
|
goto out_unmap;
|
|
}
|
|
if (pte_young(pteval) ||
|
|
page_is_young(page) || PageReferenced(page) ||
|
|
mmu_notifier_test_young(vma->vm_mm, address))
|
|
referenced++;
|
|
}
|
|
if (writable) {
|
|
if (referenced) {
|
|
result = SCAN_SUCCEED;
|
|
ret = 1;
|
|
} else {
|
|
result = SCAN_LACK_REFERENCED_PAGE;
|
|
}
|
|
} else {
|
|
result = SCAN_PAGE_RO;
|
|
}
|
|
out_unmap:
|
|
pte_unmap_unlock(pte, ptl);
|
|
if (ret) {
|
|
node = khugepaged_find_target_node();
|
|
/* collapse_huge_page will return with the mmap_sem released */
|
|
collapse_huge_page(mm, address, hpage, node, referenced);
|
|
}
|
|
out:
|
|
trace_mm_khugepaged_scan_pmd(mm, page, writable, referenced,
|
|
none_or_zero, result, unmapped);
|
|
return ret;
|
|
}
|
|
|
|
static void collect_mm_slot(struct mm_slot *mm_slot)
|
|
{
|
|
struct mm_struct *mm = mm_slot->mm;
|
|
|
|
lockdep_assert_held(&khugepaged_mm_lock);
|
|
|
|
if (khugepaged_test_exit(mm)) {
|
|
/* free mm_slot */
|
|
hash_del(&mm_slot->hash);
|
|
list_del(&mm_slot->mm_node);
|
|
|
|
/*
|
|
* Not strictly needed because the mm exited already.
|
|
*
|
|
* clear_bit(MMF_VM_HUGEPAGE, &mm->flags);
|
|
*/
|
|
|
|
/* khugepaged_mm_lock actually not necessary for the below */
|
|
free_mm_slot(mm_slot);
|
|
mmdrop(mm);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_SHMEM) && defined(CONFIG_TRANSPARENT_HUGE_PAGECACHE)
|
|
/*
|
|
* Notify khugepaged that given addr of the mm is pte-mapped THP. Then
|
|
* khugepaged should try to collapse the page table.
|
|
*/
|
|
static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
|
|
unsigned long addr)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
|
|
VM_BUG_ON(addr & ~HPAGE_PMD_MASK);
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
mm_slot = get_mm_slot(mm);
|
|
if (likely(mm_slot && mm_slot->nr_pte_mapped_thp < MAX_PTE_MAPPED_THP))
|
|
mm_slot->pte_mapped_thp[mm_slot->nr_pte_mapped_thp++] = addr;
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Try to collapse a pte-mapped THP for mm at address haddr.
|
|
*
|
|
* This function checks whether all the PTEs in the PMD are pointing to the
|
|
* pse_pte_mapped_thpright THP. If so, retract the page table so the THP can refault in with
|
|
* as pmd-mapped.
|
|
*/
|
|
void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
|
|
{
|
|
unsigned long haddr = addr & HPAGE_PMD_MASK;
|
|
struct vm_area_struct *vma = find_vma(mm, haddr);
|
|
struct page *hpage;
|
|
pte_t *start_pte, *pte;
|
|
pmd_t *pmd, _pmd;
|
|
spinlock_t *ptl;
|
|
int count = 0;
|
|
int i;
|
|
struct mmu_notifier_range range;
|
|
|
|
if (!vma || !vma->vm_file ||
|
|
vma->vm_start > haddr || vma->vm_end < haddr + HPAGE_PMD_SIZE)
|
|
return;
|
|
|
|
/*
|
|
* This vm_flags may not have VM_HUGEPAGE if the page was not
|
|
* collapsed by this mm. But we can still collapse if the page is
|
|
* the valid THP. Add extra VM_HUGEPAGE so hugepage_vma_check()
|
|
* will not fail the vma for missing VM_HUGEPAGE
|
|
*/
|
|
if (!hugepage_vma_check(vma, vma->vm_flags | VM_HUGEPAGE))
|
|
return;
|
|
|
|
hpage = find_lock_page(vma->vm_file->f_mapping,
|
|
linear_page_index(vma, haddr));
|
|
if (!hpage)
|
|
return;
|
|
|
|
if (!PageHead(hpage))
|
|
goto drop_hpage;
|
|
|
|
pmd = mm_find_pmd(mm, haddr);
|
|
if (!pmd)
|
|
goto drop_hpage;
|
|
|
|
vm_write_begin(vma);
|
|
/*
|
|
* We need to lock the mapping so that from here on, only GUP-fast and
|
|
* hardware page walks can access the parts of the page tables that
|
|
* we're operating on.
|
|
*/
|
|
i_mmap_lock_write(vma->vm_file->f_mapping);
|
|
|
|
/*
|
|
* This spinlock should be unnecessary: Nobody else should be accessing
|
|
* the page tables under spinlock protection here, only
|
|
* lockless_pages_from_mm() and the hardware page walker can access page
|
|
* tables while all the high-level locks are held in write mode.
|
|
*/
|
|
start_pte = pte_offset_map_lock(mm, pmd, haddr, &ptl);
|
|
|
|
/* step 1: check all mapped PTEs are to the right huge page */
|
|
for (i = 0, addr = haddr, pte = start_pte;
|
|
i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE, pte++) {
|
|
struct page *page;
|
|
|
|
/* empty pte, skip */
|
|
if (pte_none(*pte))
|
|
continue;
|
|
|
|
/* page swapped out, abort */
|
|
if (!pte_present(*pte))
|
|
goto abort;
|
|
|
|
page = vm_normal_page(vma, addr, *pte);
|
|
|
|
/*
|
|
* Note that uprobe, debugger, or MAP_PRIVATE may change the
|
|
* page table, but the new page will not be a subpage of hpage.
|
|
*/
|
|
if (hpage + i != page)
|
|
goto abort;
|
|
count++;
|
|
}
|
|
|
|
/* step 2: adjust rmap */
|
|
for (i = 0, addr = haddr, pte = start_pte;
|
|
i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE, pte++) {
|
|
struct page *page;
|
|
|
|
if (pte_none(*pte))
|
|
continue;
|
|
page = vm_normal_page(vma, addr, *pte);
|
|
page_remove_rmap(page, false);
|
|
}
|
|
|
|
pte_unmap_unlock(start_pte, ptl);
|
|
|
|
/* step 3: set proper refcount and mm_counters. */
|
|
if (count) {
|
|
page_ref_sub(hpage, count);
|
|
add_mm_counter(vma->vm_mm, mm_counter_file(hpage), -count);
|
|
}
|
|
|
|
/* step 4: collapse pmd */
|
|
/* we make no change to anon, but protect concurrent anon page lookup */
|
|
if (vma->anon_vma)
|
|
anon_vma_lock_write(vma->anon_vma);
|
|
|
|
mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, NULL, mm, haddr,
|
|
haddr + HPAGE_PMD_SIZE);
|
|
mmu_notifier_invalidate_range_start(&range);
|
|
_pmd = pmdp_collapse_flush(vma, haddr, pmd);
|
|
spin_unlock(ptl);
|
|
vm_write_end(vma);
|
|
mm_dec_nr_ptes(mm);
|
|
tlb_remove_table_sync_one();
|
|
mmu_notifier_invalidate_range_end(&range);
|
|
pte_free(mm, pmd_pgtable(_pmd));
|
|
|
|
if (vma->anon_vma)
|
|
anon_vma_unlock_write(vma->anon_vma);
|
|
i_mmap_unlock_write(vma->vm_file->f_mapping);
|
|
|
|
drop_hpage:
|
|
unlock_page(hpage);
|
|
put_page(hpage);
|
|
return;
|
|
|
|
abort:
|
|
pte_unmap_unlock(start_pte, ptl);
|
|
vm_write_end(vma);
|
|
i_mmap_unlock_write(vma->vm_file->f_mapping);
|
|
goto drop_hpage;
|
|
}
|
|
|
|
static int khugepaged_collapse_pte_mapped_thps(struct mm_slot *mm_slot)
|
|
{
|
|
struct mm_struct *mm = mm_slot->mm;
|
|
int i;
|
|
|
|
if (likely(mm_slot->nr_pte_mapped_thp == 0))
|
|
return 0;
|
|
|
|
if (!down_write_trylock(&mm->mmap_sem))
|
|
return -EBUSY;
|
|
|
|
if (unlikely(khugepaged_test_exit(mm)))
|
|
goto out;
|
|
|
|
for (i = 0; i < mm_slot->nr_pte_mapped_thp; i++)
|
|
collapse_pte_mapped_thp(mm, mm_slot->pte_mapped_thp[i]);
|
|
|
|
out:
|
|
mm_slot->nr_pte_mapped_thp = 0;
|
|
up_write(&mm->mmap_sem);
|
|
return 0;
|
|
}
|
|
|
|
static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
|
|
{
|
|
struct vm_area_struct *vma;
|
|
struct mm_struct *mm;
|
|
unsigned long addr;
|
|
pmd_t *pmd, _pmd;
|
|
|
|
i_mmap_lock_write(mapping);
|
|
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
|
|
/*
|
|
* Check vma->anon_vma to exclude MAP_PRIVATE mappings that
|
|
* got written to. These VMAs are likely not worth investing
|
|
* down_write(mmap_sem) as PMD-mapping is likely to be split
|
|
* later.
|
|
*
|
|
* Not that vma->anon_vma check is racy: it can be set up after
|
|
* the check but before we took mmap_sem by the fault path.
|
|
* But page lock would prevent establishing any new ptes of the
|
|
* page, so we are safe.
|
|
*
|
|
* An alternative would be drop the check, but check that page
|
|
* table is clear before calling pmdp_collapse_flush() under
|
|
* ptl. It has higher chance to recover THP for the VMA, but
|
|
* has higher cost too. It would also probably require locking
|
|
* the anon_vma.
|
|
*/
|
|
if (vma->anon_vma)
|
|
continue;
|
|
addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
|
|
if (addr & ~HPAGE_PMD_MASK)
|
|
continue;
|
|
if (vma->vm_end < addr + HPAGE_PMD_SIZE)
|
|
continue;
|
|
mm = vma->vm_mm;
|
|
pmd = mm_find_pmd(mm, addr);
|
|
if (!pmd)
|
|
continue;
|
|
/*
|
|
* We need exclusive mmap_sem to retract page table.
|
|
*
|
|
* We use trylock due to lock inversion: we need to acquire
|
|
* mmap_sem while holding page lock. Fault path does it in
|
|
* reverse order. Trylock is a way to avoid deadlock.
|
|
*/
|
|
if (down_write_trylock(&mm->mmap_sem)) {
|
|
if (!khugepaged_test_exit(mm)) {
|
|
vm_write_begin(vma);
|
|
spinlock_t *ptl = pmd_lock(mm, pmd);
|
|
struct mmu_notifier_range range;
|
|
|
|
mmu_notifier_range_init(&range,
|
|
MMU_NOTIFY_CLEAR, 0,
|
|
NULL, mm, addr,
|
|
addr + HPAGE_PMD_SIZE);
|
|
mmu_notifier_invalidate_range_start(&range);
|
|
/* assume page table is clear */
|
|
_pmd = pmdp_collapse_flush(vma, addr, pmd);
|
|
spin_unlock(ptl);
|
|
vm_write_end(vma);
|
|
mm_dec_nr_ptes(mm);
|
|
tlb_remove_table_sync_one();
|
|
pte_free(mm, pmd_pgtable(_pmd));
|
|
mmu_notifier_invalidate_range_end(&range);
|
|
}
|
|
up_write(&mm->mmap_sem);
|
|
} else {
|
|
/* Try again later */
|
|
khugepaged_add_pte_mapped_thp(mm, addr);
|
|
}
|
|
}
|
|
i_mmap_unlock_write(mapping);
|
|
}
|
|
|
|
/**
|
|
* collapse_file - collapse filemap/tmpfs/shmem pages into huge one.
|
|
*
|
|
* Basic scheme is simple, details are more complex:
|
|
* - allocate and lock a new huge page;
|
|
* - scan page cache replacing old pages with the new one
|
|
* + swap/gup in pages if necessary;
|
|
* + fill in gaps;
|
|
* + keep old pages around in case rollback is required;
|
|
* - if replacing succeeds:
|
|
* + copy data over;
|
|
* + free old pages;
|
|
* + unlock huge page;
|
|
* - if replacing failed;
|
|
* + put all pages back and unfreeze them;
|
|
* + restore gaps in the page cache;
|
|
* + unlock and free huge page;
|
|
*/
|
|
static void collapse_file(struct mm_struct *mm,
|
|
struct file *file, pgoff_t start,
|
|
struct page **hpage, int node)
|
|
{
|
|
struct address_space *mapping = file->f_mapping;
|
|
gfp_t gfp;
|
|
struct page *new_page;
|
|
struct mem_cgroup *memcg;
|
|
pgoff_t index, end = start + HPAGE_PMD_NR;
|
|
LIST_HEAD(pagelist);
|
|
XA_STATE_ORDER(xas, &mapping->i_pages, start, HPAGE_PMD_ORDER);
|
|
int nr_none = 0, result = SCAN_SUCCEED;
|
|
bool is_shmem = shmem_file(file);
|
|
|
|
VM_BUG_ON(!IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) && !is_shmem);
|
|
VM_BUG_ON(start & (HPAGE_PMD_NR - 1));
|
|
|
|
/* Only allocate from the target node */
|
|
gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
|
|
|
|
new_page = khugepaged_alloc_page(hpage, gfp, node);
|
|
if (!new_page) {
|
|
result = SCAN_ALLOC_HUGE_PAGE_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
|
|
result = SCAN_CGROUP_CHARGE_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
/* This will be less messy when we use multi-index entries */
|
|
do {
|
|
xas_lock_irq(&xas);
|
|
xas_create_range(&xas);
|
|
if (!xas_error(&xas))
|
|
break;
|
|
xas_unlock_irq(&xas);
|
|
if (!xas_nomem(&xas, GFP_KERNEL)) {
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
result = SCAN_FAIL;
|
|
goto out;
|
|
}
|
|
} while (1);
|
|
|
|
__SetPageLocked(new_page);
|
|
if (is_shmem)
|
|
__SetPageSwapBacked(new_page);
|
|
new_page->index = start;
|
|
new_page->mapping = mapping;
|
|
|
|
/*
|
|
* At this point the new_page is locked and not up-to-date.
|
|
* It's safe to insert it into the page cache, because nobody would
|
|
* be able to map it or use it in another way until we unlock it.
|
|
*/
|
|
|
|
xas_set(&xas, start);
|
|
for (index = start; index < end; index++) {
|
|
struct page *page = xas_next(&xas);
|
|
|
|
VM_BUG_ON(index != xas.xa_index);
|
|
if (is_shmem) {
|
|
if (!page) {
|
|
/*
|
|
* Stop if extent has been truncated or
|
|
* hole-punched, and is now completely
|
|
* empty.
|
|
*/
|
|
if (index == start) {
|
|
if (!xas_next_entry(&xas, end - 1)) {
|
|
result = SCAN_TRUNCATED;
|
|
goto xa_locked;
|
|
}
|
|
xas_set(&xas, index);
|
|
}
|
|
if (!shmem_charge(mapping->host, 1)) {
|
|
result = SCAN_FAIL;
|
|
goto xa_locked;
|
|
}
|
|
xas_store(&xas, new_page);
|
|
nr_none++;
|
|
continue;
|
|
}
|
|
|
|
if (xa_is_value(page) || !PageUptodate(page)) {
|
|
xas_unlock_irq(&xas);
|
|
/* swap in or instantiate fallocated page */
|
|
if (shmem_getpage(mapping->host, index, &page,
|
|
SGP_NOHUGE)) {
|
|
result = SCAN_FAIL;
|
|
goto xa_unlocked;
|
|
}
|
|
} else if (trylock_page(page)) {
|
|
get_page(page);
|
|
xas_unlock_irq(&xas);
|
|
} else {
|
|
result = SCAN_PAGE_LOCK;
|
|
goto xa_locked;
|
|
}
|
|
} else { /* !is_shmem */
|
|
if (!page || xa_is_value(page)) {
|
|
xas_unlock_irq(&xas);
|
|
page_cache_sync_readahead(mapping, &file->f_ra,
|
|
file, index,
|
|
end - index);
|
|
/* drain pagevecs to help isolate_lru_page() */
|
|
lru_add_drain();
|
|
page = find_lock_page(mapping, index);
|
|
if (unlikely(page == NULL)) {
|
|
result = SCAN_FAIL;
|
|
goto xa_unlocked;
|
|
}
|
|
} else if (trylock_page(page)) {
|
|
get_page(page);
|
|
xas_unlock_irq(&xas);
|
|
} else {
|
|
result = SCAN_PAGE_LOCK;
|
|
goto xa_locked;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The page must be locked, so we can drop the i_pages lock
|
|
* without racing with truncate.
|
|
*/
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
|
|
/* make sure the page is up to date */
|
|
if (unlikely(!PageUptodate(page))) {
|
|
result = SCAN_FAIL;
|
|
goto out_unlock;
|
|
}
|
|
|
|
/*
|
|
* If file was truncated then extended, or hole-punched, before
|
|
* we locked the first page, then a THP might be there already.
|
|
*/
|
|
if (PageTransCompound(page)) {
|
|
result = SCAN_PAGE_COMPOUND;
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (page_mapping(page) != mapping) {
|
|
result = SCAN_TRUNCATED;
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (!is_shmem && PageDirty(page)) {
|
|
/*
|
|
* khugepaged only works on read-only fd, so this
|
|
* page is dirty because it hasn't been flushed
|
|
* since first write.
|
|
*/
|
|
result = SCAN_FAIL;
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (isolate_lru_page(page)) {
|
|
result = SCAN_DEL_PAGE_LRU;
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (page_has_private(page) &&
|
|
!try_to_release_page(page, GFP_KERNEL)) {
|
|
result = SCAN_PAGE_HAS_PRIVATE;
|
|
putback_lru_page(page);
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (page_mapped(page))
|
|
unmap_mapping_pages(mapping, index, 1, false);
|
|
|
|
xas_lock_irq(&xas);
|
|
xas_set(&xas, index);
|
|
|
|
VM_BUG_ON_PAGE(page != xas_load(&xas), page);
|
|
VM_BUG_ON_PAGE(page_mapped(page), page);
|
|
|
|
/*
|
|
* The page is expected to have page_count() == 3:
|
|
* - we hold a pin on it;
|
|
* - one reference from page cache;
|
|
* - one from isolate_lru_page;
|
|
*/
|
|
if (!page_ref_freeze(page, 3)) {
|
|
result = SCAN_PAGE_COUNT;
|
|
xas_unlock_irq(&xas);
|
|
putback_lru_page(page);
|
|
goto out_unlock;
|
|
}
|
|
|
|
/*
|
|
* Add the page to the list to be able to undo the collapse if
|
|
* something go wrong.
|
|
*/
|
|
list_add_tail(&page->lru, &pagelist);
|
|
|
|
/* Finally, replace with the new page. */
|
|
xas_store(&xas, new_page);
|
|
continue;
|
|
out_unlock:
|
|
unlock_page(page);
|
|
put_page(page);
|
|
goto xa_unlocked;
|
|
}
|
|
|
|
if (is_shmem)
|
|
__inc_node_page_state(new_page, NR_SHMEM_THPS);
|
|
else {
|
|
__inc_node_page_state(new_page, NR_FILE_THPS);
|
|
filemap_nr_thps_inc(mapping);
|
|
}
|
|
|
|
if (nr_none) {
|
|
struct zone *zone = page_zone(new_page);
|
|
|
|
__mod_node_page_state(zone->zone_pgdat, NR_FILE_PAGES, nr_none);
|
|
if (is_shmem)
|
|
__mod_node_page_state(zone->zone_pgdat,
|
|
NR_SHMEM, nr_none);
|
|
}
|
|
|
|
xa_locked:
|
|
xas_unlock_irq(&xas);
|
|
xa_unlocked:
|
|
|
|
if (result == SCAN_SUCCEED) {
|
|
struct page *page, *tmp;
|
|
|
|
/*
|
|
* Replacing old pages with new one has succeeded, now we
|
|
* need to copy the content and free the old pages.
|
|
*/
|
|
index = start;
|
|
list_for_each_entry_safe(page, tmp, &pagelist, lru) {
|
|
while (index < page->index) {
|
|
clear_highpage(new_page + (index % HPAGE_PMD_NR));
|
|
index++;
|
|
}
|
|
copy_highpage(new_page + (page->index % HPAGE_PMD_NR),
|
|
page);
|
|
list_del(&page->lru);
|
|
page->mapping = NULL;
|
|
page_ref_unfreeze(page, 1);
|
|
ClearPageActive(page);
|
|
ClearPageUnevictable(page);
|
|
unlock_page(page);
|
|
put_page(page);
|
|
index++;
|
|
}
|
|
while (index < end) {
|
|
clear_highpage(new_page + (index % HPAGE_PMD_NR));
|
|
index++;
|
|
}
|
|
|
|
SetPageUptodate(new_page);
|
|
page_ref_add(new_page, HPAGE_PMD_NR - 1);
|
|
mem_cgroup_commit_charge(new_page, memcg, false, true);
|
|
|
|
if (is_shmem) {
|
|
set_page_dirty(new_page);
|
|
lru_cache_add_anon(new_page);
|
|
} else {
|
|
lru_cache_add_file(new_page);
|
|
}
|
|
count_memcg_events(memcg, THP_COLLAPSE_ALLOC, 1);
|
|
|
|
/*
|
|
* Remove pte page tables, so we can re-fault the page as huge.
|
|
*/
|
|
retract_page_tables(mapping, start);
|
|
*hpage = NULL;
|
|
|
|
khugepaged_pages_collapsed++;
|
|
} else {
|
|
struct page *page;
|
|
|
|
/* Something went wrong: roll back page cache changes */
|
|
xas_lock_irq(&xas);
|
|
mapping->nrpages -= nr_none;
|
|
|
|
if (is_shmem)
|
|
shmem_uncharge(mapping->host, nr_none);
|
|
|
|
xas_set(&xas, start);
|
|
xas_for_each(&xas, page, end - 1) {
|
|
page = list_first_entry_or_null(&pagelist,
|
|
struct page, lru);
|
|
if (!page || xas.xa_index < page->index) {
|
|
if (!nr_none)
|
|
break;
|
|
nr_none--;
|
|
/* Put holes back where they were */
|
|
xas_store(&xas, NULL);
|
|
continue;
|
|
}
|
|
|
|
VM_BUG_ON_PAGE(page->index != xas.xa_index, page);
|
|
|
|
/* Unfreeze the page. */
|
|
list_del(&page->lru);
|
|
page_ref_unfreeze(page, 2);
|
|
xas_store(&xas, page);
|
|
xas_pause(&xas);
|
|
xas_unlock_irq(&xas);
|
|
unlock_page(page);
|
|
putback_lru_page(page);
|
|
xas_lock_irq(&xas);
|
|
}
|
|
VM_BUG_ON(nr_none);
|
|
xas_unlock_irq(&xas);
|
|
|
|
mem_cgroup_cancel_charge(new_page, memcg, true);
|
|
new_page->mapping = NULL;
|
|
}
|
|
|
|
unlock_page(new_page);
|
|
out:
|
|
VM_BUG_ON(!list_empty(&pagelist));
|
|
/* TODO: tracepoints */
|
|
}
|
|
|
|
static void khugepaged_scan_file(struct mm_struct *mm,
|
|
struct file *file, pgoff_t start, struct page **hpage)
|
|
{
|
|
struct page *page = NULL;
|
|
struct address_space *mapping = file->f_mapping;
|
|
XA_STATE(xas, &mapping->i_pages, start);
|
|
int present, swap;
|
|
int node = NUMA_NO_NODE;
|
|
int result = SCAN_SUCCEED;
|
|
|
|
present = 0;
|
|
swap = 0;
|
|
memset(khugepaged_node_load, 0, sizeof(khugepaged_node_load));
|
|
rcu_read_lock();
|
|
xas_for_each(&xas, page, start + HPAGE_PMD_NR - 1) {
|
|
if (xas_retry(&xas, page))
|
|
continue;
|
|
|
|
if (xa_is_value(page)) {
|
|
if (++swap > khugepaged_max_ptes_swap) {
|
|
result = SCAN_EXCEED_SWAP_PTE;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (PageTransCompound(page)) {
|
|
result = SCAN_PAGE_COMPOUND;
|
|
break;
|
|
}
|
|
|
|
node = page_to_nid(page);
|
|
if (khugepaged_scan_abort(node)) {
|
|
result = SCAN_SCAN_ABORT;
|
|
break;
|
|
}
|
|
khugepaged_node_load[node]++;
|
|
|
|
if (!PageLRU(page)) {
|
|
result = SCAN_PAGE_LRU;
|
|
break;
|
|
}
|
|
|
|
if (page_count(page) !=
|
|
1 + page_mapcount(page) + page_has_private(page)) {
|
|
result = SCAN_PAGE_COUNT;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* We probably should check if the page is referenced here, but
|
|
* nobody would transfer pte_young() to PageReferenced() for us.
|
|
* And rmap walk here is just too costly...
|
|
*/
|
|
|
|
present++;
|
|
|
|
if (need_resched()) {
|
|
xas_pause(&xas);
|
|
cond_resched_rcu();
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
|
|
if (result == SCAN_SUCCEED) {
|
|
if (present < HPAGE_PMD_NR - khugepaged_max_ptes_none) {
|
|
result = SCAN_EXCEED_NONE_PTE;
|
|
} else {
|
|
node = khugepaged_find_target_node();
|
|
collapse_file(mm, file, start, hpage, node);
|
|
}
|
|
}
|
|
|
|
/* TODO: tracepoints */
|
|
}
|
|
#else
|
|
static void khugepaged_scan_file(struct mm_struct *mm,
|
|
struct file *file, pgoff_t start, struct page **hpage)
|
|
{
|
|
BUILD_BUG();
|
|
}
|
|
|
|
static int khugepaged_collapse_pte_mapped_thps(struct mm_slot *mm_slot)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
|
|
struct page **hpage)
|
|
__releases(&khugepaged_mm_lock)
|
|
__acquires(&khugepaged_mm_lock)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
struct mm_struct *mm;
|
|
struct vm_area_struct *vma;
|
|
int progress = 0;
|
|
|
|
VM_BUG_ON(!pages);
|
|
lockdep_assert_held(&khugepaged_mm_lock);
|
|
|
|
if (khugepaged_scan.mm_slot)
|
|
mm_slot = khugepaged_scan.mm_slot;
|
|
else {
|
|
mm_slot = list_entry(khugepaged_scan.mm_head.next,
|
|
struct mm_slot, mm_node);
|
|
khugepaged_scan.address = 0;
|
|
khugepaged_scan.mm_slot = mm_slot;
|
|
}
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
khugepaged_collapse_pte_mapped_thps(mm_slot);
|
|
|
|
mm = mm_slot->mm;
|
|
/*
|
|
* Don't wait for semaphore (to avoid long wait times). Just move to
|
|
* the next mm on the list.
|
|
*/
|
|
vma = NULL;
|
|
if (unlikely(!down_read_trylock(&mm->mmap_sem)))
|
|
goto breakouterloop_mmap_sem;
|
|
if (likely(!khugepaged_test_exit(mm)))
|
|
vma = find_vma(mm, khugepaged_scan.address);
|
|
|
|
progress++;
|
|
for (; vma; vma = vma->vm_next) {
|
|
unsigned long hstart, hend;
|
|
|
|
cond_resched();
|
|
if (unlikely(khugepaged_test_exit(mm))) {
|
|
progress++;
|
|
break;
|
|
}
|
|
if (!hugepage_vma_check(vma, vma->vm_flags)) {
|
|
skip:
|
|
progress++;
|
|
continue;
|
|
}
|
|
hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
|
|
hend = vma->vm_end & HPAGE_PMD_MASK;
|
|
if (hstart >= hend)
|
|
goto skip;
|
|
if (khugepaged_scan.address > hend)
|
|
goto skip;
|
|
if (khugepaged_scan.address < hstart)
|
|
khugepaged_scan.address = hstart;
|
|
VM_BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
|
|
|
|
while (khugepaged_scan.address < hend) {
|
|
int ret;
|
|
cond_resched();
|
|
if (unlikely(khugepaged_test_exit(mm)))
|
|
goto breakouterloop;
|
|
|
|
VM_BUG_ON(khugepaged_scan.address < hstart ||
|
|
khugepaged_scan.address + HPAGE_PMD_SIZE >
|
|
hend);
|
|
if (IS_ENABLED(CONFIG_SHMEM) && vma->vm_file) {
|
|
struct file *file;
|
|
pgoff_t pgoff = linear_page_index(vma,
|
|
khugepaged_scan.address);
|
|
|
|
if (shmem_file(vma->vm_file)
|
|
&& !shmem_huge_enabled(vma))
|
|
goto skip;
|
|
file = get_file(vma->vm_file);
|
|
up_read(&mm->mmap_sem);
|
|
ret = 1;
|
|
khugepaged_scan_file(mm, file, pgoff, hpage);
|
|
fput(file);
|
|
} else {
|
|
ret = khugepaged_scan_pmd(mm, vma,
|
|
khugepaged_scan.address,
|
|
hpage);
|
|
}
|
|
/* move to next address */
|
|
khugepaged_scan.address += HPAGE_PMD_SIZE;
|
|
progress += HPAGE_PMD_NR;
|
|
if (ret)
|
|
/* we released mmap_sem so break loop */
|
|
goto breakouterloop_mmap_sem;
|
|
if (progress >= pages)
|
|
goto breakouterloop;
|
|
}
|
|
}
|
|
breakouterloop:
|
|
up_read(&mm->mmap_sem); /* exit_mmap will destroy ptes after this */
|
|
breakouterloop_mmap_sem:
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
VM_BUG_ON(khugepaged_scan.mm_slot != mm_slot);
|
|
/*
|
|
* Release the current mm_slot if this mm is about to die, or
|
|
* if we scanned all vmas of this mm.
|
|
*/
|
|
if (khugepaged_test_exit(mm) || !vma) {
|
|
/*
|
|
* Make sure that if mm_users is reaching zero while
|
|
* khugepaged runs here, khugepaged_exit will find
|
|
* mm_slot not pointing to the exiting mm.
|
|
*/
|
|
if (mm_slot->mm_node.next != &khugepaged_scan.mm_head) {
|
|
khugepaged_scan.mm_slot = list_entry(
|
|
mm_slot->mm_node.next,
|
|
struct mm_slot, mm_node);
|
|
khugepaged_scan.address = 0;
|
|
} else {
|
|
khugepaged_scan.mm_slot = NULL;
|
|
khugepaged_full_scans++;
|
|
}
|
|
|
|
collect_mm_slot(mm_slot);
|
|
}
|
|
|
|
return progress;
|
|
}
|
|
|
|
static int khugepaged_has_work(void)
|
|
{
|
|
return !list_empty(&khugepaged_scan.mm_head) &&
|
|
khugepaged_enabled();
|
|
}
|
|
|
|
static int khugepaged_wait_event(void)
|
|
{
|
|
return !list_empty(&khugepaged_scan.mm_head) ||
|
|
kthread_should_stop();
|
|
}
|
|
|
|
static void khugepaged_do_scan(void)
|
|
{
|
|
struct page *hpage = NULL;
|
|
unsigned int progress = 0, pass_through_head = 0;
|
|
unsigned int pages = khugepaged_pages_to_scan;
|
|
bool wait = true;
|
|
|
|
barrier(); /* write khugepaged_pages_to_scan to local stack */
|
|
|
|
while (progress < pages) {
|
|
if (!khugepaged_prealloc_page(&hpage, &wait))
|
|
break;
|
|
|
|
cond_resched();
|
|
|
|
if (unlikely(kthread_should_stop() || try_to_freeze()))
|
|
break;
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
if (!khugepaged_scan.mm_slot)
|
|
pass_through_head++;
|
|
if (khugepaged_has_work() &&
|
|
pass_through_head < 2)
|
|
progress += khugepaged_scan_mm_slot(pages - progress,
|
|
&hpage);
|
|
else
|
|
progress = pages;
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
}
|
|
|
|
if (!IS_ERR_OR_NULL(hpage))
|
|
put_page(hpage);
|
|
}
|
|
|
|
static bool khugepaged_should_wakeup(void)
|
|
{
|
|
return kthread_should_stop() ||
|
|
time_after_eq(jiffies, khugepaged_sleep_expire);
|
|
}
|
|
|
|
static void khugepaged_wait_work(void)
|
|
{
|
|
if (khugepaged_has_work()) {
|
|
const unsigned long scan_sleep_jiffies =
|
|
msecs_to_jiffies(khugepaged_scan_sleep_millisecs);
|
|
|
|
if (!scan_sleep_jiffies)
|
|
return;
|
|
|
|
khugepaged_sleep_expire = jiffies + scan_sleep_jiffies;
|
|
wait_event_freezable_timeout(khugepaged_wait,
|
|
khugepaged_should_wakeup(),
|
|
scan_sleep_jiffies);
|
|
return;
|
|
}
|
|
|
|
if (khugepaged_enabled())
|
|
wait_event_freezable(khugepaged_wait, khugepaged_wait_event());
|
|
}
|
|
|
|
static int khugepaged(void *none)
|
|
{
|
|
struct mm_slot *mm_slot;
|
|
|
|
set_freezable();
|
|
set_user_nice(current, MAX_NICE);
|
|
|
|
while (!kthread_should_stop()) {
|
|
khugepaged_do_scan();
|
|
khugepaged_wait_work();
|
|
}
|
|
|
|
spin_lock(&khugepaged_mm_lock);
|
|
mm_slot = khugepaged_scan.mm_slot;
|
|
khugepaged_scan.mm_slot = NULL;
|
|
if (mm_slot)
|
|
collect_mm_slot(mm_slot);
|
|
spin_unlock(&khugepaged_mm_lock);
|
|
return 0;
|
|
}
|
|
|
|
static void set_recommended_min_free_kbytes(void)
|
|
{
|
|
struct zone *zone;
|
|
int nr_zones = 0;
|
|
unsigned long recommended_min;
|
|
|
|
for_each_populated_zone(zone) {
|
|
/*
|
|
* We don't need to worry about fragmentation of
|
|
* ZONE_MOVABLE since it only has movable pages.
|
|
*/
|
|
if (zone_idx(zone) > gfp_zone(GFP_USER))
|
|
continue;
|
|
|
|
nr_zones++;
|
|
}
|
|
|
|
/* Ensure 2 pageblocks are free to assist fragmentation avoidance */
|
|
recommended_min = pageblock_nr_pages * nr_zones * 2;
|
|
|
|
/*
|
|
* Make sure that on average at least two pageblocks are almost free
|
|
* of another type, one for a migratetype to fall back to and a
|
|
* second to avoid subsequent fallbacks of other types There are 3
|
|
* MIGRATE_TYPES we care about.
|
|
*/
|
|
recommended_min += pageblock_nr_pages * nr_zones *
|
|
MIGRATE_PCPTYPES * MIGRATE_PCPTYPES;
|
|
|
|
/* don't ever allow to reserve more than 5% of the lowmem */
|
|
recommended_min = min(recommended_min,
|
|
(unsigned long) nr_free_buffer_pages() / 20);
|
|
recommended_min <<= (PAGE_SHIFT-10);
|
|
|
|
if (recommended_min > min_free_kbytes) {
|
|
if (user_min_free_kbytes >= 0)
|
|
pr_info("raising min_free_kbytes from %d to %lu to help transparent hugepage allocations\n",
|
|
min_free_kbytes, recommended_min);
|
|
|
|
min_free_kbytes = recommended_min;
|
|
}
|
|
setup_per_zone_wmarks();
|
|
}
|
|
|
|
int start_stop_khugepaged(void)
|
|
{
|
|
int err = 0;
|
|
|
|
mutex_lock(&khugepaged_mutex);
|
|
if (khugepaged_enabled()) {
|
|
if (!khugepaged_thread)
|
|
khugepaged_thread = kthread_run(khugepaged, NULL,
|
|
"khugepaged");
|
|
if (IS_ERR(khugepaged_thread)) {
|
|
pr_err("khugepaged: kthread_run(khugepaged) failed\n");
|
|
err = PTR_ERR(khugepaged_thread);
|
|
khugepaged_thread = NULL;
|
|
goto fail;
|
|
}
|
|
|
|
if (!list_empty(&khugepaged_scan.mm_head))
|
|
wake_up_interruptible(&khugepaged_wait);
|
|
|
|
set_recommended_min_free_kbytes();
|
|
} else if (khugepaged_thread) {
|
|
kthread_stop(khugepaged_thread);
|
|
khugepaged_thread = NULL;
|
|
}
|
|
fail:
|
|
mutex_unlock(&khugepaged_mutex);
|
|
return err;
|
|
}
|
|
|
|
void khugepaged_min_free_kbytes_update(void)
|
|
{
|
|
mutex_lock(&khugepaged_mutex);
|
|
if (khugepaged_enabled() && khugepaged_thread)
|
|
set_recommended_min_free_kbytes();
|
|
mutex_unlock(&khugepaged_mutex);
|
|
}
|