添加MemoryRegion
本章我们将以添加MemoryRegion为线索,动态得考察各个数据结构及其之间的变化。
那添加MemoryRegion的线索是谁呢? 就是这个
memory_region_transaction_commit()
那就以此开始。
精简的call flow
让我们先从全局观察这个函数,获得一个全局的概念。
从上面的精简版来看,添加一个MemoryRegion需要做如下几件事:
flatviews_reset: 重构所有AddressSpace的flatview
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward)
address_space_set_flatview: 根据变化添加删除region
address_space_update_ioeventfds: 根据变化添加删除eventfd
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward)
所以总的来讲也就这五个步骤,其中第一个步骤就是将MemoryRegion转换为FlatView,而其余的四个步骤都是根据FlatView的变化做出相应的调整。
MemoryListener
为了辅助地址空间的动态变化,还需要了解一个数据结构 MemoryListener。
有经验的朋友到这估计猜出来了,这个就是一个回调函数的集合,用在必要的时间点调用到这些钩子。
那在什么地方去调用这些回调函数呢?最主要的一共有两个宏定义
MEMORY_LISTENER_CALL_GLOBAL
MEMORY_LISTENER_CALL
这两个宏定义长得非常像,只有一点点的差别。那就是调用的MemoryListener的链表不同。
在memory_listener_register注册MemoryListener的时候,会注册到两个地方
memory_listeners
as->listeners
也就是一个是全局的链表,一个是AddressSpace自身的链表。
所以我们可以总结一下添加MemoryRegion时需要做的操作
根据新的MemoryRegion树生成FlatView
比较新旧FlatView调用MemoryListener进行修改
以KVM为例
最后我们以KVM为例,看看kvm是如何将客户机的内存通知给内核模块的。
既然知道了上述的流程概述,那么就知道重点是看kvm注册的MemoryListener的回调函数是什么。
查看代码,发现有两个重要的成员是:
那我们以region_add为例,看看添加一个MemoryRegion时做的工作。
所以最后是调用了KVM_SET_USER_MEMORY_REGION这个ioctl将qemu用户态的内存传给了kvm内核模块。
Last updated