Jiri Slaby | 8a0d613 | 2010-05-01 23:52:34 +0200 | [diff] [blame] | 1 | /* |
| 2 | * This file provides functions for block I/O operations on swap/file. |
| 3 | * |
| 4 | * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> |
| 5 | * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> |
| 6 | * |
| 7 | * This file is released under the GPLv2. |
| 8 | */ |
| 9 | |
| 10 | #include <linux/bio.h> |
| 11 | #include <linux/kernel.h> |
| 12 | #include <linux/pagemap.h> |
| 13 | #include <linux/swap.h> |
| 14 | |
| 15 | #include "power.h" |
| 16 | |
| 17 | /** |
| 18 | * submit - submit BIO request. |
| 19 | * @rw: READ or WRITE. |
| 20 | * @off physical offset of page. |
| 21 | * @page: page we're reading or writing. |
| 22 | * @bio_chain: list of pending biod (for async reading) |
| 23 | * |
| 24 | * Straight from the textbook - allocate and initialize the bio. |
| 25 | * If we're reading, make sure the page is marked as dirty. |
| 26 | * Then submit it and, if @bio_chain == NULL, wait. |
| 27 | */ |
| 28 | static int submit(int rw, struct block_device *bdev, sector_t sector, |
| 29 | struct page *page, struct bio **bio_chain) |
| 30 | { |
| 31 | const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); |
| 32 | struct bio *bio; |
| 33 | |
| 34 | bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); |
| 35 | bio->bi_sector = sector; |
| 36 | bio->bi_bdev = bdev; |
| 37 | bio->bi_end_io = end_swap_bio_read; |
| 38 | |
| 39 | if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { |
Randy Dunlap | 0fef8b1 | 2010-05-04 00:03:26 +0200 | [diff] [blame] | 40 | printk(KERN_ERR "PM: Adding page to bio failed at %llu\n", |
| 41 | (unsigned long long)sector); |
Jiri Slaby | 8a0d613 | 2010-05-01 23:52:34 +0200 | [diff] [blame] | 42 | bio_put(bio); |
| 43 | return -EFAULT; |
| 44 | } |
| 45 | |
| 46 | lock_page(page); |
| 47 | bio_get(bio); |
| 48 | |
| 49 | if (bio_chain == NULL) { |
| 50 | submit_bio(bio_rw, bio); |
| 51 | wait_on_page_locked(page); |
| 52 | if (rw == READ) |
| 53 | bio_set_pages_dirty(bio); |
| 54 | bio_put(bio); |
| 55 | } else { |
| 56 | if (rw == READ) |
| 57 | get_page(page); /* These pages are freed later */ |
| 58 | bio->bi_private = *bio_chain; |
| 59 | *bio_chain = bio; |
| 60 | submit_bio(bio_rw, bio); |
| 61 | } |
| 62 | return 0; |
| 63 | } |
| 64 | |
| 65 | int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) |
| 66 | { |
| 67 | return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9), |
| 68 | virt_to_page(addr), bio_chain); |
| 69 | } |
| 70 | |
| 71 | int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain) |
| 72 | { |
| 73 | return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9), |
| 74 | virt_to_page(addr), bio_chain); |
| 75 | } |
| 76 | |
| 77 | int hib_wait_on_bio_chain(struct bio **bio_chain) |
| 78 | { |
| 79 | struct bio *bio; |
| 80 | struct bio *next_bio; |
| 81 | int ret = 0; |
| 82 | |
| 83 | if (bio_chain == NULL) |
| 84 | return 0; |
| 85 | |
| 86 | bio = *bio_chain; |
| 87 | if (bio == NULL) |
| 88 | return 0; |
| 89 | while (bio) { |
| 90 | struct page *page; |
| 91 | |
| 92 | next_bio = bio->bi_private; |
| 93 | page = bio->bi_io_vec[0].bv_page; |
| 94 | wait_on_page_locked(page); |
| 95 | if (!PageUptodate(page) || PageError(page)) |
| 96 | ret = -EIO; |
| 97 | put_page(page); |
| 98 | bio_put(bio); |
| 99 | bio = next_bio; |
| 100 | } |
| 101 | *bio_chain = NULL; |
| 102 | return ret; |
| 103 | } |