Files
android_kernel_xiaomi_sm8450/mm/vmstat.c
Blagovest Kolenichev e79e029826 Merge android-5.4.5 (9cdc723) into msm-5.4
* refs/heads/tmp-9cdc723:
  Revert "usb: dwc3: gadget: Fix logical condition"
  Revert "FROMLIST: scsi: ufs-qcom: Adjust bus bandwidth voting and unvoting"
  Linux 5.4.5
  r8169: add missing RX enabling for WoL on RTL8125
  net: mscc: ocelot: unregister the PTP clock on deinit
  ionic: keep users rss hash across lif reset
  xdp: obtain the mem_id mutex before trying to remove an entry.
  page_pool: do not release pool until inflight == 0.
  net/mlx5e: ethtool, Fix analysis of speed setting
  net/mlx5e: Fix translation of link mode into speed
  net/mlx5e: Fix freeing flow with kfree() and not kvfree()
  net/mlx5e: Fix SFF 8472 eeprom length
  act_ct: support asymmetric conntrack
  net/mlx5e: Fix TXQ indices to be sequential
  net: Fixed updating of ethertype in skb_mpls_push()
  hsr: fix a NULL pointer dereference in hsr_dev_xmit()
  Fixed updating of ethertype in function skb_mpls_pop
  gre: refetch erspan header from skb->data after pskb_may_pull()
  cls_flower: Fix the behavior using port ranges with hw-offload
  net: sched: allow indirect blocks to bind to clsact in TC
  net: core: rename indirect block ingress cb function
  tcp: Protect accesses to .ts_recent_stamp with {READ,WRITE}_ONCE()
  tcp: tighten acceptance of ACKs not matching a child socket
  tcp: fix rejected syncookies due to stale timestamps
  net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup
  net: ipv6: add net argument to ip6_dst_lookup_flow
  net/mlx5e: Query global pause state before setting prio2buffer
  tipc: fix ordering of tipc module init and exit routine
  tcp: md5: fix potential overestimation of TCP option space
  openvswitch: support asymmetric conntrack
  net/tls: Fix return values to avoid ENOTSUPP
  net: thunderx: start phy before starting autonegotiation
  net_sched: validate TCA_KIND attribute in tc_chain_tmplt_add()
  net: sched: fix dump qlen for sch_mq/sch_mqprio with NOLOCK subqueues
  net: ethernet: ti: cpsw: fix extra rx interrupt
  net: dsa: fix flow dissection on Tx path
  net: bridge: deny dev_set_mac_address() when unregistering
  mqprio: Fix out-of-bounds access in mqprio_dump
  inet: protect against too small mtu values.
  ANDROID: add initial ABI whitelist for android-5.4
  ANDROID: abi update for 5.4.4
  ANDROID: mm: Throttle rss_stat tracepoint
  FROMLIST: vsprintf: Inline call to ptr_to_hashval
  UPSTREAM: rss_stat: Add support to detect RSS updates of external mm
  UPSTREAM: mm: emit tracepoint when RSS changes
  Linux 5.4.4
  EDAC/ghes: Do not warn when incrementing refcount on 0
  r8169: fix rtl_hw_jumbo_disable for RTL8168evl
  workqueue: Fix missing kfree(rescuer) in destroy_workqueue()
  blk-mq: make sure that line break can be printed
  ext4: fix leak of quota reservations
  ext4: fix a bug in ext4_wait_for_tail_page_commit
  splice: only read in as much information as there is pipe buffer space
  rtc: disable uie before setting time and enable after
  USB: dummy-hcd: increase max number of devices to 32
  powerpc: Define arch_is_kernel_initmem_freed() for lockdep
  mm/shmem.c: cast the type of unmap_start to u64
  s390/kaslr: store KASLR offset for early dumps
  s390/smp,vdso: fix ASCE handling
  firmware: qcom: scm: Ensure 'a0' status code is treated as signed
  ext4: work around deleting a file with i_nlink == 0 safely
  mm: memcg/slab: wait for !root kmem_cache refcnt killing on root kmem_cache destruction
  mfd: rk808: Fix RK818 ID template
  mm, memfd: fix COW issue on MAP_PRIVATE and F_SEAL_FUTURE_WRITE mappings
  powerpc: Fix vDSO clock_getres()
  powerpc: Avoid clang warnings around setjmp and longjmp
  omap: pdata-quirks: remove openpandora quirks for mmc3 and wl1251
  omap: pdata-quirks: revert pandora specific gpiod additions
  iio: ad7949: fix channels mixups
  iio: ad7949: kill pointless "readback"-handling code
  Revert "scsi: qla2xxx: Fix memory leak when sending I/O fails"
  scsi: qla2xxx: Fix a dma_pool_free() call
  scsi: qla2xxx: Fix SRB leak on switch command timeout
  reiserfs: fix extended attributes on the root directory
  ext4: Fix credit estimate for final inode freeing
  quota: fix livelock in dquot_writeback_dquots
  seccomp: avoid overflow in implicit constant conversion
  ext2: check err when partial != NULL
  quota: Check that quota is not dirty before release
  video/hdmi: Fix AVI bar unpack
  powerpc/xive: Skip ioremap() of ESB pages for LSI interrupts
  powerpc: Allow flush_icache_range to work across ranges >4GB
  powerpc/xive: Prevent page fault issues in the machine crash handler
  powerpc: Allow 64bit VDSO __kernel_sync_dicache to work across ranges >4GB
  coresight: Serialize enabling/disabling a link device.
  stm class: Lose the protocol driver when dropping its reference
  ppdev: fix PPGETTIME/PPSETTIME ioctls
  RDMA/core: Fix ib_dma_max_seg_size()
  ARM: dts: omap3-tao3530: Fix incorrect MMC card detection GPIO polarity
  mmc: host: omap_hsmmc: add code for special init of wl1251 to get rid of pandora_wl1251_init_card
  pinctrl: samsung: Fix device node refcount leaks in S3C64xx wakeup controller init
  pinctrl: samsung: Fix device node refcount leaks in init code
  pinctrl: samsung: Fix device node refcount leaks in S3C24xx wakeup controller init
  pinctrl: samsung: Fix device node refcount leaks in Exynos wakeup controller init
  pinctrl: samsung: Add of_node_put() before return in error path
  pinctrl: armada-37xx: Fix irq mask access in armada_37xx_irq_set_type()
  pinctrl: rza2: Fix gpio name typos
  ACPI: PM: Avoid attaching ACPI PM domain to certain devices
  ACPI: EC: Rework flushing of pending work
  ACPI: bus: Fix NULL pointer check in acpi_bus_get_private_data()
  ACPI: OSL: only free map once in osl.c
  ACPI / hotplug / PCI: Allocate resources directly under the non-hotplug bridge
  ACPI: LPSS: Add dmi quirk for skipping _DEP check for some device-links
  ACPI: LPSS: Add LNXVIDEO -> BYT I2C1 to lpss_device_links
  ACPI: LPSS: Add LNXVIDEO -> BYT I2C7 to lpss_device_links
  ACPI / utils: Move acpi_dev_get_first_match_dev() under CONFIG_ACPI
  ALSA: hda/realtek - Line-out jack doesn't work on a Dell AIO
  ALSA: oxfw: fix return value in error path of isochronous resources reservation
  ALSA: fireface: fix return value in error path of isochronous resources reservation
  cpufreq: powernv: fix stack bloat and hard limit on number of CPUs
  PM / devfreq: Lock devfreq in trans_stat_show
  intel_th: pci: Add Tiger Lake CPU support
  intel_th: pci: Add Ice Lake CPU support
  intel_th: Fix a double put_device() in error path
  powerpc/perf: Disable trace_imc pmu
  drm/panfrost: Open/close the perfcnt BO
  perf tests: Fix out of bounds memory access
  erofs: zero out when listxattr is called with no xattr
  cpuidle: use first valid target residency as poll time
  cpuidle: teo: Fix "early hits" handling for disabled idle states
  cpuidle: teo: Consider hits and misses metrics of disabled states
  cpuidle: teo: Rename local variable in teo_select()
  cpuidle: teo: Ignore disabled idle states that are too deep
  cpuidle: Do not unset the driver if it is there already
  media: cec.h: CEC_OP_REC_FLAG_ values were swapped
  media: radio: wl1273: fix interrupt masking on release
  media: bdisp: fix memleak on release
  media: vimc: sen: remove unused kthread_sen field
  media: hantro: Fix picture order count table enable
  media: hantro: Fix motion vectors usage condition
  media: hantro: Fix s_fmt for dynamic resolution changes
  s390/mm: properly clear _PAGE_NOEXEC bit when it is not supported
  ar5523: check NULL before memcpy() in ar5523_cmd()
  wil6210: check len before memcpy() calls
  cgroup: pids: use atomic64_t for pids->limit
  blk-mq: avoid sysfs buffer overflow with too many CPU cores
  md: improve handling of bio with REQ_PREFLUSH in md_flush_request()
  ASoC: fsl_audmix: Add spin lock to protect tdms
  ASoC: Jack: Fix NULL pointer dereference in snd_soc_jack_report
  ASoC: rt5645: Fixed typo for buddy jack support.
  ASoC: rt5645: Fixed buddy jack support.
  workqueue: Fix pwq ref leak in rescuer_thread()
  workqueue: Fix spurious sanity check failures in destroy_workqueue()
  dm zoned: reduce overhead of backing device checks
  dm writecache: handle REQ_FUA
  hwrng: omap - Fix RNG wait loop timeout
  ovl: relax WARN_ON() on rename to self
  ovl: fix corner case of non-unique st_dev;st_ino
  ovl: fix lookup failure on multi lower squashfs
  lib: raid6: fix awk build warnings
  rtlwifi: rtl8192de: Fix missing enable interrupt flag
  rtlwifi: rtl8192de: Fix missing callback that tests for hw release of buffer
  rtlwifi: rtl8192de: Fix missing code to retrieve RX buffer address
  btrfs: record all roots for rename exchange on a subvol
  Btrfs: send, skip backreference walking for extents with many references
  btrfs: Remove btrfs_bio::flags member
  btrfs: Avoid getting stuck during cyclic writebacks
  Btrfs: fix negative subv_writers counter and data space leak after buffered write
  Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc
  btrfs: use refcount_inc_not_zero in kill_all_nodes
  btrfs: use btrfs_block_group_cache_done in update_block_group
  btrfs: check page->mapping when loading free space cache
  iwlwifi: pcie: fix support for transmitting SKBs with fraglist
  usb: typec: fix use after free in typec_register_port()
  phy: renesas: rcar-gen3-usb2: Fix sysfs interface of "role"
  usb: dwc3: ep0: Clear started flag on completion
  usb: dwc3: gadget: Clear started flag for non-IOC
  usb: dwc3: gadget: Fix logical condition
  usb: dwc3: pci: add ID for the Intel Comet Lake -H variant
  virtio-balloon: fix managed page counts when migrating pages between zones
  virt_wifi: fix use-after-free in virt_wifi_newlink()
  mtd: rawnand: Change calculating of position page containing BBM
  mtd: spear_smi: Fix Write Burst mode
  brcmfmac: disable PCIe interrupts before bus reset
  EDAC/altera: Use fast register IO for S10 IRQs
  tpm: Switch to platform_get_irq_optional()
  tpm: add check after commands attribs tab allocation
  usb: mon: Fix a deadlock in usbmon between mmap and read
  usb: core: urb: fix URB structure initialization function
  USB: adutux: fix interface sanity check
  usb: roles: fix a potential use after free
  USB: serial: io_edgeport: fix epic endpoint lookup
  USB: idmouse: fix interface sanity checks
  USB: atm: ueagle-atm: add missing endpoint check
  iio: adc: ad7124: Enable internal reference
  iio: adc: ad7606: fix reading unnecessary data from device
  iio: imu: inv_mpu6050: fix temperature reporting using bad unit
  iio: humidity: hdc100x: fix IIO_HUMIDITYRELATIVE channel reporting
  iio: adis16480: Fix scales factors
  iio: imu: st_lsm6dsx: fix ODR check in st_lsm6dsx_write_raw
  iio: adis16480: Add debugfs_reg_access entry
  ARM: dts: pandora-common: define wl1251 as child node of mmc3
  usb: common: usb-conn-gpio: Don't log an error on probe deferral
  interconnect: qcom: qcs404: Walk the list safely on node removal
  interconnect: qcom: sdm845: Walk the list safely on node removal
  xhci: make sure interrupts are restored to correct state
  xhci: handle some XHCI_TRUST_TX_LENGTH quirks cases as default behaviour.
  xhci: Increase STS_HALT timeout in xhci_suspend()
  xhci: fix USB3 device initiated resume race with roothub autosuspend
  xhci: Fix memory leak in xhci_add_in_port()
  usb: xhci: only set D3hot for pci device
  staging: gigaset: add endpoint-type sanity check
  staging: gigaset: fix illegal free on probe errors
  staging: gigaset: fix general protection fault on probe
  staging: vchiq: call unregister_chrdev_region() when driver registration fails
  staging: rtl8712: fix interface sanity check
  staging: rtl8188eu: fix interface sanity check
  staging: exfat: fix multiple definition error of `rename_file'
  binder: fix incorrect calculation for num_valid
  usb: host: xhci-tegra: Correct phy enable sequence
  usb: Allow USB device to be warm reset in suspended state
  USB: documentation: flags on usb-storage versus UAS
  USB: uas: heed CAPACITY_HEURISTICS
  USB: uas: honor flag to avoid CAPACITY16
  media: venus: remove invalid compat_ioctl32 handler
  ceph: fix compat_ioctl for ceph_dir_operations
  compat_ioctl: add compat_ptr_ioctl()
  scsi: qla2xxx: Fix memory leak when sending I/O fails
  scsi: qla2xxx: Fix double scsi_done for abort path
  scsi: qla2xxx: Fix driver unload hang
  scsi: qla2xxx: Do command completion on abort timeout
  scsi: zfcp: trace channel log even for FCP command responses
  scsi: lpfc: Fix bad ndlp ptr in xri aborted handling
  Revert "nvme: Add quirk for Kingston NVME SSD running FW E8FK11.T"
  nvme: Namepace identification descriptor list is optional
  usb: gadget: pch_udc: fix use after free
  usb: gadget: configfs: Fix missing spin_lock_init()
  BACKPORT: FROMLIST: scsi: ufs: Export query request interfaces
  ANDROID: update abi with unbindable_ports sysctl
  BACKPORT: FROMLIST: net: introduce ip_local_unbindable_ports sysctl
  ANDROID: update abi for 5.4.3 merge
  ANDROID: update abi_gki_aarch64.xml for ion, drm changes
  ANDROID: drivers: gpu: drm: export drm_mode_convert_umode symbol
  ANDROID: ion: flush cache before exporting non-cached buffers
  Linux 5.4.3
  kselftest: Fix NULL INSTALL_PATH for TARGETS runlist
  perf script: Fix invalid LBR/binary mismatch error
  EDAC/ghes: Fix locking and memory barrier issues
  watchdog: aspeed: Fix clock behaviour for ast2600
  drm/mcde: Fix an error handling path in 'mcde_probe()'
  md/raid0: Fix an error message in raid0_make_request()
  cpufreq: imx-cpufreq-dt: Correct i.MX8MN's default speed grade value
  ALSA: hda - Fix pending unsol events at shutdown
  KVM: x86: fix out-of-bounds write in KVM_GET_EMULATED_CPUID (CVE-2019-19332)
  binder: Handle start==NULL in binder_update_page_range()
  binder: Prevent repeated use of ->mmap() via NULL mapping
  binder: Fix race between mmap() and binder_alloc_print_pages()
  Revert "serial/8250: Add support for NI-Serial PXI/PXIe+485 devices"
  vcs: prevent write access to vcsu devices
  thermal: Fix deadlock in thermal thermal_zone_device_check
  iomap: Fix pipe page leakage during splicing
  bdev: Refresh bdev size for disks without partitioning
  bdev: Factor out bdev revalidation into a common helper
  rfkill: allocate static minor
  RDMA/qib: Validate ->show()/store() callbacks before calling them
  can: ucan: fix non-atomic allocation in completion handler
  spi: Fix NULL pointer when setting SPI_CS_HIGH for GPIO CS
  spi: Fix SPI_CS_HIGH setting when using native and GPIO CS
  spi: atmel: Fix CS high support
  spi: stm32-qspi: Fix kernel oops when unbinding driver
  spi: spi-fsl-qspi: Clear TDH bits in FLSHCR register
  crypto: user - fix memory leak in crypto_reportstat
  crypto: user - fix memory leak in crypto_report
  crypto: ecdh - fix big endian bug in ECC library
  crypto: ccp - fix uninitialized list head
  crypto: geode-aes - switch to skcipher for cbc(aes) fallback
  crypto: af_alg - cast ki_complete ternary op to int
  crypto: atmel-aes - Fix IV handling when req->nbytes < ivsize
  crypto: crypto4xx - fix double-free in crypto4xx_destroy_sdr
  KVM: x86: Grab KVM's srcu lock when setting nested state
  KVM: x86: Remove a spurious export of a static function
  KVM: x86: fix presentation of TSX feature in ARCH_CAPABILITIES
  KVM: x86: do not modify masked bits of shared MSRs
  KVM: arm/arm64: vgic: Don't rely on the wrong pending table
  KVM: nVMX: Always write vmcs02.GUEST_CR3 during nested VM-Enter
  KVM: PPC: Book3S HV: XIVE: Set kvm->arch.xive when VPs are allocated
  KVM: PPC: Book3S HV: XIVE: Fix potential page leak on error path
  KVM: PPC: Book3S HV: XIVE: Free previous EQ page when setting up a new one
  arm64: dts: exynos: Revert "Remove unneeded address space mapping for soc node"
  arm64: Validate tagged addresses in access_ok() called from kernel threads
  drm/i810: Prevent underflow in ioctl
  drm: damage_helper: Fix race checking plane->state->fb
  drm/msm: fix memleak on release
  jbd2: Fix possible overflow in jbd2_log_space_left()
  kernfs: fix ino wrap-around detection
  nfsd: restore NFSv3 ACL support
  nfsd: Ensure CLONE persists data and metadata changes to the target file
  can: slcan: Fix use-after-free Read in slcan_open
  tty: vt: keyboard: reject invalid keycodes
  CIFS: Fix SMB2 oplock break processing
  CIFS: Fix NULL-pointer dereference in smb2_push_mandatory_locks
  x86/PCI: Avoid AMD FCH XHCI USB PME# from D0 defect
  x86/mm/32: Sync only to VMALLOC_END in vmalloc_sync_all()
  media: rc: mark input device as pointing stick
  Input: Fix memory leak in psxpad_spi_probe
  coresight: etm4x: Fix input validation for sysfs.
  Input: goodix - add upside-down quirk for Teclast X89 tablet
  Input: synaptics-rmi4 - don't increment rmiaddr for SMBus transfers
  Input: synaptics-rmi4 - re-enable IRQs in f34v7_do_reflash
  Input: synaptics - switch another X1 Carbon 6 to RMI/SMbus
  soc: mediatek: cmdq: fixup wrong input order of write api
  ALSA: hda: Modify stream stripe mask only when needed
  ALSA: hda - Add mute led support for HP ProBook 645 G4
  ALSA: pcm: oss: Avoid potential buffer overflows
  ALSA: hda/realtek - Fix inverted bass GPIO pin on Acer 8951G
  ALSA: hda/realtek - Dell headphone has noise on unmute for ALC236
  ALSA: hda/realtek - Enable the headset-mic on a Xiaomi's laptop
  ALSA: hda/realtek - Enable internal speaker of ASUS UX431FLC
  SUNRPC: Avoid RPC delays when exiting suspend
  io_uring: ensure req->submit is copied when req is deferred
  io_uring: fix missing kmap() declaration on powerpc
  fuse: verify attributes
  fuse: verify write return
  fuse: verify nlink
  fuse: fix leak of fuse_io_priv
  io_uring: transform send/recvmsg() -ERESTARTSYS to -EINTR
  io_uring: fix dead-hung for non-iter fixed rw
  mwifiex: Re-work support for SDIO HW reset
  serial: ifx6x60: add missed pm_runtime_disable
  serial: 8250_dw: Avoid double error messaging when IRQ absent
  serial: stm32: fix clearing interrupt error flags
  serial: serial_core: Perform NULL checks for break_ctl ops
  serial: pl011: Fix DMA ->flush_buffer()
  tty: serial: msm_serial: Fix flow control
  tty: serial: fsl_lpuart: use the sg count from dma_map_sg
  serial: 8250-mtk: Use platform_get_irq_optional() for optional irq
  usb: gadget: u_serial: add missing port entry locking
  staging/octeon: Use stubs for MIPS && !CAVIUM_OCTEON_SOC
  mailbox: tegra: Fix superfluous IRQ error message
  time: Zero the upper 32-bits in __kernel_timespec on 32-bit
  lp: fix sparc64 LPSETTIMEOUT ioctl
  sparc64: implement ioremap_uc
  perf scripts python: exported-sql-viewer.py: Fix use of TRUE with SQLite
  arm64: tegra: Fix 'active-low' warning for Jetson Xavier regulator
  arm64: tegra: Fix 'active-low' warning for Jetson TX1 regulator
  rsi: release skb if rsi_prepare_beacon fails
  FROMLIST: scsi: ufs: Fix ufshcd_hold() caused scheduling while atomic
  FROMLIST: scsi: ufs: Add dev ref clock gating wait time support
  FROMLIST: scsi: ufs-qcom: Adjust bus bandwidth voting and unvoting
  FROMLIST: scsi: ufs: Remove the check before call setup clock notify vops
  FROMLIST: scsi: ufs: set load before setting voltage in regulators
  FROMLIST: scsi: ufs: Flush exception event before suspend
  FROMLIST: scsi: ufs: Do not rely on prefetched data
  FROMLIST: scsi: ufs: Fix up clock scaling
  FROMGIT: scsi: ufs: Do not free irq in suspend
  FROMGIT: scsi: ufs: Do not clear the DL layer timers
  FROMGIT: scsi: ufs: Release clock if DMA map fails
  FROMGIT: scsi: ufs: Use DBD setting in mode sense
  FROMGIT: scsi: core: Adjust DBD setting in MODE SENSE for caching mode page per LLD
  FROMGIT: scsi: ufs: Complete pending requests in host reset and restore path
  FROMGIT: scsi: ufs: Avoid messing up the compl_time_stamp of lrbs
  FROMGIT: scsi: ufs: Update VCCQ2 and VCCQ min/max voltage hard codes
  FROMGIT: scsi: ufs: Recheck bkops level if bkops is disabled
  ANDROID: update abi_gki_aarch64.xml for LTO, CFI, and SCS
  ANDROID: gki_defconfig: enable LTO, CFI, and SCS
  ANDROID: update abi_gki_aarch64.xml for CONFIG_GNSS
  ANDROID: cuttlefish_defconfig: Enable CONFIG_GNSS
  ANDROID: gki_defconfig: enable HID configs
  UPSTREAM: arm64: Validate tagged addresses in access_ok() called from kernel threads
  ANDROID: kbuild: limit LTO inlining
  ANDROID: kbuild: merge module sections with LTO
  ANDROID: f2fs: fix possible merge of unencrypted with encrypted I/O
  ANDROID: gki_defconfig: Enable UCLAMP by default
  ANDROID: make sure proc mount options are applied
  ANDROID: sound: usb: Add helper APIs to enable audio stream
  ANDROID: Update ABI representation
  ANDROID: Don't base allmodconfig on gki_defconfig
  ANDROID: Disable UNWINDER_ORC for allmodconfig
  ANDROID: ASoC: Fix 'allmodconfig' build break
  Linux 5.4.2
  platform/x86: hp-wmi: Fix ACPI errors caused by passing 0 as input size
  platform/x86: hp-wmi: Fix ACPI errors caused by too small buffer
  HID: core: check whether Usage Page item is after Usage ID items
  crypto: talitos - Fix build error by selecting LIB_DES
  Revert "jffs2: Fix possible null-pointer dereferences in jffs2_add_frag_to_fragtree()"
  ext4: add more paranoia checking in ext4_expand_extra_isize handling
  r8169: fix resume on cable plug-in
  r8169: fix jumbo configuration for RTL8168evl
  selftests: pmtu: use -oneline for ip route list cache
  tipc: fix link name length check
  selftests: bpf: correct perror strings
  selftests: bpf: test_sockmap: handle file creation failures gracefully
  net/tls: use sg_next() to walk sg entries
  net/tls: remove the dead inplace_crypto code
  selftests/tls: add a test for fragmented messages
  net: skmsg: fix TLS 1.3 crash with full sk_msg
  net/tls: free the record on encryption error
  net/tls: take into account that bpf_exec_tx_verdict() may free the record
  openvswitch: remove another BUG_ON()
  openvswitch: drop unneeded BUG_ON() in ovs_flow_cmd_build_info()
  sctp: cache netns in sctp_ep_common
  slip: Fix use-after-free Read in slip_open
  sctp: Fix memory leak in sctp_sf_do_5_2_4_dupcook
  openvswitch: fix flow command message size
  net: sched: fix `tc -s class show` no bstats on class with nolock subqueues
  net: psample: fix skb_over_panic
  net: macb: add missed tasklet_kill
  net: dsa: sja1105: fix sja1105_parse_rgmii_delays()
  mdio_bus: don't use managed reset-controller
  macvlan: schedule bc_work even if error
  gve: Fix the queue page list allocated pages count
  x86/fpu: Don't cache access to fpu_fpregs_owner_ctx
  thunderbolt: Power cycle the router if NVM authentication fails
  mei: me: add comet point V device id
  mei: bus: prefix device names on bus with the bus name
  USB: serial: ftdi_sio: add device IDs for U-Blox C099-F9P
  staging: rtl8723bs: Add 024c:0525 to the list of SDIO device-ids
  staging: rtl8723bs: Drop ACPI device ids
  staging: rtl8192e: fix potential use after free
  staging: wilc1000: fix illegal memory access in wilc_parse_join_bss_param()
  usb: dwc2: use a longer core rest timeout in dwc2_core_reset()
  driver core: platform: use the correct callback type for bus_find_device
  crypto: inside-secure - Fix stability issue with Macchiatobin
  net: disallow ancillary data for __sys_{send,recv}msg_file()
  net: separate out the msghdr copy from ___sys_{send,recv}msg()
  io_uring: async workers should inherit the user creds
  ANDROID: Update ABI representation
  UPSTREAM: of: property: Add device link support for interrupt-parent, dmas and -gpio(s)
  UPSTREAM: of: property: Fix the semantics of of_is_ancestor_of()
  UPSTREAM: i2c: of: Populate fwnode in of_i2c_get_board_info()
  UPSTREAM: regulator: core: Don't try to remove device links if add failed
  UPSTREAM: driver core: Clarify documentation for fwnode_operations.add_links()
  ANDROID: Update ABI representation
  ANDROID: gki_defconfig: IIO=y
  ANDROID: Update ABI representation
  ANDROID: ASoC: core - add hostless DAI support
  ANDROID: gki_defconfig: =m's applied for virtio configs in arm64
  ANDROID: Update ABI representation after 5.4.1 merge
  Linux 5.4.1
  KVM: PPC: Book3S HV: Flush link stack on guest exit to host kernel
  powerpc/book3s64: Fix link stack flush on context switch
  staging: comedi: usbduxfast: usbduxfast_ai_cmdtest rounding error
  USB: serial: option: add support for Foxconn T77W968 LTE modules
  USB: serial: option: add support for DW5821e with eSIM support
  USB: serial: mos7840: fix remote wakeup
  USB: serial: mos7720: fix remote wakeup
  USB: serial: mos7840: add USB ID to support Moxa UPort 2210
  appledisplay: fix error handling in the scheduled work
  USB: chaoskey: fix error case of a timeout
  usb-serial: cp201x: support Mark-10 digital force gauge
  usbip: Fix uninitialized symbol 'nents' in stub_recv_cmd_submit()
  usbip: tools: fix fd leakage in the function of read_attr_usbip_status
  USBIP: add config dependency for SGL_ALLOC
  ALSA: hda - Disable audio component for legacy Nvidia HDMI codecs
  media: mceusb: fix out of bounds read in MCE receiver buffer
  media: imon: invalid dereference in imon_touch_event
  media: cxusb: detect cxusb_ctrl_msg error in query
  media: b2c2-flexcop-usb: add sanity checking
  media: uvcvideo: Fix error path in control parsing failure
  futex: Prevent exit livelock
  futex: Provide distinct return value when owner is exiting
  futex: Add mutex around futex exit
  futex: Provide state handling for exec() as well
  futex: Sanitize exit state handling
  futex: Mark the begin of futex exit explicitly
  futex: Set task::futex_state to DEAD right after handling futex exit
  futex: Split futex_mm_release() for exit/exec
  exit/exec: Seperate mm_release()
  futex: Replace PF_EXITPIDONE with a state
  futex: Move futex exit handling into futex code
  cpufreq: Add NULL checks to show() and store() methods of cpufreq
  media: usbvision: Fix races among open, close, and disconnect
  media: usbvision: Fix invalid accesses after device disconnect
  media: vivid: Fix wrong locking that causes race conditions on streaming stop
  media: vivid: Set vid_cap_streaming and vid_out_streaming to true
  ALSA: usb-audio: Fix Scarlett 6i6 Gen 2 port data
  ALSA: usb-audio: Fix NULL dereference at parsing BADD
  futex: Prevent robust futex exit race
  x86/entry/32: Fix FIXUP_ESPFIX_STACK with user CR3
  x86/pti/32: Calculate the various PTI cpu_entry_area sizes correctly, make the CPU_ENTRY_AREA_PAGES assert precise
  selftests/x86/sigreturn/32: Invalidate DS and ES when abusing the kernel
  selftests/x86/mov_ss_trap: Fix the SYSENTER test
  x86/entry/32: Fix NMI vs ESPFIX
  x86/entry/32: Unwind the ESPFIX stack earlier on exception entry
  x86/entry/32: Move FIXUP_FRAME after pushing %fs in SAVE_ALL
  x86/entry/32: Use %ss segment where required
  x86/entry/32: Fix IRET exception
  x86/cpu_entry_area: Add guard page for entry stack on 32bit
  x86/pti/32: Size initial_page_table correctly
  x86/doublefault/32: Fix stack canaries in the double fault handler
  x86/xen/32: Simplify ring check in xen_iret_crit_fixup()
  x86/xen/32: Make xen_iret_crit_fixup() independent of frame layout
  x86/stackframe/32: Repair 32-bit Xen PV
  nbd: prevent memory leak
  x86/speculation: Fix redundant MDS mitigation message
  x86/speculation: Fix incorrect MDS/TAA mitigation status
  x86/insn: Fix awk regexp warnings
  md/raid10: prevent access of uninitialized resync_pages offset
  Revert "dm crypt: use WQ_HIGHPRI for the IO and crypt workqueues"
  Revert "Bluetooth: hci_ll: set operational frequency earlier"
  ath10k: restore QCA9880-AR1A (v1) detection
  ath10k: Fix HOST capability QMI incompatibility
  ath10k: Fix a NULL-ptr-deref bug in ath10k_usb_alloc_urb_from_pipe
  ath9k_hw: fix uninitialized variable data
  Bluetooth: Fix invalid-free in bcsp_close()
  ANDROID: gki_defconfig: enable CONFIG_REGULATOR_FIXED_VOLTAGE
  FROMLIST: crypto: arm64/sha: fix function types
  ANDROID: arm64: kvm: disable CFI
  ANDROID: arm64: add __nocfi to __apply_alternatives
  ANDROID: arm64: add __pa_function
  ANDROID: arm64: add __nocfi to functions that jump to a physical address
  ANDROID: arm64: bpf: implement arch_bpf_jit_check_func
  ANDROID: bpf: validate bpf_func when BPF_JIT is enabled with CFI
  ANDROID: add support for Clang's Control Flow Integrity (CFI)
  ANDROID: arm64: allow LTO_CLANG and THINLTO to be selected
  FROMLIST: arm64: fix alternatives with LLVM's integrated assembler
  FROMLIST: arm64: lse: fix LSE atomics with LLVM's integrated assembler
  ANDROID: arm64: disable HAVE_ARCH_PREL32_RELOCATIONS with LTO_CLANG
  ANDROID: arm64: vdso: disable LTO
  ANDROID: irqchip/gic-v3: rename gic_of_init to work around a ThinLTO+CFI bug
  ANDROID: soc/tegra: disable ARCH_TEGRA_210_SOC with LTO
  ANDROID: init: ensure initcall ordering with LTO
  ANDROID: drivers/misc/lkdtm: disable LTO for rodata.o
  ANDROID: efi/libstub: disable LTO
  ANDROID: scripts/mod: disable LTO for empty.c
  ANDROID: kbuild: fix dynamic ftrace with clang LTO
  ANDROID: kbuild: add support for Clang LTO
  ANDROID: kbuild: add CONFIG_LD_IS_LLD
  FROMGIT: driver core: platform: use the correct callback type for bus_find_device
  FROMLIST: arm64: implement Shadow Call Stack
  FROMLIST: arm64: disable SCS for hypervisor code
  FROMLIST: arm64: vdso: disable Shadow Call Stack
  FROMLIST: arm64: efi: restore x18 if it was corrupted
  FROMLIST: arm64: preserve x18 when CPU is suspended
  FROMLIST: arm64: reserve x18 from general allocation with SCS
  FROMLIST: arm64: disable function graph tracing with SCS
  FROMLIST: scs: add support for stack usage debugging
  FROMLIST: scs: add accounting
  FROMLIST: add support for Clang's Shadow Call Stack (SCS)
  FROMLIST: arm64: kernel: avoid x18 in __cpu_soft_restart
  FROMLIST: arm64: kvm: stop treating register x18 as caller save
  FROMLIST: arm64/lib: copy_page: avoid x18 register in assembler code
  FROMLIST: arm64: mm: avoid x18 in idmap_kpti_install_ng_mappings
  ANDROID: clang: update to 10.0.1
  ANDROID: update ABI representation

Conflicts:
	Documentation/devicetree/bindings
	Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
	arch/arm64/Kconfig
	drivers/firmware/qcom_scm-64.c
	drivers/hwtracing/coresight/coresight.c
	drivers/scsi/ufs/ufs.h
	drivers/scsi/ufs/ufshcd.c
	drivers/scsi/ufs/ufshcd.h
	drivers/scsi/ufs/unipro.h
	drivers/staging/android/ion/heaps/ion_cma_heap.c
	drivers/staging/android/ion/heaps/ion_system_heap.c
	drivers/usb/dwc3/ep0.c
	drivers/usb/dwc3/gadget.c
	include/sound/pcm.h
	include/sound/soc.h
	kernel/exit.c
	kernel/sched/core.c

Change-Id: I66ea973ddcafd352ba999a1dc98e04df33397e3b
Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>
2020-01-23 04:00:53 -08:00

2158 lines
52 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/mm/vmstat.c
*
* Manages VM statistics
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*
* zoned VM statistics
* Copyright (C) 2006 Silicon Graphics, Inc.,
* Christoph Lameter <christoph@lameter.com>
* Copyright (C) 2008-2014 Christoph Lameter
*/
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/vmstat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/sched.h>
#include <linux/math64.h>
#include <linux/writeback.h>
#include <linux/compaction.h>
#include <linux/mm_inline.h>
#include <linux/page_ext.h>
#include <linux/page_owner.h>
#include "internal.h"
#define NUMA_STATS_THRESHOLD (U16_MAX - 2)
#ifdef CONFIG_NUMA
int sysctl_vm_numa_stat = ENABLE_NUMA_STAT;
/* zero numa counters within a zone */
static void zero_zone_numa_counters(struct zone *zone)
{
int item, cpu;
for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++) {
atomic_long_set(&zone->vm_numa_stat[item], 0);
for_each_online_cpu(cpu)
per_cpu_ptr(zone->pageset, cpu)->vm_numa_stat_diff[item]
= 0;
}
}
/* zero numa counters of all the populated zones */
static void zero_zones_numa_counters(void)
{
struct zone *zone;
for_each_populated_zone(zone)
zero_zone_numa_counters(zone);
}
/* zero global numa counters */
static void zero_global_numa_counters(void)
{
int item;
for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++)
atomic_long_set(&vm_numa_stat[item], 0);
}
static void invalid_numa_statistics(void)
{
zero_zones_numa_counters();
zero_global_numa_counters();
}
static DEFINE_MUTEX(vm_numa_stat_lock);
int sysctl_vm_numa_stat_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
{
int ret, oldval;
mutex_lock(&vm_numa_stat_lock);
if (write)
oldval = sysctl_vm_numa_stat;
ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
if (ret || !write)
goto out;
if (oldval == sysctl_vm_numa_stat)
goto out;
else if (sysctl_vm_numa_stat == ENABLE_NUMA_STAT) {
static_branch_enable(&vm_numa_stat_key);
pr_info("enable numa statistics\n");
} else {
static_branch_disable(&vm_numa_stat_key);
invalid_numa_statistics();
pr_info("disable numa statistics, and clear numa counters\n");
}
out:
mutex_unlock(&vm_numa_stat_lock);
return ret;
}
#endif
#ifdef CONFIG_VM_EVENT_COUNTERS
DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
EXPORT_PER_CPU_SYMBOL(vm_event_states);
static void sum_vm_events(unsigned long *ret)
{
int cpu;
int i;
memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
for_each_online_cpu(cpu) {
struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
ret[i] += this->event[i];
}
}
/*
* Accumulate the vm event counters across all CPUs.
* The result is unavoidably approximate - it can change
* during and after execution of this function.
*/
void all_vm_events(unsigned long *ret)
{
get_online_cpus();
sum_vm_events(ret);
put_online_cpus();
}
EXPORT_SYMBOL_GPL(all_vm_events);
/*
* Fold the foreign cpu events into our own.
*
* This is adding to the events on one processor
* but keeps the global counts constant.
*/
void vm_events_fold_cpu(int cpu)
{
struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
int i;
for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
count_vm_events(i, fold_state->event[i]);
fold_state->event[i] = 0;
}
}
#endif /* CONFIG_VM_EVENT_COUNTERS */
/*
* Manage combined zone based / global counters
*
* vm_stat contains the global counters
*/
atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
atomic_long_t vm_numa_stat[NR_VM_NUMA_STAT_ITEMS] __cacheline_aligned_in_smp;
atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
EXPORT_SYMBOL(vm_zone_stat);
EXPORT_SYMBOL(vm_numa_stat);
EXPORT_SYMBOL(vm_node_stat);
#ifdef CONFIG_SMP
int calculate_pressure_threshold(struct zone *zone)
{
int threshold;
int watermark_distance;
/*
* As vmstats are not up to date, there is drift between the estimated
* and real values. For high thresholds and a high number of CPUs, it
* is possible for the min watermark to be breached while the estimated
* value looks fine. The pressure threshold is a reduced value such
* that even the maximum amount of drift will not accidentally breach
* the min watermark
*/
watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone);
threshold = max(1, (int)(watermark_distance / num_online_cpus()));
/*
* Maximum threshold is 125
*/
threshold = min(125, threshold);
return threshold;
}
int calculate_normal_threshold(struct zone *zone)
{
int threshold;
int mem; /* memory in 128 MB units */
/*
* The threshold scales with the number of processors and the amount
* of memory per zone. More memory means that we can defer updates for
* longer, more processors could lead to more contention.
* fls() is used to have a cheap way of logarithmic scaling.
*
* Some sample thresholds:
*
* Threshold Processors (fls) Zonesize fls(mem+1)
* ------------------------------------------------------------------
* 8 1 1 0.9-1 GB 4
* 16 2 2 0.9-1 GB 4
* 20 2 2 1-2 GB 5
* 24 2 2 2-4 GB 6
* 28 2 2 4-8 GB 7
* 32 2 2 8-16 GB 8
* 4 2 2 <128M 1
* 30 4 3 2-4 GB 5
* 48 4 3 8-16 GB 8
* 32 8 4 1-2 GB 4
* 32 8 4 0.9-1GB 4
* 10 16 5 <128M 1
* 40 16 5 900M 4
* 70 64 7 2-4 GB 5
* 84 64 7 4-8 GB 6
* 108 512 9 4-8 GB 6
* 125 1024 10 8-16 GB 8
* 125 1024 10 16-32 GB 9
*/
mem = zone_managed_pages(zone) >> (27 - PAGE_SHIFT);
threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
/*
* Maximum threshold is 125
*/
threshold = min(125, threshold);
return threshold;
}
/*
* Refresh the thresholds for each zone.
*/
void refresh_zone_stat_thresholds(void)
{
struct pglist_data *pgdat;
struct zone *zone;
int cpu;
int threshold;
/* Zero current pgdat thresholds */
for_each_online_pgdat(pgdat) {
for_each_online_cpu(cpu) {
per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
}
}
for_each_populated_zone(zone) {
struct pglist_data *pgdat = zone->zone_pgdat;
unsigned long max_drift, tolerate_drift;
threshold = calculate_normal_threshold(zone);
for_each_online_cpu(cpu) {
int pgdat_threshold;
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
= threshold;
/* Base nodestat threshold on the largest populated zone. */
pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
= max(threshold, pgdat_threshold);
}
/*
* Only set percpu_drift_mark if there is a danger that
* NR_FREE_PAGES reports the low watermark is ok when in fact
* the min watermark could be breached by an allocation
*/
tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone);
max_drift = num_online_cpus() * threshold;
if (max_drift > tolerate_drift)
zone->percpu_drift_mark = high_wmark_pages(zone) +
max_drift;
}
}
void set_pgdat_percpu_threshold(pg_data_t *pgdat,
int (*calculate_pressure)(struct zone *))
{
struct zone *zone;
int cpu;
int threshold;
int i;
for (i = 0; i < pgdat->nr_zones; i++) {
zone = &pgdat->node_zones[i];
if (!zone->percpu_drift_mark)
continue;
threshold = (*calculate_pressure)(zone);
for_each_online_cpu(cpu)
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
= threshold;
}
}
/*
* For use when we know that interrupts are disabled,
* or when we know that preemption is disabled and that
* particular counter cannot be updated from interrupt context.
*/
void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
long delta)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
long x;
long t;
x = delta + __this_cpu_read(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(x > t || x < -t)) {
zone_page_state_add(x, zone, item);
x = 0;
}
__this_cpu_write(*p, x);
}
EXPORT_SYMBOL(__mod_zone_page_state);
void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
long delta)
{
struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
s8 __percpu *p = pcp->vm_node_stat_diff + item;
long x;
long t;
x = delta + __this_cpu_read(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(x > t || x < -t)) {
node_page_state_add(x, pgdat, item);
x = 0;
}
__this_cpu_write(*p, x);
}
EXPORT_SYMBOL(__mod_node_page_state);
/*
* Optimized increment and decrement functions.
*
* These are only for a single page and therefore can take a struct page *
* argument instead of struct zone *. This allows the inclusion of the code
* generated for page_zone(page) into the optimized functions.
*
* No overflow check is necessary and therefore the differential can be
* incremented or decremented in place which may allow the compilers to
* generate better code.
* The increment or decrement is known and therefore one boundary check can
* be omitted.
*
* NOTE: These functions are very performance sensitive. Change only
* with care.
*
* Some processors have inc/dec instructions that are atomic vs an interrupt.
* However, the code must first determine the differential location in a zone
* based on the processor number and then inc/dec the counter. There is no
* guarantee without disabling preemption that the processor will not change
* in between and therefore the atomicity vs. interrupt cannot be exploited
* in a useful way here.
*/
void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
s8 v, t;
v = __this_cpu_inc_return(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(v > t)) {
s8 overstep = t >> 1;
zone_page_state_add(v + overstep, zone, item);
__this_cpu_write(*p, -overstep);
}
}
void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
{
struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
s8 __percpu *p = pcp->vm_node_stat_diff + item;
s8 v, t;
v = __this_cpu_inc_return(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(v > t)) {
s8 overstep = t >> 1;
node_page_state_add(v + overstep, pgdat, item);
__this_cpu_write(*p, -overstep);
}
}
void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
{
__inc_zone_state(page_zone(page), item);
}
EXPORT_SYMBOL(__inc_zone_page_state);
void __inc_node_page_state(struct page *page, enum node_stat_item item)
{
__inc_node_state(page_pgdat(page), item);
}
EXPORT_SYMBOL(__inc_node_page_state);
void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
s8 v, t;
v = __this_cpu_dec_return(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(v < - t)) {
s8 overstep = t >> 1;
zone_page_state_add(v - overstep, zone, item);
__this_cpu_write(*p, overstep);
}
}
void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
{
struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
s8 __percpu *p = pcp->vm_node_stat_diff + item;
s8 v, t;
v = __this_cpu_dec_return(*p);
t = __this_cpu_read(pcp->stat_threshold);
if (unlikely(v < - t)) {
s8 overstep = t >> 1;
node_page_state_add(v - overstep, pgdat, item);
__this_cpu_write(*p, overstep);
}
}
void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
{
__dec_zone_state(page_zone(page), item);
}
EXPORT_SYMBOL(__dec_zone_page_state);
void __dec_node_page_state(struct page *page, enum node_stat_item item)
{
__dec_node_state(page_pgdat(page), item);
}
EXPORT_SYMBOL(__dec_node_page_state);
#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
/*
* If we have cmpxchg_local support then we do not need to incur the overhead
* that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
*
* mod_state() modifies the zone counter state through atomic per cpu
* operations.
*
* Overstep mode specifies how overstep should handled:
* 0 No overstepping
* 1 Overstepping half of threshold
* -1 Overstepping minus half of threshold
*/
static inline void mod_zone_state(struct zone *zone,
enum zone_stat_item item, long delta, int overstep_mode)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
long o, n, t, z;
do {
z = 0; /* overflow to zone counters */
/*
* The fetching of the stat_threshold is racy. We may apply
* a counter threshold to the wrong the cpu if we get
* rescheduled while executing here. However, the next
* counter update will apply the threshold again and
* therefore bring the counter under the threshold again.
*
* Most of the time the thresholds are the same anyways
* for all cpus in a zone.
*/
t = this_cpu_read(pcp->stat_threshold);
o = this_cpu_read(*p);
n = delta + o;
if (n > t || n < -t) {
int os = overstep_mode * (t >> 1) ;
/* Overflow must be added to zone counters */
z = n + os;
n = -os;
}
} while (this_cpu_cmpxchg(*p, o, n) != o);
if (z)
zone_page_state_add(z, zone, item);
}
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
long delta)
{
mod_zone_state(zone, item, delta, 0);
}
EXPORT_SYMBOL(mod_zone_page_state);
void inc_zone_page_state(struct page *page, enum zone_stat_item item)
{
mod_zone_state(page_zone(page), item, 1, 1);
}
EXPORT_SYMBOL(inc_zone_page_state);
void dec_zone_page_state(struct page *page, enum zone_stat_item item)
{
mod_zone_state(page_zone(page), item, -1, -1);
}
EXPORT_SYMBOL(dec_zone_page_state);
static inline void mod_node_state(struct pglist_data *pgdat,
enum node_stat_item item, int delta, int overstep_mode)
{
struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
s8 __percpu *p = pcp->vm_node_stat_diff + item;
long o, n, t, z;
do {
z = 0; /* overflow to node counters */
/*
* The fetching of the stat_threshold is racy. We may apply
* a counter threshold to the wrong the cpu if we get
* rescheduled while executing here. However, the next
* counter update will apply the threshold again and
* therefore bring the counter under the threshold again.
*
* Most of the time the thresholds are the same anyways
* for all cpus in a node.
*/
t = this_cpu_read(pcp->stat_threshold);
o = this_cpu_read(*p);
n = delta + o;
if (n > t || n < -t) {
int os = overstep_mode * (t >> 1) ;
/* Overflow must be added to node counters */
z = n + os;
n = -os;
}
} while (this_cpu_cmpxchg(*p, o, n) != o);
if (z)
node_page_state_add(z, pgdat, item);
}
void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
long delta)
{
mod_node_state(pgdat, item, delta, 0);
}
EXPORT_SYMBOL(mod_node_page_state);
void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
{
mod_node_state(pgdat, item, 1, 1);
}
void inc_node_page_state(struct page *page, enum node_stat_item item)
{
mod_node_state(page_pgdat(page), item, 1, 1);
}
EXPORT_SYMBOL(inc_node_page_state);
void dec_node_page_state(struct page *page, enum node_stat_item item)
{
mod_node_state(page_pgdat(page), item, -1, -1);
}
EXPORT_SYMBOL(dec_node_page_state);
#else
/*
* Use interrupt disable to serialize counter updates
*/
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
long delta)
{
unsigned long flags;
local_irq_save(flags);
__mod_zone_page_state(zone, item, delta);
local_irq_restore(flags);
}
EXPORT_SYMBOL(mod_zone_page_state);
void inc_zone_page_state(struct page *page, enum zone_stat_item item)
{
unsigned long flags;
struct zone *zone;
zone = page_zone(page);
local_irq_save(flags);
__inc_zone_state(zone, item);
local_irq_restore(flags);
}
EXPORT_SYMBOL(inc_zone_page_state);
void dec_zone_page_state(struct page *page, enum zone_stat_item item)
{
unsigned long flags;
local_irq_save(flags);
__dec_zone_page_state(page, item);
local_irq_restore(flags);
}
EXPORT_SYMBOL(dec_zone_page_state);
void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
{
unsigned long flags;
local_irq_save(flags);
__inc_node_state(pgdat, item);
local_irq_restore(flags);
}
EXPORT_SYMBOL(inc_node_state);
void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
long delta)
{
unsigned long flags;
local_irq_save(flags);
__mod_node_page_state(pgdat, item, delta);
local_irq_restore(flags);
}
EXPORT_SYMBOL(mod_node_page_state);
void inc_node_page_state(struct page *page, enum node_stat_item item)
{
unsigned long flags;
struct pglist_data *pgdat;
pgdat = page_pgdat(page);
local_irq_save(flags);
__inc_node_state(pgdat, item);
local_irq_restore(flags);
}
EXPORT_SYMBOL(inc_node_page_state);
void dec_node_page_state(struct page *page, enum node_stat_item item)
{
unsigned long flags;
local_irq_save(flags);
__dec_node_page_state(page, item);
local_irq_restore(flags);
}
EXPORT_SYMBOL(dec_node_page_state);
#endif
/*
* Fold a differential into the global counters.
* Returns the number of counters updated.
*/
#ifdef CONFIG_NUMA
static int fold_diff(int *zone_diff, int *numa_diff, int *node_diff)
{
int i;
int changes = 0;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
if (zone_diff[i]) {
atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
changes++;
}
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
if (numa_diff[i]) {
atomic_long_add(numa_diff[i], &vm_numa_stat[i]);
changes++;
}
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
if (node_diff[i]) {
atomic_long_add(node_diff[i], &vm_node_stat[i]);
changes++;
}
return changes;
}
#else
static int fold_diff(int *zone_diff, int *node_diff)
{
int i;
int changes = 0;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
if (zone_diff[i]) {
atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
changes++;
}
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
if (node_diff[i]) {
atomic_long_add(node_diff[i], &vm_node_stat[i]);
changes++;
}
return changes;
}
#endif /* CONFIG_NUMA */
/*
* Update the zone counters for the current cpu.
*
* Note that refresh_cpu_vm_stats strives to only access
* node local memory. The per cpu pagesets on remote zones are placed
* in the memory local to the processor using that pageset. So the
* loop over all zones will access a series of cachelines local to
* the processor.
*
* The call to zone_page_state_add updates the cachelines with the
* statistics in the remote zone struct as well as the global cachelines
* with the global counters. These could cause remote node cache line
* bouncing and will have to be only done when necessary.
*
* The function returns the number of global counters updated.
*/
static int refresh_cpu_vm_stats(bool do_pagesets)
{
struct pglist_data *pgdat;
struct zone *zone;
int i;
int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
#ifdef CONFIG_NUMA
int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
#endif
int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
int changes = 0;
for_each_populated_zone(zone) {
struct per_cpu_pageset __percpu *p = zone->pageset;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
int v;
v = this_cpu_xchg(p->vm_stat_diff[i], 0);
if (v) {
atomic_long_add(v, &zone->vm_stat[i]);
global_zone_diff[i] += v;
#ifdef CONFIG_NUMA
/* 3 seconds idle till flush */
__this_cpu_write(p->expire, 3);
#endif
}
}
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
int v;
v = this_cpu_xchg(p->vm_numa_stat_diff[i], 0);
if (v) {
atomic_long_add(v, &zone->vm_numa_stat[i]);
global_numa_diff[i] += v;
__this_cpu_write(p->expire, 3);
}
}
if (do_pagesets) {
cond_resched();
/*
* Deal with draining the remote pageset of this
* processor
*
* Check if there are pages remaining in this pageset
* if not then there is nothing to expire.
*/
if (!__this_cpu_read(p->expire) ||
!__this_cpu_read(p->pcp.count))
continue;
/*
* We never drain zones local to this processor.
*/
if (zone_to_nid(zone) == numa_node_id()) {
__this_cpu_write(p->expire, 0);
continue;
}
if (__this_cpu_dec_return(p->expire))
continue;
if (__this_cpu_read(p->pcp.count)) {
drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
changes++;
}
}
#endif
}
for_each_online_pgdat(pgdat) {
struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
int v;
v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
if (v) {
atomic_long_add(v, &pgdat->vm_stat[i]);
global_node_diff[i] += v;
}
}
}
#ifdef CONFIG_NUMA
changes += fold_diff(global_zone_diff, global_numa_diff,
global_node_diff);
#else
changes += fold_diff(global_zone_diff, global_node_diff);
#endif
return changes;
}
/*
* Fold the data for an offline cpu into the global array.
* There cannot be any access by the offline cpu and therefore
* synchronization is simplified.
*/
void cpu_vm_stats_fold(int cpu)
{
struct pglist_data *pgdat;
struct zone *zone;
int i;
int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
#ifdef CONFIG_NUMA
int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
#endif
int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
for_each_populated_zone(zone) {
struct per_cpu_pageset *p;
p = per_cpu_ptr(zone->pageset, cpu);
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
if (p->vm_stat_diff[i]) {
int v;
v = p->vm_stat_diff[i];
p->vm_stat_diff[i] = 0;
atomic_long_add(v, &zone->vm_stat[i]);
global_zone_diff[i] += v;
}
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
if (p->vm_numa_stat_diff[i]) {
int v;
v = p->vm_numa_stat_diff[i];
p->vm_numa_stat_diff[i] = 0;
atomic_long_add(v, &zone->vm_numa_stat[i]);
global_numa_diff[i] += v;
}
#endif
}
for_each_online_pgdat(pgdat) {
struct per_cpu_nodestat *p;
p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
if (p->vm_node_stat_diff[i]) {
int v;
v = p->vm_node_stat_diff[i];
p->vm_node_stat_diff[i] = 0;
atomic_long_add(v, &pgdat->vm_stat[i]);
global_node_diff[i] += v;
}
}
#ifdef CONFIG_NUMA
fold_diff(global_zone_diff, global_numa_diff, global_node_diff);
#else
fold_diff(global_zone_diff, global_node_diff);
#endif
}
/*
* this is only called if !populated_zone(zone), which implies no other users of
* pset->vm_stat_diff[] exsist.
*/
void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
{
int i;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
if (pset->vm_stat_diff[i]) {
int v = pset->vm_stat_diff[i];
pset->vm_stat_diff[i] = 0;
atomic_long_add(v, &zone->vm_stat[i]);
atomic_long_add(v, &vm_zone_stat[i]);
}
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
if (pset->vm_numa_stat_diff[i]) {
int v = pset->vm_numa_stat_diff[i];
pset->vm_numa_stat_diff[i] = 0;
atomic_long_add(v, &zone->vm_numa_stat[i]);
atomic_long_add(v, &vm_numa_stat[i]);
}
#endif
}
#endif
#ifdef CONFIG_NUMA
void __inc_numa_state(struct zone *zone,
enum numa_stat_item item)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
u16 __percpu *p = pcp->vm_numa_stat_diff + item;
u16 v;
v = __this_cpu_inc_return(*p);
if (unlikely(v > NUMA_STATS_THRESHOLD)) {
zone_numa_state_add(v, zone, item);
__this_cpu_write(*p, 0);
}
}
/*
* Determine the per node value of a stat item. This function
* is called frequently in a NUMA machine, so try to be as
* frugal as possible.
*/
unsigned long sum_zone_node_page_state(int node,
enum zone_stat_item item)
{
struct zone *zones = NODE_DATA(node)->node_zones;
int i;
unsigned long count = 0;
for (i = 0; i < MAX_NR_ZONES; i++)
count += zone_page_state(zones + i, item);
return count;
}
/*
* Determine the per node value of a numa stat item. To avoid deviation,
* the per cpu stat number in vm_numa_stat_diff[] is also included.
*/
unsigned long sum_zone_numa_state(int node,
enum numa_stat_item item)
{
struct zone *zones = NODE_DATA(node)->node_zones;
int i;
unsigned long count = 0;
for (i = 0; i < MAX_NR_ZONES; i++)
count += zone_numa_state_snapshot(zones + i, item);
return count;
}
/*
* Determine the per node value of a stat item.
*/
unsigned long node_page_state(struct pglist_data *pgdat,
enum node_stat_item item)
{
long x = atomic_long_read(&pgdat->vm_stat[item]);
#ifdef CONFIG_SMP
if (x < 0)
x = 0;
#endif
return x;
}
#endif
#ifdef CONFIG_COMPACTION
struct contig_page_info {
unsigned long free_pages;
unsigned long free_blocks_total;
unsigned long free_blocks_suitable;
};
/*
* Calculate the number of free pages in a zone, how many contiguous
* pages are free and how many are large enough to satisfy an allocation of
* the target size. Note that this function makes no attempt to estimate
* how many suitable free blocks there *might* be if MOVABLE pages were
* migrated. Calculating that is possible, but expensive and can be
* figured out from userspace
*/
static void fill_contig_page_info(struct zone *zone,
unsigned int suitable_order,
struct contig_page_info *info)
{
unsigned int order;
info->free_pages = 0;
info->free_blocks_total = 0;
info->free_blocks_suitable = 0;
for (order = 0; order < MAX_ORDER; order++) {
unsigned long blocks;
/* Count number of free blocks */
blocks = zone->free_area[order].nr_free;
info->free_blocks_total += blocks;
/* Count free base pages */
info->free_pages += blocks << order;
/* Count the suitable free blocks */
if (order >= suitable_order)
info->free_blocks_suitable += blocks <<
(order - suitable_order);
}
}
/*
* A fragmentation index only makes sense if an allocation of a requested
* size would fail. If that is true, the fragmentation index indicates
* whether external fragmentation or a lack of memory was the problem.
* The value can be used to determine if page reclaim or compaction
* should be used
*/
static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
{
unsigned long requested = 1UL << order;
if (WARN_ON_ONCE(order >= MAX_ORDER))
return 0;
if (!info->free_blocks_total)
return 0;
/* Fragmentation index only makes sense when a request would fail */
if (info->free_blocks_suitable)
return -1000;
/*
* Index is between 0 and 1 so return within 3 decimal places
*
* 0 => allocation would fail due to lack of memory
* 1 => allocation would fail due to fragmentation
*/
return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
}
/* Same as __fragmentation index but allocs contig_page_info on stack */
int fragmentation_index(struct zone *zone, unsigned int order)
{
struct contig_page_info info;
fill_contig_page_info(zone, order, &info);
return __fragmentation_index(order, &info);
}
#endif
#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || defined(CONFIG_NUMA)
#ifdef CONFIG_ZONE_DMA
#define TEXT_FOR_DMA(xx) xx "_dma",
#else
#define TEXT_FOR_DMA(xx)
#endif
#ifdef CONFIG_ZONE_DMA32
#define TEXT_FOR_DMA32(xx) xx "_dma32",
#else
#define TEXT_FOR_DMA32(xx)
#endif
#ifdef CONFIG_HIGHMEM
#define TEXT_FOR_HIGHMEM(xx) xx "_high",
#else
#define TEXT_FOR_HIGHMEM(xx)
#endif
#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
TEXT_FOR_HIGHMEM(xx) xx "_movable",
const char * const vmstat_text[] = {
/* enum zone_stat_item countes */
"nr_free_pages",
"nr_zone_inactive_anon",
"nr_zone_active_anon",
"nr_zone_inactive_file",
"nr_zone_active_file",
"nr_zone_unevictable",
"nr_zone_write_pending",
"nr_mlock",
"nr_page_table_pages",
"nr_kernel_stack",
#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
"nr_shadow_call_stack_bytes",
#endif
"nr_bounce",
#if IS_ENABLED(CONFIG_ZSMALLOC)
"nr_zspages",
#endif
"nr_free_cma",
/* enum numa_stat_item counters */
#ifdef CONFIG_NUMA
"numa_hit",
"numa_miss",
"numa_foreign",
"numa_interleave",
"numa_local",
"numa_other",
#endif
/* Node-based counters */
"nr_inactive_anon",
"nr_active_anon",
"nr_inactive_file",
"nr_active_file",
"nr_unevictable",
"nr_slab_reclaimable",
"nr_slab_unreclaimable",
"nr_isolated_anon",
"nr_isolated_file",
"workingset_nodes",
"workingset_refault",
"workingset_activate",
"workingset_restore",
"workingset_nodereclaim",
"nr_anon_pages",
"nr_mapped",
"nr_file_pages",
"nr_dirty",
"nr_writeback",
"nr_writeback_temp",
"nr_shmem",
"nr_shmem_hugepages",
"nr_shmem_pmdmapped",
"nr_file_hugepages",
"nr_file_pmdmapped",
"nr_anon_transparent_hugepages",
"nr_unstable",
"nr_vmscan_write",
"nr_vmscan_immediate_reclaim",
"nr_dirtied",
"nr_written",
"nr_kernel_misc_reclaimable",
/* enum writeback_stat_item counters */
"nr_dirty_threshold",
"nr_dirty_background_threshold",
#ifdef CONFIG_VM_EVENT_COUNTERS
/* enum vm_event_item counters */
"pgpgin",
"pgpgout",
#ifdef CONFIG_VM_EVENT_COUNT_CLEAN_PAGE_RECLAIM
"pgpgoutclean",
#endif
"pswpin",
"pswpout",
TEXTS_FOR_ZONES("pgalloc")
TEXTS_FOR_ZONES("allocstall")
TEXTS_FOR_ZONES("pgskip")
"pgfree",
"pgactivate",
"pgdeactivate",
"pglazyfree",
"pgfault",
"pgmajfault",
"pglazyfreed",
"pgrefill",
"pgsteal_kswapd",
"pgsteal_direct",
"pgscan_kswapd",
"pgscan_direct",
"pgscan_direct_throttle",
#ifdef CONFIG_NUMA
"zone_reclaim_failed",
#endif
"pginodesteal",
"slabs_scanned",
"kswapd_inodesteal",
"kswapd_low_wmark_hit_quickly",
"kswapd_high_wmark_hit_quickly",
"pageoutrun",
"pgrotated",
"drop_pagecache",
"drop_slab",
"oom_kill",
#ifdef CONFIG_NUMA_BALANCING
"numa_pte_updates",
"numa_huge_pte_updates",
"numa_hint_faults",
"numa_hint_faults_local",
"numa_pages_migrated",
#endif
#ifdef CONFIG_MIGRATION
"pgmigrate_success",
"pgmigrate_fail",
#endif
#ifdef CONFIG_COMPACTION
"compact_migrate_scanned",
"compact_free_scanned",
"compact_isolated",
"compact_stall",
"compact_fail",
"compact_success",
"compact_daemon_wake",
"compact_daemon_migrate_scanned",
"compact_daemon_free_scanned",
#endif
#ifdef CONFIG_HUGETLB_PAGE
"htlb_buddy_alloc_success",
"htlb_buddy_alloc_fail",
#endif
"unevictable_pgs_culled",
"unevictable_pgs_scanned",
"unevictable_pgs_rescued",
"unevictable_pgs_mlocked",
"unevictable_pgs_munlocked",
"unevictable_pgs_cleared",
"unevictable_pgs_stranded",
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
"thp_fault_alloc",
"thp_fault_fallback",
"thp_collapse_alloc",
"thp_collapse_alloc_failed",
"thp_file_alloc",
"thp_file_mapped",
"thp_split_page",
"thp_split_page_failed",
"thp_deferred_split_page",
"thp_split_pmd",
#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
"thp_split_pud",
#endif
"thp_zero_page_alloc",
"thp_zero_page_alloc_failed",
"thp_swpout",
"thp_swpout_fallback",
#endif
#ifdef CONFIG_MEMORY_BALLOON
"balloon_inflate",
"balloon_deflate",
#ifdef CONFIG_BALLOON_COMPACTION
"balloon_migrate",
#endif
#endif /* CONFIG_MEMORY_BALLOON */
#ifdef CONFIG_DEBUG_TLBFLUSH
"nr_tlb_remote_flush",
"nr_tlb_remote_flush_received",
"nr_tlb_local_flush_all",
"nr_tlb_local_flush_one",
#endif /* CONFIG_DEBUG_TLBFLUSH */
#ifdef CONFIG_DEBUG_VM_VMACACHE
"vmacache_find_calls",
"vmacache_find_hits",
#endif
#ifdef CONFIG_SWAP
"swap_ra",
"swap_ra_hit",
#endif
#endif /* CONFIG_VM_EVENTS_COUNTERS */
};
#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */
#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
defined(CONFIG_PROC_FS)
static void *frag_start(struct seq_file *m, loff_t *pos)
{
pg_data_t *pgdat;
loff_t node = *pos;
for (pgdat = first_online_pgdat();
pgdat && node;
pgdat = next_online_pgdat(pgdat))
--node;
return pgdat;
}
static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
{
pg_data_t *pgdat = (pg_data_t *)arg;
(*pos)++;
return next_online_pgdat(pgdat);
}
static void frag_stop(struct seq_file *m, void *arg)
{
}
/*
* Walk zones in a node and print using a callback.
* If @assert_populated is true, only use callback for zones that are populated.
*/
static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
bool assert_populated, bool nolock,
void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
{
struct zone *zone;
struct zone *node_zones = pgdat->node_zones;
unsigned long flags;
for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
if (assert_populated && !populated_zone(zone))
continue;
if (!nolock)
spin_lock_irqsave(&zone->lock, flags);
print(m, pgdat, zone);
if (!nolock)
spin_unlock_irqrestore(&zone->lock, flags);
}
}
#endif
#ifdef CONFIG_PROC_FS
static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
struct zone *zone)
{
int order;
seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
for (order = 0; order < MAX_ORDER; ++order)
seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
seq_putc(m, '\n');
}
/*
* This walks the free areas for each zone.
*/
static int frag_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
walk_zones_in_node(m, pgdat, true, false, frag_show_print);
return 0;
}
static void pagetypeinfo_showfree_print(struct seq_file *m,
pg_data_t *pgdat, struct zone *zone)
{
int order, mtype;
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
seq_printf(m, "Node %4d, zone %8s, type %12s ",
pgdat->node_id,
zone->name,
migratetype_names[mtype]);
for (order = 0; order < MAX_ORDER; ++order) {
unsigned long freecount = 0;
struct free_area *area;
struct list_head *curr;
bool overflow = false;
area = &(zone->free_area[order]);
list_for_each(curr, &area->free_list[mtype]) {
/*
* Cap the free_list iteration because it might
* be really large and we are under a spinlock
* so a long time spent here could trigger a
* hard lockup detector. Anyway this is a
* debugging tool so knowing there is a handful
* of pages of this order should be more than
* sufficient.
*/
if (++freecount >= 100000) {
overflow = true;
break;
}
}
seq_printf(m, "%s%6lu ", overflow ? ">" : "", freecount);
spin_unlock_irq(&zone->lock);
cond_resched();
spin_lock_irq(&zone->lock);
}
seq_putc(m, '\n');
}
}
/* Print out the free pages at each order for each migatetype */
static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
{
int order;
pg_data_t *pgdat = (pg_data_t *)arg;
/* Print header */
seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
for (order = 0; order < MAX_ORDER; ++order)
seq_printf(m, "%6d ", order);
seq_putc(m, '\n');
walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
return 0;
}
static void pagetypeinfo_showblockcount_print(struct seq_file *m,
pg_data_t *pgdat, struct zone *zone)
{
int mtype;
unsigned long pfn;
unsigned long start_pfn = zone->zone_start_pfn;
unsigned long end_pfn = zone_end_pfn(zone);
unsigned long count[MIGRATE_TYPES] = { 0, };
for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
struct page *page;
page = pfn_to_online_page(pfn);
if (!page)
continue;
/* Watch for unexpected holes punched in the memmap */
if (!memmap_valid_within(pfn, page, zone))
continue;
if (page_zone(page) != zone)
continue;
mtype = get_pageblock_migratetype(page);
if (mtype < MIGRATE_TYPES)
count[mtype]++;
}
/* Print counts */
seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
seq_printf(m, "%12lu ", count[mtype]);
seq_putc(m, '\n');
}
/* Print out the number of pageblocks for each migratetype */
static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
{
int mtype;
pg_data_t *pgdat = (pg_data_t *)arg;
seq_printf(m, "\n%-23s", "Number of blocks type ");
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
walk_zones_in_node(m, pgdat, true, false,
pagetypeinfo_showblockcount_print);
return 0;
}
/*
* Print out the number of pageblocks for each migratetype that contain pages
* of other types. This gives an indication of how well fallbacks are being
* contained by rmqueue_fallback(). It requires information from PAGE_OWNER
* to determine what is going on
*/
static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
{
#ifdef CONFIG_PAGE_OWNER
int mtype;
if (!static_branch_unlikely(&page_owner_inited))
return;
drain_all_pages(NULL);
seq_printf(m, "\n%-23s", "Number of mixed blocks ");
for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
seq_printf(m, "%12s ", migratetype_names[mtype]);
seq_putc(m, '\n');
walk_zones_in_node(m, pgdat, true, true,
pagetypeinfo_showmixedcount_print);
#endif /* CONFIG_PAGE_OWNER */
}
/*
* This prints out statistics in relation to grouping pages by mobility.
* It is expensive to collect so do not constantly read the file.
*/
static int pagetypeinfo_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
/* check memoryless node */
if (!node_state(pgdat->node_id, N_MEMORY))
return 0;
seq_printf(m, "Page block order: %d\n", pageblock_order);
seq_printf(m, "Pages per block: %lu\n", pageblock_nr_pages);
seq_putc(m, '\n');
pagetypeinfo_showfree(m, pgdat);
pagetypeinfo_showblockcount(m, pgdat);
pagetypeinfo_showmixedcount(m, pgdat);
return 0;
}
static const struct seq_operations fragmentation_op = {
.start = frag_start,
.next = frag_next,
.stop = frag_stop,
.show = frag_show,
};
static const struct seq_operations pagetypeinfo_op = {
.start = frag_start,
.next = frag_next,
.stop = frag_stop,
.show = pagetypeinfo_show,
};
static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
{
int zid;
for (zid = 0; zid < MAX_NR_ZONES; zid++) {
struct zone *compare = &pgdat->node_zones[zid];
if (populated_zone(compare))
return zone == compare;
}
return false;
}
static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
struct zone *zone)
{
int i;
seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
if (is_zone_first_populated(pgdat, zone)) {
seq_printf(m, "\n per-node stats");
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
seq_printf(m, "\n %-12s %lu",
vmstat_text[i + NR_VM_ZONE_STAT_ITEMS +
NR_VM_NUMA_STAT_ITEMS],
node_page_state(pgdat, i));
}
}
seq_printf(m,
"\n pages free %lu"
"\n min %lu"
"\n low %lu"
"\n high %lu"
"\n spanned %lu"
"\n present %lu"
"\n managed %lu",
zone_page_state(zone, NR_FREE_PAGES),
min_wmark_pages(zone),
low_wmark_pages(zone),
high_wmark_pages(zone),
zone->spanned_pages,
zone->present_pages,
zone_managed_pages(zone));
seq_printf(m,
"\n protection: (%ld",
zone->lowmem_reserve[0]);
for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
seq_printf(m, ", %ld", zone->lowmem_reserve[i]);
seq_putc(m, ')');
/* If unpopulated, no other information is useful */
if (!populated_zone(zone)) {
seq_putc(m, '\n');
return;
}
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
seq_printf(m, "\n %-12s %lu", vmstat_text[i],
zone_page_state(zone, i));
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
seq_printf(m, "\n %-12s %lu",
vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
zone_numa_state_snapshot(zone, i));
#endif
seq_printf(m, "\n pagesets");
for_each_online_cpu(i) {
struct per_cpu_pageset *pageset;
pageset = per_cpu_ptr(zone->pageset, i);
seq_printf(m,
"\n cpu: %i"
"\n count: %i"
"\n high: %i"
"\n batch: %i",
i,
pageset->pcp.count,
pageset->pcp.high,
pageset->pcp.batch);
#ifdef CONFIG_SMP
seq_printf(m, "\n vm stats threshold: %d",
pageset->stat_threshold);
#endif
}
seq_printf(m,
"\n node_unreclaimable: %u"
"\n start_pfn: %lu",
pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
zone->zone_start_pfn);
seq_putc(m, '\n');
}
/*
* Output information about zones in @pgdat. All zones are printed regardless
* of whether they are populated or not: lowmem_reserve_ratio operates on the
* set of all zones and userspace would not be aware of such zones if they are
* suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio).
*/
static int zoneinfo_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
return 0;
}
static const struct seq_operations zoneinfo_op = {
.start = frag_start, /* iterate over all zones. The same as in
* fragmentation. */
.next = frag_next,
.stop = frag_stop,
.show = zoneinfo_show,
};
enum writeback_stat_item {
NR_DIRTY_THRESHOLD,
NR_DIRTY_BG_THRESHOLD,
NR_VM_WRITEBACK_STAT_ITEMS,
};
static void *vmstat_start(struct seq_file *m, loff_t *pos)
{
unsigned long *v;
int i, stat_items_size;
if (*pos >= ARRAY_SIZE(vmstat_text))
return NULL;
stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
NR_VM_NUMA_STAT_ITEMS * sizeof(unsigned long) +
NR_VM_NODE_STAT_ITEMS * sizeof(unsigned long) +
NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
#ifdef CONFIG_VM_EVENT_COUNTERS
stat_items_size += sizeof(struct vm_event_state);
#endif
BUILD_BUG_ON(stat_items_size !=
ARRAY_SIZE(vmstat_text) * sizeof(unsigned long));
v = kmalloc(stat_items_size, GFP_KERNEL);
m->private = v;
if (!v)
return ERR_PTR(-ENOMEM);
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
v[i] = global_zone_page_state(i);
v += NR_VM_ZONE_STAT_ITEMS;
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
v[i] = global_numa_state(i);
v += NR_VM_NUMA_STAT_ITEMS;
#endif
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
v[i] = global_node_page_state(i);
v += NR_VM_NODE_STAT_ITEMS;
global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
v + NR_DIRTY_THRESHOLD);
v += NR_VM_WRITEBACK_STAT_ITEMS;
#ifdef CONFIG_VM_EVENT_COUNTERS
all_vm_events(v);
v[PGPGIN] /= 2; /* sectors -> kbytes */
v[PGPGOUT] /= 2;
#endif
return (unsigned long *)m->private + *pos;
}
static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
{
(*pos)++;
if (*pos >= ARRAY_SIZE(vmstat_text))
return NULL;
return (unsigned long *)m->private + *pos;
}
static int vmstat_show(struct seq_file *m, void *arg)
{
unsigned long *l = arg;
unsigned long off = l - (unsigned long *)m->private;
seq_puts(m, vmstat_text[off]);
seq_put_decimal_ull(m, " ", *l);
seq_putc(m, '\n');
return 0;
}
static void vmstat_stop(struct seq_file *m, void *arg)
{
kfree(m->private);
m->private = NULL;
}
static const struct seq_operations vmstat_op = {
.start = vmstat_start,
.next = vmstat_next,
.stop = vmstat_stop,
.show = vmstat_show,
};
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SMP
static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
int sysctl_stat_interval __read_mostly = HZ;
#ifdef CONFIG_PROC_FS
static void refresh_vm_stats(struct work_struct *work)
{
refresh_cpu_vm_stats(true);
}
int vmstat_refresh(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
long val;
int err;
int i;
/*
* The regular update, every sysctl_stat_interval, may come later
* than expected: leaving a significant amount in per_cpu buckets.
* This is particularly misleading when checking a quantity of HUGE
* pages, immediately after running a test. /proc/sys/vm/stat_refresh,
* which can equally be echo'ed to or cat'ted from (by root),
* can be used to update the stats just before reading them.
*
* Oh, and since global_zone_page_state() etc. are so careful to hide
* transiently negative values, report an error here if any of
* the stats is negative, so we know to go looking for imbalance.
*/
err = schedule_on_each_cpu(refresh_vm_stats);
if (err)
return err;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
val = atomic_long_read(&vm_zone_stat[i]);
if (val < 0) {
pr_warn("%s: %s %ld\n",
__func__, vmstat_text[i], val);
err = -EINVAL;
}
}
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
val = atomic_long_read(&vm_numa_stat[i]);
if (val < 0) {
pr_warn("%s: %s %ld\n",
__func__, vmstat_text[i + NR_VM_ZONE_STAT_ITEMS], val);
err = -EINVAL;
}
}
#endif
if (err)
return err;
if (write)
*ppos += *lenp;
else
*lenp = 0;
return 0;
}
#endif /* CONFIG_PROC_FS */
static void vmstat_update(struct work_struct *w)
{
if (refresh_cpu_vm_stats(true) && !cpu_isolated(smp_processor_id())) {
/*
* Counters were updated so we expect more updates
* to occur in the future. Keep on running the
* update worker thread.
*/
queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
this_cpu_ptr(&vmstat_work),
round_jiffies_relative(sysctl_stat_interval));
}
}
/*
* Switch off vmstat processing and then fold all the remaining differentials
* until the diffs stay at zero. The function is used by NOHZ and can only be
* invoked when tick processing is not active.
*/
/*
* Check if the diffs for a certain cpu indicate that
* an update is needed.
*/
static bool need_update(int cpu)
{
struct zone *zone;
for_each_populated_zone(zone) {
struct per_cpu_pageset *p = per_cpu_ptr(zone->pageset, cpu);
BUILD_BUG_ON(sizeof(p->vm_stat_diff[0]) != 1);
#ifdef CONFIG_NUMA
BUILD_BUG_ON(sizeof(p->vm_numa_stat_diff[0]) != 2);
#endif
/*
* The fast way of checking if there are any vmstat diffs.
*/
if (memchr_inv(p->vm_stat_diff, 0, NR_VM_ZONE_STAT_ITEMS *
sizeof(p->vm_stat_diff[0])))
return true;
#ifdef CONFIG_NUMA
if (memchr_inv(p->vm_numa_stat_diff, 0, NR_VM_NUMA_STAT_ITEMS *
sizeof(p->vm_numa_stat_diff[0])))
return true;
#endif
}
return false;
}
/*
* Switch off vmstat processing and then fold all the remaining differentials
* until the diffs stay at zero. The function is used by NOHZ and can only be
* invoked when tick processing is not active.
*/
void quiet_vmstat(void)
{
if (system_state != SYSTEM_RUNNING)
return;
if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
return;
if (!need_update(smp_processor_id()))
return;
/*
* Just refresh counters and do not care about the pending delayed
* vmstat_update. It doesn't fire that often to matter and canceling
* it would be too expensive from this path.
* vmstat_shepherd will take care about that for us.
*/
refresh_cpu_vm_stats(false);
}
/*
* Shepherd worker thread that checks the
* differentials of processors that have their worker
* threads for vm statistics updates disabled because of
* inactivity.
*/
static void vmstat_shepherd(struct work_struct *w);
static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
static void vmstat_shepherd(struct work_struct *w)
{
int cpu;
get_online_cpus();
/* Check processors whose vmstat worker threads have been disabled */
for_each_online_cpu(cpu) {
struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
if (!delayed_work_pending(dw) && need_update(cpu) &&
!cpu_isolated(cpu))
queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
}
put_online_cpus();
schedule_delayed_work(&shepherd,
round_jiffies_relative(sysctl_stat_interval));
}
static void __init start_shepherd_timer(void)
{
int cpu;
for_each_possible_cpu(cpu)
INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
vmstat_update);
schedule_delayed_work(&shepherd,
round_jiffies_relative(sysctl_stat_interval));
}
static void __init init_cpu_node_state(void)
{
int node;
for_each_online_node(node) {
if (cpumask_weight(cpumask_of_node(node)) > 0)
node_set_state(node, N_CPU);
}
}
static int vmstat_cpu_online(unsigned int cpu)
{
refresh_zone_stat_thresholds();
node_set_state(cpu_to_node(cpu), N_CPU);
return 0;
}
static int vmstat_cpu_down_prep(unsigned int cpu)
{
cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
return 0;
}
static int vmstat_cpu_dead(unsigned int cpu)
{
const struct cpumask *node_cpus;
int node;
node = cpu_to_node(cpu);
refresh_zone_stat_thresholds();
node_cpus = cpumask_of_node(node);
if (cpumask_weight(node_cpus) > 0)
return 0;
node_clear_state(node, N_CPU);
return 0;
}
#endif
struct workqueue_struct *mm_percpu_wq;
void __init init_mm_internals(void)
{
int ret __maybe_unused;
mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
#ifdef CONFIG_SMP
ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead",
NULL, vmstat_cpu_dead);
if (ret < 0)
pr_err("vmstat: failed to register 'dead' hotplug state\n");
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmstat:online",
vmstat_cpu_online,
vmstat_cpu_down_prep);
if (ret < 0)
pr_err("vmstat: failed to register 'online' hotplug state\n");
get_online_cpus();
init_cpu_node_state();
put_online_cpus();
start_shepherd_timer();
#endif
#ifdef CONFIG_PROC_FS
proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
#endif
}
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
/*
* Return an index indicating how much of the available free memory is
* unusable for an allocation of the requested size.
*/
static int unusable_free_index(unsigned int order,
struct contig_page_info *info)
{
/* No free memory is interpreted as all free memory is unusable */
if (info->free_pages == 0)
return 1000;
/*
* Index should be a value between 0 and 1. Return a value to 3
* decimal places.
*
* 0 => no fragmentation
* 1 => high fragmentation
*/
return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages);
}
static void unusable_show_print(struct seq_file *m,
pg_data_t *pgdat, struct zone *zone)
{
unsigned int order;
int index;
struct contig_page_info info;
seq_printf(m, "Node %d, zone %8s ",
pgdat->node_id,
zone->name);
for (order = 0; order < MAX_ORDER; ++order) {
fill_contig_page_info(zone, order, &info);
index = unusable_free_index(order, &info);
seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
}
seq_putc(m, '\n');
}
/*
* Display unusable free space index
*
* The unusable free space index measures how much of the available free
* memory cannot be used to satisfy an allocation of a given size and is a
* value between 0 and 1. The higher the value, the more of free memory is
* unusable and by implication, the worse the external fragmentation is. This
* can be expressed as a percentage by multiplying by 100.
*/
static int unusable_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
/* check memoryless node */
if (!node_state(pgdat->node_id, N_MEMORY))
return 0;
walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
return 0;
}
static const struct seq_operations unusable_op = {
.start = frag_start,
.next = frag_next,
.stop = frag_stop,
.show = unusable_show,
};
static int unusable_open(struct inode *inode, struct file *file)
{
return seq_open(file, &unusable_op);
}
static const struct file_operations unusable_file_ops = {
.open = unusable_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static void extfrag_show_print(struct seq_file *m,
pg_data_t *pgdat, struct zone *zone)
{
unsigned int order;
int index;
/* Alloc on stack as interrupts are disabled for zone walk */
struct contig_page_info info;
seq_printf(m, "Node %d, zone %8s ",
pgdat->node_id,
zone->name);
for (order = 0; order < MAX_ORDER; ++order) {
fill_contig_page_info(zone, order, &info);
index = __fragmentation_index(order, &info);
seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
}
seq_putc(m, '\n');
}
/*
* Display fragmentation index for orders that allocations would fail for
*/
static int extfrag_show(struct seq_file *m, void *arg)
{
pg_data_t *pgdat = (pg_data_t *)arg;
walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
return 0;
}
static const struct seq_operations extfrag_op = {
.start = frag_start,
.next = frag_next,
.stop = frag_stop,
.show = extfrag_show,
};
static int extfrag_open(struct inode *inode, struct file *file)
{
return seq_open(file, &extfrag_op);
}
static const struct file_operations extfrag_file_ops = {
.open = extfrag_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init extfrag_debug_init(void)
{
struct dentry *extfrag_debug_root;
extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
debugfs_create_file("unusable_index", 0444, extfrag_debug_root, NULL,
&unusable_file_ops);
debugfs_create_file("extfrag_index", 0444, extfrag_debug_root, NULL,
&extfrag_file_ops);
return 0;
}
module_init(extfrag_debug_init);
#endif