diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2006-12-06 23:34:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:27 -0500 |
commit | 3aef83e0ef1ffb8ea3bea97be46821a45c952173 (patch) | |
tree | f73878eb2ecce804c9eea6fbb13603907b3674b4 /kernel/power/swap.c | |
parent | 3fc6b34f4803b959c1e30c15247e2180cd529115 (diff) |
[PATCH] swsusp: use block device offsets to identify swap locations
Make swsusp use block device offsets instead of swap offsets to identify swap
locations and make it use the same code paths for writing as well as for
reading data.
This allows us to use the same code for handling swap files and swap
partitions and to simplify the code, eg. by dropping rw_swap_page_sync().
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Cc: 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/power/swap.c')
-rw-r--r-- | kernel/power/swap.c | 133 |
1 files changed, 70 insertions, 63 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 7768c2ba7550..1b08f46bbb7e 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -34,8 +34,8 @@ extern char resume_file[]; | |||
34 | #define SWSUSP_SIG "S1SUSPEND" | 34 | #define SWSUSP_SIG "S1SUSPEND" |
35 | 35 | ||
36 | static struct swsusp_header { | 36 | static struct swsusp_header { |
37 | char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)]; | 37 | char reserved[PAGE_SIZE - 20 - sizeof(sector_t)]; |
38 | swp_entry_t image; | 38 | sector_t image; |
39 | char orig_sig[10]; | 39 | char orig_sig[10]; |
40 | char sig[10]; | 40 | char sig[10]; |
41 | } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; | 41 | } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; |
@@ -100,9 +100,9 @@ static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) | |||
100 | return submit(READ, page_off, virt_to_page(addr), bio_chain); | 100 | return submit(READ, page_off, virt_to_page(addr), bio_chain); |
101 | } | 101 | } |
102 | 102 | ||
103 | static int bio_write_page(pgoff_t page_off, void *addr) | 103 | static int bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain) |
104 | { | 104 | { |
105 | return submit(WRITE, page_off, virt_to_page(addr), NULL); | 105 | return submit(WRITE, page_off, virt_to_page(addr), bio_chain); |
106 | } | 106 | } |
107 | 107 | ||
108 | static int wait_on_bio_chain(struct bio **bio_chain) | 108 | static int wait_on_bio_chain(struct bio **bio_chain) |
@@ -157,22 +157,19 @@ static void show_speed(struct timeval *start, struct timeval *stop, | |||
157 | * Saving part | 157 | * Saving part |
158 | */ | 158 | */ |
159 | 159 | ||
160 | static int mark_swapfiles(swp_entry_t start) | 160 | static int mark_swapfiles(sector_t start) |
161 | { | 161 | { |
162 | int error; | 162 | int error; |
163 | 163 | ||
164 | rw_swap_page_sync(READ, swp_entry(root_swap, 0), | 164 | bio_read_page(0, &swsusp_header, NULL); |
165 | virt_to_page((unsigned long)&swsusp_header), NULL); | ||
166 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || | 165 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || |
167 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { | 166 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { |
168 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); | 167 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); |
169 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); | 168 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); |
170 | swsusp_header.image = start; | 169 | swsusp_header.image = start; |
171 | error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0), | 170 | error = bio_write_page(0, &swsusp_header, NULL); |
172 | virt_to_page((unsigned long)&swsusp_header), | ||
173 | NULL); | ||
174 | } else { | 171 | } else { |
175 | pr_debug("swsusp: Partition is not swap space.\n"); | 172 | printk(KERN_ERR "swsusp: Swap header not found!\n"); |
176 | error = -ENODEV; | 173 | error = -ENODEV; |
177 | } | 174 | } |
178 | return error; | 175 | return error; |
@@ -185,12 +182,21 @@ static int mark_swapfiles(swp_entry_t start) | |||
185 | 182 | ||
186 | static int swsusp_swap_check(void) /* This is called before saving image */ | 183 | static int swsusp_swap_check(void) /* This is called before saving image */ |
187 | { | 184 | { |
188 | int res = swap_type_of(swsusp_resume_device, 0); | 185 | int res; |
186 | |||
187 | res = swap_type_of(swsusp_resume_device, 0); | ||
188 | if (res < 0) | ||
189 | return res; | ||
190 | |||
191 | root_swap = res; | ||
192 | resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_WRITE); | ||
193 | if (IS_ERR(resume_bdev)) | ||
194 | return PTR_ERR(resume_bdev); | ||
195 | |||
196 | res = set_blocksize(resume_bdev, PAGE_SIZE); | ||
197 | if (res < 0) | ||
198 | blkdev_put(resume_bdev); | ||
189 | 199 | ||
190 | if (res >= 0) { | ||
191 | root_swap = res; | ||
192 | return 0; | ||
193 | } | ||
194 | return res; | 200 | return res; |
195 | } | 201 | } |
196 | 202 | ||
@@ -201,36 +207,26 @@ static int swsusp_swap_check(void) /* This is called before saving image */ | |||
201 | * @bio_chain: Link the next write BIO here | 207 | * @bio_chain: Link the next write BIO here |
202 | */ | 208 | */ |
203 | 209 | ||
204 | static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) | 210 | static int write_page(void *buf, sector_t offset, struct bio **bio_chain) |
205 | { | 211 | { |
206 | swp_entry_t entry; | 212 | void *src; |
207 | int error = -ENOSPC; | 213 | |
208 | 214 | if (!offset) | |
209 | if (offset) { | 215 | return -ENOSPC; |
210 | struct page *page = virt_to_page(buf); | 216 | |
211 | 217 | if (bio_chain) { | |
212 | if (bio_chain) { | 218 | src = (void *)__get_free_page(GFP_ATOMIC); |
213 | /* | 219 | if (src) { |
214 | * Whether or not we successfully allocated a copy page, | 220 | memcpy(src, buf, PAGE_SIZE); |
215 | * we take a ref on the page here. It gets undone in | 221 | } else { |
216 | * wait_on_bio_chain(). | 222 | WARN_ON_ONCE(1); |
217 | */ | 223 | bio_chain = NULL; /* Go synchronous */ |
218 | struct page *page_copy; | 224 | src = buf; |
219 | page_copy = alloc_page(GFP_ATOMIC); | ||
220 | if (page_copy == NULL) { | ||
221 | WARN_ON_ONCE(1); | ||
222 | bio_chain = NULL; /* Go synchronous */ | ||
223 | get_page(page); | ||
224 | } else { | ||
225 | memcpy(page_address(page_copy), | ||
226 | page_address(page), PAGE_SIZE); | ||
227 | page = page_copy; | ||
228 | } | ||
229 | } | 225 | } |
230 | entry = swp_entry(root_swap, offset); | 226 | } else { |
231 | error = rw_swap_page_sync(WRITE, entry, page, bio_chain); | 227 | src = buf; |
232 | } | 228 | } |
233 | return error; | 229 | return bio_write_page(offset, src, bio_chain); |
234 | } | 230 | } |
235 | 231 | ||
236 | /* | 232 | /* |
@@ -248,11 +244,11 @@ static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) | |||
248 | * at a time. | 244 | * at a time. |
249 | */ | 245 | */ |
250 | 246 | ||
251 | #define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(long) - 1) | 247 | #define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1) |
252 | 248 | ||
253 | struct swap_map_page { | 249 | struct swap_map_page { |
254 | unsigned long entries[MAP_PAGE_ENTRIES]; | 250 | sector_t entries[MAP_PAGE_ENTRIES]; |
255 | unsigned long next_swap; | 251 | sector_t next_swap; |
256 | }; | 252 | }; |
257 | 253 | ||
258 | /** | 254 | /** |
@@ -262,7 +258,7 @@ struct swap_map_page { | |||
262 | 258 | ||
263 | struct swap_map_handle { | 259 | struct swap_map_handle { |
264 | struct swap_map_page *cur; | 260 | struct swap_map_page *cur; |
265 | unsigned long cur_swap; | 261 | sector_t cur_swap; |
266 | struct bitmap_page *bitmap; | 262 | struct bitmap_page *bitmap; |
267 | unsigned int k; | 263 | unsigned int k; |
268 | }; | 264 | }; |
@@ -287,7 +283,7 @@ static int get_swap_writer(struct swap_map_handle *handle) | |||
287 | release_swap_writer(handle); | 283 | release_swap_writer(handle); |
288 | return -ENOMEM; | 284 | return -ENOMEM; |
289 | } | 285 | } |
290 | handle->cur_swap = alloc_swap_page(root_swap, handle->bitmap); | 286 | handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap); |
291 | if (!handle->cur_swap) { | 287 | if (!handle->cur_swap) { |
292 | release_swap_writer(handle); | 288 | release_swap_writer(handle); |
293 | return -ENOSPC; | 289 | return -ENOSPC; |
@@ -300,11 +296,11 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, | |||
300 | struct bio **bio_chain) | 296 | struct bio **bio_chain) |
301 | { | 297 | { |
302 | int error = 0; | 298 | int error = 0; |
303 | unsigned long offset; | 299 | sector_t offset; |
304 | 300 | ||
305 | if (!handle->cur) | 301 | if (!handle->cur) |
306 | return -EINVAL; | 302 | return -EINVAL; |
307 | offset = alloc_swap_page(root_swap, handle->bitmap); | 303 | offset = alloc_swapdev_block(root_swap, handle->bitmap); |
308 | error = write_page(buf, offset, bio_chain); | 304 | error = write_page(buf, offset, bio_chain); |
309 | if (error) | 305 | if (error) |
310 | return error; | 306 | return error; |
@@ -313,7 +309,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, | |||
313 | error = wait_on_bio_chain(bio_chain); | 309 | error = wait_on_bio_chain(bio_chain); |
314 | if (error) | 310 | if (error) |
315 | goto out; | 311 | goto out; |
316 | offset = alloc_swap_page(root_swap, handle->bitmap); | 312 | offset = alloc_swapdev_block(root_swap, handle->bitmap); |
317 | if (!offset) | 313 | if (!offset) |
318 | return -ENOSPC; | 314 | return -ENOSPC; |
319 | handle->cur->next_swap = offset; | 315 | handle->cur->next_swap = offset; |
@@ -413,37 +409,47 @@ int swsusp_write(void) | |||
413 | struct swsusp_info *header; | 409 | struct swsusp_info *header; |
414 | int error; | 410 | int error; |
415 | 411 | ||
416 | if ((error = swsusp_swap_check())) { | 412 | error = swsusp_swap_check(); |
413 | if (error) { | ||
417 | printk(KERN_ERR "swsusp: Cannot find swap device, try " | 414 | printk(KERN_ERR "swsusp: Cannot find swap device, try " |
418 | "swapon -a.\n"); | 415 | "swapon -a.\n"); |
419 | return error; | 416 | return error; |
420 | } | 417 | } |
421 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); | 418 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); |
422 | error = snapshot_read_next(&snapshot, PAGE_SIZE); | 419 | error = snapshot_read_next(&snapshot, PAGE_SIZE); |
423 | if (error < PAGE_SIZE) | 420 | if (error < PAGE_SIZE) { |
424 | return error < 0 ? error : -EFAULT; | 421 | if (error >= 0) |
422 | error = -EFAULT; | ||
423 | |||
424 | goto out; | ||
425 | } | ||
425 | header = (struct swsusp_info *)data_of(snapshot); | 426 | header = (struct swsusp_info *)data_of(snapshot); |
426 | if (!enough_swap(header->pages)) { | 427 | if (!enough_swap(header->pages)) { |
427 | printk(KERN_ERR "swsusp: Not enough free swap\n"); | 428 | printk(KERN_ERR "swsusp: Not enough free swap\n"); |
428 | return -ENOSPC; | 429 | error = -ENOSPC; |
430 | goto out; | ||
429 | } | 431 | } |
430 | error = get_swap_writer(&handle); | 432 | error = get_swap_writer(&handle); |
431 | if (!error) { | 433 | if (!error) { |
432 | unsigned long start = handle.cur_swap; | 434 | sector_t start = handle.cur_swap; |
435 | |||
433 | error = swap_write_page(&handle, header, NULL); | 436 | error = swap_write_page(&handle, header, NULL); |
434 | if (!error) | 437 | if (!error) |
435 | error = save_image(&handle, &snapshot, | 438 | error = save_image(&handle, &snapshot, |
436 | header->pages - 1); | 439 | header->pages - 1); |
440 | |||
437 | if (!error) { | 441 | if (!error) { |
438 | flush_swap_writer(&handle); | 442 | flush_swap_writer(&handle); |
439 | printk("S"); | 443 | printk("S"); |
440 | error = mark_swapfiles(swp_entry(root_swap, start)); | 444 | error = mark_swapfiles(start); |
441 | printk("|\n"); | 445 | printk("|\n"); |
442 | } | 446 | } |
443 | } | 447 | } |
444 | if (error) | 448 | if (error) |
445 | free_all_swap_pages(root_swap, handle.bitmap); | 449 | free_all_swap_pages(root_swap, handle.bitmap); |
446 | release_swap_writer(&handle); | 450 | release_swap_writer(&handle); |
451 | out: | ||
452 | swsusp_close(); | ||
447 | return error; | 453 | return error; |
448 | } | 454 | } |
449 | 455 | ||
@@ -459,17 +465,18 @@ static void release_swap_reader(struct swap_map_handle *handle) | |||
459 | handle->cur = NULL; | 465 | handle->cur = NULL; |
460 | } | 466 | } |
461 | 467 | ||
462 | static int get_swap_reader(struct swap_map_handle *handle, | 468 | static int get_swap_reader(struct swap_map_handle *handle, sector_t start) |
463 | swp_entry_t start) | ||
464 | { | 469 | { |
465 | int error; | 470 | int error; |
466 | 471 | ||
467 | if (!swp_offset(start)) | 472 | if (!start) |
468 | return -EINVAL; | 473 | return -EINVAL; |
474 | |||
469 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC); | 475 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC); |
470 | if (!handle->cur) | 476 | if (!handle->cur) |
471 | return -ENOMEM; | 477 | return -ENOMEM; |
472 | error = bio_read_page(swp_offset(start), handle->cur, NULL); | 478 | |
479 | error = bio_read_page(start, handle->cur, NULL); | ||
473 | if (error) { | 480 | if (error) { |
474 | release_swap_reader(handle); | 481 | release_swap_reader(handle); |
475 | return error; | 482 | return error; |
@@ -481,7 +488,7 @@ static int get_swap_reader(struct swap_map_handle *handle, | |||
481 | static int swap_read_page(struct swap_map_handle *handle, void *buf, | 488 | static int swap_read_page(struct swap_map_handle *handle, void *buf, |
482 | struct bio **bio_chain) | 489 | struct bio **bio_chain) |
483 | { | 490 | { |
484 | unsigned long offset; | 491 | sector_t offset; |
485 | int error; | 492 | int error; |
486 | 493 | ||
487 | if (!handle->cur) | 494 | if (!handle->cur) |
@@ -608,7 +615,7 @@ int swsusp_check(void) | |||
608 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { | 615 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { |
609 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); | 616 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); |
610 | /* Reset swap signature now */ | 617 | /* Reset swap signature now */ |
611 | error = bio_write_page(0, &swsusp_header); | 618 | error = bio_write_page(0, &swsusp_header, NULL); |
612 | } else { | 619 | } else { |
613 | return -EINVAL; | 620 | return -EINVAL; |
614 | } | 621 | } |