[PATCH 06/17] block: simplify bio_map_kern

Christoph Hellwig <[email protected]>
Newsgroups org.kernel.vger.linux-bcache,dev.linux.lists.dm-devel,dev.linux.lists.gfs2,org.kernel.vger.linux-block,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-pm,org.kernel.vger.linux-xfs
Message-ID <[email protected]>
Split bio_map_kern into a simple version that can use bio_add_virt_nofail
for kernel direct mapping addresses and a more complex bio_map_vmalloc
with the logic to chunk up and map vmalloc ranges using the
bio_add_vmalloc helper.

Signed-off-by: Christoph Hellwig <[email protected]>
---
 block/blk-map.c | 74 +++++++++++++++++++------------------------------
 1 file changed, 29 insertions(+), 45 deletions(-)

diff --git a/block/blk-map.c b/block/blk-map.c
index ca6b55ac0da1..7742d3cb0499 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -317,65 +317,47 @@ static void bio_map_kern_endio(struct bio *bio)
 	kfree(bio);
 }
 
-/**
- *	bio_map_kern	-	map kernel address into bio
- *	@data: pointer to buffer to map
- *	@len: length in bytes
- *	@op: bio/request operation
- *	@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.
- */
-static struct bio *bio_map_kern(void *data, unsigned int len,
-		enum req_op op, gfp_t gfp_mask)
+static struct bio *bio_map_virt(void *data, unsigned int len, enum req_op op,
+		gfp_t 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;
-	bool is_vmalloc = is_vmalloc_addr(data);
-	struct page *page;
-	int offset, i;
 	struct bio *bio;
 
-	bio = bio_kmalloc(nr_pages, gfp_mask);
+	bio = bio_kmalloc(1, gfp_mask);
 	if (!bio)
 		return ERR_PTR(-ENOMEM);
-	bio_init(bio, NULL, bio->bi_inline_vecs, nr_pages, op);
-
-	if (is_vmalloc) {
-		flush_kernel_vmap_range(data, len);
-		bio->bi_private = data;
-	}
-
-	offset = offset_in_page(kaddr);
-	for (i = 0; i < nr_pages; i++) {
-		unsigned int bytes = PAGE_SIZE - offset;
+	bio_init(bio, NULL, bio->bi_inline_vecs, 1, op);
+	bio_add_virt_nofail(bio, data, len);
+	bio->bi_end_io = bio_map_kern_endio;
+	return bio;
+}
 
-		if (len <= 0)
-			break;
+static struct bio *bio_map_vmalloc(void *data, unsigned int len, enum req_op op,
+		gfp_t gfp_mask)
+{
+	unsigned int nr_vecs = bio_vmalloc_max_vecs(data, len);
+	unsigned int added;
+	struct bio *bio;
 
-		if (bytes > len)
-			bytes = len;
+	bio = bio_kmalloc(nr_vecs, gfp_mask);
+	if (!bio)
+		return ERR_PTR(-ENOMEM);
+	bio_init(bio, NULL, bio->bi_inline_vecs, nr_vecs, op);
+	bio->bi_private = data;
+	bio->bi_end_io = bio_map_kern_endio;
 
-		if (!is_vmalloc)
-			page = virt_to_page(data);
-		else
-			page = vmalloc_to_page(data);
-		if (bio_add_page(bio, page, bytes, offset) < bytes) {
+	do {
+		added = bio_add_vmalloc(bio, data, len);
+		if (!added) {
 			/* we don't support partial mappings */
 			bio_uninit(bio);
 			kfree(bio);
 			return ERR_PTR(-EINVAL);
 		}
 
-		data += bytes;
-		len -= bytes;
-		offset = 0;
-	}
+		data += added;
+		len -= added;
+	} while (len);
 
-	bio->bi_end_io = bio_map_kern_endio;
 	return bio;
 }
 
@@ -713,8 +695,10 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
 	if (!blk_rq_aligned(rq->q, addr, len) || object_is_on_stack(kbuf) ||
 	    blk_queue_may_bounce(rq->q))
 		bio = bio_copy_kern(kbuf, len, req_op(rq), gfp_mask);
+	else if (is_vmalloc_addr(kbuf))
+		bio = bio_map_vmalloc(kbuf, len, req_op(rq), gfp_mask);
 	else
-		bio = bio_map_kern(kbuf, len, req_op(rq), gfp_mask);
+		bio = bio_map_virt(kbuf, len, req_op(rq), gfp_mask);
 
 	if (IS_ERR(bio))
 		return PTR_ERR(bio);
-- 
2.47.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.