Suspend notifiers
Subsystems (2)
cover Suspend notifiers
Hi,
The following two patches are intended to address the problem that some drivers allocate a lot of memory in their .suspend() routines causing swsusp to fail (and generally may want to do some things that shouldn't be done in .suspend()/.resume()).
Greetings,
Rafael
Signature · 3 lines
If you don't have the time to read, you don't have the time or the tools to write. - Stephen King
RFC PATCH 1/2 swsusp: Free more memory
From: Rafael J. Wysocki <[email protected]>
Move the definition of PAGES_FOR_IO to kernel/power/power.h and introduce SPARE_PAGES representing the number of pages that should be freed by the swsusp's memory shrinker in addition to PAGES_FOR_IO so that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.
--- include/linux/suspend.h | 6 ------ kernel/power/power.h | 12 +++++++++++- kernel/power/swsusp.c | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-)
include/linux/suspend.h +0 -6
@@ -60,10 +60,4 @@ struct saved_context;void __save_processor_state (struct saved_context *ctxt);void __restore_processor_state (struct saved_context *ctxt); -/* -* XXX: We try to keep some more pages free so that I/O operations succeed -* without paging. Might this be more? -*/ -#define PAGES_FOR_IO 1024 -#endif /* _LINUX_SWSUSP_H */
kernel/power/power.h +11 -1
@@ -14,8 +14,18 @@ struct swsusp_info {#ifdef CONFIG_SOFTWARE_SUSPEND -extern int pm_suspend_disk (void ); +/* +* Keep some memory free so that I/O operations can succeed without paging +* [Might this be more than 4 MB?] +*/ +#define PAGES_FOR_IO ((4096 * 1024) >> PAGE_SHIFT) +/* +* Keep 1 MB of memory free so that device drivers can allocate some pages in +* their .suspend() routines without breaking the suspend to disk. +*/ +#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) +extern int pm_suspend_disk (void );#else static inline int pm_suspend_disk (void ) {
kernel/power/swsusp.c +1 -1
@@ -233,7 +233,7 @@ int swsusp_shrink_memory(void)long size, highmem_size; highmem_size =count_highmem_pages (); - size =count_data_pages () +PAGES_FOR_IO ; + size =count_data_pages () +PAGES_FOR_IO +SPARE_PAGES ; tmp = size; size += highmem_size;for_each_zone (zone)
Re: [RFC][PATCH -mm 1/2] swsusp: Free more memory
Hi.
Quoted 7 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Move the definition of
PAGES_FOR_IOtokernel/power/power.hand introduceSPARE_PAGESrepresenting the number of pages that should be freed by the swsusp's memory shrinker in addition toPAGES_FOR_IOso that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.
1MB is not going to be enough for people with DRI. I have a cycle on my machine recording 3510 extra pages (13 meg) allocated during the atomic copy, and I know there are others with larger numbers.
Nigel
Re: [RFC][PATCH -mm 1/2] swsusp: Free more memory
Quoted 11 lines · Nigel Cunningham
Hi.
Quoted 7 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Move the definition of
PAGES_FOR_IOtokernel/power/power.hand introduceSPARE_PAGESrepresenting the number of pages that should be freed by the swsusp's memory shrinker in addition toPAGES_FOR_IOso that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.
Quoted 3 lines
1MB is not going to be enough for people with DRI. I have a cycle on my machine recording 3510 extra pages (13 meg) allocated during the atomic copy, and I know there are others with larger numbers.
I know. The other mechanism (ie. notifiers) is for them.
The idea of this patch is to make it possible to _avoid_ using the notifiers if you need only a limited amount of memory.
Greetings,
Rafael
Re: [RFC][PATCH -mm 1/2] swsusp: Free more memory
Hi.
Quoted 12 lines · Rafael J. Wysocki
Quoted 11 lines · Nigel Cunningham
Hi.
Quoted 7 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Move the definition of
PAGES_FOR_IOtokernel/power/power.hand introduceSPARE_PAGESrepresenting the number of pages that should be freed by the swsusp's memory shrinker in addition toPAGES_FOR_IOso that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.
Quoted 8 lines
Quoted 3 lines
1MB is not going to be enough for people with DRI. I have a cycle on my machine recording 3510 extra pages (13 meg) allocated during the atomic copy, and I know there are others with larger numbers.
I know. The other mechanism (ie. notifiers) is for them.
The idea of this patch is to make it possible to _avoid_ using the notifiers if you need only a limited amount of memory.
That's fine when the notifiers are actually used, but for the moment....
Regards,
Nigel
Re: [RFC][PATCH -mm 1/2] swsusp: Free more memory
Quoted 19 lines · Nigel Cunningham
Hi.
Quoted 16 lines · Rafael J. Wysocki
Quoted 14 lines · Nigel Cunningham
Hi.
Quoted 7 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Move the definition of
PAGES_FOR_IOtokernel/power/power.hand introduceSPARE_PAGESrepresenting the number of pages that should be freed by the swsusp's memory shrinker in addition toPAGES_FOR_IOso that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.1MB is not going to be enough for people with DRI. I have a cycle on my machine recording 3510 extra pages (13 meg) allocated during the atomic copy, and I know there are others with larger numbers.
Quoted 6 lines
Quoted 4 lines
I know. The other mechanism (ie. notifiers) is for them.
The idea of this patch is to make it possible to _avoid_ using the notifiers if you need only a limited amount of memory.
That's fine when the notifiers are actually used, but for the moment....
I know, but if I make SPARE_PAGES large enough for everyone, then no one will have any reason to use the notifiers. :-)
Greetings,
Rafael
Re: [RFC][PATCH -mm 1/2] swsusp: Free more memory
In reply to Rafael J. WysockiHi!
Quoted 7 lines
Move the definition of
PAGES_FOR_IOtokernel/power/power.hand introduceSPARE_PAGESrepresenting the number of pages that should be freed by the swsusp's memory shrinker in addition toPAGES_FOR_IOso that device drivers can allocate some memory (up to 1 MB total) in their .suspend() routines without causing the suspend to fail.Signed-off-by Rafael J. Wysocki <[email protected]>
ACK.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
RFC PATCH 2/2 PM: Introduce suspend notifiers
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Make it possible to register suspend notifiers so that subsystems can perform suspend-related operations which should not be carried out by device drivers' .suspend() and .resume() routines.
--- Documentation/power/suspend-notifiers.txt | 41 ++++++++++++++++++++++++ include/linux/notifier.h | 6 +++ include/linux/suspend.h | 27 +++++++++++++-- kernel/power/Makefile | 2 - kernel/power/disk.c | 21 ++++++++++++ kernel/power/main.c | 13 +++++++ kernel/power/notify.c | 51 ++++++++++++++++++++++++++++++ kernel/power/power.h | 3 + kernel/power/user.c | 19 +++++++++++ 9 files changed, 178 insertions(+), 5 deletions(-)
kernel/power/notify.c new file +51 -0
@@ -0,0 +1,51 @@ +/* +* linux/kernel/power/notify.c +* +* This file contains functions used for registering and calling suspend +* notifiers that can be used by subsystems for carrying out some special +* suspend-related operations. +* +* Copyright (C) 2007 Rafael J. Wysocki <[email protected]> +* +* This file is released under the GPLv2. +* +*/ + +#include <linux/smp.h> +#include <linux/notifier.h> +#include <linux/module.h> +#include <linux/suspend.h> + +static DEFINE_MUTEX (suspend_notifier_lock); + +static RAW_NOTIFIER_HEAD (suspend_chain); + +int register_suspend_notifier (struct notifier_block *nb) +{ +int ret; +mutex_lock (&suspend_notifier_lock); + ret =raw_notifier_chain_register (&suspend_chain, nb); +mutex_unlock (&suspend_notifier_lock); +return ret; +} +EXPORT_SYMBOL (register_suspend_notifier); + +void unregister_suspend_notifier (struct notifier_block *nb) +{ +mutex_lock (&suspend_notifier_lock); +raw_notifier_chain_unregister (&suspend_chain, nb); +mutex_unlock (&suspend_notifier_lock); +} +EXPORT_SYMBOL (unregister_suspend_notifier); + +int suspend_notifier_call_chain (unsigned long val) +{ +int error =0 ; + +mutex_lock (&suspend_notifier_lock); +if (raw_notifier_call_chain (&suspend_chain, val,NULL ) ==NOTIFY_BAD ) + error = -EINVAL ; + +mutex_unlock (&suspend_notifier_lock); +return error; +}
include/linux/suspend.h +23 -4
@@ -24,15 +24,16 @@ struct pbe {extern void drain_local_pages (void );extern void mark_free_pages (struct zone *zone); -#if defined(CONFIG_PM ) && defined(CONFIG_VT ) && defined(CONFIG_VT_CONSOLE ) +#ifdef CONFIG_PM +#if defined(CONFIG_VT ) && defined(CONFIG_VT_CONSOLE )extern int pm_prepare_console (void );extern void pm_restore_console (void );#else static inline int pm_prepare_console (void ) {return 0 ; }static inline void pm_restore_console (void ) {} -#endif +#endif /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */ -#if defined(CONFIG_PM ) && defined(CONFIG_SOFTWARE_SUSPEND ) +#ifdef CONFIG_SOFTWARE_SUSPEND /* kernel/power/swsusp.c */ extern int software_suspend (void );/* kernel/power/snapshot.c */
@@ -52,7 +53,7 @@ static inline void register_nosave_regiostatic inline int swsusp_page_is_forbidden (struct page *p) {return 0 ; }static inline void swsusp_set_page_free (struct page *p) {}static inline void swsusp_unset_page_free (struct page *p) {} -#endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */ +#endif /* CONFIG_SOFTWARE_SUSPEND */ void save_processor_state (void );void restore_processor_state (void );
@@ -60,4 +61,22 @@ struct saved_context;void __save_processor_state (struct saved_context *ctxt);void __restore_processor_state (struct saved_context *ctxt); +int register_suspend_notifier (struct notifier_block *nb); +void unregister_suspend_notifier (struct notifier_block *nb); + +#define suspend_notifier (fn, pri) { \ + static struct notifier_block fn##_nb = \ + { .notifier_call = fn, .priority = pri }; \ + register_suspend_notifier(&fn##_nb); \ +} +#else /* CONFIG_PM */ +static inline int register_suspend_notifier (struct notifier_block *nb) { +return 0 ; +} +static inline void unregister_suspend_notifier (struct notifier_block *nb) { +} + +#define suspend_notifier (fn, pri) do { (void)(fn); } while (0) +#endif +#endif /* _LINUX_SWSUSP_H */
kernel/power/Makefile +1 -1
@@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif -obj-y := main.o process.o console.o +obj-y := main.o process.o console.o notify.o obj-$(CONFIG_PM_LEGACY) += pm.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o swap.o user.o
kernel/power/power.h +3 -0
@@ -170,3 +170,6 @@ extern int suspend_enter(suspend_state_tstruct timeval ;extern void swsusp_show_speed (struct timeval *,struct timeval *,unsigned int ,char *); + +/* kernel/power/notify.c */ +extern int suspend_notifier_call_chain (unsigned long val);
include/linux/notifier.h +6 -0
@@ -197,5 +197,11 @@ extern int __srcu_notifier_call_chain(st#define CPU_LOCK_ACQUIRE 0x0008/* Acquire all hotcpu locks */ #define CPU_LOCK_RELEASE 0x0009/* Release all hotcpu locks */ +#define SUSPEND_PREPARE 0x0002/* Going to freeze tasks */ +#define SUSPEND_ENTER_PREPARE 0x0003/* Tasks are frozen, we are suspending */ +#define SUSPEND_THAW_PREPARE 0x0004/* Going to thaw frozen tasks */ +#define SUSPEND_FINISHED 0x0005/* Tasks have been thawed */ +#define SUSPEND_RESTORE_PREPARE 0x0006/* STD restore is going to happen */ +#endif /* __KERNEL__ */ #endif /* _LINUX_NOTIFIER_H */
kernel/power/disk.c +21 -0
@@ -114,6 +114,7 @@ static int prepare_processes(void)pm_prepare_console ();if (freeze_processes ()) { error = -EBUSY ; +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );unprepare_processes (); }return error;
@@ -139,6 +140,10 @@ int pm_suspend_disk(void)if (error) goto Exit; + error =suspend_notifier_call_chain (SUSPEND_PREPARE ); +if (error) + goto Finish; + error =prepare_processes ();if (error) goto Finish;
@@ -149,6 +154,10 @@ int pm_suspend_disk(void) goto Thaw; } + error =suspend_notifier_call_chain (SUSPEND_ENTER_PREPARE ); +if (error) + goto Thaw; +/* Free memory before shutting down devices. */ error =swsusp_shrink_memory ();if (error)
@@ -205,8 +214,10 @@ int pm_suspend_disk(void)device_resume ();resume_console (); Thaw: +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );unprepare_processes (); Finish: +suspend_notifier_call_chain (SUSPEND_FINISHED );free_basic_memory_bitmaps (); Exit:atomic_inc (&snapshot_device_available);
@@ -267,6 +278,10 @@ static int software_resume(void)if (error) goto Finish; + error =suspend_notifier_call_chain (SUSPEND_PREPARE ); +if (error) + goto Done; +pr_debug ("PM: Preparing processes for restore.\n" ); error =prepare_processes ();if (error) {
@@ -282,6 +297,10 @@ static int software_resume(void) goto Thaw; } + error =suspend_notifier_call_chain (SUSPEND_RESTORE_PREPARE ); +if (error) + goto Thaw; +pr_debug ("PM: Preparing devices for restore.\n" );suspend_console ();
@@ -300,8 +319,10 @@ static int software_resume(void)resume_console (); Thaw:printk (KERN_ERR "PM: Restore failed, recovering.\n" ); +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );unprepare_processes (); Done: +suspend_notifier_call_chain (SUSPEND_FINISHED );free_basic_memory_bitmaps (); Finish:atomic_inc (&snapshot_device_available);
kernel/power/main.c +13 -0
@@ -86,11 +86,19 @@ static int suspend_prepare(suspend_statepm_prepare_console (); + error =suspend_notifier_call_chain (SUSPEND_PREPARE ); +if (error) + goto Finish; +if (freeze_processes ()) { error = -EAGAIN ; goto Thaw; } + error =suspend_notifier_call_chain (SUSPEND_ENTER_PREPARE ); +if (error) + goto Thaw; +if ((free_pages =global_page_state (NR_FREE_PAGES )) <FREE_PAGE_NUMBER ) {pr_debug ("PM: free some memory\n" );
@@ -123,8 +131,11 @@ static int suspend_prepare(suspend_statedevice_resume ();resume_console (); Thaw: +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );thaw_processes (); + Finish:pm_restore_console (); +suspend_notifier_call_chain (SUSPEND_FINISHED );return error; }
@@ -162,8 +173,10 @@ static void suspend_finish(suspend_statepm_finish (state);device_resume ();resume_console (); +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );thaw_processes ();pm_restore_console (); +suspend_notifier_call_chain (SUSPEND_FINISHED ); }
kernel/power/user.c +19 -0
@@ -148,6 +148,10 @@ static inline int snapshot_suspend(int pint error;mutex_lock (&pm_mutex); + error =suspend_notifier_call_chain (SUSPEND_ENTER_PREPARE ); +if (error) + goto Finish; +/* Free memory before shutting down devices. */ error =swsusp_shrink_memory ();if (error)
@@ -186,6 +190,10 @@ static inline int snapshot_restore(int pmutex_lock (&pm_mutex);pm_prepare_console (); + error =suspend_notifier_call_chain (SUSPEND_RESTORE_PREPARE ); +if (error) + goto Finish; +if (platform_suspend) { error =platform_prepare ();if (error)
@@ -236,7 +244,12 @@ static int snapshot_ioctl(struct inode *if (data->frozen)break ;mutex_lock (&pm_mutex); + error =suspend_notifier_call_chain (SUSPEND_PREPARE ); +if (error) +break ; +if (freeze_processes ()) { +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );thaw_processes (); error = -EBUSY ; }
@@ -249,7 +262,9 @@ static int snapshot_ioctl(struct inode *if (!data->frozen)break ;mutex_lock (&pm_mutex); +suspend_notifier_call_chain (SUSPEND_THAW_PREPARE );thaw_processes (); +suspend_notifier_call_chain (SUSPEND_FINISHED );mutex_unlock (&pm_mutex); data->frozen =0 ;break ;
@@ -350,6 +365,10 @@ static int snapshot_ioctl(struct inode *break ; } + error =suspend_notifier_call_chain (SUSPEND_ENTER_PREPARE ); +if (error) +break ; +if (pm_ops->prepare) { error = pm_ops->prepare (PM_SUSPEND_MEM );if (error)
Documentation/power/suspend-notifiers.txt new file +41 -0
41 lines not on this page · raw message
Re: [RFC][PATCH -mm 2/2] PM: Introduce suspend notifiers
Hi!
Quoted 20 lines
Index:
linux-2.6.21-rc6-mm1/Documentation/power/suspend-notifiers.txt
===================================================================Documentation/power/suspend-notifiers.txt new file +15
-0@@ -0,0 +1,41 @@ +Suspend notifiers + (C) 2007 Rafael J. Wysocki <[email protected]>, GPL + +There are some operations that device drivers may want to carry out in their +.suspend() routines, but shouldn't, because they can cause a suspend to fail. +For example, a driver may want to allocate a substantial amount of memory +(like 50 MB) in .suspend(), but that shouldn't be done after the swsusp's memory +shrinker has run. Also, there may be some operations, that subsystems may want +to carry out before a suspend or after a resume, requiring the system to be +fully functional, so the drivers' .suspend() and .resume() routines are not +suitable for this purpose. + +The subsystems that have such needs can register suspend notifiers that will be +notified of the following events by the suspend core: +
Documentation/power/suspend-notifiers.txt line 25
Quoted 10 lines
Documentation/power/suspend-notifiers.txt new file +10
-0+SUSPEND_PREPARE the system is going to suspend, tasks will be frozen + immediately + +SUSPEND_ENTER_PREPARE tasks have been frozen, memory is going to be freed + and devices are going to be suspended + +SUSPEND_THAW_PREPARE devices have been resumed, tasks will be thawed + immediately + +SUSPEND_FINISHED the resume is complete, the system is fully functional
+ This hook is called even if suspend fails, so that we do not
+ leak memory.
?
Looks ok to me.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [RFC][PATCH -mm 2/2] PM: Introduce suspend notifiers
Hi,
Quoted 38 lines · Pavel Machek
Hi!
Quoted 20 lines
Index:
linux-2.6.21-rc6-mm1/Documentation/power/suspend-notifiers.txt
===================================================================Documentation/power/suspend-notifiers.txt new file +15
-0@@ -0,0 +1,41 @@ +Suspend notifiers + (C) 2007 Rafael J. Wysocki <[email protected]>, GPL + +There are some operations that device drivers may want to carry out in their +.suspend() routines, but shouldn't, because they can cause a suspend to fail. +For example, a driver may want to allocate a substantial amount of memory +(like 50 MB) in .suspend(), but that shouldn't be done after the swsusp's memory +shrinker has run. Also, there may be some operations, that subsystems may want +to carry out before a suspend or after a resume, requiring the system to be +fully functional, so the drivers' .suspend() and .resume() routines are not +suitable for this purpose. + +The subsystems that have such needs can register suspend notifiers that will be +notified of the following events by the suspend core: +Documentation/power/suspend-notifiers.txt line 25
Quoted 10 lines
Documentation/power/suspend-notifiers.txt new file +10
-0+SUSPEND_PREPARE the system is going to suspend, tasks will be frozen + immediately + +SUSPEND_ENTER_PREPARE tasks have been frozen, memory is going to be freed + and devices are going to be suspended + +SUSPEND_THAW_PREPARE devices have been resumed, tasks will be thawed + immediately + +SUSPEND_FINISHED the resume is complete, the system is fully functional+ This hook is called even if suspend fails, so that we do not
+ leak memory.
Quoted 1 line
?
Yes, I'll add something like this.