aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/swap.h3
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/swap.c133
-rw-r--r--kernel/power/swsusp.c10
-rw-r--r--kernel/power/user.c7
-rw-r--r--mm/page_io.c45
-rw-r--r--mm/swapfile.c17
7 files changed, 98 insertions, 119 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d51e35e4e16..add51cebc8d 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -218,8 +218,6 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
218/* linux/mm/page_io.c */ 218/* linux/mm/page_io.c */
219extern int swap_readpage(struct file *, struct page *); 219extern int swap_readpage(struct file *, struct page *);
220extern int swap_writepage(struct page *page, struct writeback_control *wbc); 220extern int swap_writepage(struct page *page, struct writeback_control *wbc);
221extern int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page,
222 struct bio **bio_chain);
223extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err); 221extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err);
224 222
225/* linux/mm/swap_state.c */ 223/* linux/mm/swap_state.c */
@@ -250,6 +248,7 @@ extern void free_swap_and_cache(swp_entry_t);
250extern int swap_type_of(dev_t, sector_t); 248extern int swap_type_of(dev_t, sector_t);
251extern unsigned int count_swap_pages(int, int); 249extern unsigned int count_swap_pages(int, int);
252extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); 250extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t);
251extern sector_t swapdev_block(int, pgoff_t);
253extern struct swap_info_struct *get_swap_info_struct(unsigned); 252extern struct swap_info_struct *get_swap_info_struct(unsigned);
254extern int can_share_swap_page(struct page *); 253extern int can_share_swap_page(struct page *);
255extern int remove_exclusive_swap_page(struct page *); 254extern int remove_exclusive_swap_page(struct page *);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 87ecb1856ee..210ebba2602 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -146,7 +146,7 @@ struct bitmap_page {
146 146
147extern void free_bitmap(struct bitmap_page *bitmap); 147extern void free_bitmap(struct bitmap_page *bitmap);
148extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits); 148extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
149extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap); 149extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap);
150extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); 150extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
151 151
152extern int swsusp_check(void); 152extern int swsusp_check(void);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 7768c2ba755..1b08f46bbb7 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 }
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 0b66659dc51..4147a756a8c 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -134,18 +134,18 @@ static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit)
134 return 0; 134 return 0;
135} 135}
136 136
137unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap) 137sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
138{ 138{
139 unsigned long offset; 139 unsigned long offset;
140 140
141 offset = swp_offset(get_swap_page_of_type(swap)); 141 offset = swp_offset(get_swap_page_of_type(swap));
142 if (offset) { 142 if (offset) {
143 if (bitmap_set(bitmap, offset)) { 143 if (bitmap_set(bitmap, offset))
144 swap_free(swp_entry(swap, offset)); 144 swap_free(swp_entry(swap, offset));
145 offset = 0; 145 else
146 } 146 return swapdev_block(swap, offset);
147 } 147 }
148 return offset; 148 return 0;
149} 149}
150 150
151void free_all_swap_pages(int swap, struct bitmap_page *bitmap) 151void free_all_swap_pages(int swap, struct bitmap_page *bitmap)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index a327b18a5ff..f0b7ef8bdd7 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -126,7 +126,8 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
126{ 126{
127 int error = 0; 127 int error = 0;
128 struct snapshot_data *data; 128 struct snapshot_data *data;
129 loff_t offset, avail; 129 loff_t avail;
130 sector_t offset;
130 131
131 if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) 132 if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
132 return -ENOTTY; 133 return -ENOTTY;
@@ -240,10 +241,10 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
240 break; 241 break;
241 } 242 }
242 } 243 }
243 offset = alloc_swap_page(data->swap, data->bitmap); 244 offset = alloc_swapdev_block(data->swap, data->bitmap);
244 if (offset) { 245 if (offset) {
245 offset <<= PAGE_SHIFT; 246 offset <<= PAGE_SHIFT;
246 error = put_user(offset, (loff_t __user *)arg); 247 error = put_user(offset, (sector_t __user *)arg);
247 } else { 248 } else {
248 error = -ENOSPC; 249 error = -ENOSPC;
249 } 250 }
diff --git a/mm/page_io.c b/mm/page_io.c
index d4840ecbf8f..dbffec0d78c 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -147,48 +147,3 @@ int swap_readpage(struct file *file, struct page *page)
147out: 147out:
148 return ret; 148 return ret;
149} 149}
150
151#ifdef CONFIG_SOFTWARE_SUSPEND
152/*
153 * A scruffy utility function to read or write an arbitrary swap page
154 * and wait on the I/O. The caller must have a ref on the page.
155 *
156 * We use end_swap_bio_read() even for writes, because it happens to do what
157 * we want.
158 */
159int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page,
160 struct bio **bio_chain)
161{
162 struct bio *bio;
163 int ret = 0;
164 int bio_rw;
165
166 lock_page(page);
167
168 bio = get_swap_bio(GFP_KERNEL, entry.val, page, end_swap_bio_read);
169 if (bio == NULL) {
170 unlock_page(page);
171 ret = -ENOMEM;
172 goto out;
173 }
174
175 bio_rw = rw;
176 if (!bio_chain)
177 bio_rw |= (1 << BIO_RW_SYNC);
178 if (bio_chain)
179 bio_get(bio);
180 submit_bio(bio_rw, bio);
181 if (bio_chain == NULL) {
182 wait_on_page_locked(page);
183
184 if (!PageUptodate(page) || PageError(page))
185 ret = -EIO;
186 }
187 if (bio_chain) {
188 bio->bi_private = *bio_chain;
189 *bio_chain = bio;
190 }
191out:
192 return ret;
193}
194#endif
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 2bfacbac0f4..55242363de6 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -945,6 +945,23 @@ sector_t map_swap_page(struct swap_info_struct *sis, pgoff_t offset)
945 } 945 }
946} 946}
947 947
948#ifdef CONFIG_SOFTWARE_SUSPEND
949/*
950 * Get the (PAGE_SIZE) block corresponding to given offset on the swapdev
951 * corresponding to given index in swap_info (swap type).
952 */
953sector_t swapdev_block(int swap_type, pgoff_t offset)
954{
955 struct swap_info_struct *sis;
956
957 if (swap_type >= nr_swapfiles)
958 return 0;
959
960 sis = swap_info + swap_type;
961 return (sis->flags & SWP_WRITEOK) ? map_swap_page(sis, offset) : 0;
962}
963#endif /* CONFIG_SOFTWARE_SUSPEND */
964
948/* 965/*
949 * Free all of a swapdev's extent information 966 * Free all of a swapdev's extent information
950 */ 967 */