]> xenbits.xensource.com Git - seabios.git/commitdiff
virtio-blk: split large IO according to size_max
authorAndy Pei <andy.pei@intel.com>
Tue, 7 Dec 2021 01:31:08 +0000 (09:31 +0800)
committerKevin O'Connor <kevin@koconnor.net>
Sat, 18 Dec 2021 16:52:43 +0000 (11:52 -0500)
if driver reads data larger than VIRTIO_BLK_F_SIZE_MAX,
it will cause some issue to the DMA engine.

So when upper software wants to read data larger than
VIRTIO_BLK_F_SIZE_MAX, virtio-blk driver split one large
request into multiple smaller ones.

Signed-off-by: Andy Pei <andy.pei@intel.com>
Signed-off-by: Ding Limin <dinglimin@cmss.chinamobile.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
src/hw/virtio-blk.c

index 82b1d2a8cbe5be5436c9f466a3741cd53904859c..929ba8873dc01d06c96bd978c7f03862727eff8e 100644 (file)
 #include "virtio-ring.h"
 #include "virtio-blk.h"
 
+#define min(a, b) ({\
+               typeof(a) _a = a;\
+               typeof(b) _b = b;\
+               _a < _b ? _a : _b; })
+
 struct virtiodrive_s {
     struct drive_s drive;
     struct vring_virtqueue *vq;
@@ -82,8 +87,36 @@ 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;
+
+    if (vdrive->drive.blksize != 0 && max_io_size != 0)
+        blk_num_max = (u16)max_io_size / vdrive->drive.blksize;
+    else
+        /* default blk_num_max if hardware doesnot advise a proper value */
+        blk_num_max = 8;
 
-    virtio_blk_op_one_segment(vdrive, write, sg);
+    if (op->count <= blk_num_max) {
+        virtio_blk_op_one_segment(vdrive, write, sg);
+    } else {
+        void *p  = op->buf_fl;
+        u16 count = op->count;
+
+        while (count > 0) {
+            u16 blk_num = min(count, blk_num_max);
+            sg[1].length = vdrive->drive.blksize * blk_num;
+            sg[1].addr = p;
+            virtio_blk_op_one_segment(vdrive, write, sg);
+            if (status == VIRTIO_BLK_S_OK) {
+                hdr.sector += blk_num;
+                p += sg[1].length;
+                count -= blk_num;
+            } else {
+                break;
+            }
+        }
+    }
     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
 }