diff options
author | Christoph Hellwig <hch@lst.de> | 2015-01-18 10:16:28 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-02-05 11:30:35 -0500 |
commit | 42d2683a2704ef4bbbb07fd0b9486ab312dd8c56 (patch) | |
tree | cb58108edf8735e9f984ace40e48688d2c5c82f3 /block/bio.c | |
parent | ad9cf3bbd18a94806314741ac8092c3422f5aebe (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.c | 60 |
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) | |||
1595 | struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, | 1593 | struct 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 | |||
1643 | cleanup: | ||
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 | } |
1621 | EXPORT_SYMBOL(bio_copy_kern); | 1649 | EXPORT_SYMBOL(bio_copy_kern); |
1622 | 1650 | ||