aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2005-06-20 08:04:44 -0400
committerJens Axboe <axboe@suse.de>2005-06-20 08:04:44 -0400
commitdf46b9a44ceb5af2ea2351ce8e28ae7bd840b00f (patch)
tree30ab71759486f94d60af2283fc55bfffcc22155a
parent8b22c249e7de453961e4d253b19fc2a0bdd65d53 (diff)
[PATCH] Add blk_rq_map_kern()
Add blk_rq_map_kern which takes a kernel buffer and maps it into a request and bio. This can be used by the dm hw_handlers, old sg_scsi_ioctl, and one day scsi special requests so all requests comming into scsi will have bios. All requests having bios should allow scsi to use scatter lists for all IO and allow it to use block layer functions. Signed-off-by: Jens Axboe <axboe@suse.de>
-rw-r--r--drivers/block/ll_rw_blk.c56
-rw-r--r--fs/bio.c66
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blkdev.h2
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
2177EXPORT_SYMBOL(blk_rq_unmap_user); 2178EXPORT_SYMBOL(blk_rq_unmap_user);
2178 2179
2180static 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 */
2197struct 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
2233EXPORT_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
diff --git a/fs/bio.c b/fs/bio.c
index 3a1472acc361..707b9af2dd01 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -701,6 +701,71 @@ void bio_unmap_user(struct bio *bio)
701 bio_put(bio); 701 bio_put(bio);
702} 702}
703 703
704static 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 */
750struct 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);
1088EXPORT_SYMBOL(bio_get_nr_vecs); 1153EXPORT_SYMBOL(bio_get_nr_vecs);
1089EXPORT_SYMBOL(bio_map_user); 1154EXPORT_SYMBOL(bio_map_user);
1090EXPORT_SYMBOL(bio_unmap_user); 1155EXPORT_SYMBOL(bio_unmap_user);
1156EXPORT_SYMBOL(bio_map_kern);
1091EXPORT_SYMBOL(bio_pair_release); 1157EXPORT_SYMBOL(bio_pair_release);
1092EXPORT_SYMBOL(bio_split); 1158EXPORT_SYMBOL(bio_split);
1093EXPORT_SYMBOL(bio_split_pool); 1159EXPORT_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 *);
282extern struct bio *bio_map_user(struct request_queue *, struct block_device *, 282extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
283 unsigned long, unsigned int, int); 283 unsigned long, unsigned int, int);
284extern void bio_unmap_user(struct bio *); 284extern void bio_unmap_user(struct bio *);
285extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
286 unsigned int);
285extern void bio_set_pages_dirty(struct bio *bio); 287extern void bio_set_pages_dirty(struct bio *bio);
286extern void bio_check_pages_dirty(struct bio *bio); 288extern void bio_check_pages_dirty(struct bio *bio);
287extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); 289extern 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 *);
560extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); 560extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
561extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); 561extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
562extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); 562extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int);
563extern struct request *blk_rq_map_kern(request_queue_t *, int, void *,
564 unsigned int, unsigned int);
563extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); 565extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
564 566
565static inline request_queue_t *bdev_get_queue(struct block_device *bdev) 567static inline request_queue_t *bdev_get_queue(struct block_device *bdev)