Additional function in swapfile.c (needed for swap suspend)
Subsystems (4)
cover Additional function in swapfile.c (needed for swap suspend)
Hi,
To implement the image-writing part of swsusp in the user space and maintain the compatibility with the in-kernel implementation we need to be able to ask the kernel to allocate a swap page from specific swap partition. For this purpose we need a function allowing us to specify the swap partition to allocate from.
Moreover, if we had such a function, we could change the in-kernel implementation of swsusp to avoid locking of the swap devices that are not used for suspend and this would allow us to simplify the code quite a bit.
The first of the following two patches adds such a function, and the second of them shows what can be done in swsusp if that function is available.
All of your comments and/or suggestions will be appreciated.
Greetings,
Rafael
RFC PATCH 1/2 Additional function in swapfile.c (needed for swap suspend)
This patch adds the function get_swap_page_of_type() allowing us to specify an index in swap_info[] and select a swap_info_struct structure to be used for allocating a swap page.
This function (or another one of similar functionality) will be necessary for implementing the image-writing part of swsusp in the user space. It can also be used for simplifying the current in-kernel implementation of the image-writing part of swsusp.
include/linux/swap.h | 1 + mm/swapfile.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+)
mm/swapfile.c +20 -0
@@ -211,6 +211,26 @@return (swp_entry_t ) {0 }; } +swp_entry_t get_swap_page_of_type (int type) +{ +struct swap_info_struct *si; +pgoff_t offset; + +spin_lock (&swap_lock); + si = swap_info + type; +if (si->flags &SWP_WRITEOK ) { + nr_swap_pages--; + offset =scan_swap_map (si); +if (offset) { +spin_unlock (&swap_lock); +return swp_entry (type, offset); + } + nr_swap_pages++; + } +spin_unlock (&swap_lock); +return (swp_entry_t ) {0 }; +} +static struct swap_info_struct *swap_info_get (swp_entry_t entry) {struct swap_info_struct * p;
include/linux/swap.h +1 -0
@@ -216,6 +216,7 @@extern struct swap_info_struct swap_info[];extern void si_swapinfo (struct sysinfo *);extern swp_entry_t get_swap_page (void ); +extern swp_entry_t get_swap_page_of_type (int type);extern int swap_duplicate (swp_entry_t );extern int valid_swaphandles (swp_entry_t ,unsigned long *);extern void swap_free (swp_entry_t );
RFC PATCH 2/2 Additional function in swapfile.c (needed for swap suspend)
In reply to Rafael J. WysockiThis patch contains the modification that can be made to swsusp once the function defined in the previous patch has been introduced.
kernel/power/swsusp.c | 84 +++++++++++--------------------------------------- 1 files changed, 19 insertions(+), 65 deletions(-)
kernel/power/swsusp.c +19 -65
@@ -104,13 +104,7 @@* Saving part... */ -/* We memorize in swapfile_used what swap devices are used for suspension */ -#define SWAPFILE_UNUSED 0 -#define SWAPFILE_SUSPEND 1/* This is the suspending device */ -#define SWAPFILE_IGNORED 2/* Those are other swap devices ignored for suspension */ - -static unsigned short swapfile_used[MAX_SWAPFILES ]; -static unsigned short root_swap; +static unsigned short root_swap =0xffff ;static int mark_swapfiles (swp_entry_t prev) {
@@ -146,7 +140,7 @@* devfs, since the resume code can only recognize the form /dev/hda4, * but the suspend code would see the long name.) */ -static int is_resume_device (const struct swap_info_struct *swap_info) +static inline int is_resume_device (const struct swap_info_struct *swap_info) {struct file *file = swap_info->swap_file;struct inode *inode = file->f_dentry->d_inode;
@@ -157,54 +151,22 @@static int swsusp_swap_check (void )/* This is called before saving image */ { -int i, len; - - len=strlen (resume_file); - root_swap =0xFFFF ; - -spin_lock (&swap_lock); -for (i=0 ; i<MAX_SWAPFILES ; i++) { -if (!(swap_info[i].flags &SWP_WRITEOK )) { - swapfile_used[i]=SWAPFILE_UNUSED ; - }else { -if (!len) { -printk (KERN_WARNING "resume= option should be used to set suspend device" ); -if (root_swap ==0xFFFF ) { - swapfile_used[i] =SWAPFILE_SUSPEND ; - root_swap = i; - }else - swapfile_used[i] =SWAPFILE_IGNORED ; - }else { -/* we ignore all swap devices that are not the resume_file */ -if (is_resume_device (&swap_info[i])) { - swapfile_used[i] =SWAPFILE_SUSPEND ; - root_swap = i; - }else { - swapfile_used[i] =SWAPFILE_IGNORED ; - } - } - } - } -spin_unlock (&swap_lock); -return (root_swap !=0xffff ) ?0 : -ENODEV ; -} - -/** -* This is called after saving image so modification -* will be lost after resume... and that's what we want. -* we make the device unusable. A new call to -* lock_swapdevices can unlock the devices. -*/ -static void lock_swapdevices (void ) -{int i; +if (!swsusp_resume_device) +return -ENODEV ;spin_lock (&swap_lock); -for (i =0 ; i<MAX_SWAPFILES ; i++) -if (swapfile_used[i] ==SWAPFILE_IGNORED ) { - swap_info[i].flags ^=SWP_WRITEOK ; +for (i =0 ; i <MAX_SWAPFILES ; i++) { +if (!(swap_info[i].flags &SWP_WRITEOK )) +continue ; +if (is_resume_device (swap_info + i)) { +spin_unlock (&swap_lock); + root_swap = i; +return 0 ; } + }spin_unlock (&swap_lock); +return -ENODEV ; }/**
@@ -222,19 +184,14 @@static int write_page (unsigned long addr,swp_entry_t *loc) {swp_entry_t entry; -int error =0 ; +int error = -ENOSPC ; - entry =get_swap_page (); -if (swp_offset (entry) && - swapfile_used[swp_type (entry)] ==SWAPFILE_SUSPEND ) { - error =rw_swap_page_sync (WRITE , entry, -virt_to_page (addr)); -if (error == -EIO ) - error =0 ; -if (!error) + entry =get_swap_page_of_type (root_swap); +if (swp_offset (entry)) { + error =rw_swap_page_sync (WRITE , entry,virt_to_page (addr)); +if (!error || error == -EIO ) *loc = entry; - }else - error = -ENOSPC ; + }return error; }
@@ -614,10 +571,7 @@printk (KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n" );return error; } -lock_swapdevices (); error =write_suspend_image (pblist, nr_pages); -/* This will unlock ignored swap devices since writing is finished */ -lock_swapdevices ();return error; }