swsusp: Stop using page flags
Subsystems (5)
cover swsusp: Stop using page flags
Hi,
The following three patches make swsusp use its own data structures for memory management instead of special page flags. Thus the page flags used so far by swsusp (PG_nosave, PG_nosave_free) can be used for other purposes and I believe there are some urgend needs of them. :-)
Last week I sent these patches to the linux-pm and linux-mm lists and there were no negative comments. Also I've been testing them on my x86_64 boxes for a few days and apparently they don't break anything. I think they can go into -mm for testing.
Comments are welcome.
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/3 swsusp: Use inline functions for changing page flags
From: Rafael J. Wysocki <[email protected]>
Replace direct invocations of SetPageNosave(), SetPageNosaveFree() etc. with calls to inline functions that can be changed in subsequent patches without modifying the code calling them.
--- include/linux/suspend.h | 33 +++++++++++++++++++++++++++++++++ kernel/power/snapshot.c | 48 +++++++++++++++++++++++++----------------------- mm/page_alloc.c | 6 +++--- 3 files changed, 61 insertions(+), 26 deletions(-)
include/linux/suspend.h +33 -0
@@ -8,6 +8,7 @@#include <linux/notifier.h> #include <linux/init.h> #include <linux/pm.h> +#include <linux/mm.h> /* struct pbe is used for creating lists of pages that should be restored * atomically during the resume from disk, because the page frames they have
@@ -49,6 +50,38 @@ void __save_processor_state(struct savedvoid __restore_processor_state (struct saved_context *ctxt);unsigned long get_safe_page (gfp_t gfp_mask); +/* Page management functions for the software suspend (swsusp) */ + +static inline void swsusp_set_page_forbidden (struct page *page) +{ +SetPageNosave (page); +} + +static inline int swsusp_page_is_forbidden (struct page *page) +{ +return PageNosave (page); +} + +static inline void swsusp_unset_page_forbidden (struct page *page) +{ +ClearPageNosave (page); +} + +static inline void swsusp_set_page_free (struct page *page) +{ +SetPageNosaveFree (page); +} + +static inline int swsusp_page_is_free (struct page *page) +{ +return PageNosaveFree (page); +} + +static inline void swsusp_unset_page_free (struct page *page) +{ +ClearPageNosaveFree (page); +} +/* * XXX: We try to keep some more pages free so that I/O operations succeed * without paging. Might this be more?
kernel/power/snapshot.c +25 -23
136 lines not on this page · raw message
mm/page_alloc.c +3 -3
@@ -770,8 +770,8 @@ void mark_free_pages(struct zone *zone)if (pfn_valid (pfn)) {struct page *page =pfn_to_page (pfn); -if (!PageNosave (page)) -ClearPageNosaveFree (page); +if (!swsusp_page_is_forbidden (page)) +swsusp_unset_page_free (page); }for (order =MAX_ORDER -1 ; order >=0 ; --order)
@@ -780,7 +780,7 @@ void mark_free_pages(struct zone *zone) pfn = page_to_pfn(list_entry(curr, struct page, lru));for (i =0 ; i < (1UL << order); i++) -SetPageNosaveFree (pfn_to_page (pfn + i)); +swsusp_set_page_free (pfn_to_page (pfn + i)); }spin_unlock_irqrestore (&zone->lock, flags);
Re: [RFC][PATCH 1/3] swsusp: Use inline functions for changing page flags
Hi!
Quoted 5 lines
Replace direct invocations of
SetPageNosave(),SetPageNosaveFree()etc. with calls to inline functions that can be changed in subsequent patches without modifying the code calling them.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/3 swsusp: Do not use page flags
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Make swsusp use memory bitmaps instead of page flags for marking 'nosave' and free pages. This allows us to 'recycle' two page flags that can be used for other purposes. Also, the memory needed to store the bitmaps is allocated when necessary (ie. before the suspend) and freed after the resume which is more reasonable.
The patch is designed to minimize the amount of changes and there are some nice simplifications and optimizations possible on top of it. I am going to implement them separately in the future.
--- arch/x86_64/kernel/e820.c | 26 +--- include/linux/suspend.h | 58 +++------- kernel/power/disk.c | 23 +++- kernel/power/power.h | 2 kernel/power/snapshot.c | 250 +++++++++++++++++++++++++++++++++++++++++++--- kernel/power/user.c | 4 6 files changed, 281 insertions(+), 82 deletions(-)
include/linux/suspend.h +18 -40
@@ -24,63 +24,41 @@ struct pbe {extern void drain_local_pages (void );extern void mark_free_pages (struct zone *zone); -#ifdef CONFIG_PM -/* kernel/power/swsusp.c */ -extern int software_suspend (void ); - -#if defined(CONFIG_VT ) && defined(CONFIG_VT_CONSOLE ) +#if defined(CONFIG_PM ) && 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 /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */ +#endif + +#if defined(CONFIG_PM ) && defined(CONFIG_SOFTWARE_SUSPEND ) +/* kernel/power/swsusp.c */ +extern int software_suspend (void ); +/* kernel/power/snapshot.c */ +extern void __init register_nosave_region (unsigned long ,unsigned long ); +extern int swsusp_page_is_forbidden (struct page *); +extern void swsusp_set_page_free (struct page *); +extern void swsusp_unset_page_free (struct page *); +extern unsigned long get_safe_page (gfp_t gfp_mask);#else static inline int software_suspend (void ) {printk ("Warning: fake suspend called\n" );return -ENOSYS ; } -#endif /* CONFIG_PM */ + +static inline void register_nosave_region (unsigned long b,unsigned long e) {} +static 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) */ void save_processor_state (void );void restore_processor_state (void );struct saved_context ;void __save_processor_state (struct saved_context *ctxt);void __restore_processor_state (struct saved_context *ctxt); -unsigned long get_safe_page (gfp_t gfp_mask); - -/* Page management functions for the software suspend (swsusp) */ - -static inline void swsusp_set_page_forbidden (struct page *page) -{ -SetPageNosave (page); -} - -static inline int swsusp_page_is_forbidden (struct page *page) -{ -return PageNosave (page); -} - -static inline void swsusp_unset_page_forbidden (struct page *page) -{ -ClearPageNosave (page); -} - -static inline void swsusp_set_page_free (struct page *page) -{ -SetPageNosaveFree (page); -} - -static inline int swsusp_page_is_free (struct page *page) -{ -return PageNosaveFree (page); -} - -static inline void swsusp_unset_page_free (struct page *page) -{ -ClearPageNosaveFree (page); -}/* * XXX: We try to keep some more pages free so that I/O operations succeed
kernel/power/snapshot.c +234 -16
299 lines not on this page · raw message
arch/x86_64/kernel/e820.c +6 -20
@@ -17,6 +17,8 @@#include <linux/kexec.h> #include <linux/module.h> #include <linux/mm.h> +#include <linux/suspend.h> +#include <linux/pfn.h> #include <asm/pgtable.h> #include <asm/page.h>
@@ -255,22 +257,6 @@ void __init e820_reserve_resources(void) } } -/* Mark pages corresponding to given address range as nosave */ -static void __init -e820_mark_nosave_range (unsigned long start,unsigned long end) -{ -unsigned long pfn, max_pfn; - -if (start >= end) -return ; - -printk ("Nosave address range: %016lx - %016lx\n" , start, end); - max_pfn = end >>PAGE_SHIFT ; -for (pfn = start >>PAGE_SHIFT ; pfn < max_pfn; pfn++) -if (pfn_valid (pfn)) -SetPageNosave (pfn_to_page (pfn)); -} -/* * Find the ranges of physical addresses that do not correspond to * e820 RAM areas and mark the corresponding pages as nosave for software
@@ -289,13 +275,13 @@ void __init e820_mark_nosave_regions(voistruct e820entry *ei = &e820.map[i];if (paddr < ei->addr) -e820_mark_nosave_range (paddr, -round_up (ei->addr,PAGE_SIZE )); +register_nosave_region (PFN_DOWN (paddr), +PFN_UP (ei->addr)); paddr =round_down (ei->addr + ei->size,PAGE_SIZE );if (ei->type !=E820_RAM ) -e820_mark_nosave_range (round_up (ei->addr,PAGE_SIZE ), - paddr); +register_nosave_region (PFN_UP (ei->addr), +PFN_DOWN (paddr));if (paddr >= (end_pfn <<PAGE_SHIFT ))break ;
kernel/power/power.h +2 -0
@@ -49,6 +49,8 @@ extern sector_t swsusp_resume_block; extern asmlinkage int swsusp_arch_suspend(void); extern asmlinkage int swsusp_arch_resume(void); +extern int create_basic_memory_bitmaps (void ); +extern void free_basic_memory_bitmaps (void );extern unsigned int count_data_pages (void );/**
kernel/power/user.c +4 -0
@@ -52,6 +52,9 @@ static int snapshot_open(struct inode *iif ((filp->f_flags &O_ACCMODE ) ==O_RDWR )return -ENOSYS ; +if (create_basic_memory_bitmaps ()) +return -ENOMEM ; +nonseekable_open (inode, filp); data = &snapshot_state; filp->private_data = data;
@@ -77,6 +80,7 @@ static int snapshot_release(struct inodestruct snapshot_data *data;swsusp_free (); +free_basic_memory_bitmaps (); data = filp->private_data;free_all_swap_pages (data->swap, data->bitmap);free_bitmap (data->bitmap);
kernel/power/disk.c +17 -6
@@ -127,14 +127,19 @@ int pm_suspend_disk(void)mdelay (5000 ); goto Thaw; } +/* Allocate memory management structures */ + error =create_basic_memory_bitmaps (); +if (error) + goto Thaw; +/* Free memory before shutting down devices. */ error =swsusp_shrink_memory ();if (error) - goto Thaw; + goto Finish; error =platform_prepare ();if (error) - goto Thaw; + goto Finish;suspend_console (); error =device_suspend (PMSG_FREEZE );
@@ -169,7 +174,7 @@ int pm_suspend_disk(void)power_down (pm_disk_mode); else {swsusp_free (); - goto Thaw; + goto Finish; } }else {pr_debug ("PM: Image restored successfully.\n" );
@@ -182,6 +187,8 @@ int pm_suspend_disk(void)platform_finish ();device_resume ();resume_console (); + Finish: +free_basic_memory_bitmaps (); Thaw:unprepare_processes ();return error;
@@ -227,13 +234,15 @@ static int software_resume(void) }pr_debug ("PM: Checking swsusp image.\n" ); - error =swsusp_check ();if (error) - goto Done; + goto Unlock; -pr_debug ("PM: Preparing processes for restore.\n" ); + error =create_basic_memory_bitmaps (); +if (error) + goto Unlock; +pr_debug ("PM: Preparing processes for restore.\n" ); error =prepare_processes ();if (error) {swsusp_close ();
@@ -275,7 +284,9 @@ static int software_resume(void)printk (KERN_ERR "PM: Restore failed, recovering.\n" );unprepare_processes (); Done: +free_basic_memory_bitmaps ();/* For success case, the suspend path will release the lock */ + Unlock:mutex_unlock (&pm_mutex);pr_debug ("PM: Resume from disk failed.\n" );return 0 ;
Re: [RFC][PATCH 2/3] swsusp: Do not use page flags
Hi!
Quoted 11 lines
Make swsusp use memory bitmaps instead of page flags for marking 'nosave' and free pages. This allows us to 'recycle' two page flags that can be used for other purposes. Also, the memory needed to store the bitmaps is allocated when necessary (ie. before the suspend) and freed after the resume which is more reasonable.
The patch is designed to minimize the amount of changes and there are some nice simplifications and optimizations possible on top of it. I am going to implement them separately in the future.
Signed-off-by Rafael J. Wysocki <[email protected]>
Looks ok, but needs to stay in -mm for a while. 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 3/3 mm: Remove unused page flags
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Remove the two page flags that were previously used by swsusp and are no longer needed.
--- include/linux/page-flags.h | 12 ------------ 1 file changed, 12 deletions(-)
include/linux/page-flags.h +0 -12
@@ -82,13 +82,11 @@#define PG_private 11/* If pagecache, has fs-private data */ #define PG_writeback 12/* Page is under writeback */ -#define PG_nosave 13/* Used for system suspend/resume */ #define PG_compound 14/* Part of a compound page */ #define PG_swapcache 15/* Swap page: swp_entry_t in private */ #define PG_mappedtodisk 16/* Has blocks allocated on-disk */ #define PG_reclaim 17/* To be reclaimed asap */ -#define PG_nosave_free 18/* Used for system suspend/resume */ #define PG_buddy 19/* Page is free, on buddy lists */ /* PG_owner_priv_1 users should have descriptive aliases */
@@ -214,16 +212,6 @@ static inline void SetPageUptodate(struc ret; \ }) -#define PageNosave (page) test_bit(PG_nosave, &(page)->flags) -#define SetPageNosave (page) set_bit(PG_nosave, &(page)->flags) -#define TestSetPageNosave (page) test_and_set_bit(PG_nosave, &(page)->flags) -#define ClearPageNosave (page) clear_bit(PG_nosave, &(page)->flags) -#define TestClearPageNosave (page) test_and_clear_bit(PG_nosave, &(page)->flags) - -#define PageNosaveFree (page) test_bit(PG_nosave_free, &(page)->flags) -#define SetPageNosaveFree (page) set_bit(PG_nosave_free, &(page)->flags) -#define ClearPageNosaveFree (page) clear_bit(PG_nosave_free, &(page)->flags) -#define PageBuddy (page) test_bit(PG_buddy, &(page)->flags)#define __SetPageBuddy (page) __set_bit(PG_buddy, &(page)->flags)#define __ClearPageBuddy (page) __clear_bit(PG_buddy, &(page)->flags)
Re: [RFC][PATCH 3/3] mm: Remove unused page flags
Quoted 6 lines · Rafael J. Wysocki
From: Rafael J. Wysocki <[email protected]>
Remove the two page flags that were previously used by swsusp and are no longer needed.
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
Quoted 7 lines · Rafael J. Wysocki
Hi,
The following three patches make swsusp use its own data structures for memory management instead of special page flags. Thus the page flags used so far by swsusp (
PG_nosave,PG_nosave_free) can be used for other purposes and I believe there are some urgend needs of them. :-)
Quoted 6 lines
Last week I sent these patches to the linux-pm and linux-mm lists and there were no negative comments. Also I've been testing them on my
x86_64boxes for a few days and apparently they don't break anything. I think they can go into -mm for testing.Comments are welcome.
These patches have my blessing, they look good to me, but I'm not much involved with the swsusp code, so I won't ACK them.
Again, thanks a bunch for freeing up 2 page flags :-)
Peter