aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-12-06 23:34:10 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:27 -0500
commit3aef83e0ef1ffb8ea3bea97be46821a45c952173 (patch)
treef73878eb2ecce804c9eea6fbb13603907b3674b4
parent3fc6b34f4803b959c1e30c15247e2180cd529115 (diff)
[PATCH] swsusp: use block device offsets to identify swap locations
Make swsusp use block device offsets instead of swap offsets to identify swap locations and make it use the same code paths for writing as well as for reading data. This allows us to use the same code for handling swap files and swap partitions and to simplify the code, eg. by dropping rw_swap_page_sync(). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-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 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 */
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 87ecb1856ee8..210ebba26020 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 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
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 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
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 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)
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 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 */
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 */