diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/swap.c | 221 |
1 files changed, 112 insertions, 109 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 7b10da16389e..7768c2ba7550 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -41,10 +41,121 @@ static struct swsusp_header { | |||
41 | } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; | 41 | } __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Saving part... | 44 | * General things |
45 | */ | 45 | */ |
46 | 46 | ||
47 | static unsigned short root_swap = 0xffff; | 47 | static unsigned short root_swap = 0xffff; |
48 | static struct block_device *resume_bdev; | ||
49 | |||
50 | /** | ||
51 | * submit - submit BIO request. | ||
52 | * @rw: READ or WRITE. | ||
53 | * @off physical offset of page. | ||
54 | * @page: page we're reading or writing. | ||
55 | * @bio_chain: list of pending biod (for async reading) | ||
56 | * | ||
57 | * Straight from the textbook - allocate and initialize the bio. | ||
58 | * If we're reading, make sure the page is marked as dirty. | ||
59 | * Then submit it and, if @bio_chain == NULL, wait. | ||
60 | */ | ||
61 | static int submit(int rw, pgoff_t page_off, struct page *page, | ||
62 | struct bio **bio_chain) | ||
63 | { | ||
64 | struct bio *bio; | ||
65 | |||
66 | bio = bio_alloc(GFP_ATOMIC, 1); | ||
67 | if (!bio) | ||
68 | return -ENOMEM; | ||
69 | bio->bi_sector = page_off * (PAGE_SIZE >> 9); | ||
70 | bio->bi_bdev = resume_bdev; | ||
71 | bio->bi_end_io = end_swap_bio_read; | ||
72 | |||
73 | if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { | ||
74 | printk("swsusp: ERROR: adding page to bio at %ld\n", page_off); | ||
75 | bio_put(bio); | ||
76 | return -EFAULT; | ||
77 | } | ||
78 | |||
79 | lock_page(page); | ||
80 | bio_get(bio); | ||
81 | |||
82 | if (bio_chain == NULL) { | ||
83 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
84 | wait_on_page_locked(page); | ||
85 | if (rw == READ) | ||
86 | bio_set_pages_dirty(bio); | ||
87 | bio_put(bio); | ||
88 | } else { | ||
89 | if (rw == READ) | ||
90 | get_page(page); /* These pages are freed later */ | ||
91 | bio->bi_private = *bio_chain; | ||
92 | *bio_chain = bio; | ||
93 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) | ||
99 | { | ||
100 | return submit(READ, page_off, virt_to_page(addr), bio_chain); | ||
101 | } | ||
102 | |||
103 | static int bio_write_page(pgoff_t page_off, void *addr) | ||
104 | { | ||
105 | return submit(WRITE, page_off, virt_to_page(addr), NULL); | ||
106 | } | ||
107 | |||
108 | static int wait_on_bio_chain(struct bio **bio_chain) | ||
109 | { | ||
110 | struct bio *bio; | ||
111 | struct bio *next_bio; | ||
112 | int ret = 0; | ||
113 | |||
114 | if (bio_chain == NULL) | ||
115 | return 0; | ||
116 | |||
117 | bio = *bio_chain; | ||
118 | if (bio == NULL) | ||
119 | return 0; | ||
120 | while (bio) { | ||
121 | struct page *page; | ||
122 | |||
123 | next_bio = bio->bi_private; | ||
124 | page = bio->bi_io_vec[0].bv_page; | ||
125 | wait_on_page_locked(page); | ||
126 | if (!PageUptodate(page) || PageError(page)) | ||
127 | ret = -EIO; | ||
128 | put_page(page); | ||
129 | bio_put(bio); | ||
130 | bio = next_bio; | ||
131 | } | ||
132 | *bio_chain = NULL; | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static void show_speed(struct timeval *start, struct timeval *stop, | ||
137 | unsigned nr_pages, char *msg) | ||
138 | { | ||
139 | s64 elapsed_centisecs64; | ||
140 | int centisecs; | ||
141 | int k; | ||
142 | int kps; | ||
143 | |||
144 | elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); | ||
145 | do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); | ||
146 | centisecs = elapsed_centisecs64; | ||
147 | if (centisecs == 0) | ||
148 | centisecs = 1; /* avoid div-by-zero */ | ||
149 | k = nr_pages * (PAGE_SIZE / 1024); | ||
150 | kps = (k * 100) / centisecs; | ||
151 | printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k, | ||
152 | centisecs / 100, centisecs % 100, | ||
153 | kps / 1000, (kps % 1000) / 10); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Saving part | ||
158 | */ | ||
48 | 159 | ||
49 | static int mark_swapfiles(swp_entry_t start) | 160 | static int mark_swapfiles(swp_entry_t start) |
50 | { | 161 | { |
@@ -166,26 +277,6 @@ static void release_swap_writer(struct swap_map_handle *handle) | |||
166 | handle->bitmap = NULL; | 277 | handle->bitmap = NULL; |
167 | } | 278 | } |
168 | 279 | ||
169 | static void show_speed(struct timeval *start, struct timeval *stop, | ||
170 | unsigned nr_pages, char *msg) | ||
171 | { | ||
172 | s64 elapsed_centisecs64; | ||
173 | int centisecs; | ||
174 | int k; | ||
175 | int kps; | ||
176 | |||
177 | elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); | ||
178 | do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); | ||
179 | centisecs = elapsed_centisecs64; | ||
180 | if (centisecs == 0) | ||
181 | centisecs = 1; /* avoid div-by-zero */ | ||
182 | k = nr_pages * (PAGE_SIZE / 1024); | ||
183 | kps = (k * 100) / centisecs; | ||
184 | printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k, | ||
185 | centisecs / 100, centisecs % 100, | ||
186 | kps / 1000, (kps % 1000) / 10); | ||
187 | } | ||
188 | |||
189 | static int get_swap_writer(struct swap_map_handle *handle) | 280 | static int get_swap_writer(struct swap_map_handle *handle) |
190 | { | 281 | { |
191 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL); | 282 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL); |
@@ -205,34 +296,6 @@ static int get_swap_writer(struct swap_map_handle *handle) | |||
205 | return 0; | 296 | return 0; |
206 | } | 297 | } |
207 | 298 | ||
208 | static int wait_on_bio_chain(struct bio **bio_chain) | ||
209 | { | ||
210 | struct bio *bio; | ||
211 | struct bio *next_bio; | ||
212 | int ret = 0; | ||
213 | |||
214 | if (bio_chain == NULL) | ||
215 | return 0; | ||
216 | |||
217 | bio = *bio_chain; | ||
218 | if (bio == NULL) | ||
219 | return 0; | ||
220 | while (bio) { | ||
221 | struct page *page; | ||
222 | |||
223 | next_bio = bio->bi_private; | ||
224 | page = bio->bi_io_vec[0].bv_page; | ||
225 | wait_on_page_locked(page); | ||
226 | if (!PageUptodate(page) || PageError(page)) | ||
227 | ret = -EIO; | ||
228 | put_page(page); | ||
229 | bio_put(bio); | ||
230 | bio = next_bio; | ||
231 | } | ||
232 | *bio_chain = NULL; | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static int swap_write_page(struct swap_map_handle *handle, void *buf, | 299 | static int swap_write_page(struct swap_map_handle *handle, void *buf, |
237 | struct bio **bio_chain) | 300 | struct bio **bio_chain) |
238 | { | 301 | { |
@@ -384,66 +447,6 @@ int swsusp_write(void) | |||
384 | return error; | 447 | return error; |
385 | } | 448 | } |
386 | 449 | ||
387 | static struct block_device *resume_bdev; | ||
388 | |||
389 | /** | ||
390 | * submit - submit BIO request. | ||
391 | * @rw: READ or WRITE. | ||
392 | * @off physical offset of page. | ||
393 | * @page: page we're reading or writing. | ||
394 | * @bio_chain: list of pending biod (for async reading) | ||
395 | * | ||
396 | * Straight from the textbook - allocate and initialize the bio. | ||
397 | * If we're reading, make sure the page is marked as dirty. | ||
398 | * Then submit it and, if @bio_chain == NULL, wait. | ||
399 | */ | ||
400 | static int submit(int rw, pgoff_t page_off, struct page *page, | ||
401 | struct bio **bio_chain) | ||
402 | { | ||
403 | struct bio *bio; | ||
404 | |||
405 | bio = bio_alloc(GFP_ATOMIC, 1); | ||
406 | if (!bio) | ||
407 | return -ENOMEM; | ||
408 | bio->bi_sector = page_off * (PAGE_SIZE >> 9); | ||
409 | bio->bi_bdev = resume_bdev; | ||
410 | bio->bi_end_io = end_swap_bio_read; | ||
411 | |||
412 | if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { | ||
413 | printk("swsusp: ERROR: adding page to bio at %ld\n", page_off); | ||
414 | bio_put(bio); | ||
415 | return -EFAULT; | ||
416 | } | ||
417 | |||
418 | lock_page(page); | ||
419 | bio_get(bio); | ||
420 | |||
421 | if (bio_chain == NULL) { | ||
422 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
423 | wait_on_page_locked(page); | ||
424 | if (rw == READ) | ||
425 | bio_set_pages_dirty(bio); | ||
426 | bio_put(bio); | ||
427 | } else { | ||
428 | if (rw == READ) | ||
429 | get_page(page); /* These pages are freed later */ | ||
430 | bio->bi_private = *bio_chain; | ||
431 | *bio_chain = bio; | ||
432 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
433 | } | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) | ||
438 | { | ||
439 | return submit(READ, page_off, virt_to_page(addr), bio_chain); | ||
440 | } | ||
441 | |||
442 | static int bio_write_page(pgoff_t page_off, void *addr) | ||
443 | { | ||
444 | return submit(WRITE, page_off, virt_to_page(addr), NULL); | ||
445 | } | ||
446 | |||
447 | /** | 450 | /** |
448 | * The following functions allow us to read data using a swap map | 451 | * The following functions allow us to read data using a swap map |
449 | * in a file-alike way | 452 | * in a file-alike way |