Commit 1adf6c8e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: improve handling of swap partitions

This changes the handling of swap partitions by swsusp to avoid locking of the
swap devices that are not used for suspend and, consequently, simplifies the
code.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3a291a20
...@@ -104,13 +104,7 @@ static struct swsusp_info swsusp_info; ...@@ -104,13 +104,7 @@ static struct swsusp_info swsusp_info;
* Saving part... * Saving part...
*/ */
/* We memorize in swapfile_used what swap devices are used for suspension */ static unsigned short root_swap = 0xffff;
#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 int mark_swapfiles(swp_entry_t prev) static int mark_swapfiles(swp_entry_t prev)
{ {
...@@ -146,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev) ...@@ -146,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev)
* devfs, since the resume code can only recognize the form /dev/hda4, * devfs, since the resume code can only recognize the form /dev/hda4,
* but the suspend code would see the long name.) * 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 file *file = swap_info->swap_file;
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
...@@ -156,55 +150,23 @@ static int is_resume_device(const struct swap_info_struct *swap_info) ...@@ -156,55 +150,23 @@ static int is_resume_device(const struct swap_info_struct *swap_info)
} }
static int swsusp_swap_check(void) /* This is called before saving image */ 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; int i;
if (!swsusp_resume_device)
return -ENODEV;
spin_lock(&swap_lock); spin_lock(&swap_lock);
for (i = 0; i< MAX_SWAPFILES; i++) for (i = 0; i < MAX_SWAPFILES; i++) {
if (swapfile_used[i] == SWAPFILE_IGNORED) { if (!(swap_info[i].flags & SWP_WRITEOK))
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); spin_unlock(&swap_lock);
return -ENODEV;
} }
/** /**
...@@ -222,19 +184,14 @@ static void lock_swapdevices(void) ...@@ -222,19 +184,14 @@ static void lock_swapdevices(void)
static int write_page(unsigned long addr, swp_entry_t *loc) static int write_page(unsigned long addr, swp_entry_t *loc)
{ {
swp_entry_t entry; swp_entry_t entry;
int error = 0; int error = -ENOSPC;
entry = get_swap_page(); entry = get_swap_page_of_type(root_swap);
if (swp_offset(entry) && if (swp_offset(entry)) {
swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { error = rw_swap_page_sync(WRITE, entry, virt_to_page(addr));
error = rw_swap_page_sync(WRITE, entry, if (!error || error == -EIO)
virt_to_page(addr));
if (error == -EIO)
error = 0;
if (!error)
*loc = entry; *loc = entry;
} else }
error = -ENOSPC;
return error; return error;
} }
...@@ -539,31 +496,38 @@ static int save_image_metadata(struct pbe *pblist, ...@@ -539,31 +496,38 @@ static int save_image_metadata(struct pbe *pblist,
* enough_swap - Make sure we have enough swap to save the image. * enough_swap - Make sure we have enough swap to save the image.
* *
* Returns TRUE or FALSE after checking the total amount of swap * Returns TRUE or FALSE after checking the total amount of swap
* space avaiable. * space avaiable from the resume partition.
*
* FIXME: si_swapinfo(&i) returns all swap devices information.
* We should only consider resume_device.
*/ */
static int enough_swap(unsigned int nr_pages) static int enough_swap(unsigned int nr_pages)
{ {
struct sysinfo i; unsigned int free_swap = swap_info[root_swap].pages -
swap_info[root_swap].inuse_pages;
si_swapinfo(&i); pr_debug("swsusp: free swap pages: %u\n", free_swap);
pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); return free_swap > (nr_pages + PAGES_FOR_IO +
return i.freeswap > (nr_pages + PAGES_FOR_IO +
(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
} }
/** /**
* write_suspend_image - Write entire image and metadata. * swsusp_write - Write entire image and metadata.
*
* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/ */
static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages)
int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
{ {
struct swap_map_page *swap_map; struct swap_map_page *swap_map;
struct swap_map_handle handle; struct swap_map_handle handle;
int error; int error;
if ((error = swsusp_swap_check())) {
printk(KERN_ERR "swsusp: Cannot find swap device, try swapon -a.\n");
return error;
}
if (!enough_swap(nr_pages)) { if (!enough_swap(nr_pages)) {
printk(KERN_ERR "swsusp: Not enough free swap\n"); printk(KERN_ERR "swsusp: Not enough free swap\n");
return -ENOSPC; return -ENOSPC;
...@@ -601,26 +565,6 @@ static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages) ...@@ -601,26 +565,6 @@ static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages)
goto Free_swap_map; goto Free_swap_map;
} }
/* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.)
*/
int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
{
int error;
if ((error = swsusp_swap_check())) {
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;
}
/** /**
* swsusp_shrink_memory - Try to free as much memory as needed * swsusp_shrink_memory - Try to free as much memory as needed
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment