summaryrefslogtreecommitdiffstats
path: root/block/bio.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-01-18 10:16:28 -0500
committerJens Axboe <axboe@fb.com>2015-02-05 11:30:35 -0500
commit42d2683a2704ef4bbbb07fd0b9486ab312dd8c56 (patch)
treecb58108edf8735e9f984ace40e48688d2c5c82f3 /block/bio.c
parentad9cf3bbd18a94806314741ac8092c3422f5aebe (diff)
block: simplify bio_map_kern
Just open code the trivial mapping from a kernel virtual address to a bio instead of going through the complex user address mapping machinery. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Ming Lei <tom.leiming@gmail.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/bio.c')
-rw-r--r--block/bio.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/block/bio.c b/block/bio.c
index 471d7382c7d1..54da51ed43de 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1563,9 +1563,8 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
1563{ 1563{
1564 struct bio_vec *bvec; 1564 struct bio_vec *bvec;
1565 const int read = bio_data_dir(bio) == READ; 1565 const int read = bio_data_dir(bio) == READ;
1566 struct bio_map_data *bmd = bio->bi_private; 1566 char *p = bio->bi_private;
1567 int i; 1567 int i;
1568 char *p = bmd->sgvecs[0].iov_base;
1569 1568
1570 bio_for_each_segment_all(bvec, bio, i) { 1569 bio_for_each_segment_all(bvec, bio, i) {
1571 char *addr = page_address(bvec->bv_page); 1570 char *addr = page_address(bvec->bv_page);
@@ -1577,7 +1576,6 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
1577 p += bvec->bv_len; 1576 p += bvec->bv_len;
1578 } 1577 }
1579 1578
1580 kfree(bmd);
1581 bio_put(bio); 1579 bio_put(bio);
1582} 1580}
1583 1581
@@ -1595,28 +1593,58 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
1595struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, 1593struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
1596 gfp_t gfp_mask, int reading) 1594 gfp_t gfp_mask, int reading)
1597{ 1595{
1598 struct bio *bio; 1596 unsigned long kaddr = (unsigned long)data;
1597 unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
1598 unsigned long start = kaddr >> PAGE_SHIFT;
1599 struct bio_vec *bvec; 1599 struct bio_vec *bvec;
1600 int i; 1600 struct bio *bio;
1601 void *p = data;
1602 int nr_pages = 0, i;
1601 1603
1602 bio = bio_copy_user(q, NULL, (unsigned long)data, len, 1, gfp_mask); 1604 /*
1603 if (IS_ERR(bio)) 1605 * Overflow, abort
1604 return bio; 1606 */
1607 if (end < start)
1608 return ERR_PTR(-EINVAL);
1605 1609
1606 if (!reading) { 1610 nr_pages = end - start;
1607 void *p = data; 1611 bio = bio_kmalloc(gfp_mask, nr_pages);
1612 if (!bio)
1613 return ERR_PTR(-ENOMEM);
1608 1614
1609 bio_for_each_segment_all(bvec, bio, i) { 1615 while (len) {
1610 char *addr = page_address(bvec->bv_page); 1616 struct page *page;
1617 unsigned int bytes = PAGE_SIZE;
1611 1618
1612 memcpy(addr, p, bvec->bv_len); 1619 if (bytes > len)
1613 p += bvec->bv_len; 1620 bytes = len;
1614 } 1621
1622 page = alloc_page(q->bounce_gfp | gfp_mask);
1623 if (!page)
1624 goto cleanup;
1625
1626 if (!reading)
1627 memcpy(page_address(page), p, bytes);
1628
1629 if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)
1630 break;
1631
1632 len -= bytes;
1633 p += bytes;
1615 } 1634 }
1616 1635
1617 bio->bi_end_io = bio_copy_kern_endio; 1636 if (!reading)
1637 bio->bi_rw |= REQ_WRITE;
1618 1638
1639 bio->bi_private = data;
1640 bio->bi_end_io = bio_copy_kern_endio;
1619 return bio; 1641 return bio;
1642
1643cleanup:
1644 bio_for_each_segment_all(bvec, bio, i)
1645 __free_page(bvec->bv_page);
1646 bio_put(bio);
1647 return ERR_PTR(-ENOMEM);
1620} 1648}
1621EXPORT_SYMBOL(bio_copy_kern); 1649EXPORT_SYMBOL(bio_copy_kern);
1622 1650