我想做下Lab5的Challenge:实现Copy on Write机制。搜了一下资料,发现ucore的直接实现有两个地方,一个是ucorebook_code,做的比较早,与现在的ucore_lab还是有一定的差距的,另一个是ucore_lab中的lab5_X分支,实现较为简陋,没有实现swap下的COW机制。还有就是ucore的一部分算法思想是基于Linux 2.4.0的,可以在这里找到一些相关实现。
这里我主要研究的是 ucorebook_code上的实现。这里在proj9.2、物理内存管理的时候就已经开始为COW做准备,到proj12、实现用户态程序的地方算是完整实现了基于COW的进程创建。主要实现在两个地方,一个是pmm.c中的copy_range,是在创建进程、复制内存的时候起作用。还有一个是vmm.c中的do_pgfault,是在中断处理的时候起作用。
这里有一个参考资料是ucore_book中的实现写时复制
不过ucorebook_code中的代码注释很少,相关的资料也比较少,我看这个花了很长实现,查看了Linux中的相关实现以及其他一些参考资料,也半推断半猜测地解决了一些问题,但觉得还是有很多不是很清楚的问题。
下面是我在看代码的过程中的总结和一些疑问。
首先是copy_mm这个函数。这个函数会判断clone_flags中CLONE_VM为是否为1。这里的CLONE_VM跟COW并没啥关系,而是说父子进程共用一个mm结构,也就意味着一个进程对于其内存的修改会直接影响到另一个进程。
如果没有CLONE_VM标志的话,就会进行内存的复制。
复制的关键函数在dup_mmap。这个函数有两个参数,父子进程的mm结构。
dup_mmap进程会对父进程的所有vma进行遍历,然后创建相应的vma结构给子进程。最后会调用copy_range复制vma的内容。
这里的copy_range有一个参数是share,不过这个同样跟COW没啥直接的关系。share的值是这样确定的:“bool share = (vma->vm_flags & VM_SHARE);”。
注意:这里我们可以发现有两个有关共享内存的标志:CLONE_VM和VM_SHARE。要注意两者的区别:CLONE_VM是clone的参数,说明父子进程是否使用相同的mm结构。而VM_SHARE是具体某个vma的标志,如果没有CLONE_VM的话,则会将父进程所有的vma结构都复制给子进程,在这个过程中会判断该vma结构的VM_SHARE是否为1,如果是的话则对该vma结构不是使用复制操作而是直接共享内存。
一个我觉得需要注意的地方是,这个COW机制,其实并没有哪个函数的哪个参数指定要不要使用。而是跟操作系统是否实现了这个机制有关。如果操作系统实现了,那能用到COW的地方都会用到COW。如果操作系统没实现,那么就都不使用。这里把具体细节屏蔽了,具体的进程是感觉不到的。
这里实现COW主要就是如果发现源PTE的PTE_W为1,则将该位清零之后同时加入到父子进程中。
具体操作是把改PTE的page结构和权限perm都提出来,去掉perm中的PTE_W属性,然后再重现通过page_insert添加到原来的位置,以实现修改perm的效果。
疑问:对于父进程,有:"page_insert(from, page, start, perm | (*ptep & PTE_SWAP));",而对于子进程则是"page_insert(to, page, start, perm);",这里的PTE_SWAP起到什么作用?
疑问:这里如果ptep的PTE_P位置一的话会进行COW的复制,可是如果PTE_P位为0则会通过swap_duplicate进行一些处理。这个处理是干什么的?在ucore_lab中也有swap