android_kernel_samsung_sm8650/kernel/power/swap.c
Greg Kroah-Hartman 87a4e67740 Merge tag 'android14-6.1.78_r00' into branch android14-6.1
This brings the android14-6.1 branch up to date with the 6.1.78 LTS
release.  Included in here are the following commits:

* 4b97573495 Revert "hrtimer: Report offline hrtimer enqueue"
*   0e5af42a0a Merge 6.1.78 into android14-6.1-lts
|\
| * 8b4118fabd Linux 6.1.78
| * 1296c110c5 netfilter: nft_set_rbtree: skip end interval element from gc
| * d89a80e482 net: stmmac: xgmac: fix a typo of register name in DPP safety handling
| * 7b430fb924 ALSA: usb-audio: Sort quirk table entries
| * 06040fadbf net: stmmac: xgmac: use #define for string constants
| * 499e6e9f07 clocksource: Skip watchdog check for large watchdog intervals
| * 492e0aba08 block: treat poll queue enter similarly to timeouts
| * cf3d57ad6f f2fs: add helper to check compression level
| * 9f74b3d718 RDMA/irdma: Fix support for 64k pages
| * 4675661672 vhost: use kzalloc() instead of kmalloc() followed by memset()
| * d8712c6c6a Revert "ASoC: amd: Add new dmi entries for acp5x platform"
| * fbd77ce1d1 io_uring/net: fix sr->len for IORING_OP_RECV with MSG_WAITALL and buffers
| * 08249dc3d9 Input: atkbd - skip ATKBD_CMD_SETLEDS when skipping ATKBD_CMD_GETID
| * 315075ac73 Input: i8042 - fix strange behavior of touchpad on Clevo NS70PU
| * a94d303bea hrtimer: Report offline hrtimer enqueue
| * 8b380ad970 usb: host: xhci-plat: Add support for XHCI_SG_TRB_CACHE_SIZE_QUIRK
| * f2cf6db285 usb: dwc3: host: Set XHCI_SG_TRB_CACHE_SIZE_QUIRK
| * 041cb58f54 USB: serial: cp210x: add ID for IMST iM871A-USB
| * 36ef5b7b4f USB: serial: option: add Fibocom FM101-GL variant
| * 234099ab7f USB: serial: qcserial: add new usb-id for Dell Wireless DW5826e
| * 39fbca505f ALSA: usb-audio: add quirk for RODE NT-USB+
| * 2552f6b1bd ALSA: usb-audio: Add a quirk for Yamaha YIT-W12TX transmitter
| * b8259a5023 ALSA: usb-audio: Add delay quirk for MOTU M Series 2nd revision
| * 82761993d4 mtd: parsers: ofpart: add workaround for #size-cells 0
| * b478e414cf fs: dlm: don't put dlm_local_addrs on heap
| * e5dc63f01e blk-iocost: Fix an UBSAN shift-out-of-bounds warning
| * 1ebd75cefa scsi: core: Move scsi_host_busy() out of host lock if it is for per-command
| * ec1bedd797 fs/ntfs3: Fix an NULL dereference bug
| * a442ff5405 netfilter: nft_set_pipapo: remove scratch_aligned pointer
| * fac3478d5b netfilter: nft_set_pipapo: add helper to release pcpu scratch area
| * 3eaab7d565 netfilter: nft_set_pipapo: store index in scratch maps
| * 181dade251 netfilter: nft_ct: reject direction for ct id
| * efdd665ce1 drm/amd/display: Implement bounds check for stream encoder creation in DCN301
| * a060da3235 netfilter: nft_compat: restrict match/target protocol to u16
| * 8762bcc927 netfilter: nft_compat: reject unused compat flag
| * e79ef7966e netfilter: nft_compat: narrow down revision to unsigned 8-bits
| * 69d66d493b selftests: cmsg_ipv6: repeat the exact packet
| * 4e2c4846b2 ppp_async: limit MRU to 64K
| * e0e09186d8 af_unix: Call kfree_skb() for dead unix_(sk)->oob_skb in GC.
| * 3d3a5b31b4 tipc: Check the bearer type before calling tipc_udp_nl_bearer_add()
| * cf6b97e183 rxrpc: Fix response to PING RESPONSE ACKs to a dead call
| * 05a4d0e166 drm/i915/gvt: Fix uninitialized variable in handle_mmio()
| * 5453875221 inet: read sk->sk_family once in inet_recv_error()
| * 3fa78ee0e3 hwmon: (coretemp) Fix bogus core_id to attr name mapping
| * 9bce694192 hwmon: (coretemp) Fix out-of-bounds memory access
| * a3156be201 hwmon: (aspeed-pwm-tacho) mutex for tach reading
| * 4065746686 octeontx2-pf: Fix a memleak otx2_sq_init
| * cbf2e16602 atm: idt77252: fix a memleak in open_card_ubr0
| * e37cde7a57 tunnels: fix out of bounds access when building IPv6 PMTU error
| * 90fe47743a selftests: net: avoid just another constant wait
| * 7f484179c5 selftests: net: cut more slack for gro fwd tests.
| * 466ceebe48 net: atlantic: Fix DMA mapping for PTP hwts ring
| * 0193e0660c netdevsim: avoid potential loop in nsim_dev_trap_report_work()
| * bcabbf8ab5 wifi: mac80211: fix waiting for beacons logic
| * e42ff0844f net: stmmac: xgmac: fix handling of DPP safety error for DMA channels
| * fb8bfc6ea3 drm/msm/dpu: check for valid hw_pp in dpu_encoder_helper_phys_cleanup
| * 42939a1ea6 drm/msm/dp: return correct Colorimetry for DP_TEST_DYNAMIC_RANGE_CEA case
| * d2b7e247f3 drm/msms/dp: fixed link clock divider bits be over written in BPC unknown case
| * cbc53148cc cifs: failure to add channel on iface should bump up weight
| * 0430bfcd46 phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
| * 296fb308f4 dmaengine: fix is_slave_direction() return false when DMA_DEV_TO_DEV
| * ed3bb52a05 phy: renesas: rcar-gen3-usb2: Fix returning wrong error code
| * 25ab4d72eb dmaengine: fsl-qdma: Fix a memory leak related to the queue command DMA
| * 13535ae766 dmaengine: fsl-qdma: Fix a memory leak related to the status queue DMA
| * 908939b8e8 dmaengine: ti: k3-udma: Report short packet errors
| * a1d7ca71ba dmaengine: fsl-dpaa2-qdma: Fix the size of dma pools
| * 78327acd4c ext4: regenerate buddy after block freeing failed if under fc replay
* | 19c319d14d Revert "drm/mipi-dsi: Fix detach call without attach"
* | 20b90d46a0 Merge 6.1.77 into android14-6.1-lts
|\|
| * f1bb70486c Linux 6.1.77
| * d78690bb5d drm/amdgpu: Fix missing error code in 'gmc_v6/7/8/9_0_hw_init()'
| * f086c50a98 ASoC: codecs: wsa883x: fix PA volume control
| * ac86261fa8 ASoC: codecs: lpass-wsa-macro: fix compander volume hack
| * 2386ee6cba bonding: remove print in bond_verify_device_path
| * e1edd8e6c0 gve: Fix use-after-free vulnerability
| * 9e584ea101 LoongArch/smp: Call rcutree_report_cpu_starting() at tlb_init()
| * 98c392a91a drm/msm/dsi: Enable runtime PM
| * befdb0a8a1 Revert "drm/amd/display: Disable PSR-SU on Parade 0803 TCON again"
| * dc904345e3 mm, kmsan: fix infinite recursion due to RCU critical section
| * c5a12dfbfa arm64: irq: set the correct node for shadow call stack
| * ddd367ebc4 selftests: bonding: Check initial state
| * 7ebe20e632 selftests: team: Add missing config options
| * aaa8f76845 net: sysfs: Fix /sys/class/net/<iface> path
| * bea0fbf857 selftests: net: fix available tunnels detection
| * a2104f4387 af_unix: fix lockdep positive in sk_diag_dump_icons()
| * fde3d47efe net: ipv4: fix a memleak in ip_setup_cork
| * 0f501dae16 netfilter: nft_ct: sanitize layer 3 and 4 protocol number in custom expectations
| * 9ff981cd65 netfilter: nf_log: replace BUG_ON by WARN_ON_ONCE when putting logger
| * 67f0ca0a4c netfilter: nf_tables: restrict tunnel object to NFPROTO_NETDEV
| * 8a51dbf7b7 netfilter: conntrack: correct window scaling with retransmitted SYN
| * cd091ca44c selftests: net: add missing config for GENEVE
| * 04a553d8ac bridge: mcast: fix disabled snooping after long uptime
| * 9c333d9891 llc: call sock_orphan() at release time
| * c59ed6592f ipv6: Ensure natural alignment of const ipv6 loopback and router addresses
| * 2f3d9829f7 net: dsa: qca8k: fix illegal usage of GPIO
| * 1e4c227805 ixgbe: Fix an error handling path in ixgbe_read_iosf_sb_reg_x550()
| * 3b84b7000c ixgbe: Refactor overtemp event handling
| * 9c8eafc5e9 ixgbe: Refactor returning internal error codes
| * b383d4ea27 tcp: add sanity checks to rx zerocopy
| * 046260ce7c net: lan966x: Fix port configuration when using SGMII interface
| * d2f1b7fe74 ipmr: fix kernel panic when forwarding mcast packets
| * 03dc5b73af ipv4: raw: add drop reasons
| * d54e4da98b ip6_tunnel: make sure to pull inner header in __ip6_tnl_rcv()
| * 262caadfa9 selftests: net: give more time for GRO aggregation
| * 53e94ec530 HID: hidraw: fix a problem of memory leak in hidraw_release()
| * db6338f459 scsi: core: Move scsi_host_busy() out of host lock for waking up EH handler
| * 81e92f0c97 regulator: ti-abb: don't use devm_platform_ioremap_resource_byname for shared interrupt register
| * 7eb86ddaf1 scsi: isci: Fix an error code problem in isci_io_request_build()
| * 206dcd2624 drm: using mul_u32_u32() requires linux/math64.h
| * a2f30104fe wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
| * 071d98d5ee perf: Fix the nr_addr_filters fix
| * 8eea7e1d69 drm/amdkfd: Fix 'node' NULL check in 'svm_range_get_range_boundaries()'
| * 7513f0906c drm/amdgpu: Release 'adev->pm.fw' before return in 'amdgpu_device_need_post()'
| * af8e292615 drm/amdgpu: Fix with right return code '-EIO' in 'amdgpu_gmc_vram_checking()'
| * d282ea0703 drm/amd/powerplay: Fix kzalloc parameter 'ATOM_Tonga_PPM_Table' in 'get_platform_power_management_table()'
| * 3fbfeb8536 ceph: fix invalid pointer access if get_quota_realm return ERR_PTR
| * 7f2649c942 ceph: fix deadlock or deadcode of misusing dget()
| * 692ead237d ceph: reinitialize mds feature bit even when session in open
| * 1d9c777d3e blk-mq: fix IO hang from sbitmap wakeup race
| * 1f7a018857 virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region of size 10" warnings
| * b602f098f7 drm/amdkfd: Fix lock dependency warning with srcu
| * 8b25d39716 drm/amdkfd: Fix lock dependency warning
| * 49a7b708da libsubcmd: Fix memory leak in uniq()
| * 2c1164ad92 misc: lis3lv02d_i2c: Add missing setting of the reg_ctrl callback
| * 91f1977487 9p: Fix initialisation of netfs_inode for 9p
| * fc557b76dc PCI/AER: Decode Requester ID when no error info found
| * 83c895561a PCI: Fix 64GT/s effective data rate calculation
| * 521f28eedd spmi: mediatek: Fix UAF on device remove
| * 089ebfab24 fs/kernfs/dir: obey S_ISGID
| * c13bcbdb84 tty: allow TIOCSLCKTRMIOS with CAP_CHECKPOINT_RESTORE
| * d8d7ffefc0 selftests/sgx: Fix linker script asserts
| * fa3f6cd20d usb: hub: Add quirk to decrease IN-ep poll interval for Microchip USB491x hub
| * 9cdf5ddb06 usb: hub: Replace hardcoded quirk value with BIT() macro
| * 4c8ca96124 perf cs-etm: Bump minimum OpenCSD version to ensure a bugfix is present
| * 1d83c85922 PCI: switchtec: Fix stdev_release() crash after surprise hot remove
| * 5e0160dab1 PCI: Only override AMD USB controller if required
| * 26b8a35fef mailbox: arm_mhuv2: Fix a bug for mhuv2_sender_interrupt
| * 6e8c0eda6c mfd: ti_am335x_tscadc: Fix TI SoC dependencies
| * 52e7f05549 xen/gntdev: Fix the abuse of underlying struct page in DMA-buf import
| * e827364bc1 i3c: master: cdns: Update maximum prescaler value for i2c clock
| * 4f7dad73df um: time-travel: fix time corruption
| * d8512cc8ac um: net: Fix return type of uml_net_start_xmit()
| * d8264ce2f8 um: Don't use vfprintf() for os_info()
| * a95e52af36 um: Fix naming clash between UML and scheduler
| * 7d1c4e5809 leds: trigger: panic: Don't register panic notifier if creating the trigger failed
| * 2cb659ef0a ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140
| * 05a0900bd7 drm/amdkfd: Fix iterator used outside loop in 'kfd_add_peer_prop()'
| * 34bb1b97c3 drm/amdgpu: Drop 'fence' check in 'to_amdgpu_amdkfd_fence()'
| * 66d38977e2 drm/amdgpu: Fix '*fw' from request_firmware() not released in 'amdgpu_ucode_request()'
| * da08dbb647 drm/amdgpu: Let KFD sync with VM fences
| * adae24c5b3 drm/amdgpu: Fix ecc irq enable/disable unpaired
| * aade0a0760 clk: imx: clk-imx8qxp: fix LVDS bypass, pixel and phy clocks
| * 7294b1bbaa drm/amd/display: make flip_timestamp_in_us a 64-bit variable
| * c95d2144be watchdog: it87_wdt: Keep WDTCTRL bit 3 unmodified for IT8784/IT8786
| * ec74a45e80 clk: mmp: pxa168: Fix memory leak in pxa168_clk_init()
| * 14992bc77f clk: hi3620: Fix memory leak in hi3620_mmc_clk_init()
| * d443fb67ca drm/amdgpu: fix ftrace event amdgpu_bo_move always move on same heap
| * fe7e8ec072 drm/msm/dpu: fix writeback programming for YUV cases
| * 7593e62702 drm/msm/dpu: Ratelimit framedone timeout msgs
| * fb017c3e6a drm/amd/display: For prefetch mode > 0, extend prefetch if possible
| * 4ef53b7e30 media: i2c: imx335: Fix hblank min/max values
| * 5008bde32c media: ddbridge: fix an error code problem in ddb_probe
| * 6408851d05 media: amphion: remove mutext lock in condition of wait_event
| * 5108a2dc2d IB/ipoib: Fix mcast list locking
| * fe80290b2a drm/exynos: Call drm_atomic_helper_shutdown() at shutdown/unbind time
| * 7c972c8945 f2fs: fix to tag gcing flag on page during block migration
| * fb55c3cee6 hwmon: (nct6775) Fix fan speed set failure in automatic mode
| * bf808f5868 media: rkisp1: Fix IRQ disable race issue
| * f0d0fe3787 media: rkisp1: Store IRQ lines
| * fb71b54856 media: rkisp1: Fix IRQ handler return values
| * 1c51b6b0c6 media: rkisp1: Drop IRQF_SHARED
| * c3f77c5d63 ALSA: hda: Intel: add HDA_ARL PCI ID support
| * 3b28da57d0 PCI: add INTEL_HDA_ARL to pci_ids.h
| * 16786b7090 media: rockchip: rga: fix swizzling for RGB formats
| * 1ef8beb4bf media: stk1160: Fixed high volume of stk1160_dbg messages
| * 25eaa9f999 drm/mipi-dsi: Fix detach call without attach
| * f3e41cc260 drm/framebuffer: Fix use of uninitialized variable
| * 406f8d5bad drm/drm_file: fix use of uninitialized variable
| * 48ad42cd95 ASoC: amd: Add new dmi entries for acp5x platform
| * b6ca70f06e f2fs: fix write pointers on zoned device after roll forward
| * 9773a96eac drm/amd/display: Fix tiled display misalignment
| * 126543736f drm/bridge: anx7625: Fix Set HPD irq detect window to 2ms
| * 3c2bd20dc9 drm/panel-edp: Add override_edid_mode quirk for generic edp
| * 055c849724 RDMA/IPoIB: Fix error code return in ipoib_mcast_join
| * c4cb42824e fast_dput(): handle underflows gracefully
| * 0ee8e0a183 ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument
| * 52e25a323c ALSA: hda: Refer to correct stream index at loops
| * b1020a5467 f2fs: fix to check return value of f2fs_reserve_new_block()
| * 332a7c108e net: dsa: qca8k: put MDIO bus OF node on qca8k_mdio_register() failure
| * 0438a985de octeontx2-af: Fix max NPC MCAM entry check while validating ref_entry
| * 95173204b1 i40e: Fix VF disable behavior to block all traffic
| * 9f9ac39adb bridge: cfm: fix enum typo in br_cc_ccm_tx_parse
| * a243e0818e net/smc: disable SEID on non-s390 archs where virtual ISM may be used
| * 388736c62b Bluetooth: L2CAP: Fix possible multiple reject send
| * 6d95ade9e6 Bluetooth: hci_sync: fix BR/EDR wakeup bug
| * a836b1c333 Bluetooth: qca: Set both WIDEBAND_SPEECH and LE_STATES quirks for QCA2066
| * da1a6e9f01 wifi: cfg80211: free beacon_ies when overridden from hidden BSS
| * 3bb09b9af1 wifi: rtlwifi: rtl8723{be,ae}: using calculate_bit_shift()
| * 12473265f5 libbpf: Fix NULL pointer dereference in bpf_object__collect_prog_relos
| * 68ef19417a wifi: rtl8xxxu: Add additional USB IDs for RTL8192EU devices
| * e15fa0c67e arm64: dts: amlogic: fix format for s4 uart node
| * 9e8338b72b ice: fix pre-shifted bit usage
| * 9c5541f3f0 arm64: dts: qcom: msm8998: Fix 'out-ports' is a required property
| * 2fdbf9d9a0 arm64: dts: qcom: msm8996: Fix 'in-ports' is a required property
| * fd9a2c7003 md: Whenassemble the array, consult the superblock of the freshest device
| * 8ae4201900 block: prevent an integer overflow in bvec_try_merge_hw_page
| * 44f6b75c09 net: dsa: mv88e6xxx: Fix mv88e6352_serdes_get_stats error path
| * 0edb3ae8bf net: atlantic: eliminate double free in error handling logic
| * ea12794ea6 ice: fix ICE_AQ_VSI_Q_OPT_RSS_* register values
| * d4560c11c3 scsi: hisi_sas: Set .phy_attached before notifing phyup event HISI_PHYE_PHY_UP_PM
| * dc15b313f3 ARM: dts: imx23/28: Fix the DMA controller node name
| * 9388665a12 ARM: dts: imx23-sansa: Use preferred i2c-gpios properties
| * fb8e41af95 ARM: dts: imx27-apf27dev: Fix LED name
| * 6ebe86575b ARM: dts: imx25/27: Pass timing0
| * 68b2e26225 ARM: dts: imx25: Fix the iim compatible string
| * af7bbdac89 block/rnbd-srv: Check for unlikely string overflow
| * 238ec612a2 ionic: bypass firmware cmds when stuck in reset
| * 434fcaf372 ionic: pass opcode to devcmd_wait
| * 7dc0fefd37 net: phy: at803x: fix passing the wrong reference for config_intr
| * e7398f3e45 ARM: dts: imx1: Fix sram node
| * 7721a55c02 ARM: dts: imx27: Fix sram node
| * 8a0285ed7e ARM: dts: imx: Use flash@0,0 pattern
| * 8953b37bb1 ARM: dts: imx25/27-eukrea: Fix RTC node name
| * 1acdaf9f29 ARM: dts: rockchip: fix rk3036 hdmi ports node
| * 574dcd3126 wifi: wfx: fix possible NULL pointer dereference in wfx_set_mfp_ap()
| * 5a44a664ab bpf: Set uattr->batch.count as zero before batched update or deletion
| * 7719e56b20 scsi: libfc: Fix up timeout error in fc_fcp_rec_error()
| * 73fe92ddf9 scsi: libfc: Don't schedule abort twice
| * d6d6fe4bb1 bpf: Check rcu_read_lock_trace_held() before calling bpf map helpers
| * c07965d1a7 wifi: ath11k: fix race due to setting ATH11K_FLAG_EXT_IRQ_ENABLED too early
| * 25c6f49ef5 wifi: ath9k: Fix potential array-index-out-of-bounds read in ath9k_htc_txstatus()
| * db30f469ae ARM: dts: imx7s: Fix nand-controller #size-cells
| * 6fa750d62f ARM: dts: imx7s: Fix lcdif compatible
| * c9c2a35820 ARM: dts: imx7d: Fix coresight funnel ports
| * 89fdf0a2c7 scsi: arcmsr: Support new PCI device IDs 1883 and 1886
| * 61c859bd66 scsi: mpi3mr: Add PCI checks where SAS5116 diverges from SAS4116
| * 5c4cbec510 net: usb: ax88179_178a: avoid two consecutive device resets
| * cd4cdad9bd bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk
| * c0d5a69322 PCI: Add no PM reset quirk for NVIDIA Spectrum devices
| * 04dcef4a78 scsi: lpfc: Fix possible file string name overflow when updating firmware
| * c0a96adce2 soc: xilinx: fix unhandled SGI warning message
| * 01946c3c83 soc: xilinx: Fix for call trace due to the usage of smp_processor_id()
| * fd937767d5 selftests/bpf: Fix issues in setup_classid_environment()
| * f58cfb63e4 wifi: rt2x00: correct wrong BBP register in RxDCOC calibration
| * ad0e7bbc0b selftests/bpf: Fix pyperf180 compilation failure with clang18
| * 76ab331d6d selftests/bpf: satisfy compiler by having explicit return in btf test
| * 739b3ccd94 wifi: rt2x00: restart beacon queue when hardware reset
| * 6d2cbf517d ext4: avoid online resizing failures due to oversized flex bg
| * dd10f82ece ext4: remove unnecessary check from alloc_flex_gd()
| * 60292a12a0 ext4: unify the type of flexbg_size to unsigned int
| * 069ede0475 ext4: fix inconsistent between segment fstrim and full fstrim
| * 80cab9dad5 ecryptfs: Reject casefold directory inodes
| * e8ca3e7330 SUNRPC: Fix a suspicious RCU usage warning
| * 0671f42a9c KVM: s390: fix setting of fpc register
| * 7a4d6481fb s390/ptrace: handle setting of fpc register correctly
| * 08f65c9067 s390/vfio-ap: fix sysfs status attribute for AP queue devices
| * d6c8d8ab76 arch: consolidate arch_irq_work_raise prototypes
| * 3537f92cd2 jfs: fix array-index-out-of-bounds in diNewExt
| * b03d76cc66 rxrpc_find_service_conn_rcu: fix the usage of read_seqbegin_or_lock()
| * ea4eb77c53 afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
| * eef7c4cd98 afs: fix the usage of read_seqbegin_or_lock() in afs_lookup_volume_rcu()
| * 91256fcd57 crypto: stm32/crc32 - fix parsing list of devices
| * e0e78522b4 erofs: fix ztailpacking for subpage compressed blocks
| * 6c7bdb97d4 crypto: octeontx2 - Fix cptvf driver cleanup
| * 75b0f71b26 pstore/ram: Fix crash when setting number of cpus to an odd number
| * 32e8f2d955 jfs: fix uaf in jfs_evict_inode
| * 70780914cb jfs: fix array-index-out-of-bounds in dbAdjTree
| * cab0c265ba jfs: fix slab-out-of-bounds Read in dtSearch
| * e4cbc857d7 UBSAN: array-index-out-of-bounds in dtSplitRoot
| * 42f433785f FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
| * 185d97e5be ACPI: APEI: set memory failure flags as MF_ACTION_REQUIRED on synchronous events
| * 31569995fc PM / devfreq: Synchronize devfreq_monitor_[start/stop]
| * 7633b7a036 ACPI: NUMA: Fix the logic of getting the fake_pxm value
| * 33650372e3 ACPI: extlog: fix NULL pointer dereference check
| * 431c1a4921 PNP: ACPI: fix fortify warning
| * 81eb8b56e7 ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
| * 4d4e06eaa2 audit: Send netlink ACK before setting connection in auditd_set
| * 3430936a01 regulator: core: Only increment use_count when enable_count changes
| * b3ae38966d debugobjects: Stop accessing objects after releasing hash bucket lock
| * 74ec093dba perf/core: Fix narrow startup race when creating the perf nr_addr_filters sysfs file
| * d67e43be0e x86/mce: Mark fatal MCE's page as poison to avoid panic in the kdump kernel
| * abd26515d4 powerpc/lib: Validate size for vector operations
| * 0be5614f26 powerpc: pmd_move_must_withdraw() is only needed for CONFIG_TRANSPARENT_HUGEPAGE
| * d4908b3431 x86/boot: Ignore NMIs during very early boot
| * a6fd14db75 powerpc/64s: Fix CONFIG_NUMA=n build due to create_section_mapping()
| * cf3256c431 powerpc/mm: Fix build failures due to arch_reserved_kernel_pages()
| * 7ad4b2a6b2 powerpc: Fix build error due to is_valid_bugaddr()
| * d87d9a23a1 drivers/perf: pmuv3: don't expose SW_INCR event in sysfs
| * 4431284f4a arm64: irq: set the correct node for VMAP stack
| * d482d61025 powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
| * 9e5c37e0fa asm-generic: make sparse happy with odd-sized put_unaligned_*()
* | f28d3f0d96 Merge branch 'android14-6.1' into branch 'android14-6.1-lts'
* | 7a8376be74 ANDROID: use reserved cpucaps for new capability
* | c801066eca Revert "mm/sparsemem: fix race in accessing memory_section->usage"
* | 2dbddbe358 Merge 6.1.76 into android-6.1
|\|
| * e5c3b988b8 Linux 6.1.76
| * d7dc6a8604 net/mlx5e: Handle hardware IPsec limits events
| * e90c7d26ca serial: core: fix kernel-doc for uart_port_unlock_irqrestore()
| * c02d3872c8 x86/entry/ia32: Ensure s32 is sign extended to s64
| * cf0b4ba4b0 tick/sched: Preserve number of idle sleeps across CPU hotplug events
| * e333bbb557 mips: Call lose_fpu(0) before initializing fcr31 in mips_set_personality_nan
| * ec745eeff4 cxl/region:Fix overflow issue in alloc_hpa()
| * 1111abee59 MIPS: lantiq: register smp_ops on non-smp platforms
| * b086f6d979 spi: fix finalize message on error return
| * 598af91f62 spi: bcm-qspi: fix SFDP BFPT read by usig mspi read
| * a2fa86e2bb drm/bridge: anx7625: Ensure bridge is suspended in disable()
| * 9564767b67 block: Move checking GENHD_FL_NO_PART to bdev_add_partition()
| * 4b84411165 gpio: eic-sprd: Clear interrupt after set the interrupt type
| * 23cf4cf429 drm/exynos: gsc: minor fix for loop iteration in gsc_runtime_resume
| * ba930885bf drm/exynos: fix accidental on-stack copy of exynos_drm_plane
| * c1cd4f9da5 drm/bridge: parade-ps8640: Make sure we drop the AUX mutex in the error case
| * 6ba690e7f7 drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()
| * 279f1cc562 drm/bridge: sii902x: Fix audio codec unregistration
| * e0f83c234e drm/bridge: sii902x: Fix probing race issue
| * c46f9c7f93 drm/bridge: sii902x: Use devm_regulator_bulk_get_enable()
| * ed555f5b5c drm: panel-simple: add missing bus flags for Tianma tm070jvhg[30/33]
| * 6b7fb2903a drm/bridge: parade-ps8640: Wait for HPD when doing an AUX transfer
| * f9a4c401bf Revert "powerpc/64s: Increase default stack size to 32KB"
| * ec5e692cba drm/panel-edp: drm/panel-edp: Fix AUO B116XAK01 name and timing
| * f91c77d2c3 btrfs: zoned: optimize hint byte for zoned allocator
| * 4c45143447 btrfs: zoned: factor out prepare_allocation_zoned()
| * b168029d67 serial: sc16is7xx: fix unconditional activation of THRI interrupt
| * 49d733c4bb serial: sc16is7xx: Use port lock wrappers
| * 4fd9a02121 serial: core: Provide port lock wrappers
| * e11dea8f50 dlm: use kernel_connect() and kernel_bind()
| * fd7c2ffa0e ARM: dts: qcom: sdx55: fix USB SS wakeup
| * ecf87621b4 ARM: dts: qcom: sdx55: fix USB DP/DM HS PHY interrupts
| * 34d2c909c7 ARM: dts: qcom: sdx55: fix pdc '#interrupt-cells'
| * bba1320ef2 ARM: dts: samsung: exynos4210-i9100: Unconditionally enable LDO12
| * 46cd7ef69f ARM: dts: qcom: sdx55: fix USB wakeup interrupt types
| * b87a1229d8 pipe: wakeup wr_wait after setting max_usage
| * 6f5c4aaddd fs/pipe: move check to pipe_has_watch_queue()
| * 28f010dc50 thermal: intel: hfi: Add syscore callbacks for system-wide PM
| * b2517d1412 thermal: intel: hfi: Disable an HFI instance when all its CPUs go offline
| * a8056e821c thermal: intel: hfi: Refactor enabling code into helper functions
| * e1c9d32c98 PM: sleep: Fix possible deadlocks in core system-wide PM code
| * a9dbf8ca31 PM: core: Remove unnecessary (void *) conversions
| * ea3357c6cf bus: mhi: ep: Do not allocate event ring element on stack
| * 512fc4d735 media: ov13b10: Enable runtime PM before registering async sub-device
| * a14c2431e5 media: ov13b10: Support device probe in non-zero ACPI D state
| * 33bf23c994 erofs: fix lz4 inplace decompression
| * 2197389e1a erofs: get rid of the remaining kmap_atomic()
| * 471ab2e8b7 drm/amdgpu/pm: Fix the power source flag error
| * b4cbd01832 drm/amd/display: Port DENTIST hang and TDR fixes to OTG disable W/A
| * 7960f14fca drm/bridge: nxp-ptn3460: simplify some error checking
| * 6341140b04 platform/x86: intel-uncore-freq: Fix types in sysfs callbacks
| * 85d16c03dd drm/amd/display: Disable PSR-SU on Parade 0803 TCON again
| * b5fcb340b7 drm/tidss: Fix atomic_flush check
| * 2a81e844d1 drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking
| * 62f2e79cf9 drm: Don't unref the same fb many times by mistake due to deadlock handling
| * 635e996e6e cpufreq: intel_pstate: Refine computation of P-state for given frequency
| * 242996f500 gpiolib: acpi: Ignore touchpad wakeup on GPD G1619-04
| * 6c495c84e2 xfs: read only mounts with fsopen mount API are busted
| * 7f95f6997f firmware: arm_scmi: Check mailbox/SMT channel for consistency
| * 2c939c74ef ksmbd: fix global oob in ksmbd_nl_policy
| * 2841631a03 platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe
| * 8e34430e33 netfilter: nf_tables: reject QUEUE/DROP verdict parameters
| * af149a4689 netfilter: nft_chain_filter: handle NETDEV_UNREGISTER for inet/ingress basechain
| * 5e7d8ddf2a hv_netvsc: Calculate correct ring size when PAGE_SIZE is not 4 Kbytes
| * aa2cc93639 wifi: iwlwifi: fix a memory corruption
| * dcc54a54de exec: Fix error handling in begin_new_exec()
| * 4646445756 rbd: don't move requests to the running list on errors
| * 6e6bca99e8 btrfs: don't abort filesystem when attempting to snapshot deleted subvolume
| * 52e02f26d0 btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
| * 86aff7c5f7 btrfs: don't warn if discard range is not aligned to sector
| * b60f748a2f btrfs: tree-checker: fix inline ref size in error messages
| * c91c247be4 btrfs: ref-verify: free ref cache before clearing mount opt
| * 9ebd514fbd btrfs: avoid copying BTRFS_ROOT_SUBVOL_DEAD flag to snapshot of subvolume being deleted
| * d9c54763e5 nbd: always initialize struct msghdr completely
| * 0a5a083c2b net: fec: fix the unhandled context fault from smmu
| * 5b1086d226 fjes: fix memleaks in fjes_hw_setup
| * 4b4dcb3f42 selftests: netdevsim: fix the udp_tunnel_nic test
| * cec65f09c4 net: mvpp2: clear BM pool before initialization
| * acb6eaf2ea net: stmmac: Wait a bit for the reset to take effect
| * 67ee37360d netfilter: nf_tables: validate NFPROTO_* family
| * ed5b62bbd4 netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
| * c25d7922ef btrfs: fix race between reading a directory and adding entries to it
| * fd968e683b btrfs: refresh dir last index during a rewinddir(3) call
| * a045b6b197 btrfs: set last dir index to the current last index when opening dir
| * 2aa515b5b5 btrfs: fix infinite directory reads
| * bc6e242bb7 netfilter: nft_limit: reject configurations that cause integer overflow
| * c817f5c016 rcu: Defer RCU kthreads wakeup when CPU is dying
| * b2fa86b2ac net/mlx5e: fix a potential double-free in fs_any_create_groups
| * 42876db001 net/mlx5e: fix a double-free in arfs_create_groups
| * 890881d10f net/mlx5e: Allow software parsing when IPsec crypto is enabled
| * 62ce16005e net/mlx5: Use mlx5 device constant for selecting CQ period mode for ASO
| * 75d9ed4930 net/mlx5: DR, Can't go to uplink vport on RX rule
| * e54aedd4d0 net/mlx5: DR, Use the right GVMI number for drop action
| * f11792c389 ipv6: init the accept_queue's spinlocks in inet6_create
| * de061604f8 netlink: fix potential sleeping issue in mqueue_flush_file
| * 90fba981ca tcp: Add memory barrier to tcp_push()
| * ab49164c60 afs: Hide silly-rename files from userspace
| * f4f7e696db tracing: Ensure visibility when inserting an element into tracing_map
| * 82a9bc343b netfs, fscache: Prevent Oops in fscache_put_cache()
| * 71024928b3 net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
| * fcb0b4b6bc net: micrel: Fix PTP frame parsing for lan8814
| * 7a581f597a tun: add missing rx stats accounting in tun_xdp_act
| * 41e7decdad tun: fix missing dropped counter in tun_xdp_act
| * a2232f29bf net: fix removing a namespace with conflicting altnames
| * 6646145be9 udp: fix busy polling
| * 660c3053d9 llc: Drop support for ETH_P_TR_802_2.
| * 6d53b813ff llc: make llc_ui_sendmsg() more robust against bonding changes
| * c5e7fa4f9d vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
| * 4ee0613868 bnxt_en: Wait for FLR to complete during probe
| * b1e0a68a0c tcp: make sure init the accept_queue's spinlocks once
| * 6994dba063 net/smc: fix illegal rmb_desc access in SMC-D connection dump
| * 49aaeb8c53 wifi: mac80211: fix potential sta-link leak
| * b59e08c872 drm/amd/display: pbn_div need be updated for hotplug event
| * a5046e5eb8 Revert "drm/amd: Enable PCIe PME from D3"
| * b1c06ee2d1 ksmbd: Add missing set_freezable() for freezable kthread
| * 844dfef316 ksmbd: send lease break notification on FILE_RENAME_INFORMATION
| * de603a52af ksmbd: don't increment epoch if current state and request state are same
| * e61fc656ce ksmbd: fix potential circular locking issue in smb2_set_ea()
| * 8fa25e67fd ksmbd: set v2 lease version on lease upgrade
| * 3101b9fd74 mm: page_alloc: unreserve highatomic page blocks before oom
| * 1d15da5601 LoongArch/smp: Call rcutree_report_cpu_starting() earlier
| * 0e0653d53a serial: sc16is7xx: improve do/while loop in sc16is7xx_irq()
| * 80beb4424d serial: sc16is7xx: remove obsolete loop in sc16is7xx_port_irq()
| * de8e41f78f serial: sc16is7xx: fix invalid sc16is7xx_lines bitfield in case of probe error
| * 416b10d281 serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO
| * 4b068e55bf serial: sc16is7xx: change EFR lock to operate on each channels
| * f6c58552a8 serial: sc16is7xx: remove unused line structure member
| * 6dca71e6e1 serial: sc16is7xx: remove global regmap from struct sc16is7xx_port
| * 9bcb019aee serial: sc16is7xx: remove wasteful static buffer in sc16is7xx_regmap_name()
| * 45ec1b7acc serial: sc16is7xx: improve regmap debugfs by using one regmap per port
| * 362be9ec32 rename(): fix the locking of subdirectories
| * 68ed9e3332 mm/sparsemem: fix race in accessing memory_section->usage
| * 367a47ef4c mm/rmap: fix misplaced parenthesis of a likely()
| * 5d01dcda81 ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
| * 13a6ceeb5b nouveau/vmm: don't set addr on the fail path to avoid warning
| * 40c23b5e07 rtc: Extend timeout for waiting for UIP to clear to 1s
| * 7971389316 rtc: Add support for configuring the UIP timeout for RTC reads
| * fd1f5396be rtc: mc146818-lib: Adjust failure return code for mc146818_get_time()
| * 911e7206c8 rtc: Adjust failure return code for cmos_set_alarm()
| * aca1ea92f5 rtc: cmos: Use ACPI alarm for non-Intel x86 systems too
| * 2b1dc0666e arm64: Rename ARM64_WORKAROUND_2966298
| * 9fec4db7ff media: mtk-jpeg: Fix use after free bug due to error path handling in mtk_jpeg_dec_device_run
| * a33fbb8b6d mmc: mmc_spi: remove custom DMA mapped buffers
| * c4edcd134b mmc: core: Use mrq.sbc in close-ended ffu
| * d78fac87c6 media: videobuf2-dma-sg: fix vmap callback
| * c160f2ac85 scripts/get_abi: fix source path leak
| * efe3ec7066 docs: kernel_abi.py: fix command injection
| * c014490c0b lsm: new security_file_ioctl_compat() hook
| * 2647770eac arm64: dts: qcom: sm8150: fix USB DP/DM HS PHY interrupts
| * 0168530568 arm64: dts: qcom: sdm845: fix USB DP/DM HS PHY interrupts
| * 69ee126bba arm64: dts: qcom: sc7280: fix usb_1 wakeup interrupt types
| * eec1f92949 arm64: dts: qcom: sm8150: fix USB wakeup interrupt types
| * 595d35c6ae arm64: dts: qcom: sdm845: fix USB wakeup interrupt types
| * 8191aa4146 arm64: dts: qcom: sc7180: fix USB wakeup interrupt types
| * 9f29c5d2bf scsi: ufs: core: Remove the ufshcd_hba_exit() call from ufshcd_async_scan()
| * 2ab32986a0 dmaengine: fix NULL pointer in channel unregistration function
| * 0c8ada71d9 iio: adc: ad7091r: Enable internal vref if external vref is not supplied
| * fcf8e37152 async: Introduce async_schedule_dev_nocall()
| * 6e8aab4de7 async: Split async_schedule_node_domain()
| * b37c1b0db1 parisc/power: Fix power soft-off button emulation on qemu
| * 71602d95ae parisc/firmware: Fix F-extend for PDC addresses
| * 0b093176fd bus: mhi: host: Add spinlock to protect WP access when queueing TREs
| * 3c5ec66b4b bus: mhi: host: Drop chan lock before queuing buffers
| * 2df39ac8f8 bus: mhi: host: Add alignment check for event ring read pointer
| * 574f69b46b mips: Fix max_mapnr being uninitialized on early stages
| * 6690a0acbb s390/vfio-ap: let on_scan_complete() callback filter matrix and update guest's APCB
| * baf3fcb268 s390/vfio-ap: loop over the shadow APCB when filtering guest's AP configuration
| * d6b8d034b5 s390/vfio-ap: always filter entire AP matrix
| * 51a7c02bc7 media: ov9734: Enable runtime PM before registering async sub-device
| * f4bb1d5daf rpmsg: virtio: Free driver_override when rpmsg_remove()
| * e8757cd139 media: imx355: Enable runtime PM before registering async sub-device
| * 8a7729cda2 PM / devfreq: Fix buffer overflow in trans_stat_show
| * f4518de40a s390/vfio-ap: unpin pages on gisc registration failure
| * dbc9a791a7 crypto: s390/aes - Fix buffer overread in CTR mode
| * aa8aa16ed9 hwrng: core - Fix page fault dead lock on mmap-ed hwrng
| * 3a081586c7 PM: hibernate: Enforce ordering during image compression/decompression
| * 680eb0a993 crypto: api - Disallow identical driver names
| * 562850a008 btrfs: sysfs: validate scrub_speed_max value
| * 29e2da3eab OPP: Pass rounded rate to _set_opp()
| * 4b5f8a187f arm64: properly install vmlinuz.efi
| * 852b6b2a2f ext4: allow for the last group to be marked as trimmed
| * 137568aa54 iio: adc: ad7091r: Allow users to configure device events
| * 6f57121e9c iio: adc: ad7091r: Set alert bit in config register
| * fafda9f08a Revert "nSVM: Check for reserved encodings of TLB_CONTROL in nested VMCB"
| * c519a9054b usb: dwc3: gadget: Handle EP0 request dequeuing properly
| * c8fe8ce07f usb: dwc3: gadget: Queue PM runtime idle on disconnect event
| * ce27046883 usb: dwc3: gadget: Refactor EP0 forced stall/restart into a separate API
* 0eac7b614d Merge branch 'android14-6.1' into branch 'android14-6.1-lts'
* 63040ce8e9 Merge branch 'android14-6.1' into branch 'android14-6.1-lts'
* 50fe3d2012 ANDROID: Add symbols for IIO SCMI module
* e666b8755f ANDROID: Update symbols list for open-dice.ko

