aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swap.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-12-06 23:34:10 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:27 -0500
commit3aef83e0ef1ffb8ea3bea97be46821a45c952173 (patch)
treef73878eb2ecce804c9eea6fbb13603907b3674b4 /kernel/power/swap.c
parent3fc6b34f4803b959c1e30c15247e2180cd529115 (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.c133
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
36static struct swsusp_header { 36static 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
103static int bio_write_page(pgoff_t page_off, void *addr) 103static 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
108static int wait_on_bio_chain(struct bio **bio_chain) 108static 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
160static int mark_swapfiles(swp_entry_t start) 160static 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
186static int swsusp_swap_check(void) /* This is called before saving image */ 183static 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
204static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) 210static 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
253struct swap_map_page { 249struct 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
263struct swap_map_handle { 259struct 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);
451out:
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
462static int get_swap_reader(struct swap_map_handle *handle, 468static 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,
481static int swap_read_page(struct swap_map_handle *handle, void *buf, 488static 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 }