Rafael: This patch adds the icebox, for use by kernel threads that want to freeze themselves without using the freezer -- which is likely to crop up when the freezer gets eliminated. It's straightforward enough. It could be used as-is, for example for freezing workqueue threads. Using it for other sorts of kernel threads seems to be rather difficult, requiring a fair amount of extra code that's hard to centralize since each thread will have to be woken up its own way. Do you have any particular suggestions? Alan Stern Index: usb-2.6/include/linux/freezer.h =================================================================== --- usb-2.6.orig/include/linux/freezer.h +++ usb-2.6/include/linux/freezer.h @@ -157,6 +157,12 @@ static inline void set_freezable(void) } while (try_to_freeze()); \ __retval; \ }) + +/* + * Kernel threads that want to freeze themselves go into the icebox. + */ +extern void icebox(void); + #else /* !CONFIG_PM_SLEEP */ static inline int frozen(struct task_struct *p) { return 0; } static inline int freezing(struct task_struct *p) { return 0; } @@ -181,6 +187,7 @@ static inline void set_freezable(void) { #define wait_event_freezable_timeout(wq, condition, timeout) \ wait_event_interruptible_timeout(wq, condition, timeout) +static inline void icebox(void) {} #endif /* !CONFIG_PM_SLEEP */ #endif /* FREEZER_H_INCLUDED */ Index: usb-2.6/kernel/power/power.h =================================================================== --- usb-2.6.orig/kernel/power/power.h +++ usb-2.6/kernel/power/power.h @@ -205,3 +205,8 @@ static inline int suspend_devices_and_en /* kernel/power/process.c */ extern int pm_notifier_call_chain(unsigned long val); + +#ifdef CONFIG_PM_SLEEP +extern void start_icebox(void); +extern void stop_icebox(void); +#endif Index: usb-2.6/kernel/power/main.c =================================================================== --- usb-2.6.orig/kernel/power/main.c +++ usb-2.6/kernel/power/main.c @@ -71,6 +71,8 @@ static int suspend_prepare(void) if (!suspend_ops || !suspend_ops->enter) return -EPERM; + start_icebox(); + error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); if (error) goto Finish; @@ -98,6 +100,7 @@ static int suspend_prepare(void) thaw_processes(); pm_restore_console(); Finish: + stop_icebox(); pm_notifier_call_chain(PM_POST_SUSPEND); return error; } @@ -191,6 +194,7 @@ static void suspend_finish(void) { thaw_processes(); pm_restore_console(); + stop_icebox(); pm_notifier_call_chain(PM_POST_SUSPEND); } Index: usb-2.6/kernel/power/disk.c =================================================================== --- usb-2.6.orig/kernel/power/disk.c +++ usb-2.6/kernel/power/disk.c @@ -389,6 +389,8 @@ int hibernate(void) goto Unlock; } + start_icebox(); + error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); if (error) goto Exit; @@ -431,6 +433,7 @@ int hibernate(void) Finish: free_basic_memory_bitmaps(); Exit: + stop_icebox(); pm_notifier_call_chain(PM_POST_HIBERNATION); atomic_inc(&snapshot_device_available); Unlock: @@ -489,6 +492,8 @@ static int software_resume(void) goto Unlock; } + start_icebox(); + error = pm_notifier_call_chain(PM_RESTORE_PREPARE); if (error) goto Finish; @@ -516,6 +521,7 @@ static int software_resume(void) Done: free_basic_memory_bitmaps(); Finish: + stop_icebox(); pm_notifier_call_chain(PM_POST_RESTORE); atomic_inc(&snapshot_device_available); /* For success case, the suspend path will release the lock */ Index: usb-2.6/kernel/power/user.c =================================================================== --- usb-2.6.orig/kernel/power/user.c +++ usb-2.6/kernel/power/user.c @@ -45,6 +45,7 @@ static int snapshot_open(struct inode *i { struct snapshot_data *data; int error; + unsigned long cancel; if (!atomic_add_unless(&snapshot_device_available, -1, 0)) return -EBUSY; @@ -61,21 +62,22 @@ static int snapshot_open(struct inode *i data = &snapshot_state; filp->private_data = data; memset(&data->handle, 0, sizeof(struct snapshot_handle)); + start_icebox(); if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { data->swap = swsusp_resume_device ? swap_type_of(swsusp_resume_device, 0, NULL) : -1; data->mode = O_RDONLY; error = pm_notifier_call_chain(PM_RESTORE_PREPARE); - if (error) - pm_notifier_call_chain(PM_POST_RESTORE); + cancel = PM_POST_RESTORE; } else { data->swap = -1; data->mode = O_WRONLY; error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); - if (error) - pm_notifier_call_chain(PM_POST_HIBERNATION); + cancel = PM_POST_HIBERNATION; } if (error) { + stop_icebox(); + pm_notifier_call_chain(cancel); atomic_inc(&snapshot_device_available); return error; } @@ -99,6 +101,7 @@ static int snapshot_release(struct inode thaw_processes(); mutex_unlock(&pm_mutex); } + stop_icebox(); pm_notifier_call_chain(data->mode == O_WRONLY ? PM_POST_HIBERNATION : PM_POST_RESTORE); atomic_inc(&snapshot_device_available); Index: usb-2.6/kernel/power/process.c =================================================================== --- usb-2.6.orig/kernel/power/process.c +++ usb-2.6/kernel/power/process.c @@ -14,6 +14,8 @@ #include <linux/syscalls.h> #include <linux/freezer.h> +#include "power.h" + /* * Timeout for stopping processes */ @@ -305,3 +307,49 @@ int pm_notifier_call_chain(unsigned long return (blocking_notifier_call_chain(&pm_chain_head, val, NULL) == NOTIFY_BAD) ? -EINVAL : 0; } + +/* + * Routines for kernel threads that want to freeze themselves + */ +static DECLARE_WAIT_QUEUE_HEAD(icebox_wait_queue_head); +static int icebox_active; + +/** + * start_icebox -- activate the icebox + * + * Kernel power code should call this routine before sending the + * PM_HIBERNATION_PREPARE or PM_SUSPEND_PREPARE notifications. + */ +void start_icebox(void) +{ + icebox_active = 1; +} + +/** + * stop_icebox -- deactivate the icebox and awaken waiting threads + * + * Kernel power code should call this routine before sending the + * PM_POST_HIBERNATION or PM_POST_SUSPEND notifications. + */ +void stop_icebox(void) +{ + icebox_active = 0; + wake_up_all(&icebox_wait_queue_head); +} + +/** + * icebox -- place for kernel threads to wait during suspend or hibernation + * + * Threads can call this routine at any time. It will return immediately + * unless a system suspend or hibernation has started and the icebox is + * active, in which case it won't return until the suspend/hibernation + * is over. + * + * Freezable kernel threads should use this routine rather than relying on + * the freezer. + */ +void icebox(void) +{ + wait_event(icebox_wait_queue_head, !icebox_active); +} +EXPORT_SYMBOL_GPL(icebox); _______________________________________________ linux-pm mailing list linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/linux-pm