diff options
Diffstat (limited to 'kernel/power/swap.c')
-rw-r--r-- | kernel/power/swap.c | 146 |
1 files changed, 124 insertions, 22 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index b101cdc4df3f..09b2b0ae9e9d 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -38,6 +38,107 @@ struct swsusp_header { | |||
38 | 38 | ||
39 | static struct swsusp_header *swsusp_header; | 39 | static struct swsusp_header *swsusp_header; |
40 | 40 | ||
41 | /** | ||
42 | * The following functions are used for tracing the allocated | ||
43 | * swap pages, so that they can be freed in case of an error. | ||
44 | */ | ||
45 | |||
46 | struct swsusp_extent { | ||
47 | struct rb_node node; | ||
48 | unsigned long start; | ||
49 | unsigned long end; | ||
50 | }; | ||
51 | |||
52 | static struct rb_root swsusp_extents = RB_ROOT; | ||
53 | |||
54 | static int swsusp_extents_insert(unsigned long swap_offset) | ||
55 | { | ||
56 | struct rb_node **new = &(swsusp_extents.rb_node); | ||
57 | struct rb_node *parent = NULL; | ||
58 | struct swsusp_extent *ext; | ||
59 | |||
60 | /* Figure out where to put the new node */ | ||
61 | while (*new) { | ||
62 | ext = container_of(*new, struct swsusp_extent, node); | ||
63 | parent = *new; | ||
64 | if (swap_offset < ext->start) { | ||
65 | /* Try to merge */ | ||
66 | if (swap_offset == ext->start - 1) { | ||
67 | ext->start--; | ||
68 | return 0; | ||
69 | } | ||
70 | new = &((*new)->rb_left); | ||
71 | } else if (swap_offset > ext->end) { | ||
72 | /* Try to merge */ | ||
73 | if (swap_offset == ext->end + 1) { | ||
74 | ext->end++; | ||
75 | return 0; | ||
76 | } | ||
77 | new = &((*new)->rb_right); | ||
78 | } else { | ||
79 | /* It already is in the tree */ | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | } | ||
83 | /* Add the new node and rebalance the tree. */ | ||
84 | ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL); | ||
85 | if (!ext) | ||
86 | return -ENOMEM; | ||
87 | |||
88 | ext->start = swap_offset; | ||
89 | ext->end = swap_offset; | ||
90 | rb_link_node(&ext->node, parent, new); | ||
91 | rb_insert_color(&ext->node, &swsusp_extents); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * alloc_swapdev_block - allocate a swap page and register that it has | ||
97 | * been allocated, so that it can be freed in case of an error. | ||
98 | */ | ||
99 | |||
100 | sector_t alloc_swapdev_block(int swap) | ||
101 | { | ||
102 | unsigned long offset; | ||
103 | |||
104 | offset = swp_offset(get_swap_page_of_type(swap)); | ||
105 | if (offset) { | ||
106 | if (swsusp_extents_insert(offset)) | ||
107 | swap_free(swp_entry(swap, offset)); | ||
108 | else | ||
109 | return swapdev_block(swap, offset); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * free_all_swap_pages - free swap pages allocated for saving image data. | ||
116 | * It also frees the extents used to register which swap entres had been | ||
117 | * allocated. | ||
118 | */ | ||
119 | |||
120 | void free_all_swap_pages(int swap) | ||
121 | { | ||
122 | struct rb_node *node; | ||
123 | |||
124 | while ((node = swsusp_extents.rb_node)) { | ||
125 | struct swsusp_extent *ext; | ||
126 | unsigned long offset; | ||
127 | |||
128 | ext = container_of(node, struct swsusp_extent, node); | ||
129 | rb_erase(node, &swsusp_extents); | ||
130 | for (offset = ext->start; offset <= ext->end; offset++) | ||
131 | swap_free(swp_entry(swap, offset)); | ||
132 | |||
133 | kfree(ext); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | int swsusp_swap_in_use(void) | ||
138 | { | ||
139 | return (swsusp_extents.rb_node != NULL); | ||
140 | } | ||
141 | |||
41 | /* | 142 | /* |
42 | * General things | 143 | * General things |
43 | */ | 144 | */ |
@@ -314,7 +415,6 @@ static int save_image(struct swap_map_handle *handle, | |||
314 | { | 415 | { |
315 | unsigned int m; | 416 | unsigned int m; |
316 | int ret; | 417 | int ret; |
317 | int error = 0; | ||
318 | int nr_pages; | 418 | int nr_pages; |
319 | int err2; | 419 | int err2; |
320 | struct bio *bio; | 420 | struct bio *bio; |
@@ -329,26 +429,27 @@ static int save_image(struct swap_map_handle *handle, | |||
329 | nr_pages = 0; | 429 | nr_pages = 0; |
330 | bio = NULL; | 430 | bio = NULL; |
331 | do_gettimeofday(&start); | 431 | do_gettimeofday(&start); |
332 | do { | 432 | while (1) { |
333 | ret = snapshot_read_next(snapshot, PAGE_SIZE); | 433 | ret = snapshot_read_next(snapshot, PAGE_SIZE); |
334 | if (ret > 0) { | 434 | if (ret <= 0) |
335 | error = swap_write_page(handle, data_of(*snapshot), | 435 | break; |
336 | &bio); | 436 | ret = swap_write_page(handle, data_of(*snapshot), &bio); |
337 | if (error) | 437 | if (ret) |
338 | break; | 438 | break; |
339 | if (!(nr_pages % m)) | 439 | if (!(nr_pages % m)) |
340 | printk("\b\b\b\b%3d%%", nr_pages / m); | 440 | printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m); |
341 | nr_pages++; | 441 | nr_pages++; |
342 | } | 442 | } |
343 | } while (ret > 0); | ||
344 | err2 = wait_on_bio_chain(&bio); | 443 | err2 = wait_on_bio_chain(&bio); |
345 | do_gettimeofday(&stop); | 444 | do_gettimeofday(&stop); |
346 | if (!error) | 445 | if (!ret) |
347 | error = err2; | 446 | ret = err2; |
348 | if (!error) | 447 | if (!ret) |
349 | printk("\b\b\b\bdone\n"); | 448 | printk(KERN_CONT "\b\b\b\bdone\n"); |
449 | else | ||
450 | printk(KERN_CONT "\n"); | ||
350 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); | 451 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); |
351 | return error; | 452 | return ret; |
352 | } | 453 | } |
353 | 454 | ||
354 | /** | 455 | /** |
@@ -536,7 +637,8 @@ static int load_image(struct swap_map_handle *handle, | |||
536 | snapshot_write_finalize(snapshot); | 637 | snapshot_write_finalize(snapshot); |
537 | if (!snapshot_image_loaded(snapshot)) | 638 | if (!snapshot_image_loaded(snapshot)) |
538 | error = -ENODATA; | 639 | error = -ENODATA; |
539 | } | 640 | } else |
641 | printk("\n"); | ||
540 | swsusp_show_speed(&start, &stop, nr_to_read, "Read"); | 642 | swsusp_show_speed(&start, &stop, nr_to_read, "Read"); |
541 | return error; | 643 | return error; |
542 | } | 644 | } |
@@ -572,8 +674,6 @@ int swsusp_read(unsigned int *flags_p) | |||
572 | error = load_image(&handle, &snapshot, header->pages - 1); | 674 | error = load_image(&handle, &snapshot, header->pages - 1); |
573 | release_swap_reader(&handle); | 675 | release_swap_reader(&handle); |
574 | 676 | ||
575 | blkdev_put(resume_bdev, FMODE_READ); | ||
576 | |||
577 | if (!error) | 677 | if (!error) |
578 | pr_debug("PM: Image successfully loaded\n"); | 678 | pr_debug("PM: Image successfully loaded\n"); |
579 | else | 679 | else |
@@ -596,7 +696,7 @@ int swsusp_check(void) | |||
596 | error = bio_read_page(swsusp_resume_block, | 696 | error = bio_read_page(swsusp_resume_block, |
597 | swsusp_header, NULL); | 697 | swsusp_header, NULL); |
598 | if (error) | 698 | if (error) |
599 | return error; | 699 | goto put; |
600 | 700 | ||
601 | if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) { | 701 | if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) { |
602 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); | 702 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); |
@@ -604,8 +704,10 @@ int swsusp_check(void) | |||
604 | error = bio_write_page(swsusp_resume_block, | 704 | error = bio_write_page(swsusp_resume_block, |
605 | swsusp_header, NULL); | 705 | swsusp_header, NULL); |
606 | } else { | 706 | } else { |
607 | return -EINVAL; | 707 | error = -EINVAL; |
608 | } | 708 | } |
709 | |||
710 | put: | ||
609 | if (error) | 711 | if (error) |
610 | blkdev_put(resume_bdev, FMODE_READ); | 712 | blkdev_put(resume_bdev, FMODE_READ); |
611 | else | 713 | else |