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) |