Commit 152e283fdfea0cd11e297d982378b55937842dde
Committed by
Jens Axboe
1 parent
a3bce90edd
Exists in
master
and in
39 other branches
block: introduce struct rq_map_data to use reserved pages
This patch introduces struct rq_map_data to enable bio_copy_use_iov() use reserved pages. Currently, bio_copy_user_iov allocates bounce pages but drivers/scsi/sg.c wants to allocate pages by itself and use them. struct rq_map_data can be used to pass allocated pages to bio_copy_user_iov. The current users of bio_copy_user_iov simply passes NULL (they don't want to use pre-allocated pages). Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Cc: Jens Axboe <jens.axboe@oracle.com> Cc: Douglas Gilbert <dougg@torque.net> Cc: Mike Christie <michaelc@cs.wisc.edu> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 8 changed files with 80 additions and 39 deletions Side-by-side Diff
block/blk-map.c
... | ... | @@ -41,8 +41,8 @@ |
41 | 41 | } |
42 | 42 | |
43 | 43 | static int __blk_rq_map_user(struct request_queue *q, struct request *rq, |
44 | - void __user *ubuf, unsigned int len, | |
45 | - gfp_t gfp_mask) | |
44 | + struct rq_map_data *map_data, void __user *ubuf, | |
45 | + unsigned int len, gfp_t gfp_mask) | |
46 | 46 | { |
47 | 47 | unsigned long uaddr; |
48 | 48 | unsigned int alignment; |
49 | 49 | |
... | ... | @@ -57,10 +57,10 @@ |
57 | 57 | */ |
58 | 58 | uaddr = (unsigned long) ubuf; |
59 | 59 | alignment = queue_dma_alignment(q) | q->dma_pad_mask; |
60 | - if (!(uaddr & alignment) && !(len & alignment)) | |
60 | + if (!(uaddr & alignment) && !(len & alignment) && !map_data) | |
61 | 61 | bio = bio_map_user(q, NULL, uaddr, len, reading, gfp_mask); |
62 | 62 | else |
63 | - bio = bio_copy_user(q, uaddr, len, reading, gfp_mask); | |
63 | + bio = bio_copy_user(q, map_data, uaddr, len, reading, gfp_mask); | |
64 | 64 | |
65 | 65 | if (IS_ERR(bio)) |
66 | 66 | return PTR_ERR(bio); |
... | ... | @@ -89,6 +89,7 @@ |
89 | 89 | * blk_rq_map_user - map user data to a request, for REQ_TYPE_BLOCK_PC usage |
90 | 90 | * @q: request queue where request should be inserted |
91 | 91 | * @rq: request structure to fill |
92 | + * @map_data: pointer to the rq_map_data holding pages (if necessary) | |
92 | 93 | * @ubuf: the user buffer |
93 | 94 | * @len: length of user data |
94 | 95 | * @gfp_mask: memory allocation flags |
... | ... | @@ -107,7 +108,8 @@ |
107 | 108 | * unmapping. |
108 | 109 | */ |
109 | 110 | int blk_rq_map_user(struct request_queue *q, struct request *rq, |
110 | - void __user *ubuf, unsigned long len, gfp_t gfp_mask) | |
111 | + struct rq_map_data *map_data, void __user *ubuf, | |
112 | + unsigned long len, gfp_t gfp_mask) | |
111 | 113 | { |
112 | 114 | unsigned long bytes_read = 0; |
113 | 115 | struct bio *bio = NULL; |
... | ... | @@ -134,7 +136,8 @@ |
134 | 136 | if (end - start > BIO_MAX_PAGES) |
135 | 137 | map_len -= PAGE_SIZE; |
136 | 138 | |
137 | - ret = __blk_rq_map_user(q, rq, ubuf, map_len, gfp_mask); | |
139 | + ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len, | |
140 | + gfp_mask); | |
138 | 141 | if (ret < 0) |
139 | 142 | goto unmap_rq; |
140 | 143 | if (!bio) |
... | ... | @@ -159,6 +162,7 @@ |
159 | 162 | * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage |
160 | 163 | * @q: request queue where request should be inserted |
161 | 164 | * @rq: request to map data to |
165 | + * @map_data: pointer to the rq_map_data holding pages (if necessary) | |
162 | 166 | * @iov: pointer to the iovec |
163 | 167 | * @iov_count: number of elements in the iovec |
164 | 168 | * @len: I/O byte count |
... | ... | @@ -178,8 +182,8 @@ |
178 | 182 | * unmapping. |
179 | 183 | */ |
180 | 184 | int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, |
181 | - struct sg_iovec *iov, int iov_count, unsigned int len, | |
182 | - gfp_t gfp_mask) | |
185 | + struct rq_map_data *map_data, struct sg_iovec *iov, | |
186 | + int iov_count, unsigned int len, gfp_t gfp_mask) | |
183 | 187 | { |
184 | 188 | struct bio *bio; |
185 | 189 | int i, read = rq_data_dir(rq) == READ; |
... | ... | @@ -197,8 +201,9 @@ |
197 | 201 | } |
198 | 202 | } |
199 | 203 | |
200 | - if (unaligned || (q->dma_pad_mask & len)) | |
201 | - bio = bio_copy_user_iov(q, iov, iov_count, read, gfp_mask); | |
204 | + if (unaligned || (q->dma_pad_mask & len) || map_data) | |
205 | + bio = bio_copy_user_iov(q, map_data, iov, iov_count, read, | |
206 | + gfp_mask); | |
202 | 207 | else |
203 | 208 | bio = bio_map_user_iov(q, NULL, iov, iov_count, read, gfp_mask); |
204 | 209 | |
... | ... | @@ -220,6 +225,7 @@ |
220 | 225 | rq->buffer = rq->data = NULL; |
221 | 226 | return 0; |
222 | 227 | } |
228 | +EXPORT_SYMBOL(blk_rq_map_user_iov); | |
223 | 229 | |
224 | 230 | /** |
225 | 231 | * blk_rq_unmap_user - unmap a request with user data |
block/bsg.c
... | ... | @@ -283,8 +283,8 @@ |
283 | 283 | next_rq->cmd_type = rq->cmd_type; |
284 | 284 | |
285 | 285 | dxferp = (void*)(unsigned long)hdr->din_xferp; |
286 | - ret = blk_rq_map_user(q, next_rq, dxferp, hdr->din_xfer_len, | |
287 | - GFP_KERNEL); | |
286 | + ret = blk_rq_map_user(q, next_rq, NULL, dxferp, | |
287 | + hdr->din_xfer_len, GFP_KERNEL); | |
288 | 288 | if (ret) |
289 | 289 | goto out; |
290 | 290 | } |
... | ... | @@ -299,7 +299,8 @@ |
299 | 299 | dxfer_len = 0; |
300 | 300 | |
301 | 301 | if (dxfer_len) { |
302 | - ret = blk_rq_map_user(q, rq, dxferp, dxfer_len, GFP_KERNEL); | |
302 | + ret = blk_rq_map_user(q, rq, NULL, dxferp, dxfer_len, | |
303 | + GFP_KERNEL); | |
303 | 304 | if (ret) |
304 | 305 | goto out; |
305 | 306 | } |
block/scsi_ioctl.c
... | ... | @@ -314,11 +314,11 @@ |
314 | 314 | goto out; |
315 | 315 | } |
316 | 316 | |
317 | - ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count, | |
317 | + ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count, | |
318 | 318 | hdr->dxfer_len, GFP_KERNEL); |
319 | 319 | kfree(iov); |
320 | 320 | } else if (hdr->dxfer_len) |
321 | - ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len, | |
321 | + ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, | |
322 | 322 | GFP_KERNEL); |
323 | 323 | |
324 | 324 | if (ret) |
drivers/cdrom/cdrom.c
drivers/scsi/scsi_tgt_lib.c
... | ... | @@ -362,7 +362,7 @@ |
362 | 362 | int err; |
363 | 363 | |
364 | 364 | dprintk("%lx %u\n", uaddr, len); |
365 | - err = blk_rq_map_user(q, rq, (void *)uaddr, len, GFP_KERNEL); | |
365 | + err = blk_rq_map_user(q, rq, NULL, (void *)uaddr, len, GFP_KERNEL); | |
366 | 366 | if (err) { |
367 | 367 | /* |
368 | 368 | * TODO: need to fixup sg_tablesize, max_segment_size, |
fs/bio.c
... | ... | @@ -439,16 +439,19 @@ |
439 | 439 | |
440 | 440 | struct bio_map_data { |
441 | 441 | struct bio_vec *iovecs; |
442 | - int nr_sgvecs; | |
443 | 442 | struct sg_iovec *sgvecs; |
443 | + int nr_sgvecs; | |
444 | + int is_our_pages; | |
444 | 445 | }; |
445 | 446 | |
446 | 447 | static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio, |
447 | - struct sg_iovec *iov, int iov_count) | |
448 | + struct sg_iovec *iov, int iov_count, | |
449 | + int is_our_pages) | |
448 | 450 | { |
449 | 451 | memcpy(bmd->iovecs, bio->bi_io_vec, sizeof(struct bio_vec) * bio->bi_vcnt); |
450 | 452 | memcpy(bmd->sgvecs, iov, sizeof(struct sg_iovec) * iov_count); |
451 | 453 | bmd->nr_sgvecs = iov_count; |
454 | + bmd->is_our_pages = is_our_pages; | |
452 | 455 | bio->bi_private = bmd; |
453 | 456 | } |
454 | 457 | |
... | ... | @@ -483,7 +486,8 @@ |
483 | 486 | } |
484 | 487 | |
485 | 488 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, |
486 | - struct sg_iovec *iov, int iov_count, int uncopy) | |
489 | + struct sg_iovec *iov, int iov_count, int uncopy, | |
490 | + int do_free_page) | |
487 | 491 | { |
488 | 492 | int ret = 0, i; |
489 | 493 | struct bio_vec *bvec; |
... | ... | @@ -526,7 +530,7 @@ |
526 | 530 | } |
527 | 531 | } |
528 | 532 | |
529 | - if (uncopy) | |
533 | + if (do_free_page) | |
530 | 534 | __free_page(bvec->bv_page); |
531 | 535 | } |
532 | 536 | |
... | ... | @@ -545,7 +549,8 @@ |
545 | 549 | struct bio_map_data *bmd = bio->bi_private; |
546 | 550 | int ret; |
547 | 551 | |
548 | - ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, bmd->nr_sgvecs, 1); | |
552 | + ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, bmd->nr_sgvecs, 1, | |
553 | + bmd->is_our_pages); | |
549 | 554 | |
550 | 555 | bio_free_map_data(bmd); |
551 | 556 | bio_put(bio); |
... | ... | @@ -555,6 +560,7 @@ |
555 | 560 | /** |
556 | 561 | * bio_copy_user_iov - copy user data to bio |
557 | 562 | * @q: destination block queue |
563 | + * @map_data: pointer to the rq_map_data holding pages (if necessary) | |
558 | 564 | * @iov: the iovec. |
559 | 565 | * @iov_count: number of elements in the iovec |
560 | 566 | * @write_to_vm: bool indicating writing to pages or not |
... | ... | @@ -564,8 +570,10 @@ |
564 | 570 | * to/from kernel pages as necessary. Must be paired with |
565 | 571 | * call bio_uncopy_user() on io completion. |
566 | 572 | */ |
567 | -struct bio *bio_copy_user_iov(struct request_queue *q, struct sg_iovec *iov, | |
568 | - int iov_count, int write_to_vm, gfp_t gfp_mask) | |
573 | +struct bio *bio_copy_user_iov(struct request_queue *q, | |
574 | + struct rq_map_data *map_data, | |
575 | + struct sg_iovec *iov, int iov_count, | |
576 | + int write_to_vm, gfp_t gfp_mask) | |
569 | 577 | { |
570 | 578 | struct bio_map_data *bmd; |
571 | 579 | struct bio_vec *bvec; |
572 | 580 | |
573 | 581 | |
574 | 582 | |
... | ... | @@ -600,13 +608,26 @@ |
600 | 608 | bio->bi_rw |= (!write_to_vm << BIO_RW); |
601 | 609 | |
602 | 610 | ret = 0; |
611 | + i = 0; | |
603 | 612 | while (len) { |
604 | - unsigned int bytes = PAGE_SIZE; | |
613 | + unsigned int bytes; | |
605 | 614 | |
615 | + if (map_data) | |
616 | + bytes = 1U << (PAGE_SHIFT + map_data->page_order); | |
617 | + else | |
618 | + bytes = PAGE_SIZE; | |
619 | + | |
606 | 620 | if (bytes > len) |
607 | 621 | bytes = len; |
608 | 622 | |
609 | - page = alloc_page(q->bounce_gfp | gfp_mask); | |
623 | + if (map_data) { | |
624 | + if (i == map_data->nr_entries) { | |
625 | + ret = -ENOMEM; | |
626 | + break; | |
627 | + } | |
628 | + page = map_data->pages[i++]; | |
629 | + } else | |
630 | + page = alloc_page(q->bounce_gfp | gfp_mask); | |
610 | 631 | if (!page) { |
611 | 632 | ret = -ENOMEM; |
612 | 633 | break; |
613 | 634 | |
614 | 635 | |
... | ... | @@ -625,16 +646,17 @@ |
625 | 646 | * success |
626 | 647 | */ |
627 | 648 | if (!write_to_vm) { |
628 | - ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0); | |
649 | + ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0); | |
629 | 650 | if (ret) |
630 | 651 | goto cleanup; |
631 | 652 | } |
632 | 653 | |
633 | - bio_set_map_data(bmd, bio, iov, iov_count); | |
654 | + bio_set_map_data(bmd, bio, iov, iov_count, map_data ? 0 : 1); | |
634 | 655 | return bio; |
635 | 656 | cleanup: |
636 | - bio_for_each_segment(bvec, bio, i) | |
637 | - __free_page(bvec->bv_page); | |
657 | + if (!map_data) | |
658 | + bio_for_each_segment(bvec, bio, i) | |
659 | + __free_page(bvec->bv_page); | |
638 | 660 | |
639 | 661 | bio_put(bio); |
640 | 662 | out_bmd: |
... | ... | @@ -645,6 +667,7 @@ |
645 | 667 | /** |
646 | 668 | * bio_copy_user - copy user data to bio |
647 | 669 | * @q: destination block queue |
670 | + * @map_data: pointer to the rq_map_data holding pages (if necessary) | |
648 | 671 | * @uaddr: start of user address |
649 | 672 | * @len: length in bytes |
650 | 673 | * @write_to_vm: bool indicating writing to pages or not |
651 | 674 | |
... | ... | @@ -654,15 +677,16 @@ |
654 | 677 | * to/from kernel pages as necessary. Must be paired with |
655 | 678 | * call bio_uncopy_user() on io completion. |
656 | 679 | */ |
657 | -struct bio *bio_copy_user(struct request_queue *q, unsigned long uaddr, | |
658 | - unsigned int len, int write_to_vm, gfp_t gfp_mask) | |
680 | +struct bio *bio_copy_user(struct request_queue *q, struct rq_map_data *map_data, | |
681 | + unsigned long uaddr, unsigned int len, | |
682 | + int write_to_vm, gfp_t gfp_mask) | |
659 | 683 | { |
660 | 684 | struct sg_iovec iov; |
661 | 685 | |
662 | 686 | iov.iov_base = (void __user *)uaddr; |
663 | 687 | iov.iov_len = len; |
664 | 688 | |
665 | - return bio_copy_user_iov(q, &iov, 1, write_to_vm, gfp_mask); | |
689 | + return bio_copy_user_iov(q, map_data, &iov, 1, write_to_vm, gfp_mask); | |
666 | 690 | } |
667 | 691 | |
668 | 692 | static struct bio *__bio_map_user_iov(struct request_queue *q, |
... | ... | @@ -1028,7 +1052,7 @@ |
1028 | 1052 | bio->bi_private = bmd; |
1029 | 1053 | bio->bi_end_io = bio_copy_kern_endio; |
1030 | 1054 | |
1031 | - bio_set_map_data(bmd, bio, &iov, 1); | |
1055 | + bio_set_map_data(bmd, bio, &iov, 1, 1); | |
1032 | 1056 | return bio; |
1033 | 1057 | cleanup: |
1034 | 1058 | bio_for_each_segment(bvec, bio, i) |
include/linux/bio.h
... | ... | @@ -327,6 +327,7 @@ |
327 | 327 | extern struct bio *bio_map_user(struct request_queue *, struct block_device *, |
328 | 328 | unsigned long, unsigned int, int, gfp_t); |
329 | 329 | struct sg_iovec; |
330 | +struct rq_map_data; | |
330 | 331 | extern struct bio *bio_map_user_iov(struct request_queue *, |
331 | 332 | struct block_device *, |
332 | 333 | struct sg_iovec *, int, int, gfp_t); |
... | ... | @@ -337,9 +338,10 @@ |
337 | 338 | gfp_t, int); |
338 | 339 | extern void bio_set_pages_dirty(struct bio *bio); |
339 | 340 | extern void bio_check_pages_dirty(struct bio *bio); |
340 | -extern struct bio *bio_copy_user(struct request_queue *, unsigned long, | |
341 | - unsigned int, int, gfp_t); | |
342 | -extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *, | |
341 | +extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *, | |
342 | + unsigned long, unsigned int, int, gfp_t); | |
343 | +extern struct bio *bio_copy_user_iov(struct request_queue *, | |
344 | + struct rq_map_data *, struct sg_iovec *, | |
343 | 345 | int, int, gfp_t); |
344 | 346 | extern int bio_uncopy_user(struct bio *); |
345 | 347 | void zero_fill_bio(struct bio *bio); |
include/linux/blkdev.h
... | ... | @@ -642,6 +642,12 @@ |
642 | 642 | } |
643 | 643 | #endif /* CONFIG_MMU */ |
644 | 644 | |
645 | +struct rq_map_data { | |
646 | + struct page **pages; | |
647 | + int page_order; | |
648 | + int nr_entries; | |
649 | +}; | |
650 | + | |
645 | 651 | struct req_iterator { |
646 | 652 | int i; |
647 | 653 | struct bio *bio; |
648 | 654 | |
... | ... | @@ -711,11 +717,13 @@ |
711 | 717 | extern void blk_run_queue(struct request_queue *); |
712 | 718 | extern void blk_start_queueing(struct request_queue *); |
713 | 719 | extern int blk_rq_map_user(struct request_queue *, struct request *, |
714 | - void __user *, unsigned long, gfp_t); | |
720 | + struct rq_map_data *, void __user *, unsigned long, | |
721 | + gfp_t); | |
715 | 722 | extern int blk_rq_unmap_user(struct bio *); |
716 | 723 | extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t); |
717 | 724 | extern int blk_rq_map_user_iov(struct request_queue *, struct request *, |
718 | - struct sg_iovec *, int, unsigned int, gfp_t); | |
725 | + struct rq_map_data *, struct sg_iovec *, int, | |
726 | + unsigned int, gfp_t); | |
719 | 727 | extern int blk_execute_rq(struct request_queue *, struct gendisk *, |
720 | 728 | struct request *, int); |
721 | 729 | extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, |