花点时间来总结一下前阵子的工作。
qemu的底层块设备无疑是我所见过的最复杂的模块了,说得好像我很精通很多模块一样(大雾)。
它的raw镜像格式文件的驱动的核心代码主要都是在raw-posix.c文件下面了看看那里的各种API吧哈哈哈。名字也起的特别的显眼,很容易就让人清楚那个API究竟是干啥用的。
目前阅读代码所能认知到那群维护者所用到的技术有 异步IO(AIO),多线程,协程(couroutine)。
对于异步IO的内容,不想在这里说太多,读者有空可以看看《UNP》卷一,那里有一章节对于各种各样的IO总结的很棒。
qemu对于异步IO有两种的选择方式,你可以在guest的启动脚本里对其进行设置,实际上就是aio的选项,aio=native的话,那么你就要为你的linux安装好libaio库,这样子你的linux机器才能跑得动异步io的程序,这样子qemu才能在块设备驱动的读写当中用到异步IO的接口。如果aio=threads的话,那么qemu就会使用自己创建的线程池来模拟这么一个异步IO。。。哈哈哈真是太吊了。。。这部分的代码真是神才能写的出来。。。。那些神究竟要对这些玩意儿脑子里多清楚才能写得出来啊。。这两个选择我们可以在这里看到
CONFIG_LINUX_AIO就是针对于linux本地的aio库的一个宏,如果没有定义(host上没有libaio库),这段红色的代码就会被忽略过去而跑去执行paio_submit,也就是用线程池模拟的异步IO
咱们现在来跳到handle_aiocb_rw这里,这个接口主要就是针对快设备数据((RawPosixAIOData )的读写的一个接口,没错,qemu就是这么的叼炸天,读和写都放在同一个接口里面处理!
总体来说,qemu貌似很喜欢使用io向量来处理数据(或许效率更高)?妈蛋,那要我们怎么拦截读写请求的数据嘛,没关系,qemu的作者很细心,似乎考虑到总有想我们这一群qemu hacker,也或许是防止qemu的io向量的处理机制出问题了
/* * We have more than one iovec, and all are properly aligned. * * Try preadv/pwritev first and fall back to linearizing the * buffer if it's not supported. */
如果处理io向量出问题了,
那么后面就会有相应的处理机制,将所有的io向量对其到一个linear buffer里面
利用这一纯天然没有任何防腐添加剂的方法,我们可以通过这个步骤来讲所有的数据转换成linear buffer形式的,那我们就可以将这些数据进行拦截并扔到缓存里面咯~
很简单,只要将preadv_present从true改写成false,那么他就无法正确读取io向量的数据咯~拦截下来扔到缓存里面就ok了。
缓存的实现目前还不适合公开,因为性能还远未达到我们的要求,还在处于不断地优化调试当中,不过已经可以正常地跑起来了,并且我相信最终会有性能提高的,因为我们现在将线程池里面线程的数目设置为1,原先的是64个线程,主要遇到了多个io线程同步的问题不得不先将线程的数目设置为1。不过这几个月总算没有白费,收获还是不少滴~