diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /mm/page_io.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'mm/page_io.c')
-rw-r--r-- | mm/page_io.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/mm/page_io.c b/mm/page_io.c new file mode 100644 index 000000000000..667c76df1ec2 --- /dev/null +++ b/mm/page_io.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * linux/mm/page_io.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds | ||
5 | * | ||
6 | * Swap reorganised 29.12.95, | ||
7 | * Asynchronous swapping added 30.12.95. Stephen Tweedie | ||
8 | * Removed race in async swapping. 14.4.1996. Bruno Haible | ||
9 | * Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie | ||
10 | * Always use brw_page, life becomes simpler. 12 May 1998 Eric Biederman | ||
11 | */ | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | #include <linux/kernel_stat.h> | ||
15 | #include <linux/pagemap.h> | ||
16 | #include <linux/swap.h> | ||
17 | #include <linux/bio.h> | ||
18 | #include <linux/swapops.h> | ||
19 | #include <linux/writeback.h> | ||
20 | #include <asm/pgtable.h> | ||
21 | |||
22 | static struct bio *get_swap_bio(unsigned int __nocast gfp_flags, pgoff_t index, | ||
23 | struct page *page, bio_end_io_t end_io) | ||
24 | { | ||
25 | struct bio *bio; | ||
26 | |||
27 | bio = bio_alloc(gfp_flags, 1); | ||
28 | if (bio) { | ||
29 | struct swap_info_struct *sis; | ||
30 | swp_entry_t entry = { .val = index, }; | ||
31 | |||
32 | sis = get_swap_info_struct(swp_type(entry)); | ||
33 | bio->bi_sector = map_swap_page(sis, swp_offset(entry)) * | ||
34 | (PAGE_SIZE >> 9); | ||
35 | bio->bi_bdev = sis->bdev; | ||
36 | bio->bi_io_vec[0].bv_page = page; | ||
37 | bio->bi_io_vec[0].bv_len = PAGE_SIZE; | ||
38 | bio->bi_io_vec[0].bv_offset = 0; | ||
39 | bio->bi_vcnt = 1; | ||
40 | bio->bi_idx = 0; | ||
41 | bio->bi_size = PAGE_SIZE; | ||
42 | bio->bi_end_io = end_io; | ||
43 | } | ||
44 | return bio; | ||
45 | } | ||
46 | |||
47 | static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) | ||
48 | { | ||
49 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | ||
50 | struct page *page = bio->bi_io_vec[0].bv_page; | ||
51 | |||
52 | if (bio->bi_size) | ||
53 | return 1; | ||
54 | |||
55 | if (!uptodate) | ||
56 | SetPageError(page); | ||
57 | end_page_writeback(page); | ||
58 | bio_put(bio); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) | ||
63 | { | ||
64 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | ||
65 | struct page *page = bio->bi_io_vec[0].bv_page; | ||
66 | |||
67 | if (bio->bi_size) | ||
68 | return 1; | ||
69 | |||
70 | if (!uptodate) { | ||
71 | SetPageError(page); | ||
72 | ClearPageUptodate(page); | ||
73 | } else { | ||
74 | SetPageUptodate(page); | ||
75 | } | ||
76 | unlock_page(page); | ||
77 | bio_put(bio); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * We may have stale swap cache pages in memory: notice | ||
83 | * them here and get rid of the unnecessary final write. | ||
84 | */ | ||
85 | int swap_writepage(struct page *page, struct writeback_control *wbc) | ||
86 | { | ||
87 | struct bio *bio; | ||
88 | int ret = 0, rw = WRITE; | ||
89 | |||
90 | if (remove_exclusive_swap_page(page)) { | ||
91 | unlock_page(page); | ||
92 | goto out; | ||
93 | } | ||
94 | bio = get_swap_bio(GFP_NOIO, page->private, page, end_swap_bio_write); | ||
95 | if (bio == NULL) { | ||
96 | set_page_dirty(page); | ||
97 | unlock_page(page); | ||
98 | ret = -ENOMEM; | ||
99 | goto out; | ||
100 | } | ||
101 | if (wbc->sync_mode == WB_SYNC_ALL) | ||
102 | rw |= (1 << BIO_RW_SYNC); | ||
103 | inc_page_state(pswpout); | ||
104 | set_page_writeback(page); | ||
105 | unlock_page(page); | ||
106 | submit_bio(rw, bio); | ||
107 | out: | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | int swap_readpage(struct file *file, struct page *page) | ||
112 | { | ||
113 | struct bio *bio; | ||
114 | int ret = 0; | ||
115 | |||
116 | BUG_ON(!PageLocked(page)); | ||
117 | ClearPageUptodate(page); | ||
118 | bio = get_swap_bio(GFP_KERNEL, page->private, page, end_swap_bio_read); | ||
119 | if (bio == NULL) { | ||
120 | unlock_page(page); | ||
121 | ret = -ENOMEM; | ||
122 | goto out; | ||
123 | } | ||
124 | inc_page_state(pswpin); | ||
125 | submit_bio(READ, bio); | ||
126 | out: | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK) | ||
131 | /* | ||
132 | * A scruffy utility function to read or write an arbitrary swap page | ||
133 | * and wait on the I/O. The caller must have a ref on the page. | ||
134 | * | ||
135 | * We use end_swap_bio_read() even for writes, because it happens to do what | ||
136 | * we want. | ||
137 | */ | ||
138 | int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page) | ||
139 | { | ||
140 | struct bio *bio; | ||
141 | int ret = 0; | ||
142 | |||
143 | lock_page(page); | ||
144 | |||
145 | bio = get_swap_bio(GFP_KERNEL, entry.val, page, end_swap_bio_read); | ||
146 | if (bio == NULL) { | ||
147 | unlock_page(page); | ||
148 | ret = -ENOMEM; | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
153 | wait_on_page_locked(page); | ||
154 | |||
155 | if (!PageUptodate(page) || PageError(page)) | ||
156 | ret = -EIO; | ||
157 | out: | ||
158 | return ret; | ||
159 | } | ||
160 | #endif | ||