This is an implementation of the new rw_page interface. It primarily demonstrates a low-impact, low-reward method for adding support to a driver. I don't expect it to improve performance; in fact I expect it to worsen performance slightly since there are still memory allocations in the I/O path. Please don't apply this patch. Signed-off-by: Matthew Wilcox <matthew.r.wilcox@xxxxxxxxx> --- drivers/block/virtio_blk.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6a680d4..4c1c9ad 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -110,11 +110,22 @@ static int __virtblk_add_req(struct virtqueue *vq, return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); } +#define rw_to_dmad(rw) (((rw) == WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) + static inline void virtblk_request_done(struct virtblk_req *vbr) { struct request *req = vbr->req; int error = virtblk_result(vbr); + if ((unsigned long)req & 1) { + struct virtio_blk *vblk = (void *)((unsigned long)req & ~1UL); + int rw = (vbr->out_hdr.type & VIRTIO_BLK_T_OUT) ? WRITE : READ; + struct page *page = sg_page(vbr->sg); + dma_unmap_sg(&vblk->vdev->dev, vbr->sg, 1, rw_to_dmad(rw)); + page_endio(page, rw, error); + return; + } + if (req->cmd_type == REQ_TYPE_BLOCK_PC) { req->resid_len = vbr->in_hdr.residual; req->sense_len = vbr->in_hdr.sense_len; @@ -239,6 +250,38 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) return err; } +static int virtblk_rw_page(struct block_device *bdev, sector_t sector, + struct page *page, int rw) +{ + unsigned long flags; + struct virtio_blk *vblk = bdev->bd_disk->private_data; + struct virtblk_req *vbr; + int err; + + vbr = kmalloc(sizeof(*vbr) + sizeof(struct scatterlist), GFP_NOFS); + if (!vbr) + return -ENOMEM; + + vbr->req = (void *)((unsigned long)vblk | 1); + vbr->out_hdr.type = (rw == WRITE) ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN; + vbr->out_hdr.sector = sector; + vbr->out_hdr.ioprio = 0; + + sg_init_table(vbr->sg, 1); + sg_set_page(vbr->sg, page, PAGE_CACHE_SIZE, 0); + sg_mark_end(vbr->sg); + if (dma_map_sg(&vblk->vdev->dev, vbr->sg, 1, rw_to_dmad(rw))) { + kfree(vbr); + return -ENOMEM; + } + + spin_lock_irqsave(&vblk->vq_lock, flags); + err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, 1); + virtqueue_kick(vblk->vq); + spin_unlock_irqrestore(&vblk->vq_lock, flags); + return err; +} + static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long data) { @@ -278,6 +321,7 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) } static const struct block_device_operations virtblk_fops = { + .rw_page = virtblk_rw_page, .ioctl = virtblk_ioctl, .owner = THIS_MODULE, .getgeo = virtblk_getgeo, -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html