“写时复制”的概念已经不算陌生了,它大大节省了新进程需要的内存和产生新进程所需的时间,但是有一个美中不足的地方,如果允许内核随意写用户空间地址,哪怕是写保护的地址,那么写时复制将很难实现,因为内核必须向用户空间写东西,比如read调用的结果就是从内核的页高速缓存中复制过来的;如果用户空间向一个写保护的页面写数据,那么将会产生缺页异常,而在fork的时候,父进程的空间将全部设置为写保护来和子进程共享,然后子进程或父进程中的任意一个对地址空间进行写操作时,将会产生一个写保护缺页异常,而缺页异常处理程序会复制页面到一个新分配的页面,这就是写时复制,为了让内核写用户写保护页面也 能产生一个写保护缺页异常,有两种实现方案,一个基于硬件,一个基于软件,还好,现代处理器很多都提供了这样的功能,比如intel的处理器的cr0的 wp位就是干这个的,如果置1就使能用户空间写保护,这样内核在写用户空间的写保护页面时会产生页面异常,进而写保护缺页异常处理会处理一切,正如上面所 述,分配新页面,拷贝旧页面到新页面,如果wp位置0则不使能用户空间写保护,要实现完全的用户空间写保护必须通过软件实现,那么怎么实现呢?实际上我们想一下就明白,这个实现并不算难,毕竟不用加很多代码,只要在内核往用户空间写数据的点上放一个关卡就可以了,如果要写的是写保护页面,则分配新页面,复 制旧页面到新页面,若不是,直接拷贝,用memspy就行,于是我们来看一下哪里需要写用户空间,无非就是put_user/copy_to...之类的函数,而这些函数最终都要调用__copy_to_user_ll,下面看一下__copy_to_user_ll(内核版本2.6.9):

unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n)

{

#ifndef CONFIG_X86_WP_WORKS_OK