Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux内核如何检测内存地址是否被修改以实现COW?_C_Linux_Linux Kernel_Copy On Write - Fatal编程技术网

Linux内核如何检测内存地址是否被修改以实现COW?

Linux内核如何检测内存地址是否被修改以实现COW?,c,linux,linux-kernel,copy-on-write,C,Linux,Linux Kernel,Copy On Write,源代码如下: #include <stdio.h> #include <stdlib.h> void main() { int *a = malloc(sizeof(int)); *a = 11; int b = 22;//on the stack int pid = fork(); if (pid == 0) { printf("pid=%d, a = %d, &a=%p\n", g

源代码如下:

 #include <stdio.h>
 #include <stdlib.h>

 void main() {
     int *a = malloc(sizeof(int));
     *a = 11;
     int b = 22;//on the stack

     int pid = fork();

     if (pid == 0) {
         printf("pid=%d, a = %d, &a=%p\n", getpid(), *a, a);
         printf("pid=%d, b = %d, &b=%p\n", getpid(), b, &b);
         getchar();
         *a = 33;// ===========cow=========happend here=====
         b = 44;
         printf("pid=%d, a = %d, &a=%p\n", getpid(), *a, a);
         printf("pid=%d, b = %d, &b=%p\n", getpid(), b, &b);
     } else {
         printf("pid=%d, a = %d, &a=%p\n", getpid(), *a, a);
         printf("pid=%d, b = %d, &b=%p\n", getpid(), b, &b);
     }
     pause();
 }
在gdb中键入ni后(将a的值更改为33),再次使用vtop。我可以看到进程的一个物理地址已更改

crash> vtop 0x602010
VIRTUAL     PHYSICAL
602010      5d755010

   PML: 24e6f000 => 2409c067
   PUD: 2409c000 => 7144067
   PMD: 7144018 => 19847067
   PTE: 19847010 => 800000005d755067
  PAGE: 5d755000



crash> vtop 0x602010
VIRTUAL     PHYSICAL
602010      2a683010

   PML: 36df9000 => 3a654067
   PUD: 3a654000 => 1a71a067
   PMD: 1a71a018 => 18f2a067
   PTE: 18f2a010 => 800000002a683065
  PAGE: 2a683000
我的问题是cpu执行时发生了什么

movl   $0x2c,-0x20(%rbp)
内核如何知道它正在更改共享内存,因此在编写之前需要执行一个处理?我猜它使用了类似于页面错误中断的东西。但我没有发现任何与此相关的中断

如果由内核负责,请提供内核的源代码

我的问题是cpu执行时发生了什么

movl$0x2c,-0x20(%rbp)

内核如何知道它正在更改共享内存,因此在编写之前需要执行一个处理?我猜它使用了类似于页面错误中断的东西。但我没有发现任何与此相关的中断

这是通过处理器和操作系统的协作实现的

处理器端:

当CPU执行此类指令时:

movl$0x2c,-0x20(%rbp)

i、 e.获取存储在%rbp寄存器中的地址,并向其添加偏移量-x20,然后对其发出内存访问(movl)

在提交内存访问时,处理器将遍历硬件页表(在大多数情况下,访问TLB是一条捷径,但我在这里只讨论基本原则)。当然,页面表应该由操作系统预先设置

假设处理器到达最后一级页表,只找到该地址对应的页表条目(将其称为pte) 建议包含地址内容的页面不在内存中!(它只参考该pte的特定页面标志),然后,根据处理器体系结构,引发硬件异常!根据Intel术语,它将此类异常分类为故障,您必须经常听到术语“页面故障”(一种可以修复并恢复执行的异常,就好像根本没有发生此类异常一样!)

操作系统端:

然后我们将堆栈向上移动到操作系统域中。在引导过程中,操作系统将设置一个异常和中断处理程序表(用x86术语我们称之为IDT),并将其注册到处理器

然后,一旦发生此页面错误,处理器将执行预设置处理程序(从技术上讲,处理器应首先保存CPU上下文,如推动cs和rip寄存器、rflags寄存器等)

处理程序可以分为特定于arch的部分(操作系统将进一步执行一些与硬件相关的工作,如保存更多寄存器、调用特定于arch的钩子、确定是否允许页面错误等)和独立于arch的部分(页面错误逻辑),因此毫不奇怪,处理程序入口点依赖于arch

对于x86上的Linux,特定于arch的部分位于arch/x86/entry/entry_64.S(对于64位)和arch/x86/mm/fault.C中的do_page_fault()C函数中。然后在do_page_fault()中,它将调用arch独立的C函数handle_mm_fault(),该函数位于核心mm代码mm/memory.C


对于这个问题,在handle_mm_fault()中,do_wp_page()处理COW逻辑。基本上,handle_mm_fault()只是遍历出错地址的页表,发现它是一个写保护页(存在,但未设置写标志),因此它调用do_wp_page()来分配一个新页。

如果内核负责此操作,请提供内核的源代码@AndrewHenle不错的一个:-)我觉得这一个比github好。好了,这一个怎么样:
crash> vtop 0x602010
VIRTUAL     PHYSICAL
602010      5d755010

   PML: 24e6f000 => 2409c067
   PUD: 2409c000 => 7144067
   PMD: 7144018 => 19847067
   PTE: 19847010 => 800000005d755067
  PAGE: 5d755000



crash> vtop 0x602010
VIRTUAL     PHYSICAL
602010      2a683010

   PML: 36df9000 => 3a654067
   PUD: 3a654000 => 1a71a067
   PMD: 1a71a018 => 18f2a067
   PTE: 18f2a010 => 800000002a683065
  PAGE: 2a683000
movl   $0x2c,-0x20(%rbp)