fork() 进程如何将 parent 的 PTE 标记为只读?
How does fork() process mark parent's PTE's as read only?
我搜索了很多资源,但没有找到关于此事的具体内容:
我知道对于某些 linux 系统,fork()
系统调用与 copy-on-write 一起工作;也就是说,parent和child共享相同的地址space,但PTE现在被标记为read-only,以供使用后来的牛。当任何一个尝试访问页面时,都会发生 PAGE_FAULT
并且该页面被复制到另一个可以修改的地方。
但是,我无法理解 OS 如何到达共享 PTE 并将它们标记为 "read"。我假设当 fork()
系统调用发生时,OS 在 parent 的页面 table 上执行 "page walk" 并将它们标记为 read-only - 但我没有找到对此的确认,也没有找到有关该过程的任何信息。
有谁知道这些页面是如何被标记为只读的?将不胜感激任何帮助。谢谢!
Linux OS 通过遍历父进程的所有内存范围(mmap
s、栈和堆)实现系统调用 fork。复制该范围 (VMA - Virtual memory areas is in function copy_page_range
(mn/memory.c),它在页面 table 条目上循环:
copy_page_range
will iterate over pgd 并调用
copy_pud_range
遍历 pud 并调用
copy_pmd_range
遍历 pmd 并调用
copy_pte_range
遍历 pte 并调用
copy_one_pte
执行内存使用统计 (RSS) 并有几个代码段来处理 COW 情况:
/*
* If it's a COW mapping, write protect it both
* in the parent and the child
*/
if (is_cow_mapping(vm_flags)) {
ptep_set_wrprotect(src_mm, addr, src_pte);
pte = pte_wrprotect(pte);
}
其中 is_cow_mapping
对于私有页面和潜在的 writable 页面是正确的(检查共享位域标志和 maywrite bits 并且应该只设置 maywrite 位)
#define VM_SHARED 0x00000008
#define VM_MAYWRITE 0x00000020
static inline bool is_cow_mapping(vm_flags_t flags)
{
return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
}
PUD、PMD 和 PTE 在 https://www.kernel.org/doc/gorman/html/understand/understand006.html and in articles like LWN 2005: "Four-level page tables merged".
等书籍中有描述
fork 实现如何调用 copy_page_range
:
- fork 系统调用实现 (sys_fork? or syscall_define0(fork)) is
do_fork
(kernel/fork.c) 将调用
copy_process
which will call many copy_* functions,包括
copy_mm
调用
dup_mm
分配和填充新的 mm 结构,其中大部分工作由 完成
dup_mmap
(still kernel/fork.c) which will check what was mmaped and how. (Here I was unable to get exact path to COW implementation so I used the Internet Search Machine with something like "fork+COW+dup_mm" to get hints like [1] or [2] or [3])。检查 mmap 类型后,有 retval = copy_page_range(mm, oldmm, mpnt);
行可以做实际工作。
我搜索了很多资源,但没有找到关于此事的具体内容:
我知道对于某些 linux 系统,fork()
系统调用与 copy-on-write 一起工作;也就是说,parent和child共享相同的地址space,但PTE现在被标记为read-only,以供使用后来的牛。当任何一个尝试访问页面时,都会发生 PAGE_FAULT
并且该页面被复制到另一个可以修改的地方。
但是,我无法理解 OS 如何到达共享 PTE 并将它们标记为 "read"。我假设当 fork()
系统调用发生时,OS 在 parent 的页面 table 上执行 "page walk" 并将它们标记为 read-only - 但我没有找到对此的确认,也没有找到有关该过程的任何信息。
有谁知道这些页面是如何被标记为只读的?将不胜感激任何帮助。谢谢!
Linux OS 通过遍历父进程的所有内存范围(mmap
s、栈和堆)实现系统调用 fork。复制该范围 (VMA - Virtual memory areas is in function copy_page_range
(mn/memory.c),它在页面 table 条目上循环:
copy_page_range
will iterate over pgd 并调用copy_pud_range
遍历 pud 并调用copy_pmd_range
遍历 pmd 并调用copy_pte_range
遍历 pte 并调用copy_one_pte
执行内存使用统计 (RSS) 并有几个代码段来处理 COW 情况:
/*
* If it's a COW mapping, write protect it both
* in the parent and the child
*/
if (is_cow_mapping(vm_flags)) {
ptep_set_wrprotect(src_mm, addr, src_pte);
pte = pte_wrprotect(pte);
}
其中 is_cow_mapping
对于私有页面和潜在的 writable 页面是正确的(检查共享位域标志和 maywrite bits 并且应该只设置 maywrite 位)
#define VM_SHARED 0x00000008
#define VM_MAYWRITE 0x00000020
static inline bool is_cow_mapping(vm_flags_t flags)
{
return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
}
PUD、PMD 和 PTE 在 https://www.kernel.org/doc/gorman/html/understand/understand006.html and in articles like LWN 2005: "Four-level page tables merged".
等书籍中有描述fork 实现如何调用 copy_page_range
:
- fork 系统调用实现 (sys_fork? or syscall_define0(fork)) is
do_fork
(kernel/fork.c) 将调用 copy_process
which will call many copy_* functions,包括copy_mm
调用dup_mm
分配和填充新的 mm 结构,其中大部分工作由 完成
dup_mmap
(still kernel/fork.c) which will check what was mmaped and how. (Here I was unable to get exact path to COW implementation so I used the Internet Search Machine with something like "fork+COW+dup_mm" to get hints like [1] or [2] or [3])。检查 mmap 类型后,有retval = copy_page_range(mm, oldmm, mpnt);
行可以做实际工作。