]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
[PATCH] Add blk_rq_map_kern()
authorMike Christie <michaelc@cs.wisc.edu>
Mon, 20 Jun 2005 12:04:44 +0000 (14:04 +0200)
committerJens Axboe <axboe@suse.de>
Mon, 20 Jun 2005 12:04:44 +0000 (14:04 +0200)
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>
drivers/block/ll_rw_blk.c
fs/bio.c
include/linux/bio.h
include/linux/blkdev.h

index f20eba22b14b254553933848e94f3f4192552603..e30a3c93b70c04921783a6ca84a667a214baf09a 100644 (file)
@@ -281,6 +281,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
        rq->special = NULL;
        rq->data_len = 0;
        rq->data = NULL;
+       rq->nr_phys_segments = 0;
        rq->sense = NULL;
        rq->end_io = NULL;
        rq->end_io_data = NULL;
@@ -2176,6 +2177,61 @@ int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen)
 
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
+static int blk_rq_map_kern_endio(struct bio *bio, unsigned int bytes_done,
+                                int error)
+{
+       if (bio->bi_size)
+               return 1;
+
+       bio_put(bio);
+       return 0;
+}
+
+/**
+ * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage
+ * @q:         request queue where request should be inserted
+ * @rw:                READ or WRITE data
+ * @kbuf:      the kernel buffer
+ * @len:       length of user data
+ */
+struct request *blk_rq_map_kern(request_queue_t *q, int rw, void *kbuf,
+                               unsigned int len, unsigned int gfp_mask)
+{
+       struct request *rq;
+       struct bio *bio;
+
+       if (len > (q->max_sectors << 9))
+               return ERR_PTR(-EINVAL);
+       if ((!len && kbuf) || (len && !kbuf))
+               return ERR_PTR(-EINVAL);
+
+       rq = blk_get_request(q, rw, gfp_mask);
+       if (!rq)
+               return ERR_PTR(-ENOMEM);
+
+       bio = bio_map_kern(q, kbuf, len, gfp_mask);
+       if (!IS_ERR(bio)) {
+               if (rw)
+                       bio->bi_rw |= (1 << BIO_RW);
+               bio->bi_end_io = blk_rq_map_kern_endio;
+
+               rq->bio = rq->biotail = bio;
+               blk_rq_bio_prep(q, rq, bio);
+
+               rq->buffer = rq->data = NULL;
+               rq->data_len = len;
+               return rq;
+       }
+
+       /*
+        * bio is the err-ptr
+        */
+       blk_put_request(rq);
+       return (struct request *) bio;
+}
+
+EXPORT_SYMBOL(blk_rq_map_kern);
+
 /**
  * blk_execute_rq - insert a request into queue for execution
  * @q:         queue to insert the request in
index 3a1472acc361ef0e95f03843cac07f5b92f23e61..707b9af2dd01a6a5e9a9b94c5800f8b2cde7387b 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -701,6 +701,71 @@ void bio_unmap_user(struct bio *bio)
        bio_put(bio);
 }
 
+static struct bio *__bio_map_kern(request_queue_t *q, void *data,
+                                 unsigned int len, unsigned int gfp_mask)
+{
+       unsigned long kaddr = (unsigned long)data;
+       unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       unsigned long start = kaddr >> PAGE_SHIFT;
+       const int nr_pages = end - start;
+       int offset, i;
+       struct bio *bio;
+
+       bio = bio_alloc(gfp_mask, nr_pages);
+       if (!bio)
+               return ERR_PTR(-ENOMEM);
+
+       offset = offset_in_page(kaddr);
+       for (i = 0; i < nr_pages; i++) {
+               unsigned int bytes = PAGE_SIZE - offset;
+
+               if (len <= 0)
+                       break;
+
+               if (bytes > len)
+                       bytes = len;
+
+               if (__bio_add_page(q, bio, virt_to_page(data), bytes,
+                                  offset) < bytes)
+                       break;
+
+               data += bytes;
+               len -= bytes;
+               offset = 0;
+       }
+
+       return bio;
+}
+
+/**
+ *     bio_map_kern    -       map kernel address into bio
+ *     @q: the request_queue_t for the bio
+ *     @data: pointer to buffer to map
+ *     @len: length in bytes
+ *     @gfp_mask: allocation flags for bio allocation
+ *
+ *     Map the kernel address into a bio suitable for io to a block
+ *     device. Returns an error pointer in case of error.
+ */
+struct bio *bio_map_kern(request_queue_t *q, void *data, unsigned int len,
+                        unsigned int gfp_mask)
+{
+       struct bio *bio;
+
+       bio = __bio_map_kern(q, data, len, gfp_mask);
+       if (IS_ERR(bio))
+               return bio;
+
+       if (bio->bi_size == len)
+               return bio;
+
+       /*
+        * Don't support partial mappings.
+        */
+       bio_put(bio);
+       return ERR_PTR(-EINVAL);
+}
+
 /*
  * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
  * for performing direct-IO in BIOs.
@@ -1088,6 +1153,7 @@ EXPORT_SYMBOL(bio_add_page);
 EXPORT_SYMBOL(bio_get_nr_vecs);
 EXPORT_SYMBOL(bio_map_user);
 EXPORT_SYMBOL(bio_unmap_user);
+EXPORT_SYMBOL(bio_map_kern);
 EXPORT_SYMBOL(bio_pair_release);
 EXPORT_SYMBOL(bio_split);
 EXPORT_SYMBOL(bio_split_pool);
index 038022763f09535e97525cd531c17c9352fffda4..1dd2bc2e84ae4f0257d075f85cad8e55fb324035 100644 (file)
@@ -282,6 +282,8 @@ extern int bio_get_nr_vecs(struct block_device *);
 extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
                                unsigned long, unsigned int, int);
 extern void bio_unmap_user(struct bio *);
+extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
+                               unsigned int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
 extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
index 4a99b76c5a338d027cfbb48b0a27e4a0dfe5fe4d..67339bc5f6bced179b13426339bc1a52bcf03d42 100644 (file)
@@ -560,6 +560,8 @@ extern void blk_run_queue(request_queue_t *);
 extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
 extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
 extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int);
+extern struct request *blk_rq_map_kern(request_queue_t *, int, void *,
+                                       unsigned int, unsigned int);
 extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
 
 static inline request_queue_t *bdev_get_queue(struct block_device *bdev)