Change-Id: Icb970da9bfba44d188465ce8c8148858a4a2fb1a
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2024-05-30 15:23:39 +00:00

1694 lines
40 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/kernel/power/swap.c
*
* This file provides functions for reading the suspend image from
* and writing it to a swap partition.
*
* Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
* Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com>
*/
#define pr_fmt(fmt) "PM: " fmt
#include <linux/module.h>
#include <linux/file.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/cpumask.h>
#include <linux/atomic.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
#include <linux/ktime.h>
#include <trace/hooks/bl_hib.h>
#include "power.h"
#define HIBERNATE_SIG "S1SUSPEND"
u32 swsusp_hardware_signature;
/*
* When reading an {un,}compressed image, we may restore pages in place,
* in which case some architectures need these pages cleaning before they
* can be executed. We don't know which pages these may be, so clean the lot.
*/
static bool clean_pages_on_read;
static bool clean_pages_on_decompress;
/*
* The swap map is a data structure used for keeping track of each page
* written to a swap partition. It consists of many swap_map_page
* structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
* These structures are stored on the swap and linked together with the
* help of the .next_swap member.
*
* The swap map is created during suspend. The swap map pages are
* allocated and populated one at a time, so we only need one memory
* page to set up the entire structure.
*
* During resume we pick up all swap_map_page structures into a list.
*/
#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1)
/*
* Number of free pages that are not high.
*/
static inline unsigned long low_free_pages(void)
{
return nr_free_pages() - nr_free_highpages();
}
/*
* Number of pages required to be kept free while writing the image. Always
* half of all available low pages before the writing starts.
*/
static inline unsigned long reqd_free_pages(void)
{
return low_free_pages() / 2;
}
struct swap_map_page {
sector_t entries[MAP_PAGE_ENTRIES];
sector_t next_swap;
};
struct swap_map_page_list {
struct swap_map_page *map;
struct swap_map_page_list *next;
};
/*
* The swap_map_handle structure is used for handling swap in
* a file-alike way
*/
struct swap_map_handle {
struct swap_map_page *cur;
struct swap_map_page_list *maps;
sector_t cur_swap;
sector_t first_sector;
unsigned int k;
unsigned long reqd_free_pages;
u32 crc32;
};
struct swsusp_header {
char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
sizeof(u32) - sizeof(u32)];
u32 hw_sig;
u32 crc32;
sector_t image;
unsigned int flags; /* Flags to pass to the "boot" kernel */
char orig_sig[10];
char sig[10];
} __packed;
static struct swsusp_header *swsusp_header;
/*
* The following functions are used for tracing the allocated
* swap pages, so that they can be freed in case of an error.
*/
struct swsusp_extent {
struct rb_node node;
unsigned long start;
unsigned long end;
};
static struct rb_root swsusp_extents = RB_ROOT;
static int swsusp_extents_insert(unsigned long swap_offset)
{
struct rb_node **new = &(swsusp_extents.rb_node);
struct rb_node *parent = NULL;
struct swsusp_extent *ext;
/* Figure out where to put the new node */
while (*new) {
ext = rb_entry(*new, struct swsusp_extent, node);
parent = *new;
if (swap_offset < ext->start) {
/* Try to merge */
if (swap_offset == ext->start - 1) {
ext->start--;
return 0;
}
new = &((*new)->rb_left);
} else if (swap_offset > ext->end) {
/* Try to merge */
if (swap_offset == ext->end + 1) {
ext->end++;
return 0;
}
new = &((*new)->rb_right);
} else {
/* It already is in the tree */
return -EINVAL;
}
}
/* Add the new node and rebalance the tree. */
ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
if (!ext)
return -ENOMEM;
ext->start = swap_offset;
ext->end = swap_offset;
rb_link_node(&ext->node, parent, new);
rb_insert_color(&ext->node, &swsusp_extents);
return 0;
}
/*
* alloc_swapdev_block - allocate a swap page and register that it has
* been allocated, so that it can be freed in case of an error.
*/
sector_t alloc_swapdev_block(int swap)
{
unsigned long offset;
offset = swp_offset(get_swap_page_of_type(swap));
if (offset) {
if (swsusp_extents_insert(offset))
swap_free(swp_entry(swap, offset));
else
return swapdev_block(swap, offset);
}
return 0;
}
EXPORT_SYMBOL_GPL(alloc_swapdev_block);
/*
* free_all_swap_pages - free swap pages allocated for saving image data.
* It also frees the extents used to register which swap entries had been
* allocated.
*/
void free_all_swap_pages(int swap)
{
struct rb_node *node;
while ((node = swsusp_extents.rb_node)) {
struct swsusp_extent *ext;
unsigned long offset;
ext = rb_entry(node, struct swsusp_extent, node);
rb_erase(node, &swsusp_extents);
for (offset = ext->start; offset <= ext->end; offset++)
swap_free(swp_entry(swap, offset));
kfree(ext);
}
}
int swsusp_swap_in_use(void)
{
return (swsusp_extents.rb_node != NULL);
}
/*
* General things
*/
static unsigned short root_swap = 0xffff;
static struct block_device *hib_resume_bdev;
struct hib_bio_batch {
atomic_t count;
wait_queue_head_t wait;
blk_status_t error;
struct blk_plug plug;
};
static void hib_init_batch(struct hib_bio_batch *hb)
{
atomic_set(&hb->count, 0);
init_waitqueue_head(&hb->wait);
hb->error = BLK_STS_OK;
blk_start_plug(&hb->plug);
}
static void hib_finish_batch(struct hib_bio_batch *hb)
{
blk_finish_plug(&hb->plug);
}
static void hib_end_io(struct bio *bio)
{
struct hib_bio_batch *hb = bio->bi_private;
struct page *page = bio_first_page_all(bio);
if (bio->bi_status) {
pr_alert("Read-error on swap-device (%u:%u:%Lu)\n",
MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)),
(unsigned long long)bio->bi_iter.bi_sector);
}
if (bio_data_dir(bio) == WRITE)
put_page(page);
else if (clean_pages_on_read)
flush_icache_range((unsigned long)page_address(page),
(unsigned long)page_address(page) + PAGE_SIZE);
if (bio->bi_status && !hb->error)
hb->error = bio->bi_status;
if (atomic_dec_and_test(&hb->count))
wake_up(&hb->wait);
bio_put(bio);
}
static int hib_submit_io(blk_opf_t opf, pgoff_t page_off, void *addr,
struct hib_bio_batch *hb)
{
struct page *page = virt_to_page(addr);
struct bio *bio;
int error = 0;
bio = bio_alloc(hib_resume_bdev, 1, opf, GFP_NOIO | __GFP_HIGH);
bio->bi_iter.bi_sector = page_off * (PAGE_SIZE >> 9);
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
pr_err("Adding page to bio failed at %llu\n",
(unsigned long long)bio->bi_iter.bi_sector);
bio_put(bio);
return -EFAULT;
}
if (hb) {
bio->bi_end_io = hib_end_io;
bio->bi_private = hb;
atomic_inc(&hb->count);
submit_bio(bio);
} else {
error = submit_bio_wait(bio);
bio_put(bio);
}
return error;
}
static int hib_wait_io(struct hib_bio_batch *hb)
{
/*
* We are relying on the behavior of blk_plug that a thread with
* a plug will flush the plug list before sleeping.
*/
wait_event(hb->wait, atomic_read(&hb->count) == 0);
return blk_status_to_errno(hb->error);
}
/*
* Saving part
*/
static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
{
int error;
hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header, NULL);
if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
!memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
memcpy(swsusp_header->sig, HIBERNATE_SIG, 10);
swsusp_header->image = handle->first_sector;
if (swsusp_hardware_signature) {
swsusp_header->hw_sig = swsusp_hardware_signature;
flags |= SF_HW_SIG;
}
swsusp_header->flags = flags;
if (flags & SF_CRC32_MODE)
swsusp_header->crc32 = handle->crc32;
error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
swsusp_resume_block, swsusp_header, NULL);
} else {
pr_err("Swap header not found!\n");
error = -ENODEV;
}
return error;
}
/*
* Hold the swsusp_header flag. This is used in software_resume() in
* 'kernel/power/hibernate' to check if the image is compressed and query
* for the compression algorithm support(if so).
*/
unsigned int swsusp_header_flags;
/**
* swsusp_swap_check - check if the resume device is a swap device
* and get its index (if so)
*
* This is called before saving image
*/
static int swsusp_swap_check(void)
{
int res;
if (swsusp_resume_device)
res = swap_type_of(swsusp_resume_device, swsusp_resume_block);
else
res = find_first_swap(&swsusp_resume_device);
if (res < 0)
return res;
root_swap = res;
hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device, FMODE_WRITE,
NULL);
if (IS_ERR(hib_resume_bdev))
return PTR_ERR(hib_resume_bdev);
res = set_blocksize(hib_resume_bdev, PAGE_SIZE);
if (res < 0)
blkdev_put(hib_resume_bdev, FMODE_WRITE);
return res;
}
/**
* write_page - Write one page to given swap location.
* @buf: Address we're writing.
* @offset: Offset of the swap page we're writing to.
* @hb: bio completion batch
*/
static int write_page(void *buf, sector_t offset, struct hib_bio_batch *hb)
{
void *src;
int ret;
if (!offset)
return -ENOSPC;
if (hb) {
src = (void *)__get_free_page(GFP_NOIO | __GFP_NOWARN |
__GFP_NORETRY);
if (src) {
copy_page(src, buf);
} else {
ret = hib_wait_io(hb); /* Free pages */
if (ret)
return ret;
src = (void *)__get_free_page(GFP_NOIO |
__GFP_NOWARN |
__GFP_NORETRY);
if (src) {
copy_page(src, buf);
} else {
WARN_ON_ONCE(1);
hb = NULL; /* Go synchronous */
src = buf;
}
}
} else {
src = buf;
}
return hib_submit_io(REQ_OP_WRITE | REQ_SYNC, offset, src, hb);
}
static void release_swap_writer(struct swap_map_handle *handle)
{
if (handle->cur)
free_page((unsigned long)handle->cur);
handle->cur = NULL;
}
static int get_swap_writer(struct swap_map_handle *handle)
{
int ret;
ret = swsusp_swap_check();
if (ret) {
if (ret != -ENOSPC)
pr_err("Cannot find swap device, try swapon -a\n");
return ret;
}
handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
if (!handle->cur) {
ret = -ENOMEM;
goto err_close;
}
handle->cur_swap = alloc_swapdev_block(root_swap);
if (!handle->cur_swap) {
ret = -ENOSPC;
goto err_rel;
}
handle->k = 0;
handle->reqd_free_pages = reqd_free_pages();
handle->first_sector = handle->cur_swap;
return 0;
err_rel:
release_swap_writer(handle);
err_close:
swsusp_close(FMODE_WRITE);
return ret;
}
static int swap_write_page(struct swap_map_handle *handle, void *buf,
struct hib_bio_batch *hb)
{
int error = 0;
sector_t offset;
bool skip = false;
if (!handle->cur)
return -EINVAL;
offset = alloc_swapdev_block(root_swap);
error = write_page(buf, offset, hb);
if (error)
return error;
handle->cur->entries[handle->k++] = offset;
if (handle->k >= MAP_PAGE_ENTRIES) {
offset = alloc_swapdev_block(root_swap);
if (!offset)
return -ENOSPC;
handle->cur->next_swap = offset;
trace_android_vh_skip_swap_map_write(&skip);
if (!skip) {
error = write_page(handle->cur, handle->cur_swap, hb);
if (error)
goto out;
}
clear_page(handle->cur);
handle->cur_swap = offset;
handle->k = 0;
if (hb && low_free_pages() <= handle->reqd_free_pages) {
error = hib_wait_io(hb);
if (error)
goto out;
/*
* Recalculate the number of required free pages, to
* make sure we never take more than half.
*/
handle->reqd_free_pages = reqd_free_pages();
}
}
out:
return error;
}
static int flush_swap_writer(struct swap_map_handle *handle)
{
if (handle->cur && handle->cur_swap)
return write_page(handle->cur, handle->cur_swap, NULL);
else
return -EINVAL;
}
static int swap_writer_finish(struct swap_map_handle *handle,
unsigned int flags, int error)
{
if (!error) {
pr_info("S");
error = mark_swapfiles(handle, flags);
pr_cont("|\n");
flush_swap_writer(handle);
}
if (error)
free_all_swap_pages(root_swap);
release_swap_writer(handle);
swsusp_close(FMODE_WRITE);
return error;
}
/*
* Bytes we need for compressed data in worst case. We assume(limitation)
* this is the worst of all the compression algorithms.
*/
#define bytes_worst_compress(x) ((x) + ((x) / 16) + 64 + 3 + 2)
/* We need to remember how much compressed data we need to read. */
#define CMP_HEADER sizeof(size_t)
/* Number of pages/bytes we'll compress at one time. */
#define UNC_PAGES 32
#define UNC_SIZE (UNC_PAGES * PAGE_SIZE)
/* Number of pages we need for compressed data (worst case). */
#define CMP_PAGES DIV_ROUND_UP(bytes_worst_compress(UNC_SIZE) + \
CMP_HEADER, PAGE_SIZE)
#define CMP_SIZE (CMP_PAGES * PAGE_SIZE)
/* Maximum number of threads for compression/decompression. */
#define CMP_THREADS 3
/* Minimum/maximum number of pages for read buffering. */
#define CMP_MIN_RD_PAGES 1024
#define CMP_MAX_RD_PAGES 8192
/**
* save_image - save the suspend image data
*/
static int save_image(struct swap_map_handle *handle,
struct snapshot_handle *snapshot,
unsigned int nr_to_write)
{
unsigned int m;
int ret;
int nr_pages;
int err2;
struct hib_bio_batch hb;
ktime_t start;
ktime_t stop;
hib_init_batch(&hb);
pr_info("Saving image data pages (%u pages)...\n",
nr_to_write);
m = nr_to_write / 10;
if (!m)
m = 1;
nr_pages = 0;
start = ktime_get();
while (1) {
ret = snapshot_read_next(snapshot);
if (ret <= 0)
break;
trace_android_vh_encrypt_page(data_of(*snapshot));
ret = swap_write_page(handle, data_of(*snapshot), &hb);
if (ret)
break;
if (!(nr_pages % m))
pr_info("Image saving progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
}
err2 = hib_wait_io(&hb);
hib_finish_batch(&hb);
stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
pr_info("Image saving done\n");
swsusp_show_speed(start, stop, nr_to_write, "Wrote");
return ret;
}
/**
* Structure used for CRC32.
*/
struct crc_data {
struct task_struct *thr; /* thread */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */
unsigned run_threads; /* nr current threads */
wait_queue_head_t go; /* start crc update */
wait_queue_head_t done; /* crc update done */
u32 *crc32; /* points to handle's crc32 */
size_t *unc_len[CMP_THREADS]; /* uncompressed lengths */
unsigned char *unc[CMP_THREADS]; /* uncompressed data */
};
/**
* CRC32 update function that runs in its own thread.
*/
static int crc32_threadfn(void *data)
{
struct crc_data *d = data;
unsigned i;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
kthread_should_stop());
if (kthread_should_stop()) {
d->thr = NULL;
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
break;
}
atomic_set(&d->ready, 0);
for (i = 0; i < d->run_threads; i++)
*d->crc32 = crc32_le(*d->crc32,
d->unc[i], *d->unc_len[i]);
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
}
return 0;
}
/**
* Structure used for data compression.
*/
struct cmp_data {
struct task_struct *thr; /* thread */
struct crypto_comp *cc; /* crypto compressor stream */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */
int ret; /* return code */
wait_queue_head_t go; /* start compression */
wait_queue_head_t done; /* compression done */
size_t unc_len; /* uncompressed length */
size_t cmp_len; /* compressed length */
unsigned char unc[UNC_SIZE]; /* uncompressed buffer */
unsigned char cmp[CMP_SIZE]; /* compressed buffer */
};
/* Indicates the image size after compression */
static atomic_t compressed_size = ATOMIC_INIT(0);
/**
* Compression function that runs in its own thread.
*/
static int compress_threadfn(void *data)
{
struct cmp_data *d = data;
unsigned int cmp_len = 0;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
kthread_should_stop());
if (kthread_should_stop()) {
d->thr = NULL;
d->ret = -1;
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
break;
}
atomic_set(&d->ready, 0);
cmp_len = CMP_SIZE - CMP_HEADER;
d->ret = crypto_comp_compress(d->cc, d->unc, d->unc_len,
d->cmp + CMP_HEADER,
&cmp_len);
d->cmp_len = cmp_len;
atomic_set(&compressed_size, atomic_read(&compressed_size) + d->cmp_len);
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
}
return 0;
}
/**
* save_compressed_image - Save the suspend image data after compression.
* @handle: Swap map handle to use for saving the image.
* @snapshot: Image to read data from.
* @nr_to_write: Number of pages to save.
*/
static int save_compressed_image(struct swap_map_handle *handle,
struct snapshot_handle *snapshot,
unsigned int nr_to_write)
{
unsigned int m;
int ret = 0;
int nr_pages;
int err2;
struct hib_bio_batch hb;
ktime_t start;
ktime_t stop;
size_t off;
unsigned thr, run_threads, nr_threads;
unsigned char *page = NULL;
struct cmp_data *data = NULL;
struct crc_data *crc = NULL;
hib_init_batch(&hb);
atomic_set(&compressed_size, 0);
/*
* We'll limit the number of threads for compression to limit memory
* footprint.
*/
nr_threads = num_online_cpus() - 1;
nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
page = (void *)__get_free_page(GFP_NOIO | __GFP_HIGH);
if (!page) {
pr_err("Failed to allocate %s page\n", hib_comp_algo);
ret = -ENOMEM;
goto out_clean;
}
data = vzalloc(array_size(nr_threads, sizeof(*data)));
if (!data) {
pr_err("Failed to allocate %s data\n", hib_comp_algo);
ret = -ENOMEM;
goto out_clean;
}
crc = kzalloc(sizeof(*crc), GFP_KERNEL);
if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM;
goto out_clean;
}
/*
* Start the compression threads.
*/
for (thr = 0; thr < nr_threads; thr++) {
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
data[thr].cc = crypto_alloc_comp(hib_comp_algo, 0, 0);
if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT;
goto out_clean;
}
data[thr].thr = kthread_run(compress_threadfn,
&data[thr],
"image_compress/%u", thr);
if (IS_ERR(data[thr].thr)) {
data[thr].thr = NULL;
pr_err("Cannot start compression threads\n");
ret = -ENOMEM;
goto out_clean;
}
}
/*
* Start the CRC32 thread.
*/
init_waitqueue_head(&crc->go);
init_waitqueue_head(&crc->done);
handle->crc32 = 0;
crc->crc32 = &handle->crc32;
for (thr = 0; thr < nr_threads; thr++) {
crc->unc[thr] = data[thr].unc;
crc->unc_len[thr] = &data[thr].unc_len;
}
crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
if (IS_ERR(crc->thr)) {
crc->thr = NULL;
pr_err("Cannot start CRC32 thread\n");
ret = -ENOMEM;
goto out_clean;
}
/*
* Adjust the number of required free pages after all allocations have
* been done. We don't want to run out of pages when writing.
*/
handle->reqd_free_pages = reqd_free_pages();
pr_info("Using %u thread(s) for %s compression\n", nr_threads, hib_comp_algo);
pr_info("Compressing and saving image data (%u pages)...\n",
nr_to_write);
m = nr_to_write / 10;
if (!m)
m = 1;
nr_pages = 0;
start = ktime_get();
for (;;) {
for (thr = 0; thr < nr_threads; thr++) {
for (off = 0; off < UNC_SIZE; off += PAGE_SIZE) {
ret = snapshot_read_next(snapshot);
if (ret < 0)
goto out_finish;
if (!ret)
break;
memcpy(data[thr].unc + off,
data_of(*snapshot), PAGE_SIZE);
if (!(nr_pages % m))
pr_info("Image saving progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
}
if (!off)
break;
data[thr].unc_len = off;
atomic_set_release(&data[thr].ready, 1);
wake_up(&data[thr].go);
}
if (!thr)
break;
crc->run_threads = thr;
atomic_set_release(&crc->ready, 1);
wake_up(&crc->go);
for (run_threads = thr, thr = 0; thr < run_threads; thr++) {
wait_event(data[thr].done,
atomic_read_acquire(&data[thr].stop));
atomic_set(&data[thr].stop, 0);
ret = data[thr].ret;
if (ret < 0) {
pr_err("%s compression failed\n", hib_comp_algo);
goto out_finish;
}
if (unlikely(!data[thr].cmp_len ||
data[thr].cmp_len >
bytes_worst_compress(data[thr].unc_len))) {
pr_err("Invalid %s compressed length\n", hib_comp_algo);
ret = -1;
goto out_finish;
}
*(size_t *)data[thr].cmp = data[thr].cmp_len;
/*
* Given we are writing one page at a time to disk, we
* copy that much from the buffer, although the last
* bit will likely be smaller than full page. This is
* OK - we saved the length of the compressed data, so
* any garbage at the end will be discarded when we
* read it.
*/
for (off = 0;
off < CMP_HEADER + data[thr].cmp_len;
off += PAGE_SIZE) {
memcpy(page, data[thr].cmp + off, PAGE_SIZE);
trace_android_vh_encrypt_page(page);
ret = swap_write_page(handle, page, &hb);
if (ret)
goto out_finish;
}
trace_android_vh_hibernate_save_cmp_len(data[thr].cmp_len + CMP_HEADER);
}
wait_event(crc->done, atomic_read_acquire(&crc->stop));
atomic_set(&crc->stop, 0);
}
out_finish:
err2 = hib_wait_io(&hb);
stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
pr_info("Image saving done\n");
swsusp_show_speed(start, stop, nr_to_write, "Wrote");
pr_info("Image size after compression: %d kbytes\n",
(atomic_read(&compressed_size) / 1024));
out_clean:
hib_finish_batch(&hb);
if (crc) {
if (crc->thr)
kthread_stop(crc->thr);
kfree(crc);
}
if (data) {
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
kthread_stop(data[thr].thr);
if (data[thr].cc)
crypto_free_comp(data[thr].cc);
}
vfree(data);
}
if (page) free_page((unsigned long)page);
return ret;
}
/**
* enough_swap - Make sure we have enough swap to save the image.
*
* Returns TRUE or FALSE after checking the total amount of swap
* space available from the resume partition.
*/
static int enough_swap(unsigned int nr_pages)
{
unsigned int free_swap = count_swap_pages(root_swap, 1);
unsigned int required;
pr_debug("Free swap pages: %u\n", free_swap);
required = PAGES_FOR_IO + nr_pages;
return free_swap > required;
}
/**
* swsusp_write - Write entire image and metadata.
* @flags: flags to pass to the "boot" kernel in the image header
*
* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/
int swsusp_write(unsigned int flags)
{
struct swap_map_handle handle;
struct snapshot_handle snapshot;
struct swsusp_info *header;
unsigned long pages;
int error = 0;
pages = snapshot_get_image_size();
/*
* The memory allocated by this vendor hook is later freed as part of
* PM_POST_HIBERNATION notifier call.
*/
trace_android_vh_hibernated_do_mem_alloc(pages, flags, &error);
if (error < 0) {
pr_err("Failed to allocate required memory\n");
return error;
}
error = get_swap_writer(&handle);
if (error) {
pr_err("Cannot get swap writer\n");
return error;
}
trace_android_vh_init_aes_encrypt(NULL);
if (flags & SF_NOCOMPRESS_MODE) {
if (!enough_swap(pages)) {
pr_err("Not enough free swap\n");
error = -ENOSPC;
goto out_finish;
}
}
memset(&snapshot, 0, sizeof(struct snapshot_handle));
error = snapshot_read_next(&snapshot);
if (error < (int)PAGE_SIZE) {
if (error >= 0)
error = -EFAULT;
goto out_finish;
}
header = (struct swsusp_info *)data_of(snapshot);
error = swap_write_page(&handle, header, NULL);
if (!error) {
error = (flags & SF_NOCOMPRESS_MODE) ?
save_image(&handle, &snapshot, pages - 1) :
save_compressed_image(&handle, &snapshot, pages - 1);
if (!error)
trace_android_vh_post_image_save(root_swap);
}
out_finish:
error = swap_writer_finish(&handle, flags, error);
return error;
}
/**
* The following functions allow us to read data using a swap map
* in a file-alike way
*/
static void release_swap_reader(struct swap_map_handle *handle)
{
struct swap_map_page_list *tmp;
while (handle->maps) {
if (handle->maps->map)
free_page((unsigned long)handle->maps->map);
tmp = handle->maps;
handle->maps = handle->maps->next;
kfree(tmp);
}
handle->cur = NULL;
}
static int get_swap_reader(struct swap_map_handle *handle,
unsigned int *flags_p)
{
int error;
struct swap_map_page_list *tmp, *last;
sector_t offset;
*flags_p = swsusp_header->flags;
if (!swsusp_header->image) /* how can this happen? */
return -EINVAL;
handle->cur = NULL;
last = handle->maps = NULL;
offset = swsusp_header->image;
while (offset) {
tmp = kzalloc(sizeof(*handle->maps), GFP_KERNEL);
if (!tmp) {
release_swap_reader(handle);
return -ENOMEM;
}
if (!handle->maps)
handle->maps = tmp;
if (last)
last->next = tmp;
last = tmp;
tmp->map = (struct swap_map_page *)
__get_free_page(GFP_NOIO | __GFP_HIGH);
if (!tmp->map) {
release_swap_reader(handle);
return -ENOMEM;
}
error = hib_submit_io(REQ_OP_READ, offset, tmp->map, NULL);
if (error) {
release_swap_reader(handle);
return error;
}
offset = tmp->map->next_swap;
}
handle->k = 0;
handle->cur = handle->maps->map;
return 0;
}
static int swap_read_page(struct swap_map_handle *handle, void *buf,
struct hib_bio_batch *hb)
{
sector_t offset;
int error;
struct swap_map_page_list *tmp;
if (!handle->cur)
return -EINVAL;
offset = handle->cur->entries[handle->k];
if (!offset)
return -EFAULT;
error = hib_submit_io(REQ_OP_READ, offset, buf, hb);
if (error)
return error;
if (++handle->k >= MAP_PAGE_ENTRIES) {
handle->k = 0;
free_page((unsigned long)handle->maps->map);
tmp = handle->maps;
handle->maps = handle->maps->next;
kfree(tmp);
if (!handle->maps)
release_swap_reader(handle);
else
handle->cur = handle->maps->map;
}
return error;
}
static int swap_reader_finish(struct swap_map_handle *handle)
{
release_swap_reader(handle);
return 0;
}
/**
* load_image - load the image using the swap map handle
* @handle and the snapshot handle @snapshot
* (assume there are @nr_pages pages to load)
*/
static int load_image(struct swap_map_handle *handle,
struct snapshot_handle *snapshot,
unsigned int nr_to_read)
{
unsigned int m;
int ret = 0;
ktime_t start;
ktime_t stop;
struct hib_bio_batch hb;
int err2;
unsigned nr_pages;
hib_init_batch(&hb);
clean_pages_on_read = true;
pr_info("Loading image data pages (%u pages)...\n", nr_to_read);
m = nr_to_read / 10;
if (!m)
m = 1;
nr_pages = 0;
start = ktime_get();
for ( ; ; ) {
ret = snapshot_write_next(snapshot);
if (ret <= 0)
break;
ret = swap_read_page(handle, data_of(*snapshot), &hb);
if (ret)
break;
if (snapshot->sync_read)
ret = hib_wait_io(&hb);
if (ret)
break;
if (!(nr_pages % m))
pr_info("Image loading progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
}
err2 = hib_wait_io(&hb);
hib_finish_batch(&hb);
stop = ktime_get();
if (!ret)
ret = err2;
if (!ret) {
pr_info("Image loading done\n");
snapshot_write_finalize(snapshot);
if (!snapshot_image_loaded(snapshot))
ret = -ENODATA;
}
swsusp_show_speed(start, stop, nr_to_read, "Read");
return ret;
}
/**
* Structure used for data decompression.
*/
struct dec_data {
struct task_struct *thr; /* thread */
struct crypto_comp *cc; /* crypto compressor stream */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */
int ret; /* return code */
wait_queue_head_t go; /* start decompression */
wait_queue_head_t done; /* decompression done */
size_t unc_len; /* uncompressed length */
size_t cmp_len; /* compressed length */
unsigned char unc[UNC_SIZE]; /* uncompressed buffer */
unsigned char cmp[CMP_SIZE]; /* compressed buffer */
};
/**
* Decompression function that runs in its own thread.
*/
static int decompress_threadfn(void *data)
{
struct dec_data *d = data;
unsigned int unc_len = 0;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
kthread_should_stop());
if (kthread_should_stop()) {
d->thr = NULL;
d->ret = -1;
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
break;
}
atomic_set(&d->ready, 0);
unc_len = UNC_SIZE;
d->ret = crypto_comp_decompress(d->cc, d->cmp + CMP_HEADER, d->cmp_len,
d->unc, &unc_len);
d->unc_len = unc_len;
if (clean_pages_on_decompress)
flush_icache_range((unsigned long)d->unc,
(unsigned long)d->unc + d->unc_len);
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
}
return 0;
}
/**
* load_compressed_image - Load compressed image data and decompress it.
* @handle: Swap map handle to use for loading data.
* @snapshot: Image to copy uncompressed data into.
* @nr_to_read: Number of pages to load.
*/
static int load_compressed_image(struct swap_map_handle *handle,
struct snapshot_handle *snapshot,
unsigned int nr_to_read)
{
unsigned int m;
int ret = 0;
int eof = 0;
struct hib_bio_batch hb;
ktime_t start;
ktime_t stop;
unsigned nr_pages;
size_t off;
unsigned i, thr, run_threads, nr_threads;
unsigned ring = 0, pg = 0, ring_size = 0,
have = 0, want, need, asked = 0;
unsigned long read_pages = 0;
unsigned char **page = NULL;
struct dec_data *data = NULL;
struct crc_data *crc = NULL;
hib_init_batch(&hb);
/*
* We'll limit the number of threads for decompression to limit memory
* footprint.
*/
nr_threads = num_online_cpus() - 1;
nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
page = vmalloc(array_size(CMP_MAX_RD_PAGES, sizeof(*page)));
if (!page) {
pr_err("Failed to allocate %s page\n", hib_comp_algo);
ret = -ENOMEM;
goto out_clean;
}
data = vzalloc(array_size(nr_threads, sizeof(*data)));
if (!data) {
pr_err("Failed to allocate %s data\n", hib_comp_algo);
ret = -ENOMEM;
goto out_clean;
}
crc = kzalloc(sizeof(*crc), GFP_KERNEL);
if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM;
goto out_clean;
}
clean_pages_on_decompress = true;
/*
* Start the decompression threads.
*/
for (thr = 0; thr < nr_threads; thr++) {
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
data[thr].cc = crypto_alloc_comp(hib_comp_algo, 0, 0);
if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT;
goto out_clean;
}
data[thr].thr = kthread_run(decompress_threadfn,
&data[thr],
"image_decompress/%u", thr);
if (IS_ERR(data[thr].thr)) {
data[thr].thr = NULL;
pr_err("Cannot start decompression threads\n");
ret = -ENOMEM;
goto out_clean;
}
}
/*
* Start the CRC32 thread.
*/
init_waitqueue_head(&crc->go);
init_waitqueue_head(&crc->done);
handle->crc32 = 0;
crc->crc32 = &handle->crc32;
for (thr = 0; thr < nr_threads; thr++) {
crc->unc[thr] = data[thr].unc;
crc->unc_len[thr] = &data[thr].unc_len;
}
crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
if (IS_ERR(crc->thr)) {
crc->thr = NULL;
pr_err("Cannot start CRC32 thread\n");
ret = -ENOMEM;
goto out_clean;
}
/*
* Set the number of pages for read buffering.
* This is complete guesswork, because we'll only know the real
* picture once prepare_image() is called, which is much later on
* during the image load phase. We'll assume the worst case and
* say that none of the image pages are from high memory.
*/
if (low_free_pages() > snapshot_get_image_size())
read_pages = (low_free_pages() - snapshot_get_image_size()) / 2;
read_pages = clamp_val(read_pages, CMP_MIN_RD_PAGES, CMP_MAX_RD_PAGES);
for (i = 0; i < read_pages; i++) {
page[i] = (void *)__get_free_page(i < CMP_PAGES ?
GFP_NOIO | __GFP_HIGH :
GFP_NOIO | __GFP_NOWARN |
__GFP_NORETRY);
if (!page[i]) {
if (i < CMP_PAGES) {
ring_size = i;
pr_err("Failed to allocate %s pages\n", hib_comp_algo);
ret = -ENOMEM;
goto out_clean;
} else {
break;
}
}
}
want = ring_size = i;
pr_info("Using %u thread(s) for %s decompression\n", nr_threads, hib_comp_algo);
pr_info("Loading and decompressing image data (%u pages)...\n",
nr_to_read);
m = nr_to_read / 10;
if (!m)
m = 1;
nr_pages = 0;
start = ktime_get();
ret = snapshot_write_next(snapshot);
if (ret <= 0)
goto out_finish;
for(;;) {
for (i = 0; !eof && i < want; i++) {
ret = swap_read_page(handle, page[ring], &hb);
if (ret) {
/*
* On real read error, finish. On end of data,
* set EOF flag and just exit the read loop.
*/
if (handle->cur &&
handle->cur->entries[handle->k]) {
goto out_finish;
} else {
eof = 1;
break;
}
}
if (++ring >= ring_size)
ring = 0;
}
asked += i;
want -= i;
/*
* We are out of data, wait for some more.
*/
if (!have) {
if (!asked)
break;
ret = hib_wait_io(&hb);
if (ret)
goto out_finish;
have += asked;
asked = 0;
if (eof)
eof = 2;
}
if (crc->run_threads) {
wait_event(crc->done, atomic_read_acquire(&crc->stop));
atomic_set(&crc->stop, 0);
crc->run_threads = 0;
}
for (thr = 0; have && thr < nr_threads; thr++) {
data[thr].cmp_len = *(size_t *)page[pg];
if (unlikely(!data[thr].cmp_len ||
data[thr].cmp_len >
bytes_worst_compress(UNC_SIZE))) {
pr_err("Invalid %s compressed length\n", hib_comp_algo);
ret = -1;
goto out_finish;
}
need = DIV_ROUND_UP(data[thr].cmp_len + CMP_HEADER,
PAGE_SIZE);
if (need > have) {
if (eof > 1) {
ret = -1;
goto out_finish;
}
break;
}
for (off = 0;
off < CMP_HEADER + data[thr].cmp_len;
off += PAGE_SIZE) {
memcpy(data[thr].cmp + off,
page[pg], PAGE_SIZE);
have--;
want++;
if (++pg >= ring_size)
pg = 0;
}
atomic_set_release(&data[thr].ready, 1);
wake_up(&data[thr].go);
}
/*
* Wait for more data while we are decompressing.
*/
if (have < CMP_PAGES && asked) {
ret = hib_wait_io(&hb);
if (ret)
goto out_finish;
have += asked;
asked = 0;
if (eof)
eof = 2;
}
for (run_threads = thr, thr = 0; thr < run_threads; thr++) {
wait_event(data[thr].done,
atomic_read_acquire(&data[thr].stop));
atomic_set(&data[thr].stop, 0);
ret = data[thr].ret;
if (ret < 0) {
pr_err("%s decompression failed\n", hib_comp_algo);
goto out_finish;
}
if (unlikely(!data[thr].unc_len ||
data[thr].unc_len > UNC_SIZE ||
data[thr].unc_len & (PAGE_SIZE - 1))) {
pr_err("Invalid %s uncompressed length\n", hib_comp_algo);
ret = -1;
goto out_finish;
}
for (off = 0;
off < data[thr].unc_len; off += PAGE_SIZE) {
memcpy(data_of(*snapshot),
data[thr].unc + off, PAGE_SIZE);
if (!(nr_pages % m))
pr_info("Image loading progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
ret = snapshot_write_next(snapshot);
if (ret <= 0) {
crc->run_threads = thr + 1;
atomic_set_release(&crc->ready, 1);
wake_up(&crc->go);
goto out_finish;
}
}
}
crc->run_threads = thr;
atomic_set_release(&crc->ready, 1);
wake_up(&crc->go);
}
out_finish:
if (crc->run_threads) {
wait_event(crc->done, atomic_read_acquire(&crc->stop));
atomic_set(&crc->stop, 0);
}
stop = ktime_get();
if (!ret) {
pr_info("Image loading done\n");
snapshot_write_finalize(snapshot);
if (!snapshot_image_loaded(snapshot))
ret = -ENODATA;
if (!ret) {
if (swsusp_header->flags & SF_CRC32_MODE) {
if(handle->crc32 != swsusp_header->crc32) {
pr_err("Invalid image CRC32!\n");
ret = -ENODATA;
}
}
}
}
swsusp_show_speed(start, stop, nr_to_read, "Read");
out_clean:
hib_finish_batch(&hb);
for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]);
if (crc) {
if (crc->thr)
kthread_stop(crc->thr);
kfree(crc);
}
if (data) {
for (thr = 0; thr < nr_threads; thr++) {
if (data[thr].thr)
kthread_stop(data[thr].thr);
if (data[thr].cc)
crypto_free_comp(data[thr].cc);
}
vfree(data);
}
vfree(page);
return ret;
}
/**
* swsusp_read - read the hibernation image.
* @flags_p: flags passed by the "frozen" kernel in the image header should
* be written into this memory location
*/
int swsusp_read(unsigned int *flags_p)
{
int error;
struct swap_map_handle handle;
struct snapshot_handle snapshot;
struct swsusp_info *header;
memset(&snapshot, 0, sizeof(struct snapshot_handle));
error = snapshot_write_next(&snapshot);
if (error < (int)PAGE_SIZE)
return error < 0 ? error : -EFAULT;
header = (struct swsusp_info *)data_of(snapshot);
error = get_swap_reader(&handle, flags_p);
if (error)
goto end;
if (!error)
error = swap_read_page(&handle, header, NULL);
if (!error) {
error = (*flags_p & SF_NOCOMPRESS_MODE) ?
load_image(&handle, &snapshot, header->pages - 1) :
load_compressed_image(&handle, &snapshot, header->pages - 1);
}
swap_reader_finish(&handle);
end:
if (!error)
pr_debug("Image successfully loaded\n");
else
pr_debug("Error %d resuming\n", error);
return error;
}
/**
* swsusp_check - Check for swsusp signature in the resume device
*/
int swsusp_check(void)
{
int error;
void *holder;
fmode_t mode = FMODE_READ;
if (snapshot_test)
mode |= FMODE_EXCL;
hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device,
mode, &holder);
if (!IS_ERR(hib_resume_bdev)) {
set_blocksize(hib_resume_bdev, PAGE_SIZE);
trace_android_vh_save_hib_resume_bdev(hib_resume_bdev);
clear_page(swsusp_header);
error = hib_submit_io(REQ_OP_READ, swsusp_resume_block,
swsusp_header, NULL);
if (error)
goto put;
if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) {
memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
swsusp_header_flags = swsusp_header->flags;
/* Reset swap signature now */
error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
swsusp_resume_block,
swsusp_header, NULL);
} else {
error = -EINVAL;
}
if (!error && swsusp_header->flags & SF_HW_SIG &&
swsusp_header->hw_sig != swsusp_hardware_signature) {
pr_info("Suspend image hardware signature mismatch (%08x now %08x); aborting resume.\n",
swsusp_header->hw_sig, swsusp_hardware_signature);
error = -EINVAL;
}
put:
if (error)
blkdev_put(hib_resume_bdev, mode);
else
pr_debug("Image signature found, resuming\n");
} else {
error = PTR_ERR(hib_resume_bdev);
}
if (error)
pr_debug("Image not found (code %d)\n", error);
return error;
}
/**
* swsusp_close - close swap device.
*/
void swsusp_close(fmode_t mode)
{
if (IS_ERR(hib_resume_bdev)) {
pr_debug("Image device not initialised\n");
return;
}
blkdev_put(hib_resume_bdev, mode);
}
/**
* swsusp_unmark - Unmark swsusp signature in the resume device
*/
#ifdef CONFIG_SUSPEND
int swsusp_unmark(void)
{
int error;
hib_submit_io(REQ_OP_READ, swsusp_resume_block,
swsusp_header, NULL);
if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
swsusp_resume_block,
swsusp_header, NULL);
} else {
pr_err("Cannot find swsusp signature!\n");
error = -ENODEV;
}
/*
* We just returned from suspend, we don't need the image any more.
*/
free_all_swap_pages(root_swap);
return error;
}
#endif
static int __init swsusp_header_init(void)
{
swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
if (!swsusp_header)
panic("Could not allocate memory for swsusp_header\n");
return 0;
}
core_initcall(swsusp_header_init);