aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-01-06 03:17:16 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:43 -0500
commit1adf6c8ea916bc4a2587a881ec7715fece63fb5e (patch)
tree0cfeb2d3ea23fbfac3674cf9b7291f80a055aad1 /kernel
parent3a291a20bd6fcfafb2109031f0760a0d3e92ecd7 (diff)
[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: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/swsusp.c128
1 files changed, 36 insertions, 92 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index d760a6a719f0..0479c9be7d71 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -104,13 +104,7 @@ static struct swsusp_info swsusp_info;
104 * Saving part... 104 * Saving part...
105 */ 105 */
106 106
107/* We memorize in swapfile_used what swap devices are used for suspension */ 107static unsigned short root_swap = 0xffff;
108#define SWAPFILE_UNUSED 0
109#define SWAPFILE_SUSPEND 1 /* This is the suspending device */
110#define SWAPFILE_IGNORED 2 /* Those are other swap devices ignored for suspension */
111
112static unsigned short swapfile_used[MAX_SWAPFILES];
113static unsigned short root_swap;
114 108
115static int mark_swapfiles(swp_entry_t prev) 109static int mark_swapfiles(swp_entry_t prev)
116{ 110{
@@ -146,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev)
146 * devfs, since the resume code can only recognize the form /dev/hda4, 140 * devfs, since the resume code can only recognize the form /dev/hda4,
147 * but the suspend code would see the long name.) 141 * but the suspend code would see the long name.)
148 */ 142 */
149static int is_resume_device(const struct swap_info_struct *swap_info) 143static inline int is_resume_device(const struct swap_info_struct *swap_info)
150{ 144{
151 struct file *file = swap_info->swap_file; 145 struct file *file = swap_info->swap_file;
152 struct inode *inode = file->f_dentry->d_inode; 146 struct inode *inode = file->f_dentry->d_inode;
@@ -157,54 +151,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info)
157 151
158static int swsusp_swap_check(void) /* This is called before saving image */ 152static int swsusp_swap_check(void) /* This is called before saving image */
159{ 153{
160 int i, len;
161
162 len=strlen(resume_file);
163 root_swap = 0xFFFF;
164
165 spin_lock(&swap_lock);
166 for (i=0; i<MAX_SWAPFILES; i++) {
167 if (!(swap_info[i].flags & SWP_WRITEOK)) {
168 swapfile_used[i]=SWAPFILE_UNUSED;
169 } else {
170 if (!len) {
171 printk(KERN_WARNING "resume= option should be used to set suspend device" );
172 if (root_swap == 0xFFFF) {
173 swapfile_used[i] = SWAPFILE_SUSPEND;
174 root_swap = i;
175 } else
176 swapfile_used[i] = SWAPFILE_IGNORED;
177 } else {
178 /* we ignore all swap devices that are not the resume_file */
179 if (is_resume_device(&swap_info[i])) {
180 swapfile_used[i] = SWAPFILE_SUSPEND;
181 root_swap = i;
182 } else {
183 swapfile_used[i] = SWAPFILE_IGNORED;
184 }
185 }
186 }
187 }
188 spin_unlock(&swap_lock);
189 return (root_swap != 0xffff) ? 0 : -ENODEV;
190}
191
192/**
193 * This is called after saving image so modification
194 * will be lost after resume... and that's what we want.
195 * we make the device unusable. A new call to
196 * lock_swapdevices can unlock the devices.
197 */
198static void lock_swapdevices(void)
199{
200 int i; 154 int i;
201 155
156 if (!swsusp_resume_device)
157 return -ENODEV;
202 spin_lock(&swap_lock); 158 spin_lock(&swap_lock);
203 for (i = 0; i< MAX_SWAPFILES; i++) 159 for (i = 0; i < MAX_SWAPFILES; i++) {
204 if (swapfile_used[i] == SWAPFILE_IGNORED) { 160 if (!(swap_info[i].flags & SWP_WRITEOK))
205 swap_info[i].flags ^= SWP_WRITEOK; 161 continue;
162 if (is_resume_device(swap_info + i)) {
163 spin_unlock(&swap_lock);
164 root_swap = i;
165 return 0;
206 } 166 }
167 }
207 spin_unlock(&swap_lock); 168 spin_unlock(&swap_lock);
169 return -ENODEV;
208} 170}
209 171
210/** 172/**
@@ -222,19 +184,14 @@ static void lock_swapdevices(void)
222static int write_page(unsigned long addr, swp_entry_t *loc) 184static int write_page(unsigned long addr, swp_entry_t *loc)
223{ 185{
224 swp_entry_t entry; 186 swp_entry_t entry;
225 int error = 0; 187 int error = -ENOSPC;
226 188
227 entry = get_swap_page(); 189 entry = get_swap_page_of_type(root_swap);
228 if (swp_offset(entry) && 190 if (swp_offset(entry)) {
229 swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { 191 error = rw_swap_page_sync(WRITE, entry, virt_to_page(addr));
230 error = rw_swap_page_sync(WRITE, entry, 192 if (!error || error == -EIO)
231 virt_to_page(addr));
232 if (error == -EIO)
233 error = 0;
234 if (!error)
235 *loc = entry; 193 *loc = entry;
236 } else 194 }
237 error = -ENOSPC;
238 return error; 195 return error;
239} 196}
240 197
@@ -539,31 +496,38 @@ static int save_image_metadata(struct pbe *pblist,
539 * enough_swap - Make sure we have enough swap to save the image. 496 * enough_swap - Make sure we have enough swap to save the image.
540 * 497 *
541 * Returns TRUE or FALSE after checking the total amount of swap 498 * Returns TRUE or FALSE after checking the total amount of swap
542 * space avaiable. 499 * space avaiable from the resume partition.
543 *
544 * FIXME: si_swapinfo(&i) returns all swap devices information.
545 * We should only consider resume_device.
546 */ 500 */
547 501
548static int enough_swap(unsigned int nr_pages) 502static int enough_swap(unsigned int nr_pages)
549{ 503{
550 struct sysinfo i; 504 unsigned int free_swap = swap_info[root_swap].pages -
505 swap_info[root_swap].inuse_pages;
551 506
552 si_swapinfo(&i); 507 pr_debug("swsusp: free swap pages: %u\n", free_swap);
553 pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); 508 return free_swap > (nr_pages + PAGES_FOR_IO +
554 return i.freeswap > (nr_pages + PAGES_FOR_IO +
555 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); 509 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
556} 510}
557 511
558/** 512/**
559 * write_suspend_image - Write entire image and metadata. 513 * swsusp_write - Write entire image and metadata.
514 *
515 * It is important _NOT_ to umount filesystems at this point. We want
516 * them synced (in case something goes wrong) but we DO not want to mark
517 * filesystem clean: it is not. (And it does not matter, if we resume
518 * correctly, we'll mark system clean, anyway.)
560 */ 519 */
561static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages) 520
521int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
562{ 522{
563 struct swap_map_page *swap_map; 523 struct swap_map_page *swap_map;
564 struct swap_map_handle handle; 524 struct swap_map_handle handle;
565 int error; 525 int error;
566 526
527 if ((error = swsusp_swap_check())) {
528 printk(KERN_ERR "swsusp: Cannot find swap device, try swapon -a.\n");
529 return error;
530 }
567 if (!enough_swap(nr_pages)) { 531 if (!enough_swap(nr_pages)) {
568 printk(KERN_ERR "swsusp: Not enough free swap\n"); 532 printk(KERN_ERR "swsusp: Not enough free swap\n");
569 return -ENOSPC; 533 return -ENOSPC;
@@ -601,26 +565,6 @@ Free_image_entries:
601 goto Free_swap_map; 565 goto Free_swap_map;
602} 566}
603 567
604/* It is important _NOT_ to umount filesystems at this point. We want
605 * them synced (in case something goes wrong) but we DO not want to mark
606 * filesystem clean: it is not. (And it does not matter, if we resume
607 * correctly, we'll mark system clean, anyway.)
608 */
609int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
610{
611 int error;
612
613 if ((error = swsusp_swap_check())) {
614 printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
615 return error;
616 }
617 lock_swapdevices();
618 error = write_suspend_image(pblist, nr_pages);
619 /* This will unlock ignored swap devices since writing is finished */
620 lock_swapdevices();
621 return error;
622}
623
624/** 568/**
625 * swsusp_shrink_memory - Try to free as much memory as needed 569 * swsusp_shrink_memory - Try to free as much memory as needed
626 * 570 *