|
@@ -6,7 +6,6 @@
|
|
|
#include <linux/virtio_blk.h>
|
|
|
#include <linux/scatterlist.h>
|
|
|
|
|
|
-#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS)
|
|
|
#define PART_BITS 4
|
|
|
|
|
|
static int major, index;
|
|
@@ -26,8 +25,11 @@ struct virtio_blk
|
|
|
|
|
|
mempool_t *pool;
|
|
|
|
|
|
+ /* What host tells us, plus 2 for header & tailer. */
|
|
|
+ unsigned int sg_elems;
|
|
|
+
|
|
|
/* Scatterlist: can be too big for stack. */
|
|
|
- struct scatterlist sg[VIRTIO_MAX_SG];
|
|
|
+ struct scatterlist sg[/*sg_elems*/];
|
|
|
};
|
|
|
|
|
|
struct virtblk_req
|
|
@@ -97,8 +99,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
|
|
if (blk_barrier_rq(vbr->req))
|
|
|
vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
|
|
|
|
|
|
- /* This init could be done at vblk creation time */
|
|
|
- sg_init_table(vblk->sg, VIRTIO_MAX_SG);
|
|
|
sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
|
|
|
num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
|
|
|
sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
|
|
@@ -130,7 +130,7 @@ static void do_virtblk_request(struct request_queue *q)
|
|
|
|
|
|
while ((req = elv_next_request(q)) != NULL) {
|
|
|
vblk = req->rq_disk->private_data;
|
|
|
- BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
|
|
|
+ BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
|
|
|
|
|
|
/* If this request fails, stop queue and wait for something to
|
|
|
finish to restart it. */
|
|
@@ -196,12 +196,22 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|
|
int err;
|
|
|
u64 cap;
|
|
|
u32 v;
|
|
|
- u32 blk_size;
|
|
|
+ u32 blk_size, sg_elems;
|
|
|
|
|
|
if (index_to_minor(index) >= 1 << MINORBITS)
|
|
|
return -ENOSPC;
|
|
|
|
|
|
- vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
|
|
|
+ /* We need to know how many segments before we allocate. */
|
|
|
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
|
|
|
+ offsetof(struct virtio_blk_config, seg_max),
|
|
|
+ &sg_elems);
|
|
|
+ if (err)
|
|
|
+ sg_elems = 1;
|
|
|
+
|
|
|
+ /* We need an extra sg elements at head and tail. */
|
|
|
+ sg_elems += 2;
|
|
|
+ vdev->priv = vblk = kmalloc(sizeof(*vblk) +
|
|
|
+ sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL);
|
|
|
if (!vblk) {
|
|
|
err = -ENOMEM;
|
|
|
goto out;
|
|
@@ -210,6 +220,8 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|
|
INIT_LIST_HEAD(&vblk->reqs);
|
|
|
spin_lock_init(&vblk->lock);
|
|
|
vblk->vdev = vdev;
|
|
|
+ vblk->sg_elems = sg_elems;
|
|
|
+ sg_init_table(vblk->sg, vblk->sg_elems);
|
|
|
|
|
|
/* We expect one virtqueue, for output. */
|
|
|
vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
|
|
@@ -277,6 +289,10 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|
|
}
|
|
|
set_capacity(vblk->disk, cap);
|
|
|
|
|
|
+ /* We can handle whatever the host told us to handle. */
|
|
|
+ blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
|
|
|
+ blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
|
|
|
+
|
|
|
/* No real sector limit. */
|
|
|
blk_queue_max_sectors(vblk->disk->queue, -1U);
|
|
|
|
|
@@ -290,12 +306,6 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|
|
else
|
|
|
blk_queue_max_segment_size(vblk->disk->queue, -1UL);
|
|
|
|
|
|
- err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
|
|
|
- offsetof(struct virtio_blk_config, seg_max),
|
|
|
- &v);
|
|
|
- if (!err)
|
|
|
- blk_queue_max_hw_segments(vblk->disk->queue, v);
|
|
|
-
|
|
|
/* Host can optionally specify the block size of the device */
|
|
|
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
|
|
|
offsetof(struct virtio_blk_config, blk_size),
|