aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swap.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/swap.c')
-rw-r--r--kernel/power/swap.c112
1 files changed, 105 insertions, 7 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 890f6b11b1d3..66824d71983a 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -23,6 +23,7 @@
23#include <linux/swap.h> 23#include <linux/swap.h>
24#include <linux/swapops.h> 24#include <linux/swapops.h>
25#include <linux/pm.h> 25#include <linux/pm.h>
26#include <linux/slab.h>
26 27
27#include "power.h" 28#include "power.h"
28 29
@@ -38,6 +39,107 @@ struct swsusp_header {
38 39
39static struct swsusp_header *swsusp_header; 40static struct swsusp_header *swsusp_header;
40 41
42/**
43 * The following functions are used for tracing the allocated
44 * swap pages, so that they can be freed in case of an error.
45 */
46
47struct swsusp_extent {
48 struct rb_node node;
49 unsigned long start;
50 unsigned long end;
51};
52
53static struct rb_root swsusp_extents = RB_ROOT;
54
55static int swsusp_extents_insert(unsigned long swap_offset)
56{
57 struct rb_node **new = &(swsusp_extents.rb_node);
58 struct rb_node *parent = NULL;
59 struct swsusp_extent *ext;
60
61 /* Figure out where to put the new node */
62 while (*new) {
63 ext = container_of(*new, struct swsusp_extent, node);
64 parent = *new;
65 if (swap_offset < ext->start) {
66 /* Try to merge */
67 if (swap_offset == ext->start - 1) {
68 ext->start--;
69 return 0;
70 }
71 new = &((*new)->rb_left);
72 } else if (swap_offset > ext->end) {
73 /* Try to merge */
74 if (swap_offset == ext->end + 1) {
75 ext->end++;
76 return 0;
77 }
78 new = &((*new)->rb_right);
79 } else {
80 /* It already is in the tree */
81 return -EINVAL;
82 }
83 }
84 /* Add the new node and rebalance the tree. */
85 ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
86 if (!ext)
87 return -ENOMEM;
88
89 ext->start = swap_offset;
90 ext->end = swap_offset;
91 rb_link_node(&ext->node, parent, new);
92 rb_insert_color(&ext->node, &swsusp_extents);
93 return 0;
94}
95
96/**
97 * alloc_swapdev_block - allocate a swap page and register that it has
98 * been allocated, so that it can be freed in case of an error.
99 */
100
101sector_t alloc_swapdev_block(int swap)
102{
103 unsigned long offset;
104
105 offset = swp_offset(get_swap_page_of_type(swap));
106 if (offset) {
107 if (swsusp_extents_insert(offset))
108 swap_free(swp_entry(swap, offset));
109 else
110 return swapdev_block(swap, offset);
111 }
112 return 0;
113}
114
115/**
116 * free_all_swap_pages - free swap pages allocated for saving image data.
117 * It also frees the extents used to register which swap entres had been
118 * allocated.
119 */
120
121void free_all_swap_pages(int swap)
122{
123 struct rb_node *node;
124
125 while ((node = swsusp_extents.rb_node)) {
126 struct swsusp_extent *ext;
127 unsigned long offset;
128
129 ext = container_of(node, struct swsusp_extent, node);
130 rb_erase(node, &swsusp_extents);
131 for (offset = ext->start; offset <= ext->end; offset++)
132 swap_free(swp_entry(swap, offset));
133
134 kfree(ext);
135 }
136}
137
138int swsusp_swap_in_use(void)
139{
140 return (swsusp_extents.rb_node != NULL);
141}
142
41/* 143/*
42 * General things 144 * General things
43 */ 145 */
@@ -336,7 +438,7 @@ static int save_image(struct swap_map_handle *handle,
336 if (ret) 438 if (ret)
337 break; 439 break;
338 if (!(nr_pages % m)) 440 if (!(nr_pages % m))
339 printk("\b\b\b\b%3d%%", nr_pages / m); 441 printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
340 nr_pages++; 442 nr_pages++;
341 } 443 }
342 err2 = wait_on_bio_chain(&bio); 444 err2 = wait_on_bio_chain(&bio);
@@ -344,9 +446,9 @@ static int save_image(struct swap_map_handle *handle,
344 if (!ret) 446 if (!ret)
345 ret = err2; 447 ret = err2;
346 if (!ret) 448 if (!ret)
347 printk("\b\b\b\bdone\n"); 449 printk(KERN_CONT "\b\b\b\bdone\n");
348 else 450 else
349 printk("\n"); 451 printk(KERN_CONT "\n");
350 swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); 452 swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
351 return ret; 453 return ret;
352} 454}
@@ -556,10 +658,6 @@ int swsusp_read(unsigned int *flags_p)
556 struct swsusp_info *header; 658 struct swsusp_info *header;
557 659
558 *flags_p = swsusp_header->flags; 660 *flags_p = swsusp_header->flags;
559 if (IS_ERR(resume_bdev)) {
560 pr_debug("PM: Image device not initialised\n");
561 return PTR_ERR(resume_bdev);
562 }
563 661
564 memset(&snapshot, 0, sizeof(struct snapshot_handle)); 662 memset(&snapshot, 0, sizeof(struct snapshot_handle));
565 error = snapshot_write_next(&snapshot, PAGE_SIZE); 663 error = snapshot_write_next(&snapshot, PAGE_SIZE);