五、virtio_blk在FPGA中实现的难点分析
在virtio_blk控制器设计之中,最难的、也最重要的是对应queue的读或者写的IO不能出现丢弃的情形。因为host侧发出去的读写IO丢失,会导致host驱动异常,轻则会把对应的queue挂住,重则会引起virtio_blk控制器出现严重错误,无法工作,以致整个系统卡死。
这里面列出主要可能出现丢IO的节点,可以根据图1来说明。
(1)virtio_blk控制器到soc之间链路的存储包丢失。
(2)Soc异常导致的转发存储包丢失。
(3)远端磁盘读写异常,没有返回完成包,导致存储包丢失。
针对这三种情形,现在分别列出对应的处理策略。
(1)virtio_blk控制器到soc之间链路的存储包丢失。
当soc侧处理繁忙,一时无法接收virtio_blk控制器送过来的存储包,在FPGA内部是不会直接丢弃的,会层级反压至host侧,不过如果soc意外将virtio_net_blk模块对应的传输通道给复位了,那就会导致此通道无效,从virtio_blk控制器传输过来的包就会依次丢弃,只有等到virtio_net_blk重新被soc使能后才会继续传输存储包。针对这种情形,FPGA内部得做断点处理。具体实现方式就是,SOC在重新启动virtio_net_blk模块之前,主动的发一个断点消息告诉virtio_blk控制器,让他知道此时有丢包情况,此时virtio_blk控制器会通过used_index来判断断点的位置,进而重新发起已被丢弃的IO 的传输。同时soc侧得重现检测断点的位置。
(2)Soc异常导致转发存储包丢失。
这种情形时,处理比较容易,因为soc转发存储包采用的是TCP协议,里面是可以重新建链传输的,即使异常丢失了,也会发起重传的。
(3)远端磁盘读写异常,没有返回完成包,导致存储包丢失。
这种情况,在soc侧可以做一个超时机制,如果等待一段时间,远端磁盘还是没有回复是否完成读写操作,soc即可主动构建一个完成包返回给virtio_blk控制器,只不过对应包尾的status值则标记为异常,主机收到对应的状态后,自会进行一些列处理,这样的话整个传输就不会卡在这。如果过了超时,远端磁盘才返回完成信息,这个时候soc需要直接舍弃这个结果,以免重复引起不必要的错误。