aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2006-09-26 02:32:42 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:48:58 -0400
commitab954160350c91c77ae03740ef90458c3ad5412c (patch)
tree28f99d765c2c6d497a1f5543b1867875cd6102a5 /kernel/power
parent3a4f7577c9ef393ca80c783f02ffbc125de771c7 (diff)
[PATCH] swsusp: write speedup
Switch the swsusp writeout code from 4k-at-a-time to 4MB-at-a-time. Crufty old PIII testbox: 12.9 MB/s -> 20.9 MB/s Sony Vaio: 14.7 MB/s -> 26.5 MB/s The implementation is crude. A better one would use larger BIOs, but wouldn't gain any performance. The memcpys will be mostly pipelined with the IO and basically come for free. The ENOMEM path has not been tested. It should be. Cc: Pavel Machek <pavel@ucw.cz> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/swap.c93
1 files changed, 75 insertions, 18 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 79b66e734bdb..2dc883d361d5 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -49,18 +49,16 @@ static int mark_swapfiles(swp_entry_t start)
49{ 49{
50 int error; 50 int error;
51 51
52 rw_swap_page_sync(READ, 52 rw_swap_page_sync(READ, swp_entry(root_swap, 0),
53 swp_entry(root_swap, 0), 53 virt_to_page((unsigned long)&swsusp_header), NULL);
54 virt_to_page((unsigned long)&swsusp_header));
55 if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || 54 if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
56 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { 55 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
57 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); 56 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
58 memcpy(swsusp_header.sig,SWSUSP_SIG, 10); 57 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
59 swsusp_header.image = start; 58 swsusp_header.image = start;
60 error = rw_swap_page_sync(WRITE, 59 error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0),
61 swp_entry(root_swap, 0), 60 virt_to_page((unsigned long)&swsusp_header),
62 virt_to_page((unsigned long) 61 NULL);
63 &swsusp_header));
64 } else { 62 } else {
65 pr_debug("swsusp: Partition is not swap space.\n"); 63 pr_debug("swsusp: Partition is not swap space.\n");
66 error = -ENODEV; 64 error = -ENODEV;
@@ -88,16 +86,37 @@ static int swsusp_swap_check(void) /* This is called before saving image */
88 * write_page - Write one page to given swap location. 86 * write_page - Write one page to given swap location.
89 * @buf: Address we're writing. 87 * @buf: Address we're writing.
90 * @offset: Offset of the swap page we're writing to. 88 * @offset: Offset of the swap page we're writing to.
89 * @bio_chain: Link the next write BIO here
91 */ 90 */
92 91
93static int write_page(void *buf, unsigned long offset) 92static int write_page(void *buf, unsigned long offset, struct bio **bio_chain)
94{ 93{
95 swp_entry_t entry; 94 swp_entry_t entry;
96 int error = -ENOSPC; 95 int error = -ENOSPC;
97 96
98 if (offset) { 97 if (offset) {
98 struct page *page = virt_to_page(buf);
99
100 if (bio_chain) {
101 /*
102 * Whether or not we successfully allocated a copy page,
103 * we take a ref on the page here. It gets undone in
104 * wait_on_bio_chain().
105 */
106 struct page *page_copy;
107 page_copy = alloc_page(GFP_ATOMIC);
108 if (page_copy == NULL) {
109 WARN_ON_ONCE(1);
110 bio_chain = NULL; /* Go synchronous */
111 get_page(page);
112 } else {
113 memcpy(page_address(page_copy),
114 page_address(page), PAGE_SIZE);
115 page = page_copy;
116 }
117 }
99 entry = swp_entry(root_swap, offset); 118 entry = swp_entry(root_swap, offset);
100 error = rw_swap_page_sync(WRITE, entry, virt_to_page(buf)); 119 error = rw_swap_page_sync(WRITE, entry, page, bio_chain);
101 } 120 }
102 return error; 121 return error;
103} 122}
@@ -185,37 +204,68 @@ static int get_swap_writer(struct swap_map_handle *handle)
185 return 0; 204 return 0;
186} 205}
187 206
188static int swap_write_page(struct swap_map_handle *handle, void *buf) 207static int wait_on_bio_chain(struct bio **bio_chain)
189{ 208{
190 int error; 209 struct bio *bio;
210 struct bio *next_bio;
211 int ret = 0;
212
213 if (bio_chain == NULL)
214 return 0;
215
216 bio = *bio_chain;
217 while (bio) {
218 struct page *page;
219
220 next_bio = bio->bi_private;
221 page = bio->bi_io_vec[0].bv_page;
222 wait_on_page_locked(page);
223 if (!PageUptodate(page) || PageError(page))
224 ret = -EIO;
225 put_page(page);
226 bio_put(bio);
227 bio = next_bio;
228 }
229 *bio_chain = NULL;
230 return ret;
231}
232
233static int swap_write_page(struct swap_map_handle *handle, void *buf,
234 struct bio **bio_chain)
235{
236 int error = 0;
191 unsigned long offset; 237 unsigned long offset;
192 238
193 if (!handle->cur) 239 if (!handle->cur)
194 return -EINVAL; 240 return -EINVAL;
195 offset = alloc_swap_page(root_swap, handle->bitmap); 241 offset = alloc_swap_page(root_swap, handle->bitmap);
196 error = write_page(buf, offset); 242 error = write_page(buf, offset, bio_chain);
197 if (error) 243 if (error)
198 return error; 244 return error;
199 handle->cur->entries[handle->k++] = offset; 245 handle->cur->entries[handle->k++] = offset;
200 if (handle->k >= MAP_PAGE_ENTRIES) { 246 if (handle->k >= MAP_PAGE_ENTRIES) {
247 error = wait_on_bio_chain(bio_chain);
248 if (error)
249 goto out;
201 offset = alloc_swap_page(root_swap, handle->bitmap); 250 offset = alloc_swap_page(root_swap, handle->bitmap);
202 if (!offset) 251 if (!offset)
203 return -ENOSPC; 252 return -ENOSPC;
204 handle->cur->next_swap = offset; 253 handle->cur->next_swap = offset;
205 error = write_page(handle->cur, handle->cur_swap); 254 error = write_page(handle->cur, handle->cur_swap, NULL);
206 if (error) 255 if (error)
207 return error; 256 goto out;
208 memset(handle->cur, 0, PAGE_SIZE); 257 memset(handle->cur, 0, PAGE_SIZE);
209 handle->cur_swap = offset; 258 handle->cur_swap = offset;
210 handle->k = 0; 259 handle->k = 0;
211 } 260 }
212 return 0; 261out:
262 return error;
213} 263}
214 264
215static int flush_swap_writer(struct swap_map_handle *handle) 265static int flush_swap_writer(struct swap_map_handle *handle)
216{ 266{
217 if (handle->cur && handle->cur_swap) 267 if (handle->cur && handle->cur_swap)
218 return write_page(handle->cur, handle->cur_swap); 268 return write_page(handle->cur, handle->cur_swap, NULL);
219 else 269 else
220 return -EINVAL; 270 return -EINVAL;
221} 271}
@@ -232,6 +282,8 @@ static int save_image(struct swap_map_handle *handle,
232 int ret; 282 int ret;
233 int error = 0; 283 int error = 0;
234 int nr_pages; 284 int nr_pages;
285 int err2;
286 struct bio *bio;
235 struct timeval start; 287 struct timeval start;
236 struct timeval stop; 288 struct timeval stop;
237 289
@@ -240,11 +292,13 @@ static int save_image(struct swap_map_handle *handle,
240 if (!m) 292 if (!m)
241 m = 1; 293 m = 1;
242 nr_pages = 0; 294 nr_pages = 0;
295 bio = NULL;
243 do_gettimeofday(&start); 296 do_gettimeofday(&start);
244 do { 297 do {
245 ret = snapshot_read_next(snapshot, PAGE_SIZE); 298 ret = snapshot_read_next(snapshot, PAGE_SIZE);
246 if (ret > 0) { 299 if (ret > 0) {
247 error = swap_write_page(handle, data_of(*snapshot)); 300 error = swap_write_page(handle, data_of(*snapshot),
301 &bio);
248 if (error) 302 if (error)
249 break; 303 break;
250 if (!(nr_pages % m)) 304 if (!(nr_pages % m))
@@ -252,8 +306,11 @@ static int save_image(struct swap_map_handle *handle,
252 nr_pages++; 306 nr_pages++;
253 } 307 }
254 } while (ret > 0); 308 } while (ret > 0);
309 err2 = wait_on_bio_chain(&bio);
255 do_gettimeofday(&stop); 310 do_gettimeofday(&stop);
256 if (!error) 311 if (!error)
312 error = err2;
313 if (!error)
257 printk("\b\b\b\bdone\n"); 314 printk("\b\b\b\bdone\n");
258 show_speed(&start, &stop, nr_to_write, "Wrote"); 315 show_speed(&start, &stop, nr_to_write, "Wrote");
259 return error; 316 return error;
@@ -307,7 +364,7 @@ int swsusp_write(void)
307 error = get_swap_writer(&handle); 364 error = get_swap_writer(&handle);
308 if (!error) { 365 if (!error) {
309 unsigned long start = handle.cur_swap; 366 unsigned long start = handle.cur_swap;
310 error = swap_write_page(&handle, header); 367 error = swap_write_page(&handle, header, NULL);
311 if (!error) 368 if (!error)
312 error = save_image(&handle, &snapshot, 369 error = save_image(&handle, &snapshot,
313 header->pages - 1); 370 header->pages - 1);