Linux中用exec创建文件,Linux sys_exec中可执行文件映射的建立及读取 - 内核源码 - Linux论坛...

9931596_5.gif

2楼 发表于 2008-05-06 15:44 | 只看该作者

回复 #1 frank_seng 的帖子

从上文中可知elf_map时并没有将文件内容读入内存,假设现在程序中有一条指令需要读取上面vm_start---vm_end之间的某内容,例如mov [0x08000011], %eax,那么将会执行如下序列:

* CPU依据CR3(current->pgd)找到0x08000011地址对应的pgd[ i ],由于该pgd[ i ]内容保持为初始化状态即为0,导致CPU异常;

* do_page_fault被调用,在该函数中,为pgd[ i]在内存中分配一个页表,并让该表项指向它,如下图所示:

pgd

+-----+

|-----|    pt

|  i  |--->+-----+

|-----|    |-----|

|     |    |  j  |

+-----+    |-----|

|     |

+-----+

注意:这里i为0x08000011高10位,j为其中间10位,此时pt表项全部为0(pte[j]也为0);

* 为pte[j]分配一个真正的物理内存页面,依据vm_area_struct中的vm_file、vm_pgoff和vm_ops,调用filemap_nopage将磁盘file中vm_pgoff偏移处的内容读入到该物理页面中,如下图所示:

+-------------+

|  Disk file  |

|             |

|-------------|

| Seg Content----+

|-------------|  |

pgd                 |             |  |

+-----+             |             |  |②

|-----|    pt       +-------------+  |

|  i  |--->+-----+                   |

|-----|    |-----|   ①   page       |

|     |    |  j  |------->+-----+

+-----+    |-----|        |     |

|     |        |     |

+-----+        |     |

+-----+

①.分配物理内存页面;

②.从磁盘文件中将内容读取到物理内存页面中;

父子页面保护共享的处理 ------ COW技术

在do_fork->copy_mm中,如果vm_area_struct的属性中包含了可写属性,但非共享,则将父对应的pte[j](假设pte[j]对应了vm_area_strruct圈定的范围中的某个页面)设置为写保护,随后复制父pte[j]给子pte[j];此处采用了COW技术。

copy_mm之后的的情况如下图,可见并没有真正的复制一个page给子进程:

father

+--------+

|        |

|--------|

|pte(w=0)|--+

|--------|  |

|        |  |

+--------+  +-->+------+

|      |

son         +-->|      |

+--------+  |   | page |

|        |  |   |      |

|--------|  |   |      |

|pte(w=0)|--+   |      |

|--------|      +------+

|        |

+--------+

现在假设父进程向pte中写入,则会引发CPU异常,在异常处理机制中,处理如下:

* 创建一个新的newpage;

* 复制page内容到newpage;

* 让父pte指向newpage,并且设置父pte的w=1(可写);

* 子pte保持不变;最终如下图:

father

+--------+  +-->+------+

|        |  |   |      |

|--------|  |   | new  |

|pte(w=1)|--+   | page |

|--------|      |      |

|        |      +------+

+--------+

son

+--------+  +-->+------+

|        |  |   |      |

|--------|  |   | page |

|pte(w=0)|--+   |      |

|--------|      |      |

|        |      +------+

+--------+

如果现在子进程又向pte中写,同样导致异常,但是由于此时该pte:count==1,则直接将该pte:w=1,然后写即可;

son

+--------+  +-->+------+

|        |  |   |      |

|--------|  |   | page |

|pte(w=1)|--+   |      |

|--------|      |      |

|        |      +------+

+--------+

[本帖最后由 frank_seng 于 2008-5-7 14:02 编辑]

真的好对不起,由于历史原因,我们的产品依然跑在Linux 2.4上,因此是对着2.4说的,2.6除了网络部分外,还从没看过,sorry啊!

关于COW,我写了一些总结性文档,贴出来献丑了:假设进程A创建了子进程B,之后进程A和进程B共享A的地址空间,同时该地址空间中的页面全部被标识为写保护。此时B若写address所在的页面,由于写保护的原因会引起写异常,在异常处理中,内核会将address所在的那个写保护页面复制为一个新的页面,让B的address页表项指向该新页面,新页面可写,而A的address页表项依然指向那个写保护的页面。此后当B再访问address是就会直接访问该新的页面了,不再会访问到那个写保护的页面。当A试图写address所在的页面时,由于写保护的原因此时也会引起异常,在异常处理中,内核如果发现该页面只有一个拥有进程,此种情况下也就是A,则直接对该页面取消写保护,此后当A再访问address是不会再有写保护错误了。如果此时A又创建了子进程C,则该address所在的页面又被设置为写保护,拥有进程为A和C,同时其他的页面例如PAGEX依然维持写保护,只是拥有进程为A、B和C。如果此时A访问PAGEX,则异常处理会创建一个新页面并将PAGEX中的内容复制到该页面,同时将A相应的pte指向该新页面。如果此时C也访问PAGEX,也会复制新页面并且让C对应的pte指向新页面。如果B再访问PAGEX,则由于此时PAGEX只有一个拥有进程B,故不再复制新页面,而是直接取消该页面的写保护,由于B的pte本来就直接指向该页面,所以无需再做其他工作了。这也就是COW的实现机制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值