diff options
-rw-r--r-- | include/linux/swap.h | 3 | ||||
-rw-r--r-- | kernel/power/power.h | 2 | ||||
-rw-r--r-- | kernel/power/swap.c | 133 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 10 | ||||
-rw-r--r-- | kernel/power/user.c | 7 | ||||
-rw-r--r-- | mm/page_io.c | 45 | ||||
-rw-r--r-- | mm/swapfile.c | 17 |
7 files changed, 98 insertions, 119 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h index d51e35e4e168..add51cebc8d9 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 */ |
219 | extern int swap_readpage(struct file *, struct page *); | 219 | extern int swap_readpage(struct file *, struct page *); |
220 | extern int swap_writepage(struct page *page, struct writeback_control *wbc); | 220 | extern int swap_writepage(struct page *page, struct writeback_control *wbc); |
221 | extern int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page, | ||
222 | struct bio **bio_chain); | ||
223 | extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err); | 221 | extern 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); | |||
250 | extern int swap_type_of(dev_t, sector_t); | 248 | extern int swap_type_of(dev_t, sector_t); |
251 | extern unsigned int count_swap_pages(int, int); | 249 | extern unsigned int count_swap_pages(int, int); |
252 | extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); | 250 | extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); |
251 | extern sector_t swapdev_block(int, pgoff_t); | ||
253 | extern struct swap_info_struct *get_swap_info_struct(unsigned); | 252 | extern struct swap_info_struct *get_swap_info_struct(unsigned); |
254 | extern int can_share_swap_page(struct page *); | 253 | extern int can_share_swap_page(struct page *); |
255 | extern int remove_exclusive_swap_page(struct page *); | 254 | extern int remove_exclusive_swap_page(struct page *); |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 87ecb1856ee8..210ebba26020 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -146,7 +146,7 @@ struct bitmap_page { | |||
146 | 146 | ||
147 | extern void free_bitmap(struct bitmap_page *bitmap); | 147 | extern void free_bitmap(struct bitmap_page *bitmap); |
148 | extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits); | 148 | extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits); |
149 | extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap); | 149 | extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap); |
150 | extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); | 150 | extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); |
151 | 151 | ||
152 | extern int swsusp_check(void); | 152 | extern int swsusp_check(void); |
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 | ||
36 | static struct swsusp_header { | 36 | static 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 | ||
103 | static int bio_write_page(pgoff_t page_off, void *addr) | 103 | static 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 | ||
108 | static int wait_on_bio_chain(struct bio **bio_chain) | 108 | static 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 | ||
160 | static int mark_swapfiles(swp_entry_t start) | 160 | static 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 | ||
186 | static int swsusp_swap_check(void) /* This is called before saving image */ | 183 | static 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 | ||
204 | static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) | 210 | static 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 | ||
253 | struct swap_map_page { | 249 | struct 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 | ||
263 | struct swap_map_handle { | 259 | struct 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); |
451 | out: | ||
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 | ||
462 | static int get_swap_reader(struct swap_map_handle *handle, | 468 | static 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, | |||
481 | static int swap_read_page(struct swap_map_handle *handle, void *buf, | 488 | static 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 0b66659dc516..4147a756a8c7 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 | ||
137 | unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap) | 137 | sector_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 | ||
151 | void free_all_swap_pages(int swap, struct bitmap_page *bitmap) | 151 | void free_all_swap_pages(int swap, struct bitmap_page *bitmap) |
diff --git a/kernel/power/user.c b/kernel/power/user.c index a327b18a5ffd..f0b7ef8bdd74 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 d4840ecbf8f9..dbffec0d78c9 100644 --- a/mm/page_io.c +++ b/mm/page_io.c | |||
@@ -147,48 +147,3 @@ int swap_readpage(struct file *file, struct page *page) | |||
147 | out: | 147 | out: |
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 | */ | ||
159 | int 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 | } | ||
191 | out: | ||
192 | return ret; | ||
193 | } | ||
194 | #endif | ||
diff --git a/mm/swapfile.c b/mm/swapfile.c index 2bfacbac0f4c..55242363de64 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 | */ | ||
953 | sector_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 | */ |