aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/power.h27
-rw-r--r--kernel/power/swap.c18
-rw-r--r--kernel/power/swsusp.c137
-rw-r--r--kernel/power/user.c22
4 files changed, 86 insertions, 118 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h
index a64d3f22de97..a3e47cbdaf31 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -143,30 +143,9 @@ struct resume_swap_area {
143/* If unset, the snapshot device cannot be open. */ 143/* If unset, the snapshot device cannot be open. */
144extern atomic_t snapshot_device_available; 144extern atomic_t snapshot_device_available;
145 145
146/** 146extern sector_t alloc_swapdev_block(int swap);
147 * The bitmap is used for tracing allocated swap pages 147extern void free_all_swap_pages(int swap);
148 * 148extern int swsusp_swap_in_use(void);
149 * The entire bitmap consists of a number of bitmap_page
150 * structures linked with the help of the .next member.
151 * Thus each page can be allocated individually, so we only
152 * need to make 0-order memory allocations to create
153 * the bitmap.
154 */
155
156#define BITMAP_PAGE_SIZE (PAGE_SIZE - sizeof(void *))
157#define BITMAP_PAGE_CHUNKS (BITMAP_PAGE_SIZE / sizeof(long))
158#define BITS_PER_CHUNK (sizeof(long) * 8)
159#define BITMAP_PAGE_BITS (BITMAP_PAGE_CHUNKS * BITS_PER_CHUNK)
160
161struct bitmap_page {
162 unsigned long chunks[BITMAP_PAGE_CHUNKS];
163 struct bitmap_page *next;
164};
165
166extern void free_bitmap(struct bitmap_page *bitmap);
167extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
168extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap);
169extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
170 149
171extern int swsusp_check(void); 150extern int swsusp_check(void);
172extern int swsusp_shrink_memory(void); 151extern int swsusp_shrink_memory(void);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index b18c155cbb60..e83ed9945a80 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -243,7 +243,6 @@ struct swap_map_page {
243struct swap_map_handle { 243struct swap_map_handle {
244 struct swap_map_page *cur; 244 struct swap_map_page *cur;
245 sector_t cur_swap; 245 sector_t cur_swap;
246 struct bitmap_page *bitmap;
247 unsigned int k; 246 unsigned int k;
248}; 247};
249 248
@@ -252,9 +251,6 @@ static void release_swap_writer(struct swap_map_handle *handle)
252 if (handle->cur) 251 if (handle->cur)
253 free_page((unsigned long)handle->cur); 252 free_page((unsigned long)handle->cur);
254 handle->cur = NULL; 253 handle->cur = NULL;
255 if (handle->bitmap)
256 free_bitmap(handle->bitmap);
257 handle->bitmap = NULL;
258} 254}
259 255
260static int get_swap_writer(struct swap_map_handle *handle) 256static int get_swap_writer(struct swap_map_handle *handle)
@@ -262,12 +258,7 @@ static int get_swap_writer(struct swap_map_handle *handle)
262 handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL); 258 handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
263 if (!handle->cur) 259 if (!handle->cur)
264 return -ENOMEM; 260 return -ENOMEM;
265 handle->bitmap = alloc_bitmap(count_swap_pages(root_swap, 0)); 261 handle->cur_swap = alloc_swapdev_block(root_swap);
266 if (!handle->bitmap) {
267 release_swap_writer(handle);
268 return -ENOMEM;
269 }
270 handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap);
271 if (!handle->cur_swap) { 262 if (!handle->cur_swap) {
272 release_swap_writer(handle); 263 release_swap_writer(handle);
273 return -ENOSPC; 264 return -ENOSPC;
@@ -284,7 +275,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
284 275
285 if (!handle->cur) 276 if (!handle->cur)
286 return -EINVAL; 277 return -EINVAL;
287 offset = alloc_swapdev_block(root_swap, handle->bitmap); 278 offset = alloc_swapdev_block(root_swap);
288 error = write_page(buf, offset, bio_chain); 279 error = write_page(buf, offset, bio_chain);
289 if (error) 280 if (error)
290 return error; 281 return error;
@@ -293,7 +284,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
293 error = wait_on_bio_chain(bio_chain); 284 error = wait_on_bio_chain(bio_chain);
294 if (error) 285 if (error)
295 goto out; 286 goto out;
296 offset = alloc_swapdev_block(root_swap, handle->bitmap); 287 offset = alloc_swapdev_block(root_swap);
297 if (!offset) 288 if (!offset)
298 return -ENOSPC; 289 return -ENOSPC;
299 handle->cur->next_swap = offset; 290 handle->cur->next_swap = offset;
@@ -430,7 +421,8 @@ int swsusp_write(void)
430 } 421 }
431 } 422 }
432 if (error) 423 if (error)
433 free_all_swap_pages(root_swap, handle.bitmap); 424 free_all_swap_pages(root_swap);
425
434 release_swap_writer(&handle); 426 release_swap_writer(&handle);
435 out: 427 out:
436 swsusp_close(); 428 swsusp_close();
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 175370824f37..1109023d8358 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -50,6 +50,7 @@
50#include <linux/syscalls.h> 50#include <linux/syscalls.h>
51#include <linux/highmem.h> 51#include <linux/highmem.h>
52#include <linux/time.h> 52#include <linux/time.h>
53#include <linux/rbtree.h>
53 54
54#include "power.h" 55#include "power.h"
55 56
@@ -74,72 +75,69 @@ static inline unsigned int count_highmem_pages(void) { return 0; }
74/** 75/**
75 * The following functions are used for tracing the allocated 76 * The following functions are used for tracing the allocated
76 * swap pages, so that they can be freed in case of an error. 77 * swap pages, so that they can be freed in case of an error.
77 *
78 * The functions operate on a linked bitmap structure defined
79 * in power.h
80 */ 78 */
81 79
82void free_bitmap(struct bitmap_page *bitmap) 80struct swsusp_extent {
83{ 81 struct rb_node node;
84 struct bitmap_page *bp; 82 unsigned long start;
83 unsigned long end;
84};
85 85
86 while (bitmap) { 86static struct rb_root swsusp_extents = RB_ROOT;
87 bp = bitmap->next;
88 free_page((unsigned long)bitmap);
89 bitmap = bp;
90 }
91}
92 87
93struct bitmap_page *alloc_bitmap(unsigned int nr_bits) 88static int swsusp_extents_insert(unsigned long swap_offset)
94{ 89{
95 struct bitmap_page *bitmap, *bp; 90 struct rb_node **new = &(swsusp_extents.rb_node);
96 unsigned int n; 91 struct rb_node *parent = NULL;
97 92 struct swsusp_extent *ext;
98 if (!nr_bits) 93
99 return NULL; 94 /* Figure out where to put the new node */
100 95 while (*new) {
101 bitmap = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL); 96 ext = container_of(*new, struct swsusp_extent, node);
102 bp = bitmap; 97 parent = *new;
103 for (n = BITMAP_PAGE_BITS; n < nr_bits; n += BITMAP_PAGE_BITS) { 98 if (swap_offset < ext->start) {
104 bp->next = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL); 99 /* Try to merge */
105 bp = bp->next; 100 if (swap_offset == ext->start - 1) {
106 if (!bp) { 101 ext->start--;
107 free_bitmap(bitmap); 102 return 0;
108 return NULL; 103 }
104 new = &((*new)->rb_left);
105 } else if (swap_offset > ext->end) {
106 /* Try to merge */
107 if (swap_offset == ext->end + 1) {
108 ext->end++;
109 return 0;
110 }
111 new = &((*new)->rb_right);
112 } else {
113 /* It already is in the tree */
114 return -EINVAL;
109 } 115 }
110 } 116 }
111 return bitmap; 117 /* Add the new node and rebalance the tree. */
112} 118 ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
113 119 if (!ext)
114static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit) 120 return -ENOMEM;
115{ 121
116 unsigned int n; 122 ext->start = swap_offset;
117 123 ext->end = swap_offset;
118 n = BITMAP_PAGE_BITS; 124 rb_link_node(&ext->node, parent, new);
119 while (bitmap && n <= bit) { 125 rb_insert_color(&ext->node, &swsusp_extents);
120 n += BITMAP_PAGE_BITS;
121 bitmap = bitmap->next;
122 }
123 if (!bitmap)
124 return -EINVAL;
125 n -= BITMAP_PAGE_BITS;
126 bit -= n;
127 n = 0;
128 while (bit >= BITS_PER_CHUNK) {
129 bit -= BITS_PER_CHUNK;
130 n++;
131 }
132 bitmap->chunks[n] |= (1UL << bit);
133 return 0; 126 return 0;
134} 127}
135 128
136sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap) 129/**
130 * alloc_swapdev_block - allocate a swap page and register that it has
131 * been allocated, so that it can be freed in case of an error.
132 */
133
134sector_t alloc_swapdev_block(int swap)
137{ 135{
138 unsigned long offset; 136 unsigned long offset;
139 137
140 offset = swp_offset(get_swap_page_of_type(swap)); 138 offset = swp_offset(get_swap_page_of_type(swap));
141 if (offset) { 139 if (offset) {
142 if (bitmap_set(bitmap, offset)) 140 if (swsusp_extents_insert(offset))
143 swap_free(swp_entry(swap, offset)); 141 swap_free(swp_entry(swap, offset));
144 else 142 else
145 return swapdev_block(swap, offset); 143 return swapdev_block(swap, offset);
@@ -147,23 +145,34 @@ sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
147 return 0; 145 return 0;
148} 146}
149 147
150void free_all_swap_pages(int swap, struct bitmap_page *bitmap) 148/**
149 * free_all_swap_pages - free swap pages allocated for saving image data.
150 * It also frees the extents used to register which swap entres had been
151 * allocated.
152 */
153
154void free_all_swap_pages(int swap)
151{ 155{
152 unsigned int bit, n; 156 struct rb_node *node;
153 unsigned long test; 157
154 158 while ((node = swsusp_extents.rb_node)) {
155 bit = 0; 159 struct swsusp_extent *ext;
156 while (bitmap) { 160 unsigned long offset;
157 for (n = 0; n < BITMAP_PAGE_CHUNKS; n++) 161
158 for (test = 1UL; test; test <<= 1) { 162 ext = container_of(node, struct swsusp_extent, node);
159 if (bitmap->chunks[n] & test) 163 rb_erase(node, &swsusp_extents);
160 swap_free(swp_entry(swap, bit)); 164 for (offset = ext->start; offset <= ext->end; offset++)
161 bit++; 165 swap_free(swp_entry(swap, offset));
162 } 166
163 bitmap = bitmap->next; 167 kfree(ext);
164 } 168 }
165} 169}
166 170
171int swsusp_swap_in_use(void)
172{
173 return (swsusp_extents.rb_node != NULL);
174}
175
167/** 176/**
168 * swsusp_show_speed - print the time elapsed between two events represented by 177 * swsusp_show_speed - print the time elapsed between two events represented by
169 * @start and @stop 178 * @start and @stop
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 72dbfd01408e..ad4e10208cde 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -33,7 +33,6 @@
33static struct snapshot_data { 33static struct snapshot_data {
34 struct snapshot_handle handle; 34 struct snapshot_handle handle;
35 int swap; 35 int swap;
36 struct bitmap_page *bitmap;
37 int mode; 36 int mode;
38 char frozen; 37 char frozen;
39 char ready; 38 char ready;
@@ -69,7 +68,6 @@ static int snapshot_open(struct inode *inode, struct file *filp)
69 data->swap = -1; 68 data->swap = -1;
70 data->mode = O_WRONLY; 69 data->mode = O_WRONLY;
71 } 70 }
72 data->bitmap = NULL;
73 data->frozen = 0; 71 data->frozen = 0;
74 data->ready = 0; 72 data->ready = 0;
75 data->platform_suspend = 0; 73 data->platform_suspend = 0;
@@ -84,8 +82,7 @@ static int snapshot_release(struct inode *inode, struct file *filp)
84 swsusp_free(); 82 swsusp_free();
85 free_basic_memory_bitmaps(); 83 free_basic_memory_bitmaps();
86 data = filp->private_data; 84 data = filp->private_data;
87 free_all_swap_pages(data->swap, data->bitmap); 85 free_all_swap_pages(data->swap);
88 free_bitmap(data->bitmap);
89 if (data->frozen) { 86 if (data->frozen) {
90 mutex_lock(&pm_mutex); 87 mutex_lock(&pm_mutex);
91 thaw_processes(); 88 thaw_processes();
@@ -300,14 +297,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
300 error = -ENODEV; 297 error = -ENODEV;
301 break; 298 break;
302 } 299 }
303 if (!data->bitmap) { 300 offset = alloc_swapdev_block(data->swap);
304 data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0));
305 if (!data->bitmap) {
306 error = -ENOMEM;
307 break;
308 }
309 }
310 offset = alloc_swapdev_block(data->swap, data->bitmap);
311 if (offset) { 301 if (offset) {
312 offset <<= PAGE_SHIFT; 302 offset <<= PAGE_SHIFT;
313 error = put_user(offset, (sector_t __user *)arg); 303 error = put_user(offset, (sector_t __user *)arg);
@@ -321,13 +311,11 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
321 error = -ENODEV; 311 error = -ENODEV;
322 break; 312 break;
323 } 313 }
324 free_all_swap_pages(data->swap, data->bitmap); 314 free_all_swap_pages(data->swap);
325 free_bitmap(data->bitmap);
326 data->bitmap = NULL;
327 break; 315 break;
328 316
329 case SNAPSHOT_SET_SWAP_FILE: 317 case SNAPSHOT_SET_SWAP_FILE:
330 if (!data->bitmap) { 318 if (!swsusp_swap_in_use()) {
331 /* 319 /*
332 * User space encodes device types as two-byte values, 320 * User space encodes device types as two-byte values,
333 * so we need to recode them 321 * so we need to recode them
@@ -426,7 +414,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
426 break; 414 break;
427 415
428 case SNAPSHOT_SET_SWAP_AREA: 416 case SNAPSHOT_SET_SWAP_AREA:
429 if (data->bitmap) { 417 if (swsusp_swap_in_use()) {
430 error = -EPERM; 418 error = -EPERM;
431 } else { 419 } else {
432 struct resume_swap_area swap_area; 420 struct resume_swap_area swap_area;