diff options
| -rw-r--r-- | drivers/block/ll_rw_blk.c | 56 | ||||
| -rw-r--r-- | fs/bio.c | 66 | ||||
| -rw-r--r-- | include/linux/bio.h | 2 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 2 |
4 files changed, 126 insertions, 0 deletions
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f20eba22b14b..e30a3c93b70c 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c | |||
| @@ -281,6 +281,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq) | |||
| 281 | rq->special = NULL; | 281 | rq->special = NULL; |
| 282 | rq->data_len = 0; | 282 | rq->data_len = 0; |
| 283 | rq->data = NULL; | 283 | rq->data = NULL; |
| 284 | rq->nr_phys_segments = 0; | ||
| 284 | rq->sense = NULL; | 285 | rq->sense = NULL; |
| 285 | rq->end_io = NULL; | 286 | rq->end_io = NULL; |
| 286 | rq->end_io_data = NULL; | 287 | rq->end_io_data = NULL; |
| @@ -2176,6 +2177,61 @@ int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) | |||
| 2176 | 2177 | ||
| 2177 | EXPORT_SYMBOL(blk_rq_unmap_user); | 2178 | EXPORT_SYMBOL(blk_rq_unmap_user); |
| 2178 | 2179 | ||
| 2180 | static int blk_rq_map_kern_endio(struct bio *bio, unsigned int bytes_done, | ||
| 2181 | int error) | ||
| 2182 | { | ||
| 2183 | if (bio->bi_size) | ||
| 2184 | return 1; | ||
| 2185 | |||
| 2186 | bio_put(bio); | ||
| 2187 | return 0; | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | /** | ||
| 2191 | * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage | ||
| 2192 | * @q: request queue where request should be inserted | ||
| 2193 | * @rw: READ or WRITE data | ||
| 2194 | * @kbuf: the kernel buffer | ||
| 2195 | * @len: length of user data | ||
| 2196 | */ | ||
| 2197 | struct request *blk_rq_map_kern(request_queue_t *q, int rw, void *kbuf, | ||
| 2198 | unsigned int len, unsigned int gfp_mask) | ||
| 2199 | { | ||
| 2200 | struct request *rq; | ||
| 2201 | struct bio *bio; | ||
| 2202 | |||
| 2203 | if (len > (q->max_sectors << 9)) | ||
| 2204 | return ERR_PTR(-EINVAL); | ||
| 2205 | if ((!len && kbuf) || (len && !kbuf)) | ||
| 2206 | return ERR_PTR(-EINVAL); | ||
| 2207 | |||
| 2208 | rq = blk_get_request(q, rw, gfp_mask); | ||
| 2209 | if (!rq) | ||
| 2210 | return ERR_PTR(-ENOMEM); | ||
| 2211 | |||
| 2212 | bio = bio_map_kern(q, kbuf, len, gfp_mask); | ||
| 2213 | if (!IS_ERR(bio)) { | ||
| 2214 | if (rw) | ||
| 2215 | bio->bi_rw |= (1 << BIO_RW); | ||
| 2216 | bio->bi_end_io = blk_rq_map_kern_endio; | ||
| 2217 | |||
| 2218 | rq->bio = rq->biotail = bio; | ||
| 2219 | blk_rq_bio_prep(q, rq, bio); | ||
| 2220 | |||
| 2221 | rq->buffer = rq->data = NULL; | ||
| 2222 | rq->data_len = len; | ||
| 2223 | return rq; | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | /* | ||
| 2227 | * bio is the err-ptr | ||
| 2228 | */ | ||
| 2229 | blk_put_request(rq); | ||
| 2230 | return (struct request *) bio; | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | EXPORT_SYMBOL(blk_rq_map_kern); | ||
| 2234 | |||
| 2179 | /** | 2235 | /** |
| 2180 | * blk_execute_rq - insert a request into queue for execution | 2236 | * blk_execute_rq - insert a request into queue for execution |
| 2181 | * @q: queue to insert the request in | 2237 | * @q: queue to insert the request in |
| @@ -701,6 +701,71 @@ void bio_unmap_user(struct bio *bio) | |||
| 701 | bio_put(bio); | 701 | bio_put(bio); |
| 702 | } | 702 | } |
| 703 | 703 | ||
| 704 | static struct bio *__bio_map_kern(request_queue_t *q, void *data, | ||
| 705 | unsigned int len, unsigned int gfp_mask) | ||
| 706 | { | ||
| 707 | unsigned long kaddr = (unsigned long)data; | ||
| 708 | unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 709 | unsigned long start = kaddr >> PAGE_SHIFT; | ||
| 710 | const int nr_pages = end - start; | ||
| 711 | int offset, i; | ||
| 712 | struct bio *bio; | ||
| 713 | |||
| 714 | bio = bio_alloc(gfp_mask, nr_pages); | ||
| 715 | if (!bio) | ||
| 716 | return ERR_PTR(-ENOMEM); | ||
| 717 | |||
| 718 | offset = offset_in_page(kaddr); | ||
| 719 | for (i = 0; i < nr_pages; i++) { | ||
| 720 | unsigned int bytes = PAGE_SIZE - offset; | ||
| 721 | |||
| 722 | if (len <= 0) | ||
| 723 | break; | ||
| 724 | |||
| 725 | if (bytes > len) | ||
| 726 | bytes = len; | ||
| 727 | |||
| 728 | if (__bio_add_page(q, bio, virt_to_page(data), bytes, | ||
| 729 | offset) < bytes) | ||
| 730 | break; | ||
| 731 | |||
| 732 | data += bytes; | ||
| 733 | len -= bytes; | ||
| 734 | offset = 0; | ||
| 735 | } | ||
| 736 | |||
| 737 | return bio; | ||
| 738 | } | ||
| 739 | |||
| 740 | /** | ||
| 741 | * bio_map_kern - map kernel address into bio | ||
| 742 | * @q: the request_queue_t for the bio | ||
| 743 | * @data: pointer to buffer to map | ||
| 744 | * @len: length in bytes | ||
| 745 | * @gfp_mask: allocation flags for bio allocation | ||
| 746 | * | ||
| 747 | * Map the kernel address into a bio suitable for io to a block | ||
| 748 | * device. Returns an error pointer in case of error. | ||
| 749 | */ | ||
| 750 | struct bio *bio_map_kern(request_queue_t *q, void *data, unsigned int len, | ||
| 751 | unsigned int gfp_mask) | ||
| 752 | { | ||
| 753 | struct bio *bio; | ||
| 754 | |||
| 755 | bio = __bio_map_kern(q, data, len, gfp_mask); | ||
| 756 | if (IS_ERR(bio)) | ||
| 757 | return bio; | ||
| 758 | |||
| 759 | if (bio->bi_size == len) | ||
| 760 | return bio; | ||
| 761 | |||
| 762 | /* | ||
| 763 | * Don't support partial mappings. | ||
| 764 | */ | ||
| 765 | bio_put(bio); | ||
| 766 | return ERR_PTR(-EINVAL); | ||
| 767 | } | ||
| 768 | |||
| 704 | /* | 769 | /* |
| 705 | * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions | 770 | * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions |
| 706 | * for performing direct-IO in BIOs. | 771 | * for performing direct-IO in BIOs. |
| @@ -1088,6 +1153,7 @@ EXPORT_SYMBOL(bio_add_page); | |||
| 1088 | EXPORT_SYMBOL(bio_get_nr_vecs); | 1153 | EXPORT_SYMBOL(bio_get_nr_vecs); |
| 1089 | EXPORT_SYMBOL(bio_map_user); | 1154 | EXPORT_SYMBOL(bio_map_user); |
| 1090 | EXPORT_SYMBOL(bio_unmap_user); | 1155 | EXPORT_SYMBOL(bio_unmap_user); |
| 1156 | EXPORT_SYMBOL(bio_map_kern); | ||
| 1091 | EXPORT_SYMBOL(bio_pair_release); | 1157 | EXPORT_SYMBOL(bio_pair_release); |
| 1092 | EXPORT_SYMBOL(bio_split); | 1158 | EXPORT_SYMBOL(bio_split); |
| 1093 | EXPORT_SYMBOL(bio_split_pool); | 1159 | EXPORT_SYMBOL(bio_split_pool); |
diff --git a/include/linux/bio.h b/include/linux/bio.h index 038022763f09..1dd2bc2e84ae 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
| @@ -282,6 +282,8 @@ extern int bio_get_nr_vecs(struct block_device *); | |||
| 282 | extern struct bio *bio_map_user(struct request_queue *, struct block_device *, | 282 | extern struct bio *bio_map_user(struct request_queue *, struct block_device *, |
| 283 | unsigned long, unsigned int, int); | 283 | unsigned long, unsigned int, int); |
| 284 | extern void bio_unmap_user(struct bio *); | 284 | extern void bio_unmap_user(struct bio *); |
| 285 | extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int, | ||
| 286 | unsigned int); | ||
| 285 | extern void bio_set_pages_dirty(struct bio *bio); | 287 | extern void bio_set_pages_dirty(struct bio *bio); |
| 286 | extern void bio_check_pages_dirty(struct bio *bio); | 288 | extern void bio_check_pages_dirty(struct bio *bio); |
| 287 | extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); | 289 | extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4a99b76c5a33..67339bc5f6bc 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -560,6 +560,8 @@ extern void blk_run_queue(request_queue_t *); | |||
| 560 | extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); | 560 | extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); |
| 561 | extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); | 561 | extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); |
| 562 | extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); | 562 | extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); |
| 563 | extern struct request *blk_rq_map_kern(request_queue_t *, int, void *, | ||
| 564 | unsigned int, unsigned int); | ||
| 563 | extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); | 565 | extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); |
| 564 | 566 | ||
| 565 | static inline request_queue_t *bdev_get_queue(struct block_device *bdev) | 567 | static inline request_queue_t *bdev_get_queue(struct block_device *bdev) |
