if driver reads data larger than VIRTIO_BLK_F_SIZE_MAX, it will cause some issue to the DMA engine.
Signed-off-by: Andy Pei andy.pei@intel.com Signed-off-by: Ding Limin dinglimin@cmss.chinamobile.com --- src/hw/virtio-blk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 14 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 7935f0f..2068823 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -30,6 +30,33 @@ struct virtiodrive_s { struct vp_device vp; };
+void +virtio_blk_op_one_segment(struct virtiodrive_s *vdrive, + int write, struct vring_list sg[]) +{ + struct vring_virtqueue *vq = vdrive->vq; + + /* Add to virtqueue and kick host */ + if (write) + vring_add_buf(vq, sg, 2, 1, 0, 0); + else + vring_add_buf(vq, sg, 1, 2, 0, 0); + vring_kick(&vdrive->vp, vq, 1); + + /* Wait for reply */ + while (!vring_more_used(vq)) + usleep(5); + + /* Reclaim virtqueue element */ + vring_get_buf(vq, NULL); + + /** + ** Clear interrupt status register. Avoid leaving interrupts stuck + ** if VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. + **/ + vp_get_isr(&vdrive->vp); +} + static int virtio_blk_op(struct disk_op_s *op, int write) { @@ -56,26 +83,63 @@ virtio_blk_op(struct disk_op_s *op, int write) .length = sizeof(status), }, }; + u32 max_io_size = + vdrive->drive.max_segment_size * vdrive->drive.max_segments; + u16 blk_num_max;
- /* Add to virtqueue and kick host */ - if (write) - vring_add_buf(vq, sg, 2, 1, 0, 0); + if (vdrive->drive.blksize != 0 && max_io_size != 0) + blk_num_max = (u16)max_io_size / vdrive->drive.blksize; else - vring_add_buf(vq, sg, 1, 2, 0, 0); - vring_kick(&vdrive->vp, vq, 1); + /* default blk_num_max if hardware doesnot advise a proper value */ + blk_num_max = 8;
- /* Wait for reply */ - while (!vring_more_used(vq)) - usleep(5); + if (op->count <= blk_num_max) { + /* Add to virtqueue and kick host */ + if (write) + vring_add_buf(vq, sg, 2, 1, 0, 0); + else + vring_add_buf(vq, sg, 1, 2, 0, 0); + vring_kick(&vdrive->vp, vq, 1);
- /* Reclaim virtqueue element */ - vring_get_buf(vq, NULL); + /* Wait for reply */ + while (!vring_more_used(vq)) + usleep(5);
- /* Clear interrupt status register. Avoid leaving interrupts stuck if - * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. - */ - vp_get_isr(&vdrive->vp); + /* Reclaim virtqueue element */ + vring_get_buf(vq, NULL); + + /* Clear interrupt status register. Avoid leaving interrupts stuck if + * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. + */ + vp_get_isr(&vdrive->vp); + } else { + struct vring_list *p_sg = &sg[1]; + void *p = op->buf_fl; + u16 count = op->count; + + while (count > blk_num_max) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * blk_num_max; + virtio_blk_op_one_segment(vdrive, write, sg); + if (status == VIRTIO_BLK_S_OK) { + hdr.sector += blk_num_max; + p += p_sg->length; + count -= blk_num_max; + } else { + break; + } + }
+ if (status != VIRTIO_BLK_S_OK) + return DISK_RET_EBADTRACK; + + if (count > 0) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * count; + virtio_blk_op_one_segment(vdrive, write, sg); + } + + } return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; }
Signed-off-by: Andy Pei andy.pei@intel.com --- src/hw/virtio-blk.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 3b19896..4f9b1e7 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -30,6 +30,44 @@ struct virtiodrive_s { struct vp_device vp; };
+#define BLK_NUM_MAX 8 + +void dump(unsigned char *buf, int len) +{ + int i; + for (i = 0; i < len;) { + printf(" %2x", 0xff & buf[i++]); + if (i % 32 == 0) + printf("\n"); + } + printf("\n"); +} + +void +segment(struct virtiodrive_s *vdrive, int write, struct vring_list sg[]) +{ + struct vring_virtqueue *vq = vdrive->vq; + + /* Add to virtqueue and kick host */ + if (write) + vring_add_buf(vq, sg, 2, 1, 0, 0); + else + vring_add_buf(vq, sg, 1, 2, 0, 0); + vring_kick(&vdrive->vp, vq, 1); + + /* Wait for reply */ + while (!vring_more_used(vq)) + usleep(5); + + /* Reclaim virtqueue element */ + vring_get_buf(vq, NULL); + + /* Clear interrupt status register. Avoid leaving interrupts stuck if + * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. + */ + vp_get_isr(&vdrive->vp); +} + static int virtio_blk_op(struct disk_op_s *op, int write) { @@ -57,6 +95,7 @@ virtio_blk_op(struct disk_op_s *op, int write) }, };
+ if (op->count <= BLK_NUM_MAX) {/* added by andy */ /* Add to virtqueue and kick host */ if (write) vring_add_buf(vq, sg, 2, 1, 0, 0); @@ -75,7 +114,37 @@ virtio_blk_op(struct disk_op_s *op, int write) * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ vp_get_isr(&vdrive->vp); - + } else {/* added by Andy */ + struct vring_list *p_sg = &sg[1]; + void *p = op->buf_fl; + u16 count = op->count; + + while (count > BLK_NUM_MAX) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * BLK_NUM_MAX; + segment(vdrive, write, sg); + //dump(p, p_sg->length); + if (status == VIRTIO_BLK_S_OK) { + hdr.sector += BLK_NUM_MAX; + p += p_sg->length; + count -= BLK_NUM_MAX; + } else { + break; + } + } + + if (status != VIRTIO_BLK_S_OK) { + return DISK_RET_EBADTRACK; + } + + if(count > 0) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * count; + segment(vdrive, write, sg); + //dump(p, p_sg->length); + } + + }/* end of modification from Andy */ return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; }
Hi,
Terribly sorry for sending out a wrong patch. A V2 series will be sent, please ignore this patch set. Sorry for confusing.
-----Original Message----- From: Pei, Andy andy.pei@intel.com Sent: Wednesday, December 1, 2021 9:11 PM To: seabios@seabios.org Cc: kraxel@redhat.com; kevin@koconnor.net; Pei, Andy andy.pei@intel.com Subject: [PATCH] virtio-blk: segment large IO to 4K IO.
Signed-off-by: Andy Pei andy.pei@intel.com --- src/hw/virtio-blk.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 3b19896..4f9b1e7 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -30,6 +30,44 @@ struct virtiodrive_s { struct vp_device vp; };
+#define BLK_NUM_MAX 8 + +void dump(unsigned char *buf, int len) +{ + int i; + for (i = 0; i < len;) { + printf(" %2x", 0xff & buf[i++]); + if (i % 32 == 0) + printf("\n"); + } + printf("\n"); +} + +void +segment(struct virtiodrive_s *vdrive, int write, struct vring_list +sg[]) { + struct vring_virtqueue *vq = vdrive->vq; + + /* Add to virtqueue and kick host */ + if (write) + vring_add_buf(vq, sg, 2, 1, 0, 0); + else + vring_add_buf(vq, sg, 1, 2, 0, 0); + vring_kick(&vdrive->vp, vq, 1); + + /* Wait for reply */ + while (!vring_more_used(vq)) + usleep(5); + + /* Reclaim virtqueue element */ + vring_get_buf(vq, NULL); + + /* Clear interrupt status register. Avoid leaving interrupts stuck if + * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. + */ + vp_get_isr(&vdrive->vp); +} + static int virtio_blk_op(struct disk_op_s *op, int write) { @@ -57,6 +95,7 @@ virtio_blk_op(struct disk_op_s *op, int write) }, };
+ if (op->count <= BLK_NUM_MAX) {/* added by andy */ /* Add to virtqueue and kick host */ if (write) vring_add_buf(vq, sg, 2, 1, 0, 0); @@ -75,7 +114,37 @@ virtio_blk_op(struct disk_op_s *op, int write) * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ vp_get_isr(&vdrive->vp); - + } else {/* added by Andy */ + struct vring_list *p_sg = &sg[1]; + void *p = op->buf_fl; + u16 count = op->count; + + while (count > BLK_NUM_MAX) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * BLK_NUM_MAX; + segment(vdrive, write, sg); + //dump(p, p_sg->length); + if (status == VIRTIO_BLK_S_OK) { + hdr.sector += BLK_NUM_MAX; + p += p_sg->length; + count -= BLK_NUM_MAX; + } else { + break; + } + } + + if (status != VIRTIO_BLK_S_OK) { + return DISK_RET_EBADTRACK; + } + + if(count > 0) { + p_sg->addr = p; + p_sg->length = vdrive->drive.blksize * count; + segment(vdrive, write, sg); + //dump(p, p_sg->length); + } + + }/* end of modification from Andy */ return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; }
-- 1.8.3.1