【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

Read the fucking source code! --By 鲁迅

A picture is worth a thousand words. --By 高尔基

说明:

KVM版本:5.9.1

QEMU版本:5.0.0

工具:Source Insight 3.5, Visio

文章同步在博客园:https://www.cnblogs.com/LoyenWang/

1. 概述

汪汪汪,最近忙成狗了,一下子把我更新的节奏打乱了,草率的道个歉。

【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

前边系列将Virtio Device和Virtio Driver都已经讲完,本文将分析virtqueue;

virtqueue用于前后端之间的数据交换,一看到这种数据队列,首先想到的就是ring-buffer,实际的实现会是怎么样的呢?

2. 数据结构

先看一下核心的数据结构:

【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

通常Virtio设备操作Virtqueue时,都是通过struct virtqueue结构体,这个可以理解成对外的一个接口,而Virtqueue机制的实现依赖于struct vring_virtqueue结构体;

Virtqueue有三个核心的数据结构,由struct vring负责组织:

struct vring_desc:描述符表,每一项描述符指向一片内存,内存类型可以分为out类型和in类型,分别代表输出和输入,而内存的管理都由驱动来负责。该结构体中的next字段,可用于将多个描述符构成一个描述符链,而flag字段用于描述属性,比如只读只写等;

struct vring_avail:可用描述符区域,用于记录设备可用的描述符ID,它的主体是数组ring,实际就是一个环形缓冲区;

struct vring_used:已用描述符区域,用于记录设备已经处理完的描述符ID,同样,它的ring数组也是环形缓冲区,与struct vring_avail不同的是,它还记录了设备写回的数据长度;

这么看,当然是有点不太直观,所以,下图来了:

【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

简单来说,驱动会分配好内存(scatterlist),并通过virtqueue_add添加到描述表中,这样描述符表中的条目就都能对应到具体的物理地址了,其实可以把它理解成一个资源池子;

驱动可以将可用的资源更新到struct vring_avail中,也就是将可用的描述符ID添加到ring数组中,熟悉环形缓冲区的同学应该清楚它的机制,通过维护头尾两个指针来进行管理,Driver负责更新头指针(idx),Device负责更新尾指针(Qemu中的Device负责维护一个last_avail_idx),头尾指针,你追我赶,生生不息;

当设备使用完了后,将已用的描述符ID更新到struct vring_used中,vring_virtqueue自身维护了last_used_idx,机制与struct vring_avail一致;

3. 流程分析 3.1 发送

【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

当驱动需要把数据发送给设备时,流程如上图所示:

①A表示分配一个Buffer并添加到Virtqueue中,①B表示从Used队列中获取一个Buffer,这两种中选择一种方式;

②表示将Data拷贝到Buffer中,用于传送;

③表示更新Avail队列中的描述符索引值,注意,驱动中需要执行memory barrier操作,确保Device能看到正确的值;

④与⑤表示Driver通知Device来取数据;

⑥表示Device从Avail队列中获取到描述符索引值;

⑦表示将描述符索引对应的地址中的数据取出来;

⑧表示Device更新Used队列中的描述符索引;

⑨与⑩表示Device通知Driver数据已经取完了;

3.2 接收

【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue

当驱动从设备接收数据时,流程如上图所示:

①表示Device从Avail队列中获取可用描述符索引值;

②表示将数据拷贝至描述符索引对应的地址上;

③表示更新Used队列中的描述符索引值;

④与⑤表示Device通知Driver来取数据;

⑥表示Driver从Used队列中获取已用描述符索引值;

⑦表示将描述符索引对应地址中的数据取出来;

⑧表示将Avail队列中的描述符索引值进行更新;

⑨与⑩表示Driver通知Device有新的可用描述符;

3.3 代码分析

代码的分析将围绕下边这个图来展开(Virtio-Net),偷个懒,只分析单向数据发送了:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzpxs.html