Skip to content

Commit b4c5875

Browse files
damien-lemoalaxboe
authored andcommitted
block: Allow mapping of vmalloc-ed buffers
To allow the SCSI subsystem scsi_execute_req() function to issue requests using large buffers that are better allocated with vmalloc() rather than kmalloc(), modify bio_map_kern() to allow passing a buffer allocated with vmalloc(). To do so, detect vmalloc-ed buffers using is_vmalloc_addr(). For vmalloc-ed buffers, flush the buffer using flush_kernel_vmap_range(), use vmalloc_to_page() instead of virt_to_page() to obtain the pages of the buffer, and invalidate the buffer addresses with invalidate_kernel_vmap_range() on completion of read BIOs. This last point is executed using the function bio_invalidate_vmalloc_pages() which is defined only if the architecture defines ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE, that is, if the architecture actually needs the invalidation done. Fixes: 515ce60 ("scsi: sd_zbc: Fix sd_zbc_report_zones() buffer allocation") Fixes: e76239a ("block: add a report_zones method") Cc: [email protected] Reviewed-by: Martin K. Petersen <[email protected]> Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Chaitanya Kulkarni <[email protected]> Reviewed-by: Ming Lei <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent e7bf90e commit b4c5875

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

block/bio.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/workqueue.h>
1717
#include <linux/cgroup.h>
1818
#include <linux/blk-cgroup.h>
19+
#include <linux/highmem.h>
1920

2021
#include <trace/events/block.h>
2122
#include "blk.h"
@@ -1441,8 +1442,22 @@ void bio_unmap_user(struct bio *bio)
14411442
bio_put(bio);
14421443
}
14431444

1445+
static void bio_invalidate_vmalloc_pages(struct bio *bio)
1446+
{
1447+
#ifdef ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
1448+
if (bio->bi_private && !op_is_write(bio_op(bio))) {
1449+
unsigned long i, len = 0;
1450+
1451+
for (i = 0; i < bio->bi_vcnt; i++)
1452+
len += bio->bi_io_vec[i].bv_len;
1453+
invalidate_kernel_vmap_range(bio->bi_private, len);
1454+
}
1455+
#endif
1456+
}
1457+
14441458
static void bio_map_kern_endio(struct bio *bio)
14451459
{
1460+
bio_invalidate_vmalloc_pages(bio);
14461461
bio_put(bio);
14471462
}
14481463

@@ -1463,13 +1478,20 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
14631478
unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
14641479
unsigned long start = kaddr >> PAGE_SHIFT;
14651480
const int nr_pages = end - start;
1481+
bool is_vmalloc = is_vmalloc_addr(data);
1482+
struct page *page;
14661483
int offset, i;
14671484
struct bio *bio;
14681485

14691486
bio = bio_kmalloc(gfp_mask, nr_pages);
14701487
if (!bio)
14711488
return ERR_PTR(-ENOMEM);
14721489

1490+
if (is_vmalloc) {
1491+
flush_kernel_vmap_range(data, len);
1492+
bio->bi_private = data;
1493+
}
1494+
14731495
offset = offset_in_page(kaddr);
14741496
for (i = 0; i < nr_pages; i++) {
14751497
unsigned int bytes = PAGE_SIZE - offset;
@@ -1480,7 +1502,11 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
14801502
if (bytes > len)
14811503
bytes = len;
14821504

1483-
if (bio_add_pc_page(q, bio, virt_to_page(data), bytes,
1505+
if (!is_vmalloc)
1506+
page = virt_to_page(data);
1507+
else
1508+
page = vmalloc_to_page(data);
1509+
if (bio_add_pc_page(q, bio, page, bytes,
14841510
offset) < bytes) {
14851511
/* we don't support partial mappings */
14861512
bio_put(bio);

0 commit comments

Comments
 (0)