diff options
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/swsusp.c | 128 |
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 */ | 107 | static 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 | |||
112 | static unsigned short swapfile_used[MAX_SWAPFILES]; | ||
113 | static unsigned short root_swap; | ||
114 | 108 | ||
115 | static int mark_swapfiles(swp_entry_t prev) | 109 | static 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 | */ |
149 | static int is_resume_device(const struct swap_info_struct *swap_info) | 143 | static 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 | ||
158 | static int swsusp_swap_check(void) /* This is called before saving image */ | 152 | static 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 | */ | ||
198 | static 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) | |||
222 | static int write_page(unsigned long addr, swp_entry_t *loc) | 184 | static 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 | ||
548 | static int enough_swap(unsigned int nr_pages) | 502 | static 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 | */ |
561 | static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages) | 520 | |
521 | int 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 | */ | ||
609 | int 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 | * |