@@ -591,4 +591,12 @@ enum suspend_stat_step {
void dpm_save_failed_dev(const char *name);
void dpm_save_failed_step(enum suspend_stat_step step);
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+extern bool pm_block_user_fork;
+bool pm_should_block_fork(void);
+bool pm_freeze_process_in_progress(void);
+#else
+static inline bool pm_should_block_fork(void) { return false; };
+static inline bool pm_freeze_process_in_progress(void) { return false; };
+#endif /* CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE */
#endif /* _LINUX_SUSPEND_H */
@@ -105,6 +105,7 @@
#include <uapi/linux/pidfd.h>
#include <linux/pidfs.h>
#include <linux/tick.h>
+#include <linux/suspend.h>
#include <asm/pgalloc.h>
#include <linux/uaccess.h>
@@ -2596,6 +2597,11 @@ pid_t kernel_clone(struct kernel_clone_args *args)
trace = 0;
}
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+ if (pm_should_block_fork() && !(current->flags & PF_KTHREAD))
+ return -EBUSY;
+#endif
+
p = copy_process(NULL, trace, NUMA_NO_NODE, args);
add_latent_entropy();
@@ -375,6 +375,16 @@ config PM_GENERIC_DOMAINS_OF
def_bool y
depends on PM_GENERIC_DOMAINS && OF
+config PM_DISABLE_USER_FORK_DURING_FREEZE
+ bool "Disable user fork during process freeze"
+ depends on PM
+ default n
+ help
+ If enabled, user space processes will be forbidden from creating
+ new tasks (via fork/clone) during the process freezing stage of
+ system suspend/hibernate.
+ This can avoid process list races and reduce retries during suspend.
+
config CPU_PM
bool
@@ -994,6 +994,47 @@ static ssize_t freeze_filesystems_store(struct kobject *kobj,
power_attr(freeze_filesystems);
#endif /* CONFIG_SUSPEND || CONFIG_HIBERNATION */
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+bool strict_fork_enabled;
+bool pm_block_user_fork;
+
+bool pm_freeze_process_in_progress(void)
+{
+ return pm_block_user_fork;
+}
+
+bool pm_should_block_fork(void)
+{
+ return strict_fork_enabled && pm_freeze_process_in_progress();
+}
+EXPORT_SYMBOL_GPL(pm_should_block_fork);
+
+static ssize_t strict_fork_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", strict_fork_enabled);
+}
+
+static ssize_t strict_fork_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > 1)
+ return -EINVAL;
+
+ strict_fork_enabled = !!val;
+ return n;
+}
+
+power_attr(strict_fork);
+
+#endif /* CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE */
+
static struct attribute * g[] = {
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
@@ -1026,6 +1067,9 @@ static struct attribute * g[] = {
#endif
#if defined(CONFIG_SUSPEND) || defined(CONFIG_HIBERNATION)
&freeze_filesystems_attr.attr,
+#endif
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+ &strict_fork_attr.attr,
#endif
NULL,
};
@@ -22,6 +22,10 @@ struct swsusp_info {
extern bool filesystem_freeze_enabled;
#endif
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+extern bool strict_fork_enabled;
+#endif
+
#ifdef CONFIG_HIBERNATION
/* kernel/power/snapshot.c */
extern void __init hibernate_reserved_size_init(void);
@@ -134,7 +134,14 @@ int freeze_processes(void)
pm_wakeup_clear(0);
pm_freezing = true;
+
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+ pm_block_user_fork = true;
+#endif
error = try_to_freeze_tasks(true);
+#ifdef CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE
+ pm_block_user_fork = false;
+#endif
if (!error)
__usermodehelper_set_disable_depth(UMH_DISABLED);
Currently, the freezer traverses all tasks to freeze them during system suspend or hibernation. If a user process forks during this window, the new child may escape freezing and require a second traversal or retry, adding non-trivial overhead. This patch introduces a CONFIG_PM_DISABLE_USER_FORK_DURING_FREEZE option. When enabled, it prevents user processes from creating new processes (via fork/clone) during the freezing period. This guarantees a stable task list and avoids re-traversing the process list due to late-created user tasks, thereby improving performance. The restriction is only active during the window when the system is freezing user tasks. Once all tasks are frozen, or if the system aborts the suspend/hibernate process, the restriction is lifted. No kernel threads are affected, and kernel_create_* functions remain unrestricted. Signed-off-by: Zihuan Zhang <zhangzihuan@kylinos.cn> --- include/linux/suspend.h | 8 ++++++++ kernel/fork.c | 6 ++++++ kernel/power/Kconfig | 10 ++++++++++ kernel/power/main.c | 44 +++++++++++++++++++++++++++++++++++++++++ kernel/power/power.h | 4 ++++ kernel/power/process.c | 7 +++++++ 6 files changed, 79 insertions(+)