aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)