4922049993
Changes in 5.10.163
usb: musb: remove extra check in musb_gadget_vbus_draw
arm64: dts: qcom: ipq6018-cp01-c1: use BLSPI1 pins
arm64: dts: qcom: msm8996: fix GPU OPP table
ARM: dts: qcom: apq8064: fix coresight compatible
arm64: dts: qcom: sdm630: fix UART1 pin bias
arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
arm64: dts: qcom: msm8916: Drop MSS fallback compatible
objtool, kcsan: Add volatile read/write instrumentation to whitelist
ARM: dts: stm32: Drop stm32mp15xc.dtsi from Avenger96
ARM: dts: stm32: Fix AV96 WLAN regulator gpio property
drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
soc: qcom: llcc: make irq truly optional
soc: qcom: apr: make code more reuseable
soc: qcom: apr: Add check for idr_alloc and of_property_read_string_index
arm: dts: spear600: Fix clcd interrupt
soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of pm_runtime_get_sync
soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
arm64: dts: ti: k3-am65-main: Drop dma-coherent in crypto node
arm64: dts: ti: k3-j721e-main: Drop dma-coherent in crypto node
arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
arm64: dts: mt2712e: Fix unit address for pinctrl node
arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
arm64: dts: mediatek: pumpkin-common: Fix devicetree warnings
arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: turris-omnia: Add ethernet aliases
ARM: dts: turris-omnia: Add switch port 6 node
arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
pstore/ram: Fix error return code in ramoops_probe()
ARM: mmp: fix timer_read delay
pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
tpm/tpm_ftpm_tee: Fix error handling in ftpm_mod_init()
tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
sched/fair: Cleanup task_util and capacity type
sched/uclamp: Fix relationship between uclamp and migration margin
cpuidle: dt: Return the correct numbers of parsed idle states
alpha: fix syscall entry in !AUDUT_SYSCALL case
PM: hibernate: Fix mistake in kerneldoc comment
fs: don't audit the capability check in simple_xattr_list()
cpufreq: qcom-hw: Fix memory leak in qcom_cpufreq_hw_read_lut()
selftests/ftrace: event_triggers: wait longer for test_event_enable
perf: Fix possible memleak in pmu_dev_alloc()
lib/debugobjects: fix stat count and optimize debug_objects_mem_init
platform/x86: huawei-wmi: fix return value calculation
timerqueue: Use rb_entry_safe() in timerqueue_getnext()
proc: fixup uptime selftest
lib/fonts: fix undefined behavior in bit shift for get_default_font
ocfs2: fix memory leak in ocfs2_stack_glue_init()
MIPS: vpe-mt: fix possible memory leak while module exiting
MIPS: vpe-cmp: fix possible memory leak while module exiting
selftests/efivarfs: Add checking of the test return value
PNP: fix name memory leak in pnp_alloc_dev()
perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
perf/x86/intel/uncore: Fix reference count leak in snr_uncore_mmio_map()
perf/x86/intel/uncore: Fix reference count leak in __uncore_imc_init_box()
platform/chrome: cros_usbpd_notify: Fix error handling in cros_usbpd_notify_init()
irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
nfsd: don't call nfsd_file_put from client states seqfile display
genirq/irqdesc: Don't try to remove non-existing sysfs files
cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
lib/notifier-error-inject: fix error when writing -errno to debugfs file
docs: fault-injection: fix non-working usage of negative values
debugfs: fix error when writing negative value to atomic_t debugfs file
ocfs2: ocfs2_mount_volume does cleanup job before return error
ocfs2: rewrite error handling of ocfs2_fill_super
ocfs2: fix memory leak in ocfs2_mount_volume()
rapidio: fix possible name leaks when rio_add_device() fails
rapidio: rio: fix possible name leak in rio_register_mport()
clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
clocksource/drivers/sh_cmt: Access registers according to spec
futex: Move to kernel/futex/
futex: Resend potentially swallowed owner death notification
cpu/hotplug: Make target_store() a nop when target == state
clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()
ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
x86/xen: Fix memory leak in xen_init_lock_cpu()
xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
PM: runtime: Improve path in rpm_idle() when no callback
PM: runtime: Do not call __rpm_callback() from rpm_idle()
platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register()
MIPS: BCM63xx: Add check for NULL for clk in clk_enable
MIPS: OCTEON: warn only once if deprecated link status is being used
fs: sysv: Fix sysv_nblocks() returns wrong value
rapidio: fix possible UAF when kfifo_alloc() fails
eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
relay: fix type mismatch when allocating memory in relay_create_buf()
hfs: Fix OOB Write in hfs_asc2mac
rapidio: devices: fix missing put_device in mport_cdev_open
wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
wifi: rtl8xxxu: Fix reading the vendor of combo chips
drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge
libbpf: Fix use-after-free in btf_dump_name_dups
libbpf: Fix null-pointer dereference in find_prog_by_sec_insn()
pata_ipx4xx_cf: Fix unsigned comparison with less than zero
media: coda: jpeg: Add check for kmalloc
media: i2c: ad5820: Fix error path
venus: pm_helpers: Fix error check in vcodec_domains_get()
media: exynos4-is: Use v4l2_async_notifier_add_fwnode_remote_subdev
media: exynos4-is: don't rely on the v4l2_async_subdev internals
can: kvaser_usb: do not increase tx statistics when sending error message frames
can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
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: Handle CMD_ERROR_EVENT
can: kvaser_usb_leaf: Set Warning state even without bus errors
can: kvaser_usb_leaf: Fix improved state not being reported
can: kvaser_usb_leaf: Fix wrong CAN state after stopping
can: kvaser_usb_leaf: Fix bogus restart events
can: kvaser_usb: Add struct kvaser_usb_busparams
can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming
drm/rockchip: lvds: fix PM usage counter unbalance in poweron
clk: renesas: r9a06g032: Repair grave increment error
spi: Update reference to struct spi_controller
drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
ima: Fix fall-through warnings for Clang
ima: Handle -ESTALE returned by ima_filter_rule_match()
drm/msm/hdmi: switch to drm_bridge_connector
drm/msm/hdmi: drop unused GPIO support
bpf: Fix slot type check in check_stack_write_var_off
media: vivid: fix compose size exceed boundary
media: platform: exynos4-is: fix return value check in fimc_md_probe()
bpf: propagate precision in ALU/ALU64 operations
bpf: Check the other end of slot_type for STACK_SPILL
bpf: propagate precision across all frames, not just the last one
clk: qcom: gcc-sm8250: Use retention mode for USB GDSCs
mtd: Fix device name leak when register device failed in add_mtd_device()
Input: joystick - fix Kconfig warning for JOYSTICK_ADC
wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
media: camss: Clean up received buffers on failed start of streaming
net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
rxrpc: Fix ack.bufferSize to be 0 when generating an ack
drm/radeon: Add the missed acpi_put_table() to fix memory leak
drm/mediatek: Modify dpi power on/off sequence.
ASoC: pxa: fix null-pointer dereference in filter()
regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
drm/fourcc: Add packed 10bit YUV 4:2:0 format
drm/fourcc: Fix vsub/hsub for Q410 and Q401
integrity: Fix memory leakage in keyring allocation error path
ima: Fix misuse of dereference of pointer in template_desc_init_fields()
wifi: ath10k: Fix return value in ath10k_pci_init()
mtd: lpddr2_nvm: Fix possible null-ptr-deref
Input: elants_i2c - properly handle the reset GPIO when power is off
media: vidtv: Fix use-after-free in vidtv_bridge_dvb_init()
media: solo6x10: fix possible memory leak in solo_sysfs_init()
media: platform: exynos4-is: Fix error handling in fimc_md_init()
media: videobuf-dma-contig: use dma_mmap_coherent
inet: add READ_ONCE(sk->sk_bound_dev_if) in inet_csk_bind_conflict()
bpf: Move skb->len == 0 checks into __bpf_redirect
HID: hid-sensor-custom: set fixed size for custom attributes
ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
regulator: core: use kfree_const() to free space conditionally
clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
drm/amdgpu: fix pci device refcount leak
bonding: fix link recovery in mode 2 when updelay is nonzero
mtd: maps: pxa2xx-flash: fix memory leak in probe
drbd: fix an invalid memory access caused by incorrect use of list iterator
ASoC: qcom: Add checks for devm_kcalloc
media: vimc: Fix wrong function called when vimc_init() fails
media: imon: fix a race condition in send_packet()
clk: imx: replace osc_hdmi with dummy
pinctrl: pinconf-generic: add missing of_node_put()
media: dvb-core: Fix ignored return value in dvb_register_frontend()
media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
ASoC: dt-bindings: wcd9335: fix reset line polarity in example
ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
NFSv4.2: Fix a memory stomp in decode_attr_security_label
NFSv4.2: Fix initialisation of struct nfs4_label
NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
NFS: Fix an Oops in nfs_d_automount()
ALSA: asihpi: fix missing pci_disable_device()
wifi: iwlwifi: mvm: fix double free on tx path.
ASoC: mediatek: mt8173: Fix debugfs registration for components
ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
drm/amd/pm/smu11: BACO is supported when it's in BACO state
drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
netfilter: conntrack: set icmpv6 redirects as RELATED
bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
bonding: uninitialized variable in bond_miimon_inspect()
spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
wifi: mac80211: fix memory leak in ieee80211_if_add()
wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
wifi: mt76: fix coverity overrun-call in mt76_get_txpower()
regulator: core: fix module refcount leak in set_supply()
clk: qcom: clk-krait: fix wrong div2 functions
hsr: Add a rcu-read lock to hsr_forward_skb().
net: hsr: generate supervision frame without HSR/PRP tag
hsr: Disable netpoll.
hsr: Synchronize sending frames to have always incremented outgoing seq nr.
hsr: Synchronize sequence number updates.
configfs: fix possible memory leak in configfs_create_dir()
regulator: core: fix resource leak in regulator_register()
hwmon: (jc42) Convert register access and caching to regmap/regcache
hwmon: (jc42) Restore the min/max/critical temperatures on resume
bpf, sockmap: fix race in sock_map_free()
ALSA: pcm: Set missing stop_operating flag at undoing trigger start
media: saa7164: fix missing pci_disable_device()
ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
SUNRPC: Fix missing release socket in rpc_sockname()
NFSv4.x: Fail client initialisation if state manager thread can't run
mmc: alcor: fix return value check of mmc_add_host()
mmc: moxart: fix return value check of mmc_add_host()
mmc: mxcmmc: fix return value check of mmc_add_host()
mmc: pxamci: fix return value check of mmc_add_host()
mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
mmc: toshsd: fix return value check of mmc_add_host()
mmc: vub300: fix return value check of mmc_add_host()
mmc: wmt-sdmmc: fix return value check of mmc_add_host()
mmc: atmel-mci: fix return value check of mmc_add_host()
mmc: omap_hsmmc: fix return value check of mmc_add_host()
mmc: meson-gx: fix return value check of mmc_add_host()
mmc: via-sdmmc: fix return value check of mmc_add_host()
mmc: wbsd: fix return value check of mmc_add_host()
mmc: mmci: fix return value check of mmc_add_host()
media: c8sectpfe: Add of_node_put() when breaking out of loop
media: coda: Add check for dcoda_iram_alloc
media: coda: Add check for kmalloc
clk: samsung: Fix memory leak in _samsung_clk_register_pll()
spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
wifi: rtl8xxxu: Fix the channel width reporting
wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
blktrace: Fix output non-blktrace event when blk_classic option enabled
clk: socfpga: clk-pll: Remove unused variable 'rc'
clk: socfpga: use clk_hw_register for a5/c5
clk: socfpga: Fix memory leak in socfpga_gate_init()
net: vmw_vsock: vmci: Check memcpy_from_msg()
net: defxx: Fix missing err handling in dfx_init()
net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
net: farsync: Fix kmemleak when rmmods farsync
net/tunnel: wait until all sk_user_data reader finish before releasing the sock
net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
net: amd-xgbe: Fix logic around active and passive cables
net: amd-xgbe: Check only the minimum speed for active/passive cables
can: tcan4x5x: Remove invalid write in clear_interrupts
net: lan9303: Fix read error execution path
ntb_netdev: Use dev_kfree_skb_any() in interrupt context
sctp: sysctl: make extra pointers netns aware
Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
stmmac: fix potential division by 0
apparmor: fix a memleak in multi_transaction_new()
apparmor: fix lockdep warning when removing a namespace
apparmor: Fix abi check to include v8 abi
crypto: sun8i-ss - use dma_addr instead u32
crypto: nitrox - avoid double free on error path in nitrox_sriov_init()
scsi: core: Fix a race between scsi_done() and scsi_timeout()
apparmor: Use pointer to struct aa_label for lbs_cred
PCI: dwc: Fix n_fts[] array overrun
RDMA/core: Fix order of nldev_exit call
PCI: pci-epf-test: Register notifier if only core_init_notifier is enabled
f2fs: Fix the race condition of resize flag between resizefs
crypto: rockchip - do not do custom power management
crypto: rockchip - do not store mode globally
crypto: rockchip - add fallback for cipher
crypto: rockchip - add fallback for ahash
crypto: rockchip - better handle cipher key
crypto: rockchip - remove non-aligned handling
crypto: rockchip - delete unneeded variable initialization
crypto: rockchip - rework by using crypto_engine
apparmor: Fix memleak in alloc_ns()
f2fs: fix normal discard process
RDMA/siw: Fix immediate work request flush to completion queue
RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
RDMA/siw: Set defined status for work completion with undefined status
scsi: scsi_debug: Fix a warning in resp_write_scat()
crypto: ccree - Remove debugfs when platform_driver_register failed
crypto: cryptd - Use request context instead of stack for sub-request
crypto: hisilicon/qm - add missing pci_dev_put() in q_num_set()
RDMA/hns: Repacing 'dseg_len' by macros in fill_ext_sge_inl_data()
RDMA/hns: Fix ext_sge num error when post send
PCI: Check for alloc failure in pci_request_irq()
RDMA/hfi: Decrease PCI device reference count in error path
crypto: ccree - Make cc_debugfs_global_fini() available for module init function
RDMA/hns: fix memory leak in hns_roce_alloc_mr()
RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
scsi: hpsa: Fix possible memory leak in hpsa_init_one()
crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
padata: Always leave BHs disabled when running ->parallel()
padata: Fix list iterator in padata_do_serial()
scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
scsi: hpsa: Fix error handling in hpsa_add_sas_host()
scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
scsi: scsi_debug: Fix a warning in resp_verify()
scsi: scsi_debug: Fix a warning in resp_report_zones()
scsi: fcoe: Fix possible name leak when device_register() fails
scsi: scsi_debug: Fix possible name leak in sdebug_add_host_helper()
scsi: ipr: Fix WARNING in ipr_init()
scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
scsi: snic: Fix possible UAF in snic_tgt_create()
RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
f2fs: avoid victim selection from previous victim section
RDMA/nldev: Fix failure to send large messages
crypto: amlogic - Remove kcalloc without check
crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
riscv/mm: add arch hook arch_clear_hugepage_flags
RDMA/hfi1: Fix error return code in parse_platform_config()
RDMA/srp: Fix error return code in srp_parse_options()
orangefs: Fix sysfs not cleanup when dev init failed
RDMA/hns: Fix PBL page MTR find
RDMA/hns: Fix page size cap from firmware
crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
hwrng: amd - Fix PCI device refcount leak
hwrng: geode - Fix PCI device refcount leak
IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
drivers: dio: fix possible memory leak in dio_init()
serial: tegra: Read DMA status before terminating
class: fix possible memory leak in __class_register()
vfio: platform: Do not pass return buffer to ACPI _RST method
uio: uio_dmem_genirq: Fix missing unlock in irq configuration
uio: uio_dmem_genirq: Fix deadlock between irq config and handling
usb: fotg210-udc: Fix ages old endianness issues
staging: vme_user: Fix possible UAF in tsi148_dma_list_add
usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
usb: typec: tipd: Fix spurious fwnode_handle_put in error path
serial: amba-pl011: avoid SBSA UART accessing DMACR register
serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
serial: pch: Fix PCI device refcount leak in pch_request_dma()
tty: serial: clean up stop-tx part in altera_uart_tx_chars()
tty: serial: altera_uart_{r,t}x_chars() need only uart_port
serial: altera_uart: fix locking in polling mode
serial: sunsab: Fix error handling in sunsab_init()
test_firmware: fix memory leak in test_firmware_init()
misc: ocxl: fix possible name leak in ocxl_file_register_afu()
ocxl: fix pci device refcount leak when calling get_function_0()
misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os
firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe()
cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
iio: temperature: ltc2983: make bulk write buffer DMA-safe
genirq: Add IRQF_NO_AUTOEN for request_irq/nmi()
iio:imu:adis: Use IRQF_NO_AUTOEN instead of irq request then disable
iio: adis: handle devices that cannot unmask the drdy pin
iio: adis: stylistic changes
iio:imu:adis: Move exports into IIO_ADISLIB namespace
iio: adis: add '__adis_enable_irq()' implementation
counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
usb: gadget: f_hid: optional SETUP/SET_REPORT mode
usb: gadget: f_hid: fix f_hidg lifetime vs cdev
usb: gadget: f_hid: fix refcount leak on error path
drivers: mcb: fix resource leak in mcb_probe()
mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
chardev: fix error handling in cdev_device_add()
i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
staging: rtl8192u: Fix use after free in ieee80211_rx()
staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
vme: Fix error not catched in fake_init()
gpiolib: Get rid of redundant 'else'
gpiolib: cdev: fix NULL-pointer dereferences
i2c: mux: reg: check return value after calling platform_get_resource()
i2c: ismt: Fix an out-of-bounds bug in ismt_access()
usb: storage: Add check for kcalloc
tracing/hist: Fix issue of losting command info in error_log
samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
thermal/drivers/imx8mm_thermal: Validate temperature range
fbdev: ssd1307fb: Drop optional dependency
fbdev: pm2fb: fix missing pci_disable_device()
fbdev: via: Fix error in via_core_init()
fbdev: vermilion: decrease reference count in error path
fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
power: supply: fix residue sysfs file in error handle route of __power_supply_register()
perf trace: Return error if a system call doesn't exist
perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
perf trace: Handle failure when trace point folder is missed
perf symbol: correction while adjusting symbol
HSI: omap_ssi_core: Fix error handling in ssi_init()
power: supply: fix null pointer dereferencing in power_supply_get_battery_info
RDMA/siw: Fix pointer cast warning
iommu/sun50i: Fix reset release
iommu/sun50i: Consider all fault sources for reset
iommu/sun50i: Fix R/W permission check
iommu/sun50i: Fix flush size
phy: usb: s2 WoL wakeup_count not incremented for USB->Eth devices
include/uapi/linux/swab: Fix potentially missing __always_inline
pwm: tegra: Improve required rate calculation
dmaengine: idxd: Fix crc_val field for completion record
rtc: rtc-cmos: Do not check ACPI_FADT_LOW_POWER_S0
rtc: cmos: Fix event handler registration ordering issue
rtc: cmos: Fix wake alarm breakage
rtc: cmos: fix build on non-ACPI platforms
rtc: cmos: Call cmos_wake_setup() from cmos_do_probe()
rtc: cmos: Call rtc_wake_setup() from cmos_do_probe()
rtc: cmos: Eliminate forward declarations of some functions
rtc: cmos: Rename ACPI-related functions
rtc: cmos: Disable ACPI RTC event on removal
rtc: snvs: Allow a time difference on clock register read
rtc: pcf85063: Fix reading alarm
iommu/amd: Fix pci device refcount leak in ppr_notifier()
iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
macintosh: fix possible memory leak in macio_add_one_device()
macintosh/macio-adb: check the return value of ioremap()
powerpc/52xx: Fix a resource leak in an error handling path
cxl: Fix refcount leak in cxl_calc_capp_routing
powerpc/xmon: Enable breakpoints on 8xx
powerpc/xmon: Fix -Wswitch-unreachable warning in bpt_cmds
powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
kbuild: remove unneeded mkdir for external modules_install
kbuild: unify modules(_install) for in-tree and external modules
kbuild: refactor single builds of *.ko
powerpc/perf: callchain validate kernel stack pointer bounds
powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
powerpc/hv-gpci: Fix hv_gpci event list
selftests/powerpc: Fix resource leaks
iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY
pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
remoteproc: qcom_q6v5_pas: disable wakeup on probe fail or remove
remoteproc: qcom_q6v5_pas: detach power domains on remove
remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
powerpc/eeh: Drop redundant spinlock initialization
powerpc/pseries/eeh: use correct API for error log size
netfilter: flowtable: really fix NAT IPv6 offload
rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
rtc: pcf85063: fix pcf85063_clkout_control
NFSD: Remove spurious cb_setup_err tracepoint
nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
net: macsec: fix net device access prior to holding a lock
mISDN: hfcsusb: 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: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
nfc: pn533: Clear nfc_target before being used
r6040: Fix kmemleak in probe and remove
net: switch to storing KCOV handle directly in sk_buff
net: add inline function skb_csum_is_sctp
net: igc: use skb_csum_is_sctp instead of protocol check
net: add a helper to avoid issues with HW TX timestamping and SO_TXTIME
igc: Enhance Qbv scheduling by using first flag bit
igc: Use strict cycles for Qbv scheduling
igc: Add checking for basetime less than zero
igc: recalculate Qbv end_time by considering cycle time
igc: Lift TAPRIO schedule restriction
igc: Set Qbv start_time and end_time to end_time if not being configured in GCL
rtc: mxc_v2: Add missing clk_disable_unprepare()
selftests: devlink: fix the fd redirect in dummy_reporter_test
openvswitch: Fix flow lookup to use unmasked key
skbuff: Account for tail adjustment during pull operations
mailbox: zynq-ipi: fix error handling while device_register() fails
net_sched: reject TCF_EM_SIMPLE case for complex ematch module
rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
myri10ge: Fix an error handling path in myri10ge_probe()
net: stream: purge sk_error_queue in sk_stream_kill_queues()
rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
arm64: make is_ttbrX_addr() noinstr-safe
video: hyperv_fb: Avoid taking busy spinlock on panic path
x86/hyperv: Remove unregister syscore call from Hyper-V cleanup
binfmt_misc: fix shift-out-of-bounds in check_special_flags
fs: jfs: fix shift-out-of-bounds in dbAllocAG
udf: Avoid double brelse() in udf_rename()
fs: jfs: fix shift-out-of-bounds in dbDiscardAG
ACPICA: Fix error code path in acpi_ds_call_control_method()
nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
nilfs2: fix shift-out-of-bounds due to too large exponent of block size
acct: fix potential integer overflow in encode_comp_t()
hfs: fix OOB Read in __hfs_brec_find
drm/etnaviv: add missing quirks for GC300
brcmfmac: return error when getting invalid max_flowrings from dongle
wifi: ath9k: verify the expected usb_endpoints are present
wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
ipmi: fix memleak when unload ipmi driver
drm/amd/display: prevent memory leak
qed (gcc13): use u16 for fid to be big enough
bpf: make sure skb->len != 0 when redirecting to a tunneling device
net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
hamradio: baycom_epp: Fix return type of baycom_send_packet()
wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()
igb: Do not free q_vector unless new one was allocated
drm/amdgpu: Fix type of second parameter in trans_msg() callback
drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback
s390/ctcm: Fix return type of ctc{mp,}m_tx()
s390/netiucv: Fix return type of netiucv_tx()
s390/lcs: Fix return type of lcs_start_xmit()
drm/msm: Use drm_mode_copy()
drm/rockchip: Use drm_mode_copy()
drm/sti: Use drm_mode_copy()
drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
md/raid1: stop mdx_raid1 thread when raid1 array run failed
drm/amd/display: fix array index out of bound error in bios parser
net: add atomic_long_t to net_device_stats fields
mrp: introduce active flags to prevent UAF when applicant uninit
ppp: associate skb with a device at tx
bpf: Prevent decl_tag from being referenced in func_proto arg
ethtool: avoiding integer overflow in ethtool_phys_id()
media: dvb-frontends: fix leak of memory fw
media: dvbdev: adopts refcnt to avoid UAF
media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
blk-mq: fix possible memleak when register 'hctx' failed
libbpf: Avoid enum forward-declarations in public API in C++ mode
regulator: core: fix use_count leakage when handling boot-on
mmc: f-sdh30: Add quirks for broken timeout clock capability
mmc: renesas_sdhi: better reset from HS400 mode
media: si470x: Fix use-after-free in si470x_int_in_callback()
clk: st: Fix memory leak in st_of_quadfs_setup()
hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
hwmon: (jc42) Fix missing unlock on error in jc42_write()
ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
ALSA: hda: add snd_hdac_stop_streams() helper
ASoC: Intel: Skylake: Fix driver hang during shutdown
ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
ASoC: wm8994: Fix potential deadlock
ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()
ASoC: rt5670: Remove unbalanced pm_runtime_put()
LoadPin: Ignore the "contents" argument of the LSM hooks
pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
perf debug: Set debug_peo_args and redirect_to_stderr variable to correct values in perf_quiet_option()
afs: Fix lost servers_outstanding count
pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
ima: Simplify ima_lsm_copy_rule
ALSA: usb-audio: add the quirk for KT0206 device
ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode
usb: dwc3: core: defer probe on ulpi_read_id timeout
HID: wacom: Ensure bootloader PID is usable in hidraw mode
HID: mcp2221: don't connect hidraw
reiserfs: Add missing calls to reiserfs_security_free()
iio: adc: ad_sigma_delta: do not use internal iio_dev lock
iio: adc128s052: add proper .data members in adc128_of_match table
regulator: core: fix deadlock on regulator enable
gcov: add support for checksum field
ovl: fix use inode directly in rcu-walk mode
media: dvbdev: fix build warning due to comments
media: dvbdev: fix refcnt bug
pwm: tegra: Fix 32 bit build
usb: dwc3: qcom: Fix memory leak in dwc3_qcom_interconnect_init
cifs: fix oops during encryption
nvme-pci: fix doorbell buffer value endianness
nvme-pci: fix mempool alloc size
nvme-pci: fix page size checks
ata: ahci: Fix PCS quirk application for suspend
nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
nvmet: don't defer passthrough commands with trivial effects to the workqueue
objtool: Fix SEGFAULT
powerpc/rtas: avoid device tree lookups in rtas_os_term()
powerpc/rtas: avoid scheduling in rtas_os_term()
HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
HID: plantronics: Additional PIDs for double volume key presses quirk
pstore/zone: Use GFP_ATOMIC to allocate zone buffer
hfsplus: fix bug causing custom uid and gid being unable to be assigned with mount
binfmt: Fix error return code in load_elf_fdpic_binary()
ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
ALSA: line6: correct midi status byte when receiving data from podxt
ALSA: line6: fix stack overflow in line6_midi_transmit
pnode: terminate at peers of source
md: fix a crash in mempool_free
mm, compaction: fix fast_isolate_around() to stay within boundaries
f2fs: should put a page when checking the summary info
mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
tpm: acpi: Call acpi_put_table() to fix memory leak
tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
kcsan: Instrument memcpy/memset/memmove with newer Clang
ASoC: Intel/SOF: use set_stream() instead of set_tdm_slots() for HDAudio
ASoC/SoundWire: dai: expand 'stream' concept beyond SoundWire
net/mlx5e: Fix nullptr in mlx5e_tc_add_fdb_flow()
wifi: rtlwifi: remove always-true condition pointed out by GCC 12
wifi: rtlwifi: 8192de: correct checking of IQK reload
torture: Exclude "NOHZ tick-stop error" from fatal errors
rcu: Prevent lockdep-RCU splats on lock acquisition/release
net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
net/af_packet: make sure to pull mac header
media: stv0288: use explicitly signed char
soc: qcom: Select REMAP_MMIO for LLCC driver
kest.pl: Fix grub2 menu handling for rebooting
ktest.pl minconfig: Unset configs instead of just removing them
jbd2: use the correct print format
arm64: dts: qcom: sdm845-db845c: correct SPI2 pins drive strength
mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
btrfs: fix resolving backrefs for inline extent followed by prealloc
ARM: ux500: do not directly dereference __iomem
arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
selftests: Use optional USERCFLAGS and USERLDFLAGS
PM/devfreq: governor: Add a private governor_data for governor
cpufreq: Init completion before kobject_init_and_add()
ALSA: patch_realtek: Fix Dell Inspiron Plus 16
ALSA: hda/realtek: Apply dual codec fixup for Dell Latitude laptops
dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
dm thin: Use last transaction's pmd->root when commit failed
dm thin: resume even if in FAIL mode
dm thin: Fix UAF in run_timer_softirq()
dm integrity: Fix UAF in dm_integrity_dtr()
dm clone: Fix UAF in clone_dtr()
dm cache: Fix UAF in destroy()
dm cache: set needs_check flag after aborting metadata
tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
perf/core: Call LSM hook after copying perf_event_attr
KVM: nVMX: Inject #GP, not #UD, if "generic" VMXON CR0/CR4 check fails
x86/microcode/intel: Do not retry microcode reloading on the APs
ftrace/x86: Add back ftrace_expected for ftrace bug reports
x86/kprobes: Fix kprobes instruction boudary check with CONFIG_RETHUNK
tracing/hist: Fix wrong return value in parse_action_params()
tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line
staging: media: tegra-video: fix chan->mipi value on error
ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
media: dvb-core: Fix double free in dvb_register_device()
media: dvb-core: Fix UAF due to refcount races at releasing
cifs: fix confusing debug message
cifs: fix missing display of three mount options
rtc: ds1347: fix value written to century register
md/bitmap: Fix bitmap chunk size overflow issues
efi: Add iMac Pro 2017 to uefi skip cert quirk
wifi: wilc1000: sdio: fix module autoloading
ASoC: jz4740-i2s: Handle independent FIFO flush bits
ipmi: fix long wait in unload when IPMI disconnect
mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
ima: Fix a potential NULL pointer access in ima_restore_measurement_list
ipmi: fix use after free in _ipmi_destroy_user()
PCI: Fix pci_device_is_present() for VFs by checking PF
PCI/sysfs: Fix double free in error path
crypto: n2 - add missing hash statesize
driver core: Fix bus_type.match() error handling in __driver_attach()
iommu/amd: Fix ivrs_acpihid cmdline parsing code
remoteproc: core: Do pm_relax when in RPROC_OFFLINE state
parisc: led: Fix potential null-ptr-deref in start_task()
device_cgroup: Roll back to original exceptions after copy failure
drm/connector: send hotplug uevent on connector cleanup
drm/vmwgfx: Validate the box size for the snooped cursor
drm/i915/dsi: fix VBT send packet port selection for dual link DSI
drm/ingenic: Fix missing platform_driver_unregister() call in ingenic_drm_init()
ext4: silence the warning when evicting inode with dioread_nolock
ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop
ext4: fix use-after-free in ext4_orphan_cleanup
ext4: fix undefined behavior in bit shift for ext4_check_flag_values
ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
ext4: add helper to check quota inums
ext4: fix bug_on in __es_tree_search caused by bad quota inode
ext4: fix reserved cluster accounting in __es_remove_extent()
ext4: check and assert if marking an no_delete evicting inode dirty
ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
ext4: init quota for 'old.inode' in 'ext4_rename'
ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
ext4: fix corruption when online resizing a 1K bigalloc fs
ext4: fix error code return to user-space in ext4_get_branch()
ext4: avoid BUG_ON when creating xattrs
ext4: fix inode leak in ext4_xattr_inode_create() on an error path
ext4: initialize quota before expanding inode in setproject ioctl
ext4: avoid unaccounted block allocation when expanding inode
ext4: allocate extended attribute value in vmalloc area
drm/amdgpu: handle polaris10/11 overlap asics (v2)
drm/amdgpu: make display pinning more flexible (v2)
ARM: renumber bits related to _TIF_WORK_MASK
perf/x86/intel/uncore: Generalize I/O stacks to PMON mapping procedure
perf/x86/intel/uncore: Clear attr_update properly
btrfs: replace strncpy() with strscpy()
x86/mce: Get rid of msr_ops
x86/MCE/AMD: Clear DFR errors found in THR handler
media: s5p-mfc: Fix to handle reference queue during finishing
media: s5p-mfc: Clear workbit to handle error condition
media: s5p-mfc: Fix in register read and write for H264
perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data
x86/kprobes: Convert to insn_decode()
x86/kprobes: Fix optprobe optimization check with CONFIG_RETHUNK
staging: media: tegra-video: fix device_node use after free
ravb: Fix "failed to switch device to config mode" message during unbind
riscv/stacktrace: Fix stack output without ra on the stack top
riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument
ext4: goto right label 'failed_mount3a'
ext4: correct inconsistent error msg in nojournal mode
mm/highmem: Lift memcpy_[to|from]_page to core
ext4: use memcpy_to_page() in pagecache_write()
fs: ext4: initialize fsdata in pagecache_write()
ext4: move functions in super.c
ext4: simplify ext4 error translation
ext4: fix various seppling typos
ext4: fix leaking uninitialized memory in fast-commit journal
ext4: use kmemdup() to replace kmalloc + memcpy
mbcache: don't reclaim used entries
mbcache: add functions to delete entry if unused
ext4: remove EA inode entry from mbcache on inode eviction
ext4: unindent codeblock in ext4_xattr_block_set()
ext4: fix race when reusing xattr blocks
mbcache: automatically delete entries from cache on freeing
ext4: fix deadlock due to mbcache entry corruption
SUNRPC: ensure the matching upcall is in-flight upon downcall
bpf: pull before calling skb_postpull_rcsum()
drm/panfrost: Fix GEM handle creation ref-counting
vmxnet3: correctly report csum_level for encapsulated packet
veth: Fix race with AF_XDP exposing old or uninitialized descriptors
nfsd: shut down the NFSv4 state objects before the filecache
net: hns3: add interrupts re-initialization while doing VF FLR
net: sched: fix memory leak in tcindex_set_parms
qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
nfc: Fix potential resource leaks
vhost/vsock: Fix error handling in vhost_vsock_init()
vringh: fix range used in iotlb_translate()
vhost: fix range used in translate_desc()
net/mlx5: Add forgotten cleanup calls into mlx5_init_once() error path
net/mlx5: Avoid recovery in probe flows
net/mlx5e: IPoIB, Don't allow CQE compression to be turned on by default
net/mlx5e: Fix hw mtu initializing at XDP SQ allocation
net: amd-xgbe: add missed tasklet_kill
net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
drm/meson: Reduce the FIFO lines held when AFBC is not used
filelock: new helper: vfs_inode_has_locks
ceph: switch to vfs_inode_has_locks() to fix file lock bug
gpio: sifive: Fix refcount leak in sifive_gpio_probe
net: sched: atm: dont intepret cls results when asked to drop
net: sched: cbq: dont intepret cls results when asked to drop
netfilter: ipset: fix hash:net,port,net hang with /0 subnet
netfilter: ipset: Rework long task execution when adding/deleting entries
perf tools: Fix resources leak in perf_data__open_dir()
drivers/net/bonding/bond_3ad: return when there's no aggregator
usb: rndis_host: Secure rndis_query check against int overflow
drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
caif: fix memory leak in cfctrl_linkup_request()
udf: Fix extension of the last extent in the file
ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
nvme: fix multipath crash caused by flush request when blktrace is enabled
x86/bugs: Flush IBP in ib_prctl_set()
nfsd: fix handling of readdir in v4root vs. mount upcall timeout
fbdev: matroxfb: G200eW: Increase max memory from 1 MB to 16 MB
riscv: uaccess: fix type of 0 variable on error in get_user()
drm/i915/gvt: fix gvt debugfs destroy
drm/i915/gvt: fix vgpu debugfs clean in remove
ext4: don't allow journal inode to have encrypt flag
selftests: set the BUILD variable to absolute path
hfs/hfsplus: use WARN_ON for sanity check
hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
mbcache: Avoid nesting of cache->c_list_lock under bit locks
efi: random: combine bootloader provided RNG seed with RNG protocol output
io_uring: Fix unsigned 'res' comparison with zero in io_fixup_rw_res()
parisc: Align parisc MADV_XXX constants with all other architectures
ext4: disable fast-commit of encrypted dir operations
ext4: don't set up encryption key during jbd2 transaction
fsl_lpuart: Don't enable interrupts too early
serial: fixup backport of "serial: Deassert Transmit Enable on probe in driver-specific way"
mptcp: mark ops structures as ro_after_init
mptcp: remove MPTCP 'ifdef' in TCP SYN cookies
mptcp: dedicated request sock for subflow in v6
mptcp: use proper req destructor for IPv6
net: sched: disallow noqueue for qdisc classes
net/ulp: prevent ULP without clone op from entering the LISTEN status
ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
ALSA: hda - Enable headset mic on another Dell laptop with ALC3254
Linux 5.10.163
Change-Id: I9026971760be8484f1e1fa607f9f91243cc87785
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2721 lines
72 KiB
C
2721 lines
72 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* linux/kernel/power/snapshot.c
|
|
*
|
|
* This file provides system snapshot/restore functionality for swsusp.
|
|
*
|
|
* Copyright (C) 1998-2005 Pavel Machek <pavel@ucw.cz>
|
|
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "PM: hibernation: " fmt
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/suspend.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/device.h>
|
|
#include <linux/init.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/nmi.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/console.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/list.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/set_memory.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
#include <asm/mmu_context.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/io.h>
|
|
|
|
#include "power.h"
|
|
|
|
#if defined(CONFIG_STRICT_KERNEL_RWX) && defined(CONFIG_ARCH_HAS_SET_MEMORY)
|
|
static bool hibernate_restore_protection;
|
|
static bool hibernate_restore_protection_active;
|
|
|
|
void enable_restore_image_protection(void)
|
|
{
|
|
hibernate_restore_protection = true;
|
|
}
|
|
|
|
static inline void hibernate_restore_protection_begin(void)
|
|
{
|
|
hibernate_restore_protection_active = hibernate_restore_protection;
|
|
}
|
|
|
|
static inline void hibernate_restore_protection_end(void)
|
|
{
|
|
hibernate_restore_protection_active = false;
|
|
}
|
|
|
|
static inline void hibernate_restore_protect_page(void *page_address)
|
|
{
|
|
if (hibernate_restore_protection_active)
|
|
set_memory_ro((unsigned long)page_address, 1);
|
|
}
|
|
|
|
static inline void hibernate_restore_unprotect_page(void *page_address)
|
|
{
|
|
if (hibernate_restore_protection_active)
|
|
set_memory_rw((unsigned long)page_address, 1);
|
|
}
|
|
#else
|
|
static inline void hibernate_restore_protection_begin(void) {}
|
|
static inline void hibernate_restore_protection_end(void) {}
|
|
static inline void hibernate_restore_protect_page(void *page_address) {}
|
|
static inline void hibernate_restore_unprotect_page(void *page_address) {}
|
|
#endif /* CONFIG_STRICT_KERNEL_RWX && CONFIG_ARCH_HAS_SET_MEMORY */
|
|
|
|
static int swsusp_page_is_free(struct page *);
|
|
static void swsusp_set_page_forbidden(struct page *);
|
|
static void swsusp_unset_page_forbidden(struct page *);
|
|
|
|
/*
|
|
* Number of bytes to reserve for memory allocations made by device drivers
|
|
* from their ->freeze() and ->freeze_noirq() callbacks so that they don't
|
|
* cause image creation to fail (tunable via /sys/power/reserved_size).
|
|
*/
|
|
unsigned long reserved_size;
|
|
|
|
void __init hibernate_reserved_size_init(void)
|
|
{
|
|
reserved_size = SPARE_PAGES * PAGE_SIZE;
|
|
}
|
|
|
|
/*
|
|
* Preferred image size in bytes (tunable via /sys/power/image_size).
|
|
* When it is set to N, swsusp will do its best to ensure the image
|
|
* size will not exceed N bytes, but if that is impossible, it will
|
|
* try to create the smallest image possible.
|
|
*/
|
|
unsigned long image_size;
|
|
|
|
void __init hibernate_image_size_init(void)
|
|
{
|
|
image_size = ((totalram_pages() * 2) / 5) * PAGE_SIZE;
|
|
}
|
|
|
|
/*
|
|
* List of PBEs needed for restoring the pages that were allocated before
|
|
* the suspend and included in the suspend image, but have also been
|
|
* allocated by the "resume" kernel, so their contents cannot be written
|
|
* directly to their "original" page frames.
|
|
*/
|
|
struct pbe *restore_pblist;
|
|
|
|
/* struct linked_page is used to build chains of pages */
|
|
|
|
#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
|
|
|
|
struct linked_page {
|
|
struct linked_page *next;
|
|
char data[LINKED_PAGE_DATA_SIZE];
|
|
} __packed;
|
|
|
|
/*
|
|
* List of "safe" pages (ie. pages that were not used by the image kernel
|
|
* before hibernation) that may be used as temporary storage for image kernel
|
|
* memory contents.
|
|
*/
|
|
static struct linked_page *safe_pages_list;
|
|
|
|
/* Pointer to an auxiliary buffer (1 page) */
|
|
static void *buffer;
|
|
|
|
#define PG_ANY 0
|
|
#define PG_SAFE 1
|
|
#define PG_UNSAFE_CLEAR 1
|
|
#define PG_UNSAFE_KEEP 0
|
|
|
|
static unsigned int allocated_unsafe_pages;
|
|
|
|
/**
|
|
* get_image_page - Allocate a page for a hibernation image.
|
|
* @gfp_mask: GFP mask for the allocation.
|
|
* @safe_needed: Get pages that were not used before hibernation (restore only)
|
|
*
|
|
* During image restoration, for storing the PBE list and the image data, we can
|
|
* only use memory pages that do not conflict with the pages used before
|
|
* hibernation. The "unsafe" pages have PageNosaveFree set and we count them
|
|
* using allocated_unsafe_pages.
|
|
*
|
|
* Each allocated image page is marked as PageNosave and PageNosaveFree so that
|
|
* swsusp_free() can release it.
|
|
*/
|
|
static void *get_image_page(gfp_t gfp_mask, int safe_needed)
|
|
{
|
|
void *res;
|
|
|
|
res = (void *)get_zeroed_page(gfp_mask);
|
|
if (safe_needed)
|
|
while (res && swsusp_page_is_free(virt_to_page(res))) {
|
|
/* The page is unsafe, mark it for swsusp_free() */
|
|
swsusp_set_page_forbidden(virt_to_page(res));
|
|
allocated_unsafe_pages++;
|
|
res = (void *)get_zeroed_page(gfp_mask);
|
|
}
|
|
if (res) {
|
|
swsusp_set_page_forbidden(virt_to_page(res));
|
|
swsusp_set_page_free(virt_to_page(res));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void *__get_safe_page(gfp_t gfp_mask)
|
|
{
|
|
if (safe_pages_list) {
|
|
void *ret = safe_pages_list;
|
|
|
|
safe_pages_list = safe_pages_list->next;
|
|
memset(ret, 0, PAGE_SIZE);
|
|
return ret;
|
|
}
|
|
return get_image_page(gfp_mask, PG_SAFE);
|
|
}
|
|
|
|
unsigned long get_safe_page(gfp_t gfp_mask)
|
|
{
|
|
return (unsigned long)__get_safe_page(gfp_mask);
|
|
}
|
|
|
|
static struct page *alloc_image_page(gfp_t gfp_mask)
|
|
{
|
|
struct page *page;
|
|
|
|
page = alloc_page(gfp_mask);
|
|
if (page) {
|
|
swsusp_set_page_forbidden(page);
|
|
swsusp_set_page_free(page);
|
|
}
|
|
return page;
|
|
}
|
|
|
|
static void recycle_safe_page(void *page_address)
|
|
{
|
|
struct linked_page *lp = page_address;
|
|
|
|
lp->next = safe_pages_list;
|
|
safe_pages_list = lp;
|
|
}
|
|
|
|
/**
|
|
* free_image_page - Free a page allocated for hibernation image.
|
|
* @addr: Address of the page to free.
|
|
* @clear_nosave_free: If set, clear the PageNosaveFree bit for the page.
|
|
*
|
|
* The page to free should have been allocated by get_image_page() (page flags
|
|
* set by it are affected).
|
|
*/
|
|
static inline void free_image_page(void *addr, int clear_nosave_free)
|
|
{
|
|
struct page *page;
|
|
|
|
BUG_ON(!virt_addr_valid(addr));
|
|
|
|
page = virt_to_page(addr);
|
|
|
|
swsusp_unset_page_forbidden(page);
|
|
if (clear_nosave_free)
|
|
swsusp_unset_page_free(page);
|
|
|
|
__free_page(page);
|
|
}
|
|
|
|
static inline void free_list_of_pages(struct linked_page *list,
|
|
int clear_page_nosave)
|
|
{
|
|
while (list) {
|
|
struct linked_page *lp = list->next;
|
|
|
|
free_image_page(list, clear_page_nosave);
|
|
list = lp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* struct chain_allocator is used for allocating small objects out of
|
|
* a linked list of pages called 'the chain'.
|
|
*
|
|
* The chain grows each time when there is no room for a new object in
|
|
* the current page. The allocated objects cannot be freed individually.
|
|
* It is only possible to free them all at once, by freeing the entire
|
|
* chain.
|
|
*
|
|
* NOTE: The chain allocator may be inefficient if the allocated objects
|
|
* are not much smaller than PAGE_SIZE.
|
|
*/
|
|
struct chain_allocator {
|
|
struct linked_page *chain; /* the chain */
|
|
unsigned int used_space; /* total size of objects allocated out
|
|
of the current page */
|
|
gfp_t gfp_mask; /* mask for allocating pages */
|
|
int safe_needed; /* if set, only "safe" pages are allocated */
|
|
};
|
|
|
|
static void chain_init(struct chain_allocator *ca, gfp_t gfp_mask,
|
|
int safe_needed)
|
|
{
|
|
ca->chain = NULL;
|
|
ca->used_space = LINKED_PAGE_DATA_SIZE;
|
|
ca->gfp_mask = gfp_mask;
|
|
ca->safe_needed = safe_needed;
|
|
}
|
|
|
|
static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
|
|
{
|
|
void *ret;
|
|
|
|
if (LINKED_PAGE_DATA_SIZE - ca->used_space < size) {
|
|
struct linked_page *lp;
|
|
|
|
lp = ca->safe_needed ? __get_safe_page(ca->gfp_mask) :
|
|
get_image_page(ca->gfp_mask, PG_ANY);
|
|
if (!lp)
|
|
return NULL;
|
|
|
|
lp->next = ca->chain;
|
|
ca->chain = lp;
|
|
ca->used_space = 0;
|
|
}
|
|
ret = ca->chain->data + ca->used_space;
|
|
ca->used_space += size;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Data types related to memory bitmaps.
|
|
*
|
|
* Memory bitmap is a structure consiting of many linked lists of
|
|
* objects. The main list's elements are of type struct zone_bitmap
|
|
* and each of them corresonds to one zone. For each zone bitmap
|
|
* object there is a list of objects of type struct bm_block that
|
|
* represent each blocks of bitmap in which information is stored.
|
|
*
|
|
* struct memory_bitmap contains a pointer to the main list of zone
|
|
* bitmap objects, a struct bm_position used for browsing the bitmap,
|
|
* and a pointer to the list of pages used for allocating all of the
|
|
* zone bitmap objects and bitmap block objects.
|
|
*
|
|
* NOTE: It has to be possible to lay out the bitmap in memory
|
|
* using only allocations of order 0. Additionally, the bitmap is
|
|
* designed to work with arbitrary number of zones (this is over the
|
|
* top for now, but let's avoid making unnecessary assumptions ;-).
|
|
*
|
|
* struct zone_bitmap contains a pointer to a list of bitmap block
|
|
* objects and a pointer to the bitmap block object that has been
|
|
* most recently used for setting bits. Additionally, it contains the
|
|
* PFNs that correspond to the start and end of the represented zone.
|
|
*
|
|
* struct bm_block contains a pointer to the memory page in which
|
|
* information is stored (in the form of a block of bitmap)
|
|
* It also contains the pfns that correspond to the start and end of
|
|
* the represented memory area.
|
|
*
|
|
* The memory bitmap is organized as a radix tree to guarantee fast random
|
|
* access to the bits. There is one radix tree for each zone (as returned
|
|
* from create_mem_extents).
|
|
*
|
|
* One radix tree is represented by one struct mem_zone_bm_rtree. There are
|
|
* two linked lists for the nodes of the tree, one for the inner nodes and
|
|
* one for the leave nodes. The linked leave nodes are used for fast linear
|
|
* access of the memory bitmap.
|
|
*
|
|
* The struct rtree_node represents one node of the radix tree.
|
|
*/
|
|
|
|
#define BM_END_OF_MAP (~0UL)
|
|
|
|
#define BM_BITS_PER_BLOCK (PAGE_SIZE * BITS_PER_BYTE)
|
|
#define BM_BLOCK_SHIFT (PAGE_SHIFT + 3)
|
|
#define BM_BLOCK_MASK ((1UL << BM_BLOCK_SHIFT) - 1)
|
|
|
|
/*
|
|
* struct rtree_node is a wrapper struct to link the nodes
|
|
* of the rtree together for easy linear iteration over
|
|
* bits and easy freeing
|
|
*/
|
|
struct rtree_node {
|
|
struct list_head list;
|
|
unsigned long *data;
|
|
};
|
|
|
|
/*
|
|
* struct mem_zone_bm_rtree represents a bitmap used for one
|
|
* populated memory zone.
|
|
*/
|
|
struct mem_zone_bm_rtree {
|
|
struct list_head list; /* Link Zones together */
|
|
struct list_head nodes; /* Radix Tree inner nodes */
|
|
struct list_head leaves; /* Radix Tree leaves */
|
|
unsigned long start_pfn; /* Zone start page frame */
|
|
unsigned long end_pfn; /* Zone end page frame + 1 */
|
|
struct rtree_node *rtree; /* Radix Tree Root */
|
|
int levels; /* Number of Radix Tree Levels */
|
|
unsigned int blocks; /* Number of Bitmap Blocks */
|
|
};
|
|
|
|
/* strcut bm_position is used for browsing memory bitmaps */
|
|
|
|
struct bm_position {
|
|
struct mem_zone_bm_rtree *zone;
|
|
struct rtree_node *node;
|
|
unsigned long node_pfn;
|
|
int node_bit;
|
|
};
|
|
|
|
struct memory_bitmap {
|
|
struct list_head zones;
|
|
struct linked_page *p_list; /* list of pages used to store zone
|
|
bitmap objects and bitmap block
|
|
objects */
|
|
struct bm_position cur; /* most recently used bit position */
|
|
};
|
|
|
|
/* Functions that operate on memory bitmaps */
|
|
|
|
#define BM_ENTRIES_PER_LEVEL (PAGE_SIZE / sizeof(unsigned long))
|
|
#if BITS_PER_LONG == 32
|
|
#define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 2)
|
|
#else
|
|
#define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 3)
|
|
#endif
|
|
#define BM_RTREE_LEVEL_MASK ((1UL << BM_RTREE_LEVEL_SHIFT) - 1)
|
|
|
|
/**
|
|
* alloc_rtree_node - Allocate a new node and add it to the radix tree.
|
|
*
|
|
* This function is used to allocate inner nodes as well as the
|
|
* leave nodes of the radix tree. It also adds the node to the
|
|
* corresponding linked list passed in by the *list parameter.
|
|
*/
|
|
static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed,
|
|
struct chain_allocator *ca,
|
|
struct list_head *list)
|
|
{
|
|
struct rtree_node *node;
|
|
|
|
node = chain_alloc(ca, sizeof(struct rtree_node));
|
|
if (!node)
|
|
return NULL;
|
|
|
|
node->data = get_image_page(gfp_mask, safe_needed);
|
|
if (!node->data)
|
|
return NULL;
|
|
|
|
list_add_tail(&node->list, list);
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* add_rtree_block - Add a new leave node to the radix tree.
|
|
*
|
|
* The leave nodes need to be allocated in order to keep the leaves
|
|
* linked list in order. This is guaranteed by the zone->blocks
|
|
* counter.
|
|
*/
|
|
static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask,
|
|
int safe_needed, struct chain_allocator *ca)
|
|
{
|
|
struct rtree_node *node, *block, **dst;
|
|
unsigned int levels_needed, block_nr;
|
|
int i;
|
|
|
|
block_nr = zone->blocks;
|
|
levels_needed = 0;
|
|
|
|
/* How many levels do we need for this block nr? */
|
|
while (block_nr) {
|
|
levels_needed += 1;
|
|
block_nr >>= BM_RTREE_LEVEL_SHIFT;
|
|
}
|
|
|
|
/* Make sure the rtree has enough levels */
|
|
for (i = zone->levels; i < levels_needed; i++) {
|
|
node = alloc_rtree_node(gfp_mask, safe_needed, ca,
|
|
&zone->nodes);
|
|
if (!node)
|
|
return -ENOMEM;
|
|
|
|
node->data[0] = (unsigned long)zone->rtree;
|
|
zone->rtree = node;
|
|
zone->levels += 1;
|
|
}
|
|
|
|
/* Allocate new block */
|
|
block = alloc_rtree_node(gfp_mask, safe_needed, ca, &zone->leaves);
|
|
if (!block)
|
|
return -ENOMEM;
|
|
|
|
/* Now walk the rtree to insert the block */
|
|
node = zone->rtree;
|
|
dst = &zone->rtree;
|
|
block_nr = zone->blocks;
|
|
for (i = zone->levels; i > 0; i--) {
|
|
int index;
|
|
|
|
if (!node) {
|
|
node = alloc_rtree_node(gfp_mask, safe_needed, ca,
|
|
&zone->nodes);
|
|
if (!node)
|
|
return -ENOMEM;
|
|
*dst = node;
|
|
}
|
|
|
|
index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT);
|
|
index &= BM_RTREE_LEVEL_MASK;
|
|
dst = (struct rtree_node **)&((*dst)->data[index]);
|
|
node = *dst;
|
|
}
|
|
|
|
zone->blocks += 1;
|
|
*dst = block;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
|
|
int clear_nosave_free);
|
|
|
|
/**
|
|
* create_zone_bm_rtree - Create a radix tree for one zone.
|
|
*
|
|
* Allocated the mem_zone_bm_rtree structure and initializes it.
|
|
* This function also allocated and builds the radix tree for the
|
|
* zone.
|
|
*/
|
|
static struct mem_zone_bm_rtree *create_zone_bm_rtree(gfp_t gfp_mask,
|
|
int safe_needed,
|
|
struct chain_allocator *ca,
|
|
unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
struct mem_zone_bm_rtree *zone;
|
|
unsigned int i, nr_blocks;
|
|
unsigned long pages;
|
|
|
|
pages = end - start;
|
|
zone = chain_alloc(ca, sizeof(struct mem_zone_bm_rtree));
|
|
if (!zone)
|
|
return NULL;
|
|
|
|
INIT_LIST_HEAD(&zone->nodes);
|
|
INIT_LIST_HEAD(&zone->leaves);
|
|
zone->start_pfn = start;
|
|
zone->end_pfn = end;
|
|
nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK);
|
|
|
|
for (i = 0; i < nr_blocks; i++) {
|
|
if (add_rtree_block(zone, gfp_mask, safe_needed, ca)) {
|
|
free_zone_bm_rtree(zone, PG_UNSAFE_CLEAR);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return zone;
|
|
}
|
|
|
|
/**
|
|
* free_zone_bm_rtree - Free the memory of the radix tree.
|
|
*
|
|
* Free all node pages of the radix tree. The mem_zone_bm_rtree
|
|
* structure itself is not freed here nor are the rtree_node
|
|
* structs.
|
|
*/
|
|
static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
|
|
int clear_nosave_free)
|
|
{
|
|
struct rtree_node *node;
|
|
|
|
list_for_each_entry(node, &zone->nodes, list)
|
|
free_image_page(node->data, clear_nosave_free);
|
|
|
|
list_for_each_entry(node, &zone->leaves, list)
|
|
free_image_page(node->data, clear_nosave_free);
|
|
}
|
|
|
|
static void memory_bm_position_reset(struct memory_bitmap *bm)
|
|
{
|
|
bm->cur.zone = list_entry(bm->zones.next, struct mem_zone_bm_rtree,
|
|
list);
|
|
bm->cur.node = list_entry(bm->cur.zone->leaves.next,
|
|
struct rtree_node, list);
|
|
bm->cur.node_pfn = 0;
|
|
bm->cur.node_bit = 0;
|
|
}
|
|
|
|
static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free);
|
|
|
|
struct mem_extent {
|
|
struct list_head hook;
|
|
unsigned long start;
|
|
unsigned long end;
|
|
};
|
|
|
|
/**
|
|
* free_mem_extents - Free a list of memory extents.
|
|
* @list: List of extents to free.
|
|
*/
|
|
static void free_mem_extents(struct list_head *list)
|
|
{
|
|
struct mem_extent *ext, *aux;
|
|
|
|
list_for_each_entry_safe(ext, aux, list, hook) {
|
|
list_del(&ext->hook);
|
|
kfree(ext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* create_mem_extents - Create a list of memory extents.
|
|
* @list: List to put the extents into.
|
|
* @gfp_mask: Mask to use for memory allocations.
|
|
*
|
|
* The extents represent contiguous ranges of PFNs.
|
|
*/
|
|
static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
|
|
{
|
|
struct zone *zone;
|
|
|
|
INIT_LIST_HEAD(list);
|
|
|
|
for_each_populated_zone(zone) {
|
|
unsigned long zone_start, zone_end;
|
|
struct mem_extent *ext, *cur, *aux;
|
|
|
|
zone_start = zone->zone_start_pfn;
|
|
zone_end = zone_end_pfn(zone);
|
|
|
|
list_for_each_entry(ext, list, hook)
|
|
if (zone_start <= ext->end)
|
|
break;
|
|
|
|
if (&ext->hook == list || zone_end < ext->start) {
|
|
/* New extent is necessary */
|
|
struct mem_extent *new_ext;
|
|
|
|
new_ext = kzalloc(sizeof(struct mem_extent), gfp_mask);
|
|
if (!new_ext) {
|
|
free_mem_extents(list);
|
|
return -ENOMEM;
|
|
}
|
|
new_ext->start = zone_start;
|
|
new_ext->end = zone_end;
|
|
list_add_tail(&new_ext->hook, &ext->hook);
|
|
continue;
|
|
}
|
|
|
|
/* Merge this zone's range of PFNs with the existing one */
|
|
if (zone_start < ext->start)
|
|
ext->start = zone_start;
|
|
if (zone_end > ext->end)
|
|
ext->end = zone_end;
|
|
|
|
/* More merging may be possible */
|
|
cur = ext;
|
|
list_for_each_entry_safe_continue(cur, aux, list, hook) {
|
|
if (zone_end < cur->start)
|
|
break;
|
|
if (zone_end < cur->end)
|
|
ext->end = cur->end;
|
|
list_del(&cur->hook);
|
|
kfree(cur);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* memory_bm_create - Allocate memory for a memory bitmap.
|
|
*/
|
|
static int memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask,
|
|
int safe_needed)
|
|
{
|
|
struct chain_allocator ca;
|
|
struct list_head mem_extents;
|
|
struct mem_extent *ext;
|
|
int error;
|
|
|
|
chain_init(&ca, gfp_mask, safe_needed);
|
|
INIT_LIST_HEAD(&bm->zones);
|
|
|
|
error = create_mem_extents(&mem_extents, gfp_mask);
|
|
if (error)
|
|
return error;
|
|
|
|
list_for_each_entry(ext, &mem_extents, hook) {
|
|
struct mem_zone_bm_rtree *zone;
|
|
|
|
zone = create_zone_bm_rtree(gfp_mask, safe_needed, &ca,
|
|
ext->start, ext->end);
|
|
if (!zone) {
|
|
error = -ENOMEM;
|
|
goto Error;
|
|
}
|
|
list_add_tail(&zone->list, &bm->zones);
|
|
}
|
|
|
|
bm->p_list = ca.chain;
|
|
memory_bm_position_reset(bm);
|
|
Exit:
|
|
free_mem_extents(&mem_extents);
|
|
return error;
|
|
|
|
Error:
|
|
bm->p_list = ca.chain;
|
|
memory_bm_free(bm, PG_UNSAFE_CLEAR);
|
|
goto Exit;
|
|
}
|
|
|
|
/**
|
|
* memory_bm_free - Free memory occupied by the memory bitmap.
|
|
* @bm: Memory bitmap.
|
|
*/
|
|
static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
|
|
{
|
|
struct mem_zone_bm_rtree *zone;
|
|
|
|
list_for_each_entry(zone, &bm->zones, list)
|
|
free_zone_bm_rtree(zone, clear_nosave_free);
|
|
|
|
free_list_of_pages(bm->p_list, clear_nosave_free);
|
|
|
|
INIT_LIST_HEAD(&bm->zones);
|
|
}
|
|
|
|
/**
|
|
* memory_bm_find_bit - Find the bit for a given PFN in a memory bitmap.
|
|
*
|
|
* Find the bit in memory bitmap @bm that corresponds to the given PFN.
|
|
* The cur.zone, cur.block and cur.node_pfn members of @bm are updated.
|
|
*
|
|
* Walk the radix tree to find the page containing the bit that represents @pfn
|
|
* and return the position of the bit in @addr and @bit_nr.
|
|
*/
|
|
static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
|
|
void **addr, unsigned int *bit_nr)
|
|
{
|
|
struct mem_zone_bm_rtree *curr, *zone;
|
|
struct rtree_node *node;
|
|
int i, block_nr;
|
|
|
|
zone = bm->cur.zone;
|
|
|
|
if (pfn >= zone->start_pfn && pfn < zone->end_pfn)
|
|
goto zone_found;
|
|
|
|
zone = NULL;
|
|
|
|
/* Find the right zone */
|
|
list_for_each_entry(curr, &bm->zones, list) {
|
|
if (pfn >= curr->start_pfn && pfn < curr->end_pfn) {
|
|
zone = curr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!zone)
|
|
return -EFAULT;
|
|
|
|
zone_found:
|
|
/*
|
|
* We have found the zone. Now walk the radix tree to find the leaf node
|
|
* for our PFN.
|
|
*/
|
|
|
|
/*
|
|
* If the zone we wish to scan is the current zone and the
|
|
* pfn falls into the current node then we do not need to walk
|
|
* the tree.
|
|
*/
|
|
node = bm->cur.node;
|
|
if (zone == bm->cur.zone &&
|
|
((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
|
|
goto node_found;
|
|
|
|
node = zone->rtree;
|
|
block_nr = (pfn - zone->start_pfn) >> BM_BLOCK_SHIFT;
|
|
|
|
for (i = zone->levels; i > 0; i--) {
|
|
int index;
|
|
|
|
index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT);
|
|
index &= BM_RTREE_LEVEL_MASK;
|
|
BUG_ON(node->data[index] == 0);
|
|
node = (struct rtree_node *)node->data[index];
|
|
}
|
|
|
|
node_found:
|
|
/* Update last position */
|
|
bm->cur.zone = zone;
|
|
bm->cur.node = node;
|
|
bm->cur.node_pfn = (pfn - zone->start_pfn) & ~BM_BLOCK_MASK;
|
|
|
|
/* Set return values */
|
|
*addr = node->data;
|
|
*bit_nr = (pfn - zone->start_pfn) & BM_BLOCK_MASK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
|
|
{
|
|
void *addr;
|
|
unsigned int bit;
|
|
int error;
|
|
|
|
error = memory_bm_find_bit(bm, pfn, &addr, &bit);
|
|
BUG_ON(error);
|
|
set_bit(bit, addr);
|
|
}
|
|
|
|
static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn)
|
|
{
|
|
void *addr;
|
|
unsigned int bit;
|
|
int error;
|
|
|
|
error = memory_bm_find_bit(bm, pfn, &addr, &bit);
|
|
if (!error)
|
|
set_bit(bit, addr);
|
|
|
|
return error;
|
|
}
|
|
|
|
static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
|
|
{
|
|
void *addr;
|
|
unsigned int bit;
|
|
int error;
|
|
|
|
error = memory_bm_find_bit(bm, pfn, &addr, &bit);
|
|
BUG_ON(error);
|
|
clear_bit(bit, addr);
|
|
}
|
|
|
|
static void memory_bm_clear_current(struct memory_bitmap *bm)
|
|
{
|
|
int bit;
|
|
|
|
bit = max(bm->cur.node_bit - 1, 0);
|
|
clear_bit(bit, bm->cur.node->data);
|
|
}
|
|
|
|
static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
|
|
{
|
|
void *addr;
|
|
unsigned int bit;
|
|
int error;
|
|
|
|
error = memory_bm_find_bit(bm, pfn, &addr, &bit);
|
|
BUG_ON(error);
|
|
return test_bit(bit, addr);
|
|
}
|
|
|
|
static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn)
|
|
{
|
|
void *addr;
|
|
unsigned int bit;
|
|
|
|
return !memory_bm_find_bit(bm, pfn, &addr, &bit);
|
|
}
|
|
|
|
/*
|
|
* rtree_next_node - Jump to the next leaf node.
|
|
*
|
|
* Set the position to the beginning of the next node in the
|
|
* memory bitmap. This is either the next node in the current
|
|
* zone's radix tree or the first node in the radix tree of the
|
|
* next zone.
|
|
*
|
|
* Return true if there is a next node, false otherwise.
|
|
*/
|
|
static bool rtree_next_node(struct memory_bitmap *bm)
|
|
{
|
|
if (!list_is_last(&bm->cur.node->list, &bm->cur.zone->leaves)) {
|
|
bm->cur.node = list_entry(bm->cur.node->list.next,
|
|
struct rtree_node, list);
|
|
bm->cur.node_pfn += BM_BITS_PER_BLOCK;
|
|
bm->cur.node_bit = 0;
|
|
touch_softlockup_watchdog();
|
|
return true;
|
|
}
|
|
|
|
/* No more nodes, goto next zone */
|
|
if (!list_is_last(&bm->cur.zone->list, &bm->zones)) {
|
|
bm->cur.zone = list_entry(bm->cur.zone->list.next,
|
|
struct mem_zone_bm_rtree, list);
|
|
bm->cur.node = list_entry(bm->cur.zone->leaves.next,
|
|
struct rtree_node, list);
|
|
bm->cur.node_pfn = 0;
|
|
bm->cur.node_bit = 0;
|
|
return true;
|
|
}
|
|
|
|
/* No more zones */
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* memory_bm_rtree_next_pfn - Find the next set bit in a memory bitmap.
|
|
* @bm: Memory bitmap.
|
|
*
|
|
* Starting from the last returned position this function searches for the next
|
|
* set bit in @bm and returns the PFN represented by it. If no more bits are
|
|
* set, BM_END_OF_MAP is returned.
|
|
*
|
|
* It is required to run memory_bm_position_reset() before the first call to
|
|
* this function for the given memory bitmap.
|
|
*/
|
|
static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm)
|
|
{
|
|
unsigned long bits, pfn, pages;
|
|
int bit;
|
|
|
|
do {
|
|
pages = bm->cur.zone->end_pfn - bm->cur.zone->start_pfn;
|
|
bits = min(pages - bm->cur.node_pfn, BM_BITS_PER_BLOCK);
|
|
bit = find_next_bit(bm->cur.node->data, bits,
|
|
bm->cur.node_bit);
|
|
if (bit < bits) {
|
|
pfn = bm->cur.zone->start_pfn + bm->cur.node_pfn + bit;
|
|
bm->cur.node_bit = bit + 1;
|
|
return pfn;
|
|
}
|
|
} while (rtree_next_node(bm));
|
|
|
|
return BM_END_OF_MAP;
|
|
}
|
|
|
|
/*
|
|
* This structure represents a range of page frames the contents of which
|
|
* should not be saved during hibernation.
|
|
*/
|
|
struct nosave_region {
|
|
struct list_head list;
|
|
unsigned long start_pfn;
|
|
unsigned long end_pfn;
|
|
};
|
|
|
|
static LIST_HEAD(nosave_regions);
|
|
|
|
static void recycle_zone_bm_rtree(struct mem_zone_bm_rtree *zone)
|
|
{
|
|
struct rtree_node *node;
|
|
|
|
list_for_each_entry(node, &zone->nodes, list)
|
|
recycle_safe_page(node->data);
|
|
|
|
list_for_each_entry(node, &zone->leaves, list)
|
|
recycle_safe_page(node->data);
|
|
}
|
|
|
|
static void memory_bm_recycle(struct memory_bitmap *bm)
|
|
{
|
|
struct mem_zone_bm_rtree *zone;
|
|
struct linked_page *p_list;
|
|
|
|
list_for_each_entry(zone, &bm->zones, list)
|
|
recycle_zone_bm_rtree(zone);
|
|
|
|
p_list = bm->p_list;
|
|
while (p_list) {
|
|
struct linked_page *lp = p_list;
|
|
|
|
p_list = lp->next;
|
|
recycle_safe_page(lp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* register_nosave_region - Register a region of unsaveable memory.
|
|
*
|
|
* Register a range of page frames the contents of which should not be saved
|
|
* during hibernation (to be used in the early initialization code).
|
|
*/
|
|
void __init register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
|
|
{
|
|
struct nosave_region *region;
|
|
|
|
if (start_pfn >= end_pfn)
|
|
return;
|
|
|
|
if (!list_empty(&nosave_regions)) {
|
|
/* Try to extend the previous region (they should be sorted) */
|
|
region = list_entry(nosave_regions.prev,
|
|
struct nosave_region, list);
|
|
if (region->end_pfn == start_pfn) {
|
|
region->end_pfn = end_pfn;
|
|
goto Report;
|
|
}
|
|
}
|
|
/* This allocation cannot fail */
|
|
region = memblock_alloc(sizeof(struct nosave_region),
|
|
SMP_CACHE_BYTES);
|
|
if (!region)
|
|
panic("%s: Failed to allocate %zu bytes\n", __func__,
|
|
sizeof(struct nosave_region));
|
|
region->start_pfn = start_pfn;
|
|
region->end_pfn = end_pfn;
|
|
list_add_tail(®ion->list, &nosave_regions);
|
|
Report:
|
|
pr_info("Registered nosave memory: [mem %#010llx-%#010llx]\n",
|
|
(unsigned long long) start_pfn << PAGE_SHIFT,
|
|
((unsigned long long) end_pfn << PAGE_SHIFT) - 1);
|
|
}
|
|
|
|
/*
|
|
* Set bits in this map correspond to the page frames the contents of which
|
|
* should not be saved during the suspend.
|
|
*/
|
|
static struct memory_bitmap *forbidden_pages_map;
|
|
|
|
/* Set bits in this map correspond to free page frames. */
|
|
static struct memory_bitmap *free_pages_map;
|
|
|
|
/*
|
|
* Each page frame allocated for creating the image is marked by setting the
|
|
* corresponding bits in forbidden_pages_map and free_pages_map simultaneously
|
|
*/
|
|
|
|
void swsusp_set_page_free(struct page *page)
|
|
{
|
|
if (free_pages_map)
|
|
memory_bm_set_bit(free_pages_map, page_to_pfn(page));
|
|
}
|
|
|
|
static int swsusp_page_is_free(struct page *page)
|
|
{
|
|
return free_pages_map ?
|
|
memory_bm_test_bit(free_pages_map, page_to_pfn(page)) : 0;
|
|
}
|
|
|
|
void swsusp_unset_page_free(struct page *page)
|
|
{
|
|
if (free_pages_map)
|
|
memory_bm_clear_bit(free_pages_map, page_to_pfn(page));
|
|
}
|
|
|
|
static void swsusp_set_page_forbidden(struct page *page)
|
|
{
|
|
if (forbidden_pages_map)
|
|
memory_bm_set_bit(forbidden_pages_map, page_to_pfn(page));
|
|
}
|
|
|
|
int swsusp_page_is_forbidden(struct page *page)
|
|
{
|
|
return forbidden_pages_map ?
|
|
memory_bm_test_bit(forbidden_pages_map, page_to_pfn(page)) : 0;
|
|
}
|
|
|
|
static void swsusp_unset_page_forbidden(struct page *page)
|
|
{
|
|
if (forbidden_pages_map)
|
|
memory_bm_clear_bit(forbidden_pages_map, page_to_pfn(page));
|
|
}
|
|
|
|
/**
|
|
* mark_nosave_pages - Mark pages that should not be saved.
|
|
* @bm: Memory bitmap.
|
|
*
|
|
* Set the bits in @bm that correspond to the page frames the contents of which
|
|
* should not be saved.
|
|
*/
|
|
static void mark_nosave_pages(struct memory_bitmap *bm)
|
|
{
|
|
struct nosave_region *region;
|
|
|
|
if (list_empty(&nosave_regions))
|
|
return;
|
|
|
|
list_for_each_entry(region, &nosave_regions, list) {
|
|
unsigned long pfn;
|
|
|
|
pr_debug("Marking nosave pages: [mem %#010llx-%#010llx]\n",
|
|
(unsigned long long) region->start_pfn << PAGE_SHIFT,
|
|
((unsigned long long) region->end_pfn << PAGE_SHIFT)
|
|
- 1);
|
|
|
|
for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
|
|
if (pfn_valid(pfn)) {
|
|
/*
|
|
* It is safe to ignore the result of
|
|
* mem_bm_set_bit_check() here, since we won't
|
|
* touch the PFNs for which the error is
|
|
* returned anyway.
|
|
*/
|
|
mem_bm_set_bit_check(bm, pfn);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* create_basic_memory_bitmaps - Create bitmaps to hold basic page information.
|
|
*
|
|
* Create bitmaps needed for marking page frames that should not be saved and
|
|
* free page frames. The forbidden_pages_map and free_pages_map pointers are
|
|
* only modified if everything goes well, because we don't want the bits to be
|
|
* touched before both bitmaps are set up.
|
|
*/
|
|
int create_basic_memory_bitmaps(void)
|
|
{
|
|
struct memory_bitmap *bm1, *bm2;
|
|
int error = 0;
|
|
|
|
if (forbidden_pages_map && free_pages_map)
|
|
return 0;
|
|
else
|
|
BUG_ON(forbidden_pages_map || free_pages_map);
|
|
|
|
bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
|
|
if (!bm1)
|
|
return -ENOMEM;
|
|
|
|
error = memory_bm_create(bm1, GFP_KERNEL, PG_ANY);
|
|
if (error)
|
|
goto Free_first_object;
|
|
|
|
bm2 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
|
|
if (!bm2)
|
|
goto Free_first_bitmap;
|
|
|
|
error = memory_bm_create(bm2, GFP_KERNEL, PG_ANY);
|
|
if (error)
|
|
goto Free_second_object;
|
|
|
|
forbidden_pages_map = bm1;
|
|
free_pages_map = bm2;
|
|
mark_nosave_pages(forbidden_pages_map);
|
|
|
|
pr_debug("Basic memory bitmaps created\n");
|
|
|
|
return 0;
|
|
|
|
Free_second_object:
|
|
kfree(bm2);
|
|
Free_first_bitmap:
|
|
memory_bm_free(bm1, PG_UNSAFE_CLEAR);
|
|
Free_first_object:
|
|
kfree(bm1);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/**
|
|
* free_basic_memory_bitmaps - Free memory bitmaps holding basic information.
|
|
*
|
|
* Free memory bitmaps allocated by create_basic_memory_bitmaps(). The
|
|
* auxiliary pointers are necessary so that the bitmaps themselves are not
|
|
* referred to while they are being freed.
|
|
*/
|
|
void free_basic_memory_bitmaps(void)
|
|
{
|
|
struct memory_bitmap *bm1, *bm2;
|
|
|
|
if (WARN_ON(!(forbidden_pages_map && free_pages_map)))
|
|
return;
|
|
|
|
bm1 = forbidden_pages_map;
|
|
bm2 = free_pages_map;
|
|
forbidden_pages_map = NULL;
|
|
free_pages_map = NULL;
|
|
memory_bm_free(bm1, PG_UNSAFE_CLEAR);
|
|
kfree(bm1);
|
|
memory_bm_free(bm2, PG_UNSAFE_CLEAR);
|
|
kfree(bm2);
|
|
|
|
pr_debug("Basic memory bitmaps freed\n");
|
|
}
|
|
|
|
static void clear_or_poison_free_page(struct page *page)
|
|
{
|
|
if (page_poisoning_enabled_static())
|
|
__kernel_poison_pages(page, 1);
|
|
else if (want_init_on_free())
|
|
clear_highpage(page);
|
|
}
|
|
|
|
void clear_or_poison_free_pages(void)
|
|
{
|
|
struct memory_bitmap *bm = free_pages_map;
|
|
unsigned long pfn;
|
|
|
|
if (WARN_ON(!(free_pages_map)))
|
|
return;
|
|
|
|
if (page_poisoning_enabled() || want_init_on_free()) {
|
|
memory_bm_position_reset(bm);
|
|
pfn = memory_bm_next_pfn(bm);
|
|
while (pfn != BM_END_OF_MAP) {
|
|
if (pfn_valid(pfn))
|
|
clear_or_poison_free_page(pfn_to_page(pfn));
|
|
|
|
pfn = memory_bm_next_pfn(bm);
|
|
}
|
|
memory_bm_position_reset(bm);
|
|
pr_info("free pages cleared after restore\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* snapshot_additional_pages - Estimate the number of extra pages needed.
|
|
* @zone: Memory zone to carry out the computation for.
|
|
*
|
|
* Estimate the number of additional pages needed for setting up a hibernation
|
|
* image data structures for @zone (usually, the returned value is greater than
|
|
* the exact number).
|
|
*/
|
|
unsigned int snapshot_additional_pages(struct zone *zone)
|
|
{
|
|
unsigned int rtree, nodes;
|
|
|
|
rtree = nodes = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
|
|
rtree += DIV_ROUND_UP(rtree * sizeof(struct rtree_node),
|
|
LINKED_PAGE_DATA_SIZE);
|
|
while (nodes > 1) {
|
|
nodes = DIV_ROUND_UP(nodes, BM_ENTRIES_PER_LEVEL);
|
|
rtree += nodes;
|
|
}
|
|
|
|
return 2 * rtree;
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
/**
|
|
* count_free_highmem_pages - Compute the total number of free highmem pages.
|
|
*
|
|
* The returned number is system-wide.
|
|
*/
|
|
static unsigned int count_free_highmem_pages(void)
|
|
{
|
|
struct zone *zone;
|
|
unsigned int cnt = 0;
|
|
|
|
for_each_populated_zone(zone)
|
|
if (is_highmem(zone))
|
|
cnt += zone_page_state(zone, NR_FREE_PAGES);
|
|
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* saveable_highmem_page - Check if a highmem page is saveable.
|
|
*
|
|
* Determine whether a highmem page should be included in a hibernation image.
|
|
*
|
|
* We should save the page if it isn't Nosave or NosaveFree, or Reserved,
|
|
* and it isn't part of a free chunk of pages.
|
|
*/
|
|
static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
|
|
{
|
|
struct page *page;
|
|
|
|
if (!pfn_valid(pfn))
|
|
return NULL;
|
|
|
|
page = pfn_to_online_page(pfn);
|
|
if (!page || page_zone(page) != zone)
|
|
return NULL;
|
|
|
|
BUG_ON(!PageHighMem(page));
|
|
|
|
if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
|
|
return NULL;
|
|
|
|
if (PageReserved(page) || PageOffline(page))
|
|
return NULL;
|
|
|
|
if (page_is_guard(page))
|
|
return NULL;
|
|
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* count_highmem_pages - Compute the total number of saveable highmem pages.
|
|
*/
|
|
static unsigned int count_highmem_pages(void)
|
|
{
|
|
struct zone *zone;
|
|
unsigned int n = 0;
|
|
|
|
for_each_populated_zone(zone) {
|
|
unsigned long pfn, max_zone_pfn;
|
|
|
|
if (!is_highmem(zone))
|
|
continue;
|
|
|
|
mark_free_pages(zone);
|
|
max_zone_pfn = zone_end_pfn(zone);
|
|
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
|
|
if (saveable_highmem_page(zone, pfn))
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
#else
|
|
static inline void *saveable_highmem_page(struct zone *z, unsigned long p)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
/**
|
|
* saveable_page - Check if the given page is saveable.
|
|
*
|
|
* Determine whether a non-highmem page should be included in a hibernation
|
|
* image.
|
|
*
|
|
* We should save the page if it isn't Nosave, and is not in the range
|
|
* of pages statically defined as 'unsaveable', and it isn't part of
|
|
* a free chunk of pages.
|
|
*/
|
|
static struct page *saveable_page(struct zone *zone, unsigned long pfn)
|
|
{
|
|
struct page *page;
|
|
|
|
if (!pfn_valid(pfn))
|
|
return NULL;
|
|
|
|
page = pfn_to_online_page(pfn);
|
|
if (!page || page_zone(page) != zone)
|
|
return NULL;
|
|
|
|
BUG_ON(PageHighMem(page));
|
|
|
|
if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
|
|
return NULL;
|
|
|
|
if (PageOffline(page))
|
|
return NULL;
|
|
|
|
if (PageReserved(page)
|
|
&& (!kernel_page_present(page) || pfn_is_nosave(pfn)))
|
|
return NULL;
|
|
|
|
if (page_is_guard(page))
|
|
return NULL;
|
|
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* count_data_pages - Compute the total number of saveable non-highmem pages.
|
|
*/
|
|
static unsigned int count_data_pages(void)
|
|
{
|
|
struct zone *zone;
|
|
unsigned long pfn, max_zone_pfn;
|
|
unsigned int n = 0;
|
|
|
|
for_each_populated_zone(zone) {
|
|
if (is_highmem(zone))
|
|
continue;
|
|
|
|
mark_free_pages(zone);
|
|
max_zone_pfn = zone_end_pfn(zone);
|
|
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
|
|
if (saveable_page(zone, pfn))
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* This is needed, because copy_page and memcpy are not usable for copying
|
|
* task structs.
|
|
*/
|
|
static inline void do_copy_page(long *dst, long *src)
|
|
{
|
|
int n;
|
|
|
|
for (n = PAGE_SIZE / sizeof(long); n; n--)
|
|
*dst++ = *src++;
|
|
}
|
|
|
|
/**
|
|
* safe_copy_page - Copy a page in a safe way.
|
|
*
|
|
* Check if the page we are going to copy is marked as present in the kernel
|
|
* page tables. This always is the case if CONFIG_DEBUG_PAGEALLOC or
|
|
* CONFIG_ARCH_HAS_SET_DIRECT_MAP is not set. In that case kernel_page_present()
|
|
* always returns 'true'.
|
|
*/
|
|
static void safe_copy_page(void *dst, struct page *s_page)
|
|
{
|
|
if (kernel_page_present(s_page)) {
|
|
do_copy_page(dst, page_address(s_page));
|
|
} else {
|
|
kernel_map_pages(s_page, 1, 1);
|
|
do_copy_page(dst, page_address(s_page));
|
|
kernel_map_pages(s_page, 1, 0);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
static inline struct page *page_is_saveable(struct zone *zone, unsigned long pfn)
|
|
{
|
|
return is_highmem(zone) ?
|
|
saveable_highmem_page(zone, pfn) : saveable_page(zone, pfn);
|
|
}
|
|
|
|
static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
|
{
|
|
struct page *s_page, *d_page;
|
|
void *src, *dst;
|
|
|
|
s_page = pfn_to_page(src_pfn);
|
|
d_page = pfn_to_page(dst_pfn);
|
|
if (PageHighMem(s_page)) {
|
|
src = kmap_atomic(s_page);
|
|
dst = kmap_atomic(d_page);
|
|
do_copy_page(dst, src);
|
|
kunmap_atomic(dst);
|
|
kunmap_atomic(src);
|
|
} else {
|
|
if (PageHighMem(d_page)) {
|
|
/*
|
|
* The page pointed to by src may contain some kernel
|
|
* data modified by kmap_atomic()
|
|
*/
|
|
safe_copy_page(buffer, s_page);
|
|
dst = kmap_atomic(d_page);
|
|
copy_page(dst, buffer);
|
|
kunmap_atomic(dst);
|
|
} else {
|
|
safe_copy_page(page_address(d_page), s_page);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
#define page_is_saveable(zone, pfn) saveable_page(zone, pfn)
|
|
|
|
static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
|
{
|
|
safe_copy_page(page_address(pfn_to_page(dst_pfn)),
|
|
pfn_to_page(src_pfn));
|
|
}
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
static void copy_data_pages(struct memory_bitmap *copy_bm,
|
|
struct memory_bitmap *orig_bm)
|
|
{
|
|
struct zone *zone;
|
|
unsigned long pfn;
|
|
|
|
for_each_populated_zone(zone) {
|
|
unsigned long max_zone_pfn;
|
|
|
|
mark_free_pages(zone);
|
|
max_zone_pfn = zone_end_pfn(zone);
|
|
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
|
|
if (page_is_saveable(zone, pfn))
|
|
memory_bm_set_bit(orig_bm, pfn);
|
|
}
|
|
memory_bm_position_reset(orig_bm);
|
|
memory_bm_position_reset(copy_bm);
|
|
for(;;) {
|
|
pfn = memory_bm_next_pfn(orig_bm);
|
|
if (unlikely(pfn == BM_END_OF_MAP))
|
|
break;
|
|
copy_data_page(memory_bm_next_pfn(copy_bm), pfn);
|
|
}
|
|
}
|
|
|
|
/* Total number of image pages */
|
|
static unsigned int nr_copy_pages;
|
|
/* Number of pages needed for saving the original pfns of the image pages */
|
|
static unsigned int nr_meta_pages;
|
|
/*
|
|
* Numbers of normal and highmem page frames allocated for hibernation image
|
|
* before suspending devices.
|
|
*/
|
|
static unsigned int alloc_normal, alloc_highmem;
|
|
/*
|
|
* Memory bitmap used for marking saveable pages (during hibernation) or
|
|
* hibernation image pages (during restore)
|
|
*/
|
|
static struct memory_bitmap orig_bm;
|
|
/*
|
|
* Memory bitmap used during hibernation for marking allocated page frames that
|
|
* will contain copies of saveable pages. During restore it is initially used
|
|
* for marking hibernation image pages, but then the set bits from it are
|
|
* duplicated in @orig_bm and it is released. On highmem systems it is next
|
|
* used for marking "safe" highmem pages, but it has to be reinitialized for
|
|
* this purpose.
|
|
*/
|
|
static struct memory_bitmap copy_bm;
|
|
|
|
/**
|
|
* swsusp_free - Free pages allocated for hibernation image.
|
|
*
|
|
* Image pages are alocated before snapshot creation, so they need to be
|
|
* released after resume.
|
|
*/
|
|
void swsusp_free(void)
|
|
{
|
|
unsigned long fb_pfn, fr_pfn;
|
|
|
|
if (!forbidden_pages_map || !free_pages_map)
|
|
goto out;
|
|
|
|
memory_bm_position_reset(forbidden_pages_map);
|
|
memory_bm_position_reset(free_pages_map);
|
|
|
|
loop:
|
|
fr_pfn = memory_bm_next_pfn(free_pages_map);
|
|
fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
|
|
|
|
/*
|
|
* Find the next bit set in both bitmaps. This is guaranteed to
|
|
* terminate when fb_pfn == fr_pfn == BM_END_OF_MAP.
|
|
*/
|
|
do {
|
|
if (fb_pfn < fr_pfn)
|
|
fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
|
|
if (fr_pfn < fb_pfn)
|
|
fr_pfn = memory_bm_next_pfn(free_pages_map);
|
|
} while (fb_pfn != fr_pfn);
|
|
|
|
if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) {
|
|
struct page *page = pfn_to_page(fr_pfn);
|
|
|
|
memory_bm_clear_current(forbidden_pages_map);
|
|
memory_bm_clear_current(free_pages_map);
|
|
hibernate_restore_unprotect_page(page_address(page));
|
|
__free_page(page);
|
|
goto loop;
|
|
}
|
|
|
|
out:
|
|
nr_copy_pages = 0;
|
|
nr_meta_pages = 0;
|
|
restore_pblist = NULL;
|
|
buffer = NULL;
|
|
alloc_normal = 0;
|
|
alloc_highmem = 0;
|
|
hibernate_restore_protection_end();
|
|
}
|
|
|
|
/* Helper functions used for the shrinking of memory. */
|
|
|
|
#define GFP_IMAGE (GFP_KERNEL | __GFP_NOWARN)
|
|
|
|
/**
|
|
* preallocate_image_pages - Allocate a number of pages for hibernation image.
|
|
* @nr_pages: Number of page frames to allocate.
|
|
* @mask: GFP flags to use for the allocation.
|
|
*
|
|
* Return value: Number of page frames actually allocated
|
|
*/
|
|
static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
|
|
{
|
|
unsigned long nr_alloc = 0;
|
|
|
|
while (nr_pages > 0) {
|
|
struct page *page;
|
|
|
|
page = alloc_image_page(mask);
|
|
if (!page)
|
|
break;
|
|
memory_bm_set_bit(©_bm, page_to_pfn(page));
|
|
if (PageHighMem(page))
|
|
alloc_highmem++;
|
|
else
|
|
alloc_normal++;
|
|
nr_pages--;
|
|
nr_alloc++;
|
|
}
|
|
|
|
return nr_alloc;
|
|
}
|
|
|
|
static unsigned long preallocate_image_memory(unsigned long nr_pages,
|
|
unsigned long avail_normal)
|
|
{
|
|
unsigned long alloc;
|
|
|
|
if (avail_normal <= alloc_normal)
|
|
return 0;
|
|
|
|
alloc = avail_normal - alloc_normal;
|
|
if (nr_pages < alloc)
|
|
alloc = nr_pages;
|
|
|
|
return preallocate_image_pages(alloc, GFP_IMAGE);
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
static unsigned long preallocate_image_highmem(unsigned long nr_pages)
|
|
{
|
|
return preallocate_image_pages(nr_pages, GFP_IMAGE | __GFP_HIGHMEM);
|
|
}
|
|
|
|
/**
|
|
* __fraction - Compute (an approximation of) x * (multiplier / base).
|
|
*/
|
|
static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
|
|
{
|
|
return div64_u64(x * multiplier, base);
|
|
}
|
|
|
|
static unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
|
|
unsigned long highmem,
|
|
unsigned long total)
|
|
{
|
|
unsigned long alloc = __fraction(nr_pages, highmem, total);
|
|
|
|
return preallocate_image_pages(alloc, GFP_IMAGE | __GFP_HIGHMEM);
|
|
}
|
|
#else /* CONFIG_HIGHMEM */
|
|
static inline unsigned long preallocate_image_highmem(unsigned long nr_pages)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
|
|
unsigned long highmem,
|
|
unsigned long total)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
/**
|
|
* free_unnecessary_pages - Release preallocated pages not needed for the image.
|
|
*/
|
|
static unsigned long free_unnecessary_pages(void)
|
|
{
|
|
unsigned long save, to_free_normal, to_free_highmem, free;
|
|
|
|
save = count_data_pages();
|
|
if (alloc_normal >= save) {
|
|
to_free_normal = alloc_normal - save;
|
|
save = 0;
|
|
} else {
|
|
to_free_normal = 0;
|
|
save -= alloc_normal;
|
|
}
|
|
save += count_highmem_pages();
|
|
if (alloc_highmem >= save) {
|
|
to_free_highmem = alloc_highmem - save;
|
|
} else {
|
|
to_free_highmem = 0;
|
|
save -= alloc_highmem;
|
|
if (to_free_normal > save)
|
|
to_free_normal -= save;
|
|
else
|
|
to_free_normal = 0;
|
|
}
|
|
free = to_free_normal + to_free_highmem;
|
|
|
|
memory_bm_position_reset(©_bm);
|
|
|
|
while (to_free_normal > 0 || to_free_highmem > 0) {
|
|
unsigned long pfn = memory_bm_next_pfn(©_bm);
|
|
struct page *page = pfn_to_page(pfn);
|
|
|
|
if (PageHighMem(page)) {
|
|
if (!to_free_highmem)
|
|
continue;
|
|
to_free_highmem--;
|
|
alloc_highmem--;
|
|
} else {
|
|
if (!to_free_normal)
|
|
continue;
|
|
to_free_normal--;
|
|
alloc_normal--;
|
|
}
|
|
memory_bm_clear_bit(©_bm, pfn);
|
|
swsusp_unset_page_forbidden(page);
|
|
swsusp_unset_page_free(page);
|
|
__free_page(page);
|
|
}
|
|
|
|
return free;
|
|
}
|
|
|
|
/**
|
|
* minimum_image_size - Estimate the minimum acceptable size of an image.
|
|
* @saveable: Number of saveable pages in the system.
|
|
*
|
|
* We want to avoid attempting to free too much memory too hard, so estimate the
|
|
* minimum acceptable size of a hibernation image to use as the lower limit for
|
|
* preallocating memory.
|
|
*
|
|
* We assume that the minimum image size should be proportional to
|
|
*
|
|
* [number of saveable pages] - [number of pages that can be freed in theory]
|
|
*
|
|
* where the second term is the sum of (1) reclaimable slab pages, (2) active
|
|
* and (3) inactive anonymous pages, (4) active and (5) inactive file pages.
|
|
*/
|
|
static unsigned long minimum_image_size(unsigned long saveable)
|
|
{
|
|
unsigned long size;
|
|
|
|
size = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B)
|
|
+ global_node_page_state(NR_ACTIVE_ANON)
|
|
+ global_node_page_state(NR_INACTIVE_ANON)
|
|
+ global_node_page_state(NR_ACTIVE_FILE)
|
|
+ global_node_page_state(NR_INACTIVE_FILE);
|
|
|
|
return saveable <= size ? 0 : saveable - size;
|
|
}
|
|
|
|
/**
|
|
* hibernate_preallocate_memory - Preallocate memory for hibernation image.
|
|
*
|
|
* To create a hibernation image it is necessary to make a copy of every page
|
|
* frame in use. We also need a number of page frames to be free during
|
|
* hibernation for allocations made while saving the image and for device
|
|
* drivers, in case they need to allocate memory from their hibernation
|
|
* callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough
|
|
* estimate) and reserved_size divided by PAGE_SIZE (which is tunable through
|
|
* /sys/power/reserved_size, respectively). To make this happen, we compute the
|
|
* total number of available page frames and allocate at least
|
|
*
|
|
* ([page frames total] - PAGES_FOR_IO - [metadata pages]) / 2
|
|
* - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE)
|
|
*
|
|
* of them, which corresponds to the maximum size of a hibernation image.
|
|
*
|
|
* If image_size is set below the number following from the above formula,
|
|
* the preallocation of memory is continued until the total number of saveable
|
|
* pages in the system is below the requested image size or the minimum
|
|
* acceptable image size returned by minimum_image_size(), whichever is greater.
|
|
*/
|
|
int hibernate_preallocate_memory(void)
|
|
{
|
|
struct zone *zone;
|
|
unsigned long saveable, size, max_size, count, highmem, pages = 0;
|
|
unsigned long alloc, save_highmem, pages_highmem, avail_normal;
|
|
ktime_t start, stop;
|
|
int error;
|
|
|
|
pr_info("Preallocating image memory\n");
|
|
start = ktime_get();
|
|
|
|
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
|
|
if (error) {
|
|
pr_err("Cannot allocate original bitmap\n");
|
|
goto err_out;
|
|
}
|
|
|
|
error = memory_bm_create(©_bm, GFP_IMAGE, PG_ANY);
|
|
if (error) {
|
|
pr_err("Cannot allocate copy bitmap\n");
|
|
goto err_out;
|
|
}
|
|
|
|
alloc_normal = 0;
|
|
alloc_highmem = 0;
|
|
|
|
/* Count the number of saveable data pages. */
|
|
save_highmem = count_highmem_pages();
|
|
saveable = count_data_pages();
|
|
|
|
/*
|
|
* Compute the total number of page frames we can use (count) and the
|
|
* number of pages needed for image metadata (size).
|
|
*/
|
|
count = saveable;
|
|
saveable += save_highmem;
|
|
highmem = save_highmem;
|
|
size = 0;
|
|
for_each_populated_zone(zone) {
|
|
size += snapshot_additional_pages(zone);
|
|
if (is_highmem(zone))
|
|
highmem += zone_page_state(zone, NR_FREE_PAGES);
|
|
else
|
|
count += zone_page_state(zone, NR_FREE_PAGES);
|
|
}
|
|
avail_normal = count;
|
|
count += highmem;
|
|
count -= totalreserve_pages;
|
|
|
|
/* Compute the maximum number of saveable pages to leave in memory. */
|
|
max_size = (count - (size + PAGES_FOR_IO)) / 2
|
|
- 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE);
|
|
/* Compute the desired number of image pages specified by image_size. */
|
|
size = DIV_ROUND_UP(image_size, PAGE_SIZE);
|
|
if (size > max_size)
|
|
size = max_size;
|
|
/*
|
|
* If the desired number of image pages is at least as large as the
|
|
* current number of saveable pages in memory, allocate page frames for
|
|
* the image and we're done.
|
|
*/
|
|
if (size >= saveable) {
|
|
pages = preallocate_image_highmem(save_highmem);
|
|
pages += preallocate_image_memory(saveable - pages, avail_normal);
|
|
goto out;
|
|
}
|
|
|
|
/* Estimate the minimum size of the image. */
|
|
pages = minimum_image_size(saveable);
|
|
/*
|
|
* To avoid excessive pressure on the normal zone, leave room in it to
|
|
* accommodate an image of the minimum size (unless it's already too
|
|
* small, in which case don't preallocate pages from it at all).
|
|
*/
|
|
if (avail_normal > pages)
|
|
avail_normal -= pages;
|
|
else
|
|
avail_normal = 0;
|
|
if (size < pages)
|
|
size = min_t(unsigned long, pages, max_size);
|
|
|
|
/*
|
|
* Let the memory management subsystem know that we're going to need a
|
|
* large number of page frames to allocate and make it free some memory.
|
|
* NOTE: If this is not done, performance will be hurt badly in some
|
|
* test cases.
|
|
*/
|
|
shrink_all_memory(saveable - size);
|
|
|
|
/*
|
|
* The number of saveable pages in memory was too high, so apply some
|
|
* pressure to decrease it. First, make room for the largest possible
|
|
* image and fail if that doesn't work. Next, try to decrease the size
|
|
* of the image as much as indicated by 'size' using allocations from
|
|
* highmem and non-highmem zones separately.
|
|
*/
|
|
pages_highmem = preallocate_image_highmem(highmem / 2);
|
|
alloc = count - max_size;
|
|
if (alloc > pages_highmem)
|
|
alloc -= pages_highmem;
|
|
else
|
|
alloc = 0;
|
|
pages = preallocate_image_memory(alloc, avail_normal);
|
|
if (pages < alloc) {
|
|
/* We have exhausted non-highmem pages, try highmem. */
|
|
alloc -= pages;
|
|
pages += pages_highmem;
|
|
pages_highmem = preallocate_image_highmem(alloc);
|
|
if (pages_highmem < alloc) {
|
|
pr_err("Image allocation is %lu pages short\n",
|
|
alloc - pages_highmem);
|
|
goto err_out;
|
|
}
|
|
pages += pages_highmem;
|
|
/*
|
|
* size is the desired number of saveable pages to leave in
|
|
* memory, so try to preallocate (all memory - size) pages.
|
|
*/
|
|
alloc = (count - pages) - size;
|
|
pages += preallocate_image_highmem(alloc);
|
|
} else {
|
|
/*
|
|
* There are approximately max_size saveable pages at this point
|
|
* and we want to reduce this number down to size.
|
|
*/
|
|
alloc = max_size - size;
|
|
size = preallocate_highmem_fraction(alloc, highmem, count);
|
|
pages_highmem += size;
|
|
alloc -= size;
|
|
size = preallocate_image_memory(alloc, avail_normal);
|
|
pages_highmem += preallocate_image_highmem(alloc - size);
|
|
pages += pages_highmem + size;
|
|
}
|
|
|
|
/*
|
|
* We only need as many page frames for the image as there are saveable
|
|
* pages in memory, but we have allocated more. Release the excessive
|
|
* ones now.
|
|
*/
|
|
pages -= free_unnecessary_pages();
|
|
|
|
out:
|
|
stop = ktime_get();
|
|
pr_info("Allocated %lu pages for snapshot\n", pages);
|
|
swsusp_show_speed(start, stop, pages, "Allocated");
|
|
|
|
return 0;
|
|
|
|
err_out:
|
|
swsusp_free();
|
|
return -ENOMEM;
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
/**
|
|
* count_pages_for_highmem - Count non-highmem pages needed for copying highmem.
|
|
*
|
|
* Compute the number of non-highmem pages that will be necessary for creating
|
|
* copies of highmem pages.
|
|
*/
|
|
static unsigned int count_pages_for_highmem(unsigned int nr_highmem)
|
|
{
|
|
unsigned int free_highmem = count_free_highmem_pages() + alloc_highmem;
|
|
|
|
if (free_highmem >= nr_highmem)
|
|
nr_highmem = 0;
|
|
else
|
|
nr_highmem -= free_highmem;
|
|
|
|
return nr_highmem;
|
|
}
|
|
#else
|
|
static unsigned int count_pages_for_highmem(unsigned int nr_highmem) { return 0; }
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
/**
|
|
* enough_free_mem - Check if there is enough free memory for the image.
|
|
*/
|
|
static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
|
|
{
|
|
struct zone *zone;
|
|
unsigned int free = alloc_normal;
|
|
|
|
for_each_populated_zone(zone)
|
|
if (!is_highmem(zone))
|
|
free += zone_page_state(zone, NR_FREE_PAGES);
|
|
|
|
nr_pages += count_pages_for_highmem(nr_highmem);
|
|
pr_debug("Normal pages needed: %u + %u, available pages: %u\n",
|
|
nr_pages, PAGES_FOR_IO, free);
|
|
|
|
return free > nr_pages + PAGES_FOR_IO;
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
/**
|
|
* get_highmem_buffer - Allocate a buffer for highmem pages.
|
|
*
|
|
* If there are some highmem pages in the hibernation image, we may need a
|
|
* buffer to copy them and/or load their data.
|
|
*/
|
|
static inline int get_highmem_buffer(int safe_needed)
|
|
{
|
|
buffer = get_image_page(GFP_ATOMIC, safe_needed);
|
|
return buffer ? 0 : -ENOMEM;
|
|
}
|
|
|
|
/**
|
|
* alloc_highmem_image_pages - Allocate some highmem pages for the image.
|
|
*
|
|
* Try to allocate as many pages as needed, but if the number of free highmem
|
|
* pages is less than that, allocate them all.
|
|
*/
|
|
static inline unsigned int alloc_highmem_pages(struct memory_bitmap *bm,
|
|
unsigned int nr_highmem)
|
|
{
|
|
unsigned int to_alloc = count_free_highmem_pages();
|
|
|
|
if (to_alloc > nr_highmem)
|
|
to_alloc = nr_highmem;
|
|
|
|
nr_highmem -= to_alloc;
|
|
while (to_alloc-- > 0) {
|
|
struct page *page;
|
|
|
|
page = alloc_image_page(__GFP_HIGHMEM|__GFP_KSWAPD_RECLAIM);
|
|
memory_bm_set_bit(bm, page_to_pfn(page));
|
|
}
|
|
return nr_highmem;
|
|
}
|
|
#else
|
|
static inline int get_highmem_buffer(int safe_needed) { return 0; }
|
|
|
|
static inline unsigned int alloc_highmem_pages(struct memory_bitmap *bm,
|
|
unsigned int n) { return 0; }
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
/**
|
|
* swsusp_alloc - Allocate memory for hibernation image.
|
|
*
|
|
* We first try to allocate as many highmem pages as there are
|
|
* saveable highmem pages in the system. If that fails, we allocate
|
|
* non-highmem pages for the copies of the remaining highmem ones.
|
|
*
|
|
* In this approach it is likely that the copies of highmem pages will
|
|
* also be located in the high memory, because of the way in which
|
|
* copy_data_pages() works.
|
|
*/
|
|
static int swsusp_alloc(struct memory_bitmap *copy_bm,
|
|
unsigned int nr_pages, unsigned int nr_highmem)
|
|
{
|
|
if (nr_highmem > 0) {
|
|
if (get_highmem_buffer(PG_ANY))
|
|
goto err_out;
|
|
if (nr_highmem > alloc_highmem) {
|
|
nr_highmem -= alloc_highmem;
|
|
nr_pages += alloc_highmem_pages(copy_bm, nr_highmem);
|
|
}
|
|
}
|
|
if (nr_pages > alloc_normal) {
|
|
nr_pages -= alloc_normal;
|
|
while (nr_pages-- > 0) {
|
|
struct page *page;
|
|
|
|
page = alloc_image_page(GFP_ATOMIC);
|
|
if (!page)
|
|
goto err_out;
|
|
memory_bm_set_bit(copy_bm, page_to_pfn(page));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_out:
|
|
swsusp_free();
|
|
return -ENOMEM;
|
|
}
|
|
|
|
asmlinkage __visible int swsusp_save(void)
|
|
{
|
|
unsigned int nr_pages, nr_highmem;
|
|
|
|
pr_info("Creating image:\n");
|
|
|
|
drain_local_pages(NULL);
|
|
nr_pages = count_data_pages();
|
|
nr_highmem = count_highmem_pages();
|
|
pr_info("Need to copy %u pages\n", nr_pages + nr_highmem);
|
|
|
|
if (!enough_free_mem(nr_pages, nr_highmem)) {
|
|
pr_err("Not enough free memory\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (swsusp_alloc(©_bm, nr_pages, nr_highmem)) {
|
|
pr_err("Memory allocation failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* During allocating of suspend pagedir, new cold pages may appear.
|
|
* Kill them.
|
|
*/
|
|
drain_local_pages(NULL);
|
|
copy_data_pages(©_bm, &orig_bm);
|
|
|
|
/*
|
|
* End of critical section. From now on, we can write to memory,
|
|
* but we should not touch disk. This specially means we must _not_
|
|
* touch swap space! Except we must write out our image of course.
|
|
*/
|
|
|
|
nr_pages += nr_highmem;
|
|
nr_copy_pages = nr_pages;
|
|
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
|
|
|
|
pr_info("Image created (%d pages copied)\n", nr_pages);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifndef CONFIG_ARCH_HIBERNATION_HEADER
|
|
static int init_header_complete(struct swsusp_info *info)
|
|
{
|
|
memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
|
|
info->version_code = LINUX_VERSION_CODE;
|
|
return 0;
|
|
}
|
|
|
|
static const char *check_image_kernel(struct swsusp_info *info)
|
|
{
|
|
if (info->version_code != LINUX_VERSION_CODE)
|
|
return "kernel version";
|
|
if (strcmp(info->uts.sysname,init_utsname()->sysname))
|
|
return "system type";
|
|
if (strcmp(info->uts.release,init_utsname()->release))
|
|
return "kernel release";
|
|
if (strcmp(info->uts.version,init_utsname()->version))
|
|
return "version";
|
|
if (strcmp(info->uts.machine,init_utsname()->machine))
|
|
return "machine";
|
|
return NULL;
|
|
}
|
|
#endif /* CONFIG_ARCH_HIBERNATION_HEADER */
|
|
|
|
unsigned long snapshot_get_image_size(void)
|
|
{
|
|
return nr_copy_pages + nr_meta_pages + 1;
|
|
}
|
|
|
|
static int init_header(struct swsusp_info *info)
|
|
{
|
|
memset(info, 0, sizeof(struct swsusp_info));
|
|
info->num_physpages = get_num_physpages();
|
|
info->image_pages = nr_copy_pages;
|
|
info->pages = snapshot_get_image_size();
|
|
info->size = info->pages;
|
|
info->size <<= PAGE_SHIFT;
|
|
return init_header_complete(info);
|
|
}
|
|
|
|
/**
|
|
* pack_pfns - Prepare PFNs for saving.
|
|
* @bm: Memory bitmap.
|
|
* @buf: Memory buffer to store the PFNs in.
|
|
*
|
|
* PFNs corresponding to set bits in @bm are stored in the area of memory
|
|
* pointed to by @buf (1 page at a time).
|
|
*/
|
|
static inline void pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {
|
|
buf[j] = memory_bm_next_pfn(bm);
|
|
if (unlikely(buf[j] == BM_END_OF_MAP))
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* snapshot_read_next - Get the address to read the next image page from.
|
|
* @handle: Snapshot handle to be used for the reading.
|
|
*
|
|
* On the first call, @handle should point to a zeroed snapshot_handle
|
|
* structure. The structure gets populated then and a pointer to it should be
|
|
* passed to this function every next time.
|
|
*
|
|
* On success, the function returns a positive number. Then, the caller
|
|
* is allowed to read up to the returned number of bytes from the memory
|
|
* location computed by the data_of() macro.
|
|
*
|
|
* The function returns 0 to indicate the end of the data stream condition,
|
|
* and negative numbers are returned on errors. If that happens, the structure
|
|
* pointed to by @handle is not updated and should not be used any more.
|
|
*/
|
|
int snapshot_read_next(struct snapshot_handle *handle)
|
|
{
|
|
if (handle->cur > nr_meta_pages + nr_copy_pages)
|
|
return 0;
|
|
|
|
if (!buffer) {
|
|
/* This makes the buffer be freed by swsusp_free() */
|
|
buffer = get_image_page(GFP_ATOMIC, PG_ANY);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
}
|
|
if (!handle->cur) {
|
|
int error;
|
|
|
|
error = init_header((struct swsusp_info *)buffer);
|
|
if (error)
|
|
return error;
|
|
handle->buffer = buffer;
|
|
memory_bm_position_reset(&orig_bm);
|
|
memory_bm_position_reset(©_bm);
|
|
} else if (handle->cur <= nr_meta_pages) {
|
|
clear_page(buffer);
|
|
pack_pfns(buffer, &orig_bm);
|
|
} else {
|
|
struct page *page;
|
|
|
|
page = pfn_to_page(memory_bm_next_pfn(©_bm));
|
|
if (PageHighMem(page)) {
|
|
/*
|
|
* Highmem pages are copied to the buffer,
|
|
* because we can't return with a kmapped
|
|
* highmem page (we may not be called again).
|
|
*/
|
|
void *kaddr;
|
|
|
|
kaddr = kmap_atomic(page);
|
|
copy_page(buffer, kaddr);
|
|
kunmap_atomic(kaddr);
|
|
handle->buffer = buffer;
|
|
} else {
|
|
handle->buffer = page_address(page);
|
|
}
|
|
}
|
|
handle->cur++;
|
|
return PAGE_SIZE;
|
|
}
|
|
|
|
static void duplicate_memory_bitmap(struct memory_bitmap *dst,
|
|
struct memory_bitmap *src)
|
|
{
|
|
unsigned long pfn;
|
|
|
|
memory_bm_position_reset(src);
|
|
pfn = memory_bm_next_pfn(src);
|
|
while (pfn != BM_END_OF_MAP) {
|
|
memory_bm_set_bit(dst, pfn);
|
|
pfn = memory_bm_next_pfn(src);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* mark_unsafe_pages - Mark pages that were used before hibernation.
|
|
*
|
|
* Mark the pages that cannot be used for storing the image during restoration,
|
|
* because they conflict with the pages that had been used before hibernation.
|
|
*/
|
|
static void mark_unsafe_pages(struct memory_bitmap *bm)
|
|
{
|
|
unsigned long pfn;
|
|
|
|
/* Clear the "free"/"unsafe" bit for all PFNs */
|
|
memory_bm_position_reset(free_pages_map);
|
|
pfn = memory_bm_next_pfn(free_pages_map);
|
|
while (pfn != BM_END_OF_MAP) {
|
|
memory_bm_clear_current(free_pages_map);
|
|
pfn = memory_bm_next_pfn(free_pages_map);
|
|
}
|
|
|
|
/* Mark pages that correspond to the "original" PFNs as "unsafe" */
|
|
duplicate_memory_bitmap(free_pages_map, bm);
|
|
|
|
allocated_unsafe_pages = 0;
|
|
}
|
|
|
|
static int check_header(struct swsusp_info *info)
|
|
{
|
|
const char *reason;
|
|
|
|
reason = check_image_kernel(info);
|
|
if (!reason && info->num_physpages != get_num_physpages())
|
|
reason = "memory size";
|
|
if (reason) {
|
|
pr_err("Image mismatch: %s\n", reason);
|
|
return -EPERM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* load header - Check the image header and copy the data from it.
|
|
*/
|
|
static int load_header(struct swsusp_info *info)
|
|
{
|
|
int error;
|
|
|
|
restore_pblist = NULL;
|
|
error = check_header(info);
|
|
if (!error) {
|
|
nr_copy_pages = info->image_pages;
|
|
nr_meta_pages = info->pages - info->image_pages - 1;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* unpack_orig_pfns - Set bits corresponding to given PFNs in a memory bitmap.
|
|
* @bm: Memory bitmap.
|
|
* @buf: Area of memory containing the PFNs.
|
|
*
|
|
* For each element of the array pointed to by @buf (1 page at a time), set the
|
|
* corresponding bit in @bm.
|
|
*/
|
|
static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {
|
|
if (unlikely(buf[j] == BM_END_OF_MAP))
|
|
break;
|
|
|
|
if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j]))
|
|
memory_bm_set_bit(bm, buf[j]);
|
|
else
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
/*
|
|
* struct highmem_pbe is used for creating the list of highmem pages that
|
|
* should be restored atomically during the resume from disk, because the page
|
|
* frames they have occupied before the suspend are in use.
|
|
*/
|
|
struct highmem_pbe {
|
|
struct page *copy_page; /* data is here now */
|
|
struct page *orig_page; /* data was here before the suspend */
|
|
struct highmem_pbe *next;
|
|
};
|
|
|
|
/*
|
|
* List of highmem PBEs needed for restoring the highmem pages that were
|
|
* allocated before the suspend and included in the suspend image, but have
|
|
* also been allocated by the "resume" kernel, so their contents cannot be
|
|
* written directly to their "original" page frames.
|
|
*/
|
|
static struct highmem_pbe *highmem_pblist;
|
|
|
|
/**
|
|
* count_highmem_image_pages - Compute the number of highmem pages in the image.
|
|
* @bm: Memory bitmap.
|
|
*
|
|
* The bits in @bm that correspond to image pages are assumed to be set.
|
|
*/
|
|
static unsigned int count_highmem_image_pages(struct memory_bitmap *bm)
|
|
{
|
|
unsigned long pfn;
|
|
unsigned int cnt = 0;
|
|
|
|
memory_bm_position_reset(bm);
|
|
pfn = memory_bm_next_pfn(bm);
|
|
while (pfn != BM_END_OF_MAP) {
|
|
if (PageHighMem(pfn_to_page(pfn)))
|
|
cnt++;
|
|
|
|
pfn = memory_bm_next_pfn(bm);
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
static unsigned int safe_highmem_pages;
|
|
|
|
static struct memory_bitmap *safe_highmem_bm;
|
|
|
|
/**
|
|
* prepare_highmem_image - Allocate memory for loading highmem data from image.
|
|
* @bm: Pointer to an uninitialized memory bitmap structure.
|
|
* @nr_highmem_p: Pointer to the number of highmem image pages.
|
|
*
|
|
* Try to allocate as many highmem pages as there are highmem image pages
|
|
* (@nr_highmem_p points to the variable containing the number of highmem image
|
|
* pages). The pages that are "safe" (ie. will not be overwritten when the
|
|
* hibernation image is restored entirely) have the corresponding bits set in
|
|
* @bm (it must be unitialized).
|
|
*
|
|
* NOTE: This function should not be called if there are no highmem image pages.
|
|
*/
|
|
static int prepare_highmem_image(struct memory_bitmap *bm,
|
|
unsigned int *nr_highmem_p)
|
|
{
|
|
unsigned int to_alloc;
|
|
|
|
if (memory_bm_create(bm, GFP_ATOMIC, PG_SAFE))
|
|
return -ENOMEM;
|
|
|
|
if (get_highmem_buffer(PG_SAFE))
|
|
return -ENOMEM;
|
|
|
|
to_alloc = count_free_highmem_pages();
|
|
if (to_alloc > *nr_highmem_p)
|
|
to_alloc = *nr_highmem_p;
|
|
else
|
|
*nr_highmem_p = to_alloc;
|
|
|
|
safe_highmem_pages = 0;
|
|
while (to_alloc-- > 0) {
|
|
struct page *page;
|
|
|
|
page = alloc_page(__GFP_HIGHMEM);
|
|
if (!swsusp_page_is_free(page)) {
|
|
/* The page is "safe", set its bit the bitmap */
|
|
memory_bm_set_bit(bm, page_to_pfn(page));
|
|
safe_highmem_pages++;
|
|
}
|
|
/* Mark the page as allocated */
|
|
swsusp_set_page_forbidden(page);
|
|
swsusp_set_page_free(page);
|
|
}
|
|
memory_bm_position_reset(bm);
|
|
safe_highmem_bm = bm;
|
|
return 0;
|
|
}
|
|
|
|
static struct page *last_highmem_page;
|
|
|
|
/**
|
|
* get_highmem_page_buffer - Prepare a buffer to store a highmem image page.
|
|
*
|
|
* For a given highmem image page get a buffer that suspend_write_next() should
|
|
* return to its caller to write to.
|
|
*
|
|
* If the page is to be saved to its "original" page frame or a copy of
|
|
* the page is to be made in the highmem, @buffer is returned. Otherwise,
|
|
* the copy of the page is to be made in normal memory, so the address of
|
|
* the copy is returned.
|
|
*
|
|
* If @buffer is returned, the caller of suspend_write_next() will write
|
|
* the page's contents to @buffer, so they will have to be copied to the
|
|
* right location on the next call to suspend_write_next() and it is done
|
|
* with the help of copy_last_highmem_page(). For this purpose, if
|
|
* @buffer is returned, @last_highmem_page is set to the page to which
|
|
* the data will have to be copied from @buffer.
|
|
*/
|
|
static void *get_highmem_page_buffer(struct page *page,
|
|
struct chain_allocator *ca)
|
|
{
|
|
struct highmem_pbe *pbe;
|
|
void *kaddr;
|
|
|
|
if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) {
|
|
/*
|
|
* We have allocated the "original" page frame and we can
|
|
* use it directly to store the loaded page.
|
|
*/
|
|
last_highmem_page = page;
|
|
return buffer;
|
|
}
|
|
/*
|
|
* The "original" page frame has not been allocated and we have to
|
|
* use a "safe" page frame to store the loaded page.
|
|
*/
|
|
pbe = chain_alloc(ca, sizeof(struct highmem_pbe));
|
|
if (!pbe) {
|
|
swsusp_free();
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
pbe->orig_page = page;
|
|
if (safe_highmem_pages > 0) {
|
|
struct page *tmp;
|
|
|
|
/* Copy of the page will be stored in high memory */
|
|
kaddr = buffer;
|
|
tmp = pfn_to_page(memory_bm_next_pfn(safe_highmem_bm));
|
|
safe_highmem_pages--;
|
|
last_highmem_page = tmp;
|
|
pbe->copy_page = tmp;
|
|
} else {
|
|
/* Copy of the page will be stored in normal memory */
|
|
kaddr = safe_pages_list;
|
|
safe_pages_list = safe_pages_list->next;
|
|
pbe->copy_page = virt_to_page(kaddr);
|
|
}
|
|
pbe->next = highmem_pblist;
|
|
highmem_pblist = pbe;
|
|
return kaddr;
|
|
}
|
|
|
|
/**
|
|
* copy_last_highmem_page - Copy most the most recent highmem image page.
|
|
*
|
|
* Copy the contents of a highmem image from @buffer, where the caller of
|
|
* snapshot_write_next() has stored them, to the right location represented by
|
|
* @last_highmem_page .
|
|
*/
|
|
static void copy_last_highmem_page(void)
|
|
{
|
|
if (last_highmem_page) {
|
|
void *dst;
|
|
|
|
dst = kmap_atomic(last_highmem_page);
|
|
copy_page(dst, buffer);
|
|
kunmap_atomic(dst);
|
|
last_highmem_page = NULL;
|
|
}
|
|
}
|
|
|
|
static inline int last_highmem_page_copied(void)
|
|
{
|
|
return !last_highmem_page;
|
|
}
|
|
|
|
static inline void free_highmem_data(void)
|
|
{
|
|
if (safe_highmem_bm)
|
|
memory_bm_free(safe_highmem_bm, PG_UNSAFE_CLEAR);
|
|
|
|
if (buffer)
|
|
free_image_page(buffer, PG_UNSAFE_CLEAR);
|
|
}
|
|
#else
|
|
static unsigned int count_highmem_image_pages(struct memory_bitmap *bm) { return 0; }
|
|
|
|
static inline int prepare_highmem_image(struct memory_bitmap *bm,
|
|
unsigned int *nr_highmem_p) { return 0; }
|
|
|
|
static inline void *get_highmem_page_buffer(struct page *page,
|
|
struct chain_allocator *ca)
|
|
{
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
static inline void copy_last_highmem_page(void) {}
|
|
static inline int last_highmem_page_copied(void) { return 1; }
|
|
static inline void free_highmem_data(void) {}
|
|
#endif /* CONFIG_HIGHMEM */
|
|
|
|
#define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe))
|
|
|
|
/**
|
|
* prepare_image - Make room for loading hibernation image.
|
|
* @new_bm: Unitialized memory bitmap structure.
|
|
* @bm: Memory bitmap with unsafe pages marked.
|
|
*
|
|
* Use @bm to mark the pages that will be overwritten in the process of
|
|
* restoring the system memory state from the suspend image ("unsafe" pages)
|
|
* and allocate memory for the image.
|
|
*
|
|
* The idea is to allocate a new memory bitmap first and then allocate
|
|
* as many pages as needed for image data, but without specifying what those
|
|
* pages will be used for just yet. Instead, we mark them all as allocated and
|
|
* create a lists of "safe" pages to be used later. On systems with high
|
|
* memory a list of "safe" highmem pages is created too.
|
|
*/
|
|
static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
|
|
{
|
|
unsigned int nr_pages, nr_highmem;
|
|
struct linked_page *lp;
|
|
int error;
|
|
|
|
/* If there is no highmem, the buffer will not be necessary */
|
|
free_image_page(buffer, PG_UNSAFE_CLEAR);
|
|
buffer = NULL;
|
|
|
|
nr_highmem = count_highmem_image_pages(bm);
|
|
mark_unsafe_pages(bm);
|
|
|
|
error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE);
|
|
if (error)
|
|
goto Free;
|
|
|
|
duplicate_memory_bitmap(new_bm, bm);
|
|
memory_bm_free(bm, PG_UNSAFE_KEEP);
|
|
if (nr_highmem > 0) {
|
|
error = prepare_highmem_image(bm, &nr_highmem);
|
|
if (error)
|
|
goto Free;
|
|
}
|
|
/*
|
|
* Reserve some safe pages for potential later use.
|
|
*
|
|
* NOTE: This way we make sure there will be enough safe pages for the
|
|
* chain_alloc() in get_buffer(). It is a bit wasteful, but
|
|
* nr_copy_pages cannot be greater than 50% of the memory anyway.
|
|
*
|
|
* nr_copy_pages cannot be less than allocated_unsafe_pages too.
|
|
*/
|
|
nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
|
|
nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE);
|
|
while (nr_pages > 0) {
|
|
lp = get_image_page(GFP_ATOMIC, PG_SAFE);
|
|
if (!lp) {
|
|
error = -ENOMEM;
|
|
goto Free;
|
|
}
|
|
lp->next = safe_pages_list;
|
|
safe_pages_list = lp;
|
|
nr_pages--;
|
|
}
|
|
/* Preallocate memory for the image */
|
|
nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
|
|
while (nr_pages > 0) {
|
|
lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC);
|
|
if (!lp) {
|
|
error = -ENOMEM;
|
|
goto Free;
|
|
}
|
|
if (!swsusp_page_is_free(virt_to_page(lp))) {
|
|
/* The page is "safe", add it to the list */
|
|
lp->next = safe_pages_list;
|
|
safe_pages_list = lp;
|
|
}
|
|
/* Mark the page as allocated */
|
|
swsusp_set_page_forbidden(virt_to_page(lp));
|
|
swsusp_set_page_free(virt_to_page(lp));
|
|
nr_pages--;
|
|
}
|
|
return 0;
|
|
|
|
Free:
|
|
swsusp_free();
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* get_buffer - Get the address to store the next image data page.
|
|
*
|
|
* Get the address that snapshot_write_next() should return to its caller to
|
|
* write to.
|
|
*/
|
|
static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
|
|
{
|
|
struct pbe *pbe;
|
|
struct page *page;
|
|
unsigned long pfn = memory_bm_next_pfn(bm);
|
|
|
|
if (pfn == BM_END_OF_MAP)
|
|
return ERR_PTR(-EFAULT);
|
|
|
|
page = pfn_to_page(pfn);
|
|
if (PageHighMem(page))
|
|
return get_highmem_page_buffer(page, ca);
|
|
|
|
if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page))
|
|
/*
|
|
* We have allocated the "original" page frame and we can
|
|
* use it directly to store the loaded page.
|
|
*/
|
|
return page_address(page);
|
|
|
|
/*
|
|
* The "original" page frame has not been allocated and we have to
|
|
* use a "safe" page frame to store the loaded page.
|
|
*/
|
|
pbe = chain_alloc(ca, sizeof(struct pbe));
|
|
if (!pbe) {
|
|
swsusp_free();
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
pbe->orig_address = page_address(page);
|
|
pbe->address = safe_pages_list;
|
|
safe_pages_list = safe_pages_list->next;
|
|
pbe->next = restore_pblist;
|
|
restore_pblist = pbe;
|
|
return pbe->address;
|
|
}
|
|
|
|
/**
|
|
* snapshot_write_next - Get the address to store the next image page.
|
|
* @handle: Snapshot handle structure to guide the writing.
|
|
*
|
|
* On the first call, @handle should point to a zeroed snapshot_handle
|
|
* structure. The structure gets populated then and a pointer to it should be
|
|
* passed to this function every next time.
|
|
*
|
|
* On success, the function returns a positive number. Then, the caller
|
|
* is allowed to write up to the returned number of bytes to the memory
|
|
* location computed by the data_of() macro.
|
|
*
|
|
* The function returns 0 to indicate the "end of file" condition. Negative
|
|
* numbers are returned on errors, in which cases the structure pointed to by
|
|
* @handle is not updated and should not be used any more.
|
|
*/
|
|
int snapshot_write_next(struct snapshot_handle *handle)
|
|
{
|
|
static struct chain_allocator ca;
|
|
int error = 0;
|
|
|
|
/* Check if we have already loaded the entire image */
|
|
if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages)
|
|
return 0;
|
|
|
|
handle->sync_read = 1;
|
|
|
|
if (!handle->cur) {
|
|
if (!buffer)
|
|
/* This makes the buffer be freed by swsusp_free() */
|
|
buffer = get_image_page(GFP_ATOMIC, PG_ANY);
|
|
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
handle->buffer = buffer;
|
|
} else if (handle->cur == 1) {
|
|
error = load_header(buffer);
|
|
if (error)
|
|
return error;
|
|
|
|
safe_pages_list = NULL;
|
|
|
|
error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY);
|
|
if (error)
|
|
return error;
|
|
|
|
hibernate_restore_protection_begin();
|
|
} else if (handle->cur <= nr_meta_pages + 1) {
|
|
error = unpack_orig_pfns(buffer, ©_bm);
|
|
if (error)
|
|
return error;
|
|
|
|
if (handle->cur == nr_meta_pages + 1) {
|
|
error = prepare_image(&orig_bm, ©_bm);
|
|
if (error)
|
|
return error;
|
|
|
|
chain_init(&ca, GFP_ATOMIC, PG_SAFE);
|
|
memory_bm_position_reset(&orig_bm);
|
|
restore_pblist = NULL;
|
|
handle->buffer = get_buffer(&orig_bm, &ca);
|
|
handle->sync_read = 0;
|
|
if (IS_ERR(handle->buffer))
|
|
return PTR_ERR(handle->buffer);
|
|
}
|
|
} else {
|
|
copy_last_highmem_page();
|
|
hibernate_restore_protect_page(handle->buffer);
|
|
handle->buffer = get_buffer(&orig_bm, &ca);
|
|
if (IS_ERR(handle->buffer))
|
|
return PTR_ERR(handle->buffer);
|
|
if (handle->buffer != buffer)
|
|
handle->sync_read = 0;
|
|
}
|
|
handle->cur++;
|
|
return PAGE_SIZE;
|
|
}
|
|
|
|
/**
|
|
* snapshot_write_finalize - Complete the loading of a hibernation image.
|
|
*
|
|
* Must be called after the last call to snapshot_write_next() in case the last
|
|
* page in the image happens to be a highmem page and its contents should be
|
|
* stored in highmem. Additionally, it recycles bitmap memory that's not
|
|
* necessary any more.
|
|
*/
|
|
void snapshot_write_finalize(struct snapshot_handle *handle)
|
|
{
|
|
copy_last_highmem_page();
|
|
hibernate_restore_protect_page(handle->buffer);
|
|
/* Do that only if we have loaded the image entirely */
|
|
if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) {
|
|
memory_bm_recycle(&orig_bm);
|
|
free_highmem_data();
|
|
}
|
|
}
|
|
|
|
int snapshot_image_loaded(struct snapshot_handle *handle)
|
|
{
|
|
return !(!nr_copy_pages || !last_highmem_page_copied() ||
|
|
handle->cur <= nr_meta_pages + nr_copy_pages);
|
|
}
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
/* Assumes that @buf is ready and points to a "safe" page */
|
|
static inline void swap_two_pages_data(struct page *p1, struct page *p2,
|
|
void *buf)
|
|
{
|
|
void *kaddr1, *kaddr2;
|
|
|
|
kaddr1 = kmap_atomic(p1);
|
|
kaddr2 = kmap_atomic(p2);
|
|
copy_page(buf, kaddr1);
|
|
copy_page(kaddr1, kaddr2);
|
|
copy_page(kaddr2, buf);
|
|
kunmap_atomic(kaddr2);
|
|
kunmap_atomic(kaddr1);
|
|
}
|
|
|
|
/**
|
|
* restore_highmem - Put highmem image pages into their original locations.
|
|
*
|
|
* For each highmem page that was in use before hibernation and is included in
|
|
* the image, and also has been allocated by the "restore" kernel, swap its
|
|
* current contents with the previous (ie. "before hibernation") ones.
|
|
*
|
|
* If the restore eventually fails, we can call this function once again and
|
|
* restore the highmem state as seen by the restore kernel.
|
|
*/
|
|
int restore_highmem(void)
|
|
{
|
|
struct highmem_pbe *pbe = highmem_pblist;
|
|
void *buf;
|
|
|
|
if (!pbe)
|
|
return 0;
|
|
|
|
buf = get_image_page(GFP_ATOMIC, PG_SAFE);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
while (pbe) {
|
|
swap_two_pages_data(pbe->copy_page, pbe->orig_page, buf);
|
|
pbe = pbe->next;
|
|
}
|
|
free_image_page(buf, PG_UNSAFE_CLEAR);
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_HIGHMEM */
|