diff options
-rw-r--r-- | mm/bounce.c | 73 |
1 files changed, 19 insertions, 54 deletions
diff --git a/mm/bounce.c b/mm/bounce.c index 5f8901768602..55f512af50c7 100644 --- a/mm/bounce.c +++ b/mm/bounce.c | |||
@@ -101,7 +101,7 @@ static void copy_to_high_bio_irq(struct bio *to, struct bio *from) | |||
101 | struct bio_vec *tovec, *fromvec; | 101 | struct bio_vec *tovec, *fromvec; |
102 | int i; | 102 | int i; |
103 | 103 | ||
104 | __bio_for_each_segment(tovec, to, i, 0) { | 104 | bio_for_each_segment(tovec, to, i) { |
105 | fromvec = from->bi_io_vec + i; | 105 | fromvec = from->bi_io_vec + i; |
106 | 106 | ||
107 | /* | 107 | /* |
@@ -218,78 +218,43 @@ static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) | |||
218 | static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, | 218 | static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, |
219 | mempool_t *pool, int force) | 219 | mempool_t *pool, int force) |
220 | { | 220 | { |
221 | struct page *page; | 221 | struct bio *bio; |
222 | struct bio *bio = NULL; | 222 | int rw = bio_data_dir(*bio_orig); |
223 | int i, rw = bio_data_dir(*bio_orig); | ||
224 | struct bio_vec *to, *from; | 223 | struct bio_vec *to, *from; |
224 | unsigned i; | ||
225 | 225 | ||
226 | bio_for_each_segment(from, *bio_orig, i) { | 226 | bio_for_each_segment(from, *bio_orig, i) |
227 | page = from->bv_page; | 227 | if (page_to_pfn(from->bv_page) > queue_bounce_pfn(q)) |
228 | goto bounce; | ||
228 | 229 | ||
229 | /* | 230 | return; |
230 | * is destination page below bounce pfn? | 231 | bounce: |
231 | */ | 232 | bio = bio_clone_bioset(*bio_orig, GFP_NOIO, fs_bio_set); |
232 | if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force) | ||
233 | continue; | ||
234 | 233 | ||
235 | /* | 234 | bio_for_each_segment(to, bio, i) { |
236 | * irk, bounce it | 235 | struct page *page = to->bv_page; |
237 | */ | ||
238 | if (!bio) { | ||
239 | unsigned int cnt = (*bio_orig)->bi_vcnt; | ||
240 | |||
241 | bio = bio_alloc(GFP_NOIO, cnt); | ||
242 | memset(bio->bi_io_vec, 0, cnt * sizeof(struct bio_vec)); | ||
243 | } | ||
244 | |||
245 | 236 | ||
246 | to = bio->bi_io_vec + i; | 237 | if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force) |
238 | continue; | ||
247 | 239 | ||
248 | to->bv_page = mempool_alloc(pool, q->bounce_gfp); | ||
249 | to->bv_len = from->bv_len; | ||
250 | to->bv_offset = from->bv_offset; | ||
251 | inc_zone_page_state(to->bv_page, NR_BOUNCE); | 240 | inc_zone_page_state(to->bv_page, NR_BOUNCE); |
241 | to->bv_page = mempool_alloc(pool, q->bounce_gfp); | ||
252 | 242 | ||
253 | if (rw == WRITE) { | 243 | if (rw == WRITE) { |
254 | char *vto, *vfrom; | 244 | char *vto, *vfrom; |
255 | 245 | ||
256 | flush_dcache_page(from->bv_page); | 246 | flush_dcache_page(page); |
247 | |||
257 | vto = page_address(to->bv_page) + to->bv_offset; | 248 | vto = page_address(to->bv_page) + to->bv_offset; |
258 | vfrom = kmap(from->bv_page) + from->bv_offset; | 249 | vfrom = kmap_atomic(page) + to->bv_offset; |
259 | memcpy(vto, vfrom, to->bv_len); | 250 | memcpy(vto, vfrom, to->bv_len); |
260 | kunmap(from->bv_page); | 251 | kunmap_atomic(vfrom); |
261 | } | 252 | } |
262 | } | 253 | } |
263 | 254 | ||
264 | /* | ||
265 | * no pages bounced | ||
266 | */ | ||
267 | if (!bio) | ||
268 | return; | ||
269 | |||
270 | trace_block_bio_bounce(q, *bio_orig); | 255 | trace_block_bio_bounce(q, *bio_orig); |
271 | 256 | ||
272 | /* | ||
273 | * at least one page was bounced, fill in possible non-highmem | ||
274 | * pages | ||
275 | */ | ||
276 | __bio_for_each_segment(from, *bio_orig, i, 0) { | ||
277 | to = bio_iovec_idx(bio, i); | ||
278 | if (!to->bv_page) { | ||
279 | to->bv_page = from->bv_page; | ||
280 | to->bv_len = from->bv_len; | ||
281 | to->bv_offset = from->bv_offset; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | bio->bi_bdev = (*bio_orig)->bi_bdev; | ||
286 | bio->bi_flags |= (1 << BIO_BOUNCED); | 257 | bio->bi_flags |= (1 << BIO_BOUNCED); |
287 | bio->bi_sector = (*bio_orig)->bi_sector; | ||
288 | bio->bi_rw = (*bio_orig)->bi_rw; | ||
289 | |||
290 | bio->bi_vcnt = (*bio_orig)->bi_vcnt; | ||
291 | bio->bi_idx = (*bio_orig)->bi_idx; | ||
292 | bio->bi_size = (*bio_orig)->bi_size; | ||
293 | 258 | ||
294 | if (pool == page_pool) { | 259 | if (pool == page_pool) { |
295 | bio->bi_end_io = bounce_end_io_write; | 260 | bio->bi_end_io = bounce_end_io_write; |