Blame view

mm/page_io.c 4.45 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   *  linux/mm/page_io.c
   *
   *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   *
   *  Swap reorganised 29.12.95, 
   *  Asynchronous swapping added 30.12.95. Stephen Tweedie
   *  Removed race in async swapping. 14.4.1996. Bruno Haible
   *  Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie
   *  Always use brw_page, life becomes simpler. 12 May 1998 Eric Biederman
   */
  
  #include <linux/mm.h>
  #include <linux/kernel_stat.h>
  #include <linux/pagemap.h>
  #include <linux/swap.h>
  #include <linux/bio.h>
  #include <linux/swapops.h>
  #include <linux/writeback.h>
  #include <asm/pgtable.h>
dd0fc66fb   Al Viro   [PATCH] gfp flags...
21
  static struct bio *get_swap_bio(gfp_t gfp_flags, pgoff_t index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  				struct page *page, bio_end_io_t end_io)
  {
  	struct bio *bio;
  
  	bio = bio_alloc(gfp_flags, 1);
  	if (bio) {
  		struct swap_info_struct *sis;
  		swp_entry_t entry = { .val = index, };
  
  		sis = get_swap_info_struct(swp_type(entry));
  		bio->bi_sector = map_swap_page(sis, swp_offset(entry)) *
  					(PAGE_SIZE >> 9);
  		bio->bi_bdev = sis->bdev;
  		bio->bi_io_vec[0].bv_page = page;
  		bio->bi_io_vec[0].bv_len = PAGE_SIZE;
  		bio->bi_io_vec[0].bv_offset = 0;
  		bio->bi_vcnt = 1;
  		bio->bi_idx = 0;
  		bio->bi_size = PAGE_SIZE;
  		bio->bi_end_io = end_io;
  	}
  	return bio;
  }
  
  static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err)
  {
  	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  	struct page *page = bio->bi_io_vec[0].bv_page;
  
  	if (bio->bi_size)
  		return 1;
6ddab3b9e   Peter Zijlstra   [PATCH] mm: swap ...
53
  	if (!uptodate) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  		SetPageError(page);
6ddab3b9e   Peter Zijlstra   [PATCH] mm: swap ...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  		/*
  		 * We failed to write the page out to swap-space.
  		 * Re-dirty the page in order to avoid it being reclaimed.
  		 * Also print a dire warning that things will go BAD (tm)
  		 * very quickly.
  		 *
  		 * Also clear PG_reclaim to avoid rotate_reclaimable_page()
  		 */
  		set_page_dirty(page);
  		printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)
  ",
  				imajor(bio->bi_bdev->bd_inode),
  				iminor(bio->bi_bdev->bd_inode),
  				(unsigned long long)bio->bi_sector);
  		ClearPageReclaim(page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  	end_page_writeback(page);
  	bio_put(bio);
  	return 0;
  }
546e0d271   Andrew Morton   [PATCH] swsusp: r...
75
  int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
  {
  	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  	struct page *page = bio->bi_io_vec[0].bv_page;
  
  	if (bio->bi_size)
  		return 1;
  
  	if (!uptodate) {
  		SetPageError(page);
  		ClearPageUptodate(page);
6ddab3b9e   Peter Zijlstra   [PATCH] mm: swap ...
86
87
88
89
90
  		printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)
  ",
  				imajor(bio->bi_bdev->bd_inode),
  				iminor(bio->bi_bdev->bd_inode),
  				(unsigned long long)bio->bi_sector);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  	} else {
  		SetPageUptodate(page);
  	}
  	unlock_page(page);
  	bio_put(bio);
  	return 0;
  }
  
  /*
   * We may have stale swap cache pages in memory: notice
   * them here and get rid of the unnecessary final write.
   */
  int swap_writepage(struct page *page, struct writeback_control *wbc)
  {
  	struct bio *bio;
  	int ret = 0, rw = WRITE;
  
  	if (remove_exclusive_swap_page(page)) {
  		unlock_page(page);
  		goto out;
  	}
4c21e2f24   Hugh Dickins   [PATCH] mm: split...
112
113
  	bio = get_swap_bio(GFP_NOIO, page_private(page), page,
  				end_swap_bio_write);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
  	if (bio == NULL) {
  		set_page_dirty(page);
  		unlock_page(page);
  		ret = -ENOMEM;
  		goto out;
  	}
  	if (wbc->sync_mode == WB_SYNC_ALL)
  		rw |= (1 << BIO_RW_SYNC);
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
122
  	count_vm_event(PSWPOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  	set_page_writeback(page);
  	unlock_page(page);
  	submit_bio(rw, bio);
  out:
  	return ret;
  }
  
  int swap_readpage(struct file *file, struct page *page)
  {
  	struct bio *bio;
  	int ret = 0;
  
  	BUG_ON(!PageLocked(page));
  	ClearPageUptodate(page);
4c21e2f24   Hugh Dickins   [PATCH] mm: split...
137
138
  	bio = get_swap_bio(GFP_KERNEL, page_private(page), page,
  				end_swap_bio_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
  	if (bio == NULL) {
  		unlock_page(page);
  		ret = -ENOMEM;
  		goto out;
  	}
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
144
  	count_vm_event(PSWPIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
  	submit_bio(READ, bio);
  out:
  	return ret;
  }
648be3188   Pavel Machek   [PATCH] swsusp: k...
149
  #ifdef CONFIG_SOFTWARE_SUSPEND
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
  /*
   * A scruffy utility function to read or write an arbitrary swap page
   * and wait on the I/O.  The caller must have a ref on the page.
   *
   * We use end_swap_bio_read() even for writes, because it happens to do what
   * we want.
   */
ab9541603   Andrew Morton   [PATCH] swsusp: w...
157
158
  int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page,
  			struct bio **bio_chain)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  {
  	struct bio *bio;
  	int ret = 0;
ab9541603   Andrew Morton   [PATCH] swsusp: w...
162
  	int bio_rw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
  
  	lock_page(page);
  
  	bio = get_swap_bio(GFP_KERNEL, entry.val, page, end_swap_bio_read);
  	if (bio == NULL) {
  		unlock_page(page);
  		ret = -ENOMEM;
  		goto out;
  	}
ab9541603   Andrew Morton   [PATCH] swsusp: w...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  	bio_rw = rw;
  	if (!bio_chain)
  		bio_rw |= (1 << BIO_RW_SYNC);
  	if (bio_chain)
  		bio_get(bio);
  	submit_bio(bio_rw, bio);
  	if (bio_chain == NULL) {
  		wait_on_page_locked(page);
  
  		if (!PageUptodate(page) || PageError(page))
  			ret = -EIO;
  	}
  	if (bio_chain) {
  		bio->bi_private = *bio_chain;
  		*bio_chain = bio;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
  out:
  	return ret;
  }
  #endif