简介

        上一篇介绍vritio的生产者消费者virtio介绍 (一)生产者/消费者模式, 这一篇继续扩展,介绍下virtio的核心逻辑virtio queue

单个ring环扩展到三个ring环

       我们先解释下为什么要用三个ring环来标记数据,解释之前思考下为什么不能用一个ring环处理数据? 先看下单个环结构体如下图所示:

       单个ring环中每个idx中只能存放固定大小的数据,idx0 1 2 ~ 7中的数据大小必须一样,如果想放入比较大的数据,需要占用多个idx。除此之外,ring环使用时前端可以一次性放入ring环多个数据,但是后端必须顺序执行,举个例子来说明下。

        以上图ring环为例,假设 2 3 4 5为前端往ring 环中写入的io数据,后端将四个数据取出,解析之后提交给硬件来获取io数据,我们提交的顺序是2 --> 3 --> 4 --> 5, 但是由于io返回是由硬件决定的,不确定某个io什么时候回来,可能回来的顺序是4 --> 2 --> 5 -->3,甚至有可能3出现特别久甚至卡io。这个时候ring环中的数据是这样的:

2中的数据处理完之后,后端将读指针从2移动到3,然后buf 2现在就成了闲置缓冲器,可以重新写入数据;但是由于3没处理完,后端只能将读指针移动到3,实际上4 和 5已经处理完了,但是由于无法移动读指针,所以后端无法将io返回回去,并且4和5的buf也无法标记成闲置出来。

        总结下来就是单个ring环无法解决两个问题:

  1. io完成较早的(比如idx4和idx5的io)会被io完成交慢的阻塞(比如idx3)
  2. io的大小无法随意大小变换,尤其是io数据比较大时 

        为了解决上面这个第一个问题,我们把一个ring环扩展成两个,一个用于标记读指针(used ring),一个用于标记写指针(avail ring)。接下来我们看下两个ring环遇到上面处理idx3 idx4 idx5是的情况。

第一步:初始阶段,前端往ring环中写入数据

        

第二步:后端完成数据后

第三步:前端再次写入输入阶段

        从上面可以看出来,idx3的io虽然没有完成,但是没有阻塞整个ring环的操作流程,完美的解决了第一个问题。操作上,两个ring环由前端和后端分别维护,前端只修改avail ring,写入数据前使用used ring环作为判断;后端只修改used ring。

        接下来就是最后一个desc ring环了, 这个ring环是为了解决io大小不固定的问题。我们先看下desc ring环在实现上的数据格式:

struct vring_desc {

    __virtio64 addr;            /* Address (guest-physical). */

    __virtio32 len;              /* Length. */

    __virtio16 flags;           /* The flags as indicated above. */

    __virtio16 next;            /* We chain unused descriptors via this, too */

};

对上面数据解释下:

  • addr: 表示数据的首地址, 和len组合在一起,表示这个这个数据在内存中的大小和位置。前端和后端的内存不一致,这个地方需要地址翻译,后续会写一篇关于地址翻译的,这里默认这个地址前端和后端都能直接拿到数据。
  • len: 数据长度,和addr组合在一起,解决不固定长度的问题。
  • flag:标签,表示当前viritio的类型,有可能是packed模式,这个后面再讲解。
  • next: 下一个的位置,比如当前vring_desc的idx为10,通常next的值为11

举个例子,比如前端往想要获取一个io,判断通过avail ring和used ring找到一个可用的idx值,比如idx=4。然后把viritio通信的数据放入到vring_desc[4 - 1]中,这里是数组,所有idx -1 才是数据位置。 

virtio处理数据流程

        上面的介绍了从单个ring环扩展到三个ring环avail,used, desc的原因,我们趁热打铁,用这三个ring环完整的介绍下io在前端和后端之间流转的整个过程。

步骤一:初始化

        如下图,此时为初始化状态,

ring环大小为4,avail,used两个ring环都执指向idx0,ring环中的数据都为0;desc环我们这里用一个表来展示,desc中都为空。

步骤一:初始状态

        前端需要写入三个数据,

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