以下设备的顺序与文档顺序不太一样, 或者不全, 日后会补, 遗留的特征等不会写上来

块设备

什么是块设备

在文档中的定义如下: Virtio块设备是一个简单的虚拟块设备, 比如磁盘等, 读取和写入请求被放入在了队列中, 并由设备处理(可能不是顺序处理), 块设备的Device ID为2

块设备的特征bits

bit 特证名 解释
1 VIRTIO_BLK_F_SIZE_MAX 最大的任何segment的大小放在了size_max
2 VIRTIO_BLK_F_SEG_MAX 一个request的最大数量segment放在了seg_max
4 VIRTIO_BLK_F_GEOMETRY Disk-style geometry放在了geometry
5 VIRTIO_BLK_F_RO 设备是只读
6 VIRTIO_BLK_F_BLK_SIZE 磁盘的块大小放在了blk_size
9 VIRTIO_BLK_F_FLUSH 支持缓存刷新命令
10 VIRTIO_BLK_F_TOPOLOGY 设备利用最佳I/O对齐(optimal I/O alignment)导出消息
11 VIRTIO_BLK_F_CONFIG_WCE 设备的缓存可以在writeback和writethrough模式之间循环切换
13 VIRTIO_BLK_F_DISCARD 设备可以支持discard(丢弃)命令, 最多可以discard的sector数量放在了max_discard_sectors以及最多可以discard的segment数量放在了max_discard_seg
14 VIRTIO_BLK_F_WRITE_ZEROES 设备可以支持全写0命令, 最多可以全写0的sector数量放在了max_discard_sectors以及最多可以全写0的segment数量放在了max_discard_seg

设备配置空间

这里直接放个文档中的截图, le64代表小端64bit, le32代表小端32bit, le16代表小端16bit, u8代表8bit

image-20220917192134946

其中capacity代表一个设备能支持的最大容量, 单位为512byte的扇区, 这一字段总是存在的, 其他的需要特征是否启用, 配置空间中的max_discard_secotrs, discard_sector_alignment 以及max_write_zeroes_sectors的单位均为512-byte.

设备初始化

  1. 设备的大小可以从capacity中获取到
  2. 如果有VIRTIO_BLK_F_BLK_SIZE特征, 则blk_size可以用来决定最佳的扇区大小,这不会影响协议中其他的单位(均为512bytes).
  3. 如果有VIRTIO_BLK_F_RO特征, 则所有的写操作都会失效
  4. 如果有VIRTIO_BLK_F_TOPOLOGY特征, 则驱动可以使用topology结构体可以用来决定物理块大小和最佳的I/O长度, 同样不会影响协议中其他的单位
  5. 如果有VIRTIO_BLK_F_CONFIG_WCE特征, 则可以通过读取或者写入writeback来获取/修改缓存模式, 0代表writethrough模式, 1代表writeback模式
  6. 如果有VIRTIO_BLK_F_DISCARD特征, 则驱动可以使用max_discard_sectorsmax_discard_seg来获得最大可以discard的扇区以及segments, 当基于对齐拆分请求时, 操作系统可以使用discard_sector_alignment
  7. 如果有VIRTIO_BLK_F_WRITE_ZEROES特征, 则驱动可以使用max_write_zeroes_sectorsmax_write_zeroes_seg来获得最大可以写入0的扇区以及segments

驱动注意事项

  1. 驱动不能请求VIRTIO_BLK_F_FLUSH特征如果驱动不能发送VIRTIO_BLK_F_FLUSH命令
  2. 如果VIRTIO_BLK_F_CONFIG_WCE以及VIRTIO_BLK_F_FLUSH都没有仲裁, 那么驱动应该假设使用了缓存使用了writethrough模式, 如果前者没有仲裁, 后者由, 则驱动应该假设缓存使用了writeback模式
  3. 在FEATURES_OK之前, 驱动不能读取writeback字段

设备操作

驱动使用virtqueue来请求服务, 每个请求大致结构如下:

image-20220917193826918

其中的type只能取下面其中之一的值:

解释
0 VIRTIO_BLK_T_IN 请求读取块设备中的数据
1 VIRTIO_BLK_T_OUT 请求写入数据到块设备中
4 VIRTIO_BLK_T_FLUSH 刷新指令(缓存?可能是)
11 VIRTIO_BLK_T_DISCARD discard指令
13 VIRTIO_BLK_T_WRITE_ZEROS write zeroes指令

sector字段代表从哪个位置读取或者写入数据, 单位为512 bytes, 如果不是IN或者OUT则要设为0, discard或者write zeroes指令需要更多的字段, 这些字段被放在了data中, 字段的结构如下:

image-20220917194736992

其中sector与IN或者OUT代表的意义一样, num_sectors代表操作多少个扇区, unmap只用在write zeros命令, 允许设备discard一个特定的区域, 前提是后续读取返回0

最终读取的状态由设备写入, 他们的值以及代表的意义为:

  • VIRTIO_BLK_S_OK 0: 成功
  • VIRTIO_BLK_S_IOERR 1: 设备或者驱动出错
  • VIRTIO_BLK_S_UNSUPP: 设备不支持的请求