···454454 disables it. Reads from the file return the current value.455455 The default is "1" if the build-time "SUSPEND_SKIP_SYNC" config456456 flag is unset, or "0" otherwise.457457+458458+What: /sys/power/hibernate_compression_threads459459+Date: October 2025460460+Contact: <luoxueqin@kylinos.cn>461461+Description:462462+ Controls the number of threads used for compression463463+ and decompression of hibernation images.464464+465465+ The value can be adjusted at runtime to balance466466+ performance and CPU utilization.467467+468468+ The change takes effect on the next hibernation or469469+ resume operation.470470+471471+ Minimum value: 1472472+ Default value: 3
+10
Documentation/admin-guide/kernel-parameters.txt
···19071907 /sys/power/pm_test). Only available when CONFIG_PM_DEBUG19081908 is set. Default value is 5.1909190919101910+ hibernate_compression_threads=19111911+ [HIBERNATION]19121912+ Set the number of threads used for compressing or decompressing19131913+ hibernation images.19141914+19151915+ Format: <integer>19161916+ Default: 319171917+ Minimum: 119181918+ Example: hibernate_compression_threads=419191919+19101920 highmem=nn[KMG] [KNL,BOOT,EARLY] forces the highmem zone to have an exact19111921 size of <nn>. This works even on boxes that have no19121922 highmem otherwise. This also works to reduce highmem
···11+.. SPDX-License-Identifier: GPL-2.022+33+Debugging Kernel Shutdown Hangs with pstore44++++++++++++++++++++++++++++++++++++++++++++55+66+Overview77+========88+If the system hangs while shutting down, the kernel logs may need to be99+retrieved to debug the issue.1010+1111+On systems that have a UART available, it is best to configure the kernel to use1212+this UART for kernel console output.1313+1414+If a UART isn't available, the ``pstore`` subsystem provides a mechanism to1515+persist this data across a system reset, allowing it to be retrieved on the next1616+boot.1717+1818+Kernel Configuration1919+====================2020+To enable ``pstore`` and enable saving kernel ring buffer logs, set the2121+following kernel configuration options:2222+2323+* ``CONFIG_PSTORE=y``2424+* ``CONFIG_PSTORE_CONSOLE=y``2525+2626+Additionally, enable a backend to store the data. Depending upon your platform2727+some potential options include:2828+2929+* ``CONFIG_EFI_VARS_PSTORE=y``3030+* ``CONFIG_PSTORE_RAM=y``3131+* ``CONFIG_CHROMEOS_PSTORE=y``3232+* ``CONFIG_PSTORE_BLK=y``3333+3434+Kernel Command-line Parameters3535+==============================3636+Add these parameters to your kernel command line:3737+3838+* ``printk.always_kmsg_dump=Y``3939+ * Forces the kernel to dump the entire message buffer to pstore during4040+ shutdown4141+* ``efi_pstore.pstore_disable=N``4242+ * For EFI-based systems, ensures the EFI backend is active4343+4444+Userspace Interaction and Log Retrieval4545+=======================================4646+On the next boot after a hang, pstore logs will be available in the pstore4747+filesystem (``/sys/fs/pstore``) and can be retrieved by userspace.4848+4949+On systemd systems, the ``systemd-pstore`` service will help do the following:5050+5151+#. Locate pstore data in ``/sys/fs/pstore``5252+#. Read and save it to ``/var/lib/systemd/pstore``5353+#. Clear pstore data for the next event
···3434#include <linux/cpufreq.h>3535#include <linux/devfreq.h>3636#include <linux/timer.h>3737+#include <linux/nmi.h>37383839#include "../base.h"3940#include "power.h"···9695 return "restore";9796 case PM_EVENT_RECOVER:9897 return "recover";9898+ case PM_EVENT_POWEROFF:9999+ return "poweroff";99100 default:100101 return "(unknown PM event)";101102 }···370367 case PM_EVENT_FREEZE:371368 case PM_EVENT_QUIESCE:372369 return ops->freeze;370370+ case PM_EVENT_POWEROFF:373371 case PM_EVENT_HIBERNATE:374372 return ops->poweroff;375373 case PM_EVENT_THAW:···405401 case PM_EVENT_FREEZE:406402 case PM_EVENT_QUIESCE:407403 return ops->freeze_late;404404+ case PM_EVENT_POWEROFF:408405 case PM_EVENT_HIBERNATE:409406 return ops->poweroff_late;410407 case PM_EVENT_THAW:···440435 case PM_EVENT_FREEZE:441436 case PM_EVENT_QUIESCE:442437 return ops->freeze_noirq;438438+ case PM_EVENT_POWEROFF:443439 case PM_EVENT_HIBERNATE:444440 return ops->poweroff_noirq;445441 case PM_EVENT_THAW:···521515#define DECLARE_DPM_WATCHDOG_ON_STACK(wd) \522516 struct dpm_watchdog wd523517518518+static bool __read_mostly dpm_watchdog_all_cpu_backtrace;519519+module_param(dpm_watchdog_all_cpu_backtrace, bool, 0644);520520+MODULE_PARM_DESC(dpm_watchdog_all_cpu_backtrace,521521+ "Backtrace all CPUs on DPM watchdog timeout");522522+524523/**525524 * dpm_watchdog_handler - Driver suspend / resume watchdog handler.526525 * @t: The timer that PM watchdog depends on.···541530 unsigned int time_left;542531543532 if (wd->fatal) {533533+ unsigned int this_cpu = smp_processor_id();534534+544535 dev_emerg(wd->dev, "**** DPM device timeout ****\n");545536 show_stack(wd->tsk, NULL, KERN_EMERG);537537+ if (dpm_watchdog_all_cpu_backtrace)538538+ trigger_allbutcpu_cpu_backtrace(this_cpu);546539 panic("%s %s: unrecoverable failure\n",547540 dev_driver_string(wd->dev), dev_name(wd->dev));548541 }
+1-3
drivers/base/power/trace.c
···238238 unsigned int hash = hash_string(DEVSEED, dev_name(dev),239239 DEVHASH);240240 if (hash == value) {241241- int len = snprintf(buf, size, "%s\n",241241+ int len = scnprintf(buf, size, "%s\n",242242 dev_driver_string(dev));243243- if (len > size)244244- len = size;245243 buf += len;246244 ret += len;247245 size -= len;
+11-13
drivers/base/power/wakeup.c
···189189 if (WARN_ON(!ws))190190 return;191191192192+ /*193193+ * After shutting down the timer, wakeup_source_activate() will warn if194194+ * the given wakeup source is passed to it.195195+ */196196+ timer_shutdown_sync(&ws->timer);197197+192198 raw_spin_lock_irqsave(&events_lock, flags);193199 list_del_rcu(&ws->entry);194200 raw_spin_unlock_irqrestore(&events_lock, flags);195201 synchronize_srcu(&wakeup_srcu);196196-197197- timer_delete_sync(&ws->timer);198198- /*199199- * Clear timer.function to make wakeup_source_not_registered() treat200200- * this wakeup source as not registered.201201- */202202- ws->timer.function = NULL;203202}204203205204/**···505506EXPORT_SYMBOL_GPL(device_set_wakeup_enable);506507507508/**508508- * wakeup_source_not_registered - validate the given wakeup source.509509+ * wakeup_source_not_usable - validate the given wakeup source.509510 * @ws: Wakeup source to be validated.510511 */511511-static bool wakeup_source_not_registered(struct wakeup_source *ws)512512+static bool wakeup_source_not_usable(struct wakeup_source *ws)512513{513514 /*514514- * Use timer struct to check if the given source is initialized515515- * by wakeup_source_add.515515+ * Use the timer struct to check if the given wakeup source has been516516+ * initialized by wakeup_source_add() and it is not going away.516517 */517518 return ws->timer.function != pm_wakeup_timer_fn;518519}···557558{558559 unsigned int cec;559560560560- if (WARN_ONCE(wakeup_source_not_registered(ws),561561- "unregistered wakeup source\n"))561561+ if (WARN_ONCE(wakeup_source_not_usable(ws), "unusable wakeup source\n"))562562 return;563563564564 ws->active = true;
···17481748 break;17491749 case PM_EVENT_SUSPEND:17501750 case PM_EVENT_HIBERNATE:17511751+ case PM_EVENT_POWEROFF:17511752 case PM_EVENT_PRETHAW: /* explicitly discard hw state */17521753 port_power(sl811, 0);17531754 break;
+8-4
include/linux/freezer.h
···2222extern unsigned int freeze_timeout_msecs;23232424/*2525- * Check if a process has been frozen2525+ * Check if a process has been frozen for PM or cgroup1 freezer. Note that2626+ * cgroup2 freezer uses the job control mechanism and does not interact with2727+ * the PM freezer.2628 */2729extern bool frozen(struct task_struct *p);28302931extern bool freezing_slow_path(struct task_struct *p);30323133/*3232- * Check if there is a request to freeze a process3434+ * Check if there is a request to freeze a task from PM or cgroup1 freezer.3535+ * Note that cgroup2 freezer uses the job control mechanism and does not3636+ * interact with the PM freezer.3337 */3438static inline bool freezing(struct task_struct *p)3539{···6763extern bool set_freezable(void);68646965#ifdef CONFIG_CGROUP_FREEZER7070-extern bool cgroup_freezing(struct task_struct *task);6666+extern bool cgroup1_freezing(struct task_struct *task);7167#else /* !CONFIG_CGROUP_FREEZER */7272-static inline bool cgroup_freezing(struct task_struct *task)6868+static inline bool cgroup1_freezing(struct task_struct *task)7369{7470 return false;7571}
+6-2
include/linux/pm.h
···25252626struct device; /* we have a circular dep with device.h */2727#ifdef CONFIG_VT_CONSOLE_SLEEP2828-extern void pm_vt_switch_required(struct device *dev, bool required);2828+extern int pm_vt_switch_required(struct device *dev, bool required);2929extern void pm_vt_switch_unregister(struct device *dev);3030#else3131-static inline void pm_vt_switch_required(struct device *dev, bool required)3131+static inline int pm_vt_switch_required(struct device *dev, bool required)3232{3333+ return 0;3334}3435static inline void pm_vt_switch_unregister(struct device *dev)3536{···508507 * RECOVER Creation of a hibernation image or restoration of the main509508 * memory contents from a hibernation image has failed, call510509 * ->thaw() and ->complete() for all devices.510510+ * POWEROFF System will poweroff, call ->poweroff() for all devices.511511 *512512 * The following PM_EVENT_ messages are defined for internal use by513513 * kernel subsystems. They are never issued by the PM core.···539537#define PM_EVENT_USER 0x0100540538#define PM_EVENT_REMOTE 0x0200541539#define PM_EVENT_AUTO 0x0400540540+#define PM_EVENT_POWEROFF 0x0800542541543542#define PM_EVENT_SLEEP (PM_EVENT_SUSPEND | PM_EVENT_HIBERNATE)544543#define PM_EVENT_USER_SUSPEND (PM_EVENT_USER | PM_EVENT_SUSPEND)···554551#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, })555552#define PMSG_SUSPEND ((struct pm_message){ .event = PM_EVENT_SUSPEND, })556553#define PMSG_HIBERNATE ((struct pm_message){ .event = PM_EVENT_HIBERNATE, })554554+#define PMSG_POWEROFF ((struct pm_message){ .event = PM_EVENT_POWEROFF, })557555#define PMSG_RESUME ((struct pm_message){ .event = PM_EVENT_RESUME, })558556#define PMSG_THAW ((struct pm_message){ .event = PM_EVENT_THAW, })559557#define PMSG_RESTORE ((struct pm_message){ .event = PM_EVENT_RESTORE, })
···344344static int suspend_test(int level)345345{346346#ifdef CONFIG_PM_DEBUG347347+ int i;348348+347349 if (pm_test_level == level) {348350 pr_info("suspend debug: Waiting for %d second(s).\n",349351 pm_test_delay);350350- mdelay(pm_test_delay * 1000);352352+ for (i = 0; i < pm_test_delay && !pm_wakeup_pending(); i++)353353+ msleep(1000);354354+351355 return 1;352356 }353357#endif /* !CONFIG_PM_DEBUG */
+115-64
kernel/power/swap.c
···336336 */337337unsigned int swsusp_header_flags;338338339339-/**340340- * swsusp_swap_check - check if the resume device is a swap device341341- * and get its index (if so)342342- *343343- * This is called before saving image344344- */345339static int swsusp_swap_check(void)346340{347341 int res;348342343343+ /*344344+ * Check if the resume device is a swap device and get its index (if so).345345+ * This is called before saving the image.346346+ */349347 if (swsusp_resume_device)350348 res = swap_type_of(swsusp_resume_device, swsusp_resume_block);351349 else···359361360362 return 0;361363}362362-363363-/**364364- * write_page - Write one page to given swap location.365365- * @buf: Address we're writing.366366- * @offset: Offset of the swap page we're writing to.367367- * @hb: bio completion batch368368- */369364370365static int write_page(void *buf, sector_t offset, struct hib_bio_batch *hb)371366{···510519 CMP_HEADER, PAGE_SIZE)511520#define CMP_SIZE (CMP_PAGES * PAGE_SIZE)512521513513-/* Maximum number of threads for compression/decompression. */514514-#define CMP_THREADS 3522522+/* Default number of threads for compression/decompression. */523523+#define CMP_THREADS 3524524+static unsigned int hibernate_compression_threads = CMP_THREADS;515525516526/* Minimum/maximum number of pages for read buffering. */517527#define CMP_MIN_RD_PAGES 1024518528#define CMP_MAX_RD_PAGES 8192519519-520520-/**521521- * save_image - save the suspend image data522522- */523529524530static int save_image(struct swap_map_handle *handle,525531 struct snapshot_handle *snapshot,···573585 wait_queue_head_t go; /* start crc update */574586 wait_queue_head_t done; /* crc update done */575587 u32 *crc32; /* points to handle's crc32 */576576- size_t *unc_len[CMP_THREADS]; /* uncompressed lengths */577577- unsigned char *unc[CMP_THREADS]; /* uncompressed data */588588+ size_t **unc_len; /* uncompressed lengths */589589+ unsigned char **unc; /* uncompressed data */578590};591591+592592+static struct crc_data *alloc_crc_data(int nr_threads)593593+{594594+ struct crc_data *crc;595595+596596+ crc = kzalloc(sizeof(*crc), GFP_KERNEL);597597+ if (!crc)598598+ return NULL;599599+600600+ crc->unc = kcalloc(nr_threads, sizeof(*crc->unc), GFP_KERNEL);601601+ if (!crc->unc)602602+ goto err_free_crc;603603+604604+ crc->unc_len = kcalloc(nr_threads, sizeof(*crc->unc_len), GFP_KERNEL);605605+ if (!crc->unc_len)606606+ goto err_free_unc;607607+608608+ return crc;609609+610610+err_free_unc:611611+ kfree(crc->unc);612612+err_free_crc:613613+ kfree(crc);614614+ return NULL;615615+}616616+617617+static void free_crc_data(struct crc_data *crc)618618+{619619+ if (!crc)620620+ return;621621+622622+ if (crc->thr)623623+ kthread_stop(crc->thr);624624+625625+ kfree(crc->unc_len);626626+ kfree(crc->unc);627627+ kfree(crc);628628+}579629580630/*581631 * CRC32 update function that runs in its own thread.···697671 return 0;698672}699673700700-/**701701- * save_compressed_image - Save the suspend image data after compression.702702- * @handle: Swap map handle to use for saving the image.703703- * @snapshot: Image to read data from.704704- * @nr_to_write: Number of pages to save.705705- */706674static int save_compressed_image(struct swap_map_handle *handle,707675 struct snapshot_handle *snapshot,708676 unsigned int nr_to_write)···723703 * footprint.724704 */725705 nr_threads = num_online_cpus() - 1;726726- nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);706706+ nr_threads = clamp_val(nr_threads, 1, hibernate_compression_threads);727707728708 page = (void *)__get_free_page(GFP_NOIO | __GFP_HIGH);729709 if (!page) {···739719 goto out_clean;740720 }741721742742- crc = kzalloc(sizeof(*crc), GFP_KERNEL);722722+ crc = alloc_crc_data(nr_threads);743723 if (!crc) {744724 pr_err("Failed to allocate crc\n");745725 ret = -ENOMEM;···908888909889out_clean:910890 hib_finish_batch(&hb);911911- if (crc) {912912- if (crc->thr)913913- kthread_stop(crc->thr);914914- kfree(crc);915915- }891891+ free_crc_data(crc);916892 if (data) {917893 for (thr = 0; thr < nr_threads; thr++) {918894 if (data[thr].thr)···923907924908 return ret;925909}926926-927927-/**928928- * enough_swap - Make sure we have enough swap to save the image.929929- *930930- * Returns TRUE or FALSE after checking the total amount of swap931931- * space available from the resume partition.932932- */933910934911static int enough_swap(unsigned int nr_pages)935912{···943934 * them synced (in case something goes wrong) but we DO not want to mark944935 * filesystem clean: it is not. (And it does not matter, if we resume945936 * correctly, we'll mark system clean, anyway.)937937+ *938938+ * Return: 0 on success, negative error code on failure.946939 */947947-948940int swsusp_write(unsigned int flags)949941{950942 struct swap_map_handle handle;···10911081 return 0;10921082}1093108310941094-/**10951095- * load_image - load the image using the swap map handle10961096- * @handle and the snapshot handle @snapshot10971097- * (assume there are @nr_pages pages to load)10981098- */10991099-11001084static int load_image(struct swap_map_handle *handle,11011085 struct snapshot_handle *snapshot,11021086 unsigned int nr_to_read)···11981194 return 0;11991195}1200119612011201-/**12021202- * load_compressed_image - Load compressed image data and decompress it.12031203- * @handle: Swap map handle to use for loading data.12041204- * @snapshot: Image to copy uncompressed data into.12051205- * @nr_to_read: Number of pages to load.12061206- */12071197static int load_compressed_image(struct swap_map_handle *handle,12081198 struct snapshot_handle *snapshot,12091199 unsigned int nr_to_read)···12251227 * footprint.12261228 */12271229 nr_threads = num_online_cpus() - 1;12281228- nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);12301230+ nr_threads = clamp_val(nr_threads, 1, hibernate_compression_threads);1229123112301232 page = vmalloc_array(CMP_MAX_RD_PAGES, sizeof(*page));12311233 if (!page) {···12411243 goto out_clean;12421244 }1243124512441244- crc = kzalloc(sizeof(*crc), GFP_KERNEL);12461246+ crc = alloc_crc_data(nr_threads);12451247 if (!crc) {12461248 pr_err("Failed to allocate crc\n");12471249 ret = -ENOMEM;···15081510 hib_finish_batch(&hb);15091511 for (i = 0; i < ring_size; i++)15101512 free_page((unsigned long)page[i]);15111511- if (crc) {15121512- if (crc->thr)15131513- kthread_stop(crc->thr);15141514- kfree(crc);15151515- }15131513+ free_crc_data(crc);15161514 if (data) {15171515 for (thr = 0; thr < nr_threads; thr++) {15181516 if (data[thr].thr)···15271533 * swsusp_read - read the hibernation image.15281534 * @flags_p: flags passed by the "frozen" kernel in the image header should15291535 * be written into this memory location15361536+ *15371537+ * Return: 0 on success, negative error code on failure.15301538 */15311531-15321539int swsusp_read(unsigned int *flags_p)15331540{15341541 int error;···15661571/**15671572 * swsusp_check - Open the resume device and check for the swsusp signature.15681573 * @exclusive: Open the resume device exclusively.15741574+ *15751575+ * Return: 0 if a valid image is found, negative error code otherwise.15691576 */15701570-15711577int swsusp_check(bool exclusive)15721578{15731579 void *holder = exclusive ? &swsusp_holder : NULL;···1631163516321636/**16331637 * swsusp_unmark - Unmark swsusp signature in the resume device16381638+ *16391639+ * Return: 0 on success, negative error code on failure.16341640 */16351635-16361641#ifdef CONFIG_SUSPEND16371642int swsusp_unmark(void)16381643{···16591662}16601663#endif1661166416651665+static ssize_t hibernate_compression_threads_show(struct kobject *kobj,16661666+ struct kobj_attribute *attr, char *buf)16671667+{16681668+ return sysfs_emit(buf, "%d\n", hibernate_compression_threads);16691669+}16701670+16711671+static ssize_t hibernate_compression_threads_store(struct kobject *kobj,16721672+ struct kobj_attribute *attr,16731673+ const char *buf, size_t n)16741674+{16751675+ unsigned long val;16761676+16771677+ if (kstrtoul(buf, 0, &val))16781678+ return -EINVAL;16791679+16801680+ if (val < 1)16811681+ return -EINVAL;16821682+16831683+ hibernate_compression_threads = val;16841684+ return n;16851685+}16861686+power_attr(hibernate_compression_threads);16871687+16881688+static struct attribute *g[] = {16891689+ &hibernate_compression_threads_attr.attr,16901690+ NULL,16911691+};16921692+16931693+static const struct attribute_group attr_group = {16941694+ .attrs = g,16951695+};16961696+16621697static int __init swsusp_header_init(void)16631698{16991699+ int error;17001700+17011701+ error = sysfs_create_group(power_kobj, &attr_group);17021702+ if (error)17031703+ return -ENOMEM;17041704+16641705 swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);16651706 if (!swsusp_header)16661707 panic("Could not allocate memory for swsusp_header\n");···17061671}1707167217081673core_initcall(swsusp_header_init);16741674+16751675+static int __init hibernate_compression_threads_setup(char *str)16761676+{16771677+ int rc = kstrtouint(str, 0, &hibernate_compression_threads);16781678+16791679+ if (rc)16801680+ return rc;16811681+16821682+ if (hibernate_compression_threads < 1)16831683+ hibernate_compression_threads = CMP_THREADS;16841684+16851685+ return 1;16861686+16871687+}16881688+16891689+__setup("hibernate_compression_threads=", hibernate_compression_threads_setup);