Commit | Line | Data |
---|---|---|
8a0d613f JS |
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 | { | |
721a9602 | 31 | const int bio_rw = rw | REQ_SYNC; |
8a0d613f JS |
32 | struct bio *bio; |
33 | ||
34 | bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); | |
4f024f37 | 35 | bio->bi_iter.bi_sector = sector; |
8a0d613f JS |
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) { | |
0fef8b1e RD |
40 | printk(KERN_ERR "PM: Adding page to bio failed at %llu\n", |
41 | (unsigned long long)sector); | |
8a0d613f JS |
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 | } |