aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swsusp.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/swsusp.c')
-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 *