免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1913 | 回复: 0
打印 上一主题 下一主题

COW(copy on write) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-02-05 13:30 |只看该作者 |倒序浏览

                     COW的整个过程

Copy on write:
设计思路:当要拷贝一个虚拟地址A的可写的页面的时候, 由于lazy copy的原则,我们不想实际的区分配页面并且拷贝页面内容,尤其是不确定即使拷贝了,以后不一定要写访问那里的数据。 所以我们的做法是,将页相的属性值pte设为不可写, 然后当有进程再次往该虚拟地址写数据的时候,就出发页异常,然后由页面异常来处理,
分配页面初始化并且拷贝原页的内容。

Eg:linux在fork的时候拷贝父进程的资源的时候。具体在copy_page_range()中。
int copy_page_range(struct mm_struct *dst,
struct mm_struct *src,
                     struct
vm_area_struct *vma)

此函数的目的是将父进程的src中一个vm_area_struct 拷贝到另外一个进程dst 中。
简单的来说,当拷贝src中一个可写的虚拟地址A的时候:
假设现在A指向物理地址 phad

1:先根据dst来确定是否新的进程的页表已经ok。如果没有,还需要pmd_alloc(),pte_alloc()来分配和建立页表对应关系。极端情况下需要另外分配一个页面(此过程中有可能会调用get_free_pages, 如果是pte_alloc_one()的话,还要将整个页面清0 ),由确定的页目录表,页面表就已经确定了一个新进程的虚拟地址B。

2:dst中B指向的页面表项,和src中A指向的页面表项都设置成只读,
即仅仅拷贝页面指针和属性。(这时不同的虚拟地址指向相同的物理地址,  A ,B都指向 phad)

3:over。 哈哈就这么简单

当以后新进程需要向B写入数据的时候,由B去找pte项
发现pte的值是只读的就会触发页面异常。进入do_page_fault()。
此时的异常处理就要看error_code的值是多少了。
/* error_code:
*    bit 0 == 0 means no page found, 1 means
protection fault
*    bit 1 == 0 means read, 1 means write
*    bit 2 == 0 means kernel, 1 means user-mode
*/
我们假设页面是在内存中的,仅仅是由于写保护引起的异常。
那么会在do_page_fault()的检查error_code & 3 中转到handle_mm_fault()中去。代码中有段注释
/*
        * We need the page table lock to synchronize
with kswapd
        * and the SMP-safe atomic PTE updates.
        */
要求主要处理过程handle_pte_fault()要在一个spin_lock的保护下进行。那么我们深入进去看看到底是怎么一个处理过程。

static inline int handle_pte_fault(struct
mm_struct *mm,
       struct
vm_area_struct * vma, unsigned long address,
       int
write_access, pte_t * pte)
{
       pte_t
entry;

       entry
= *pte;
       if
(!pte_present(entry)) {
              /*
               * If it truly wasn't present, we know that
kswapd
               * and the PTE updates will not touch it later.
So
               * drop the lock.
               */
              if
(pte_none(entry))
                     return
do_no_page(mm, vma, address, write_access, pte);
              return
do_swap_page(mm, vma, address, pte, entry, write_access);
       }
       *********@********
       if
(write_access) {
              if
(!pte_write(entry))
                     return
do_wp_page(mm, vma, address, pte, entry);

              entry
= pte_mkdirty(entry);
       }
       entry
= pte_mkyoung(entry);
       establish_pte(vma,
address, pte, entry);
       spin_unlock(&mm->page_table_lock);
       return
1;
}

在我们的写保护情景中, 会直接跑到*********@********处,if (write_access)为真,我们的pte的内容是不允许写的,因此if (!pte_write(entry))也为真。进入do_wp_page()。
进而会调用copy_cow_page()。

copy_cow_page里面
       if
(from == ZERO_PAGE(address)) {
              clear_user_highpage(to,
address);
              return;
       }
       copy_user_highpage(to,
from, address);

如果不是ZERO_PAGE的话, 那么在copy_user_highpage()中调用copy_user_page()来进行真正的拷贝。但是令人迷惑的是在此函数中
void mmx_copy_page(void *to, void *from)
{
       if(in_interrupt())
              slow_copy_page(to,
from);
       else
              fast_copy_page(to,
from);
}
在中断里反而调用slow_copy_page, 而之外调用fast_copy_page??? 为什么呢?不能理解。(不过google一下,好像fast_copy_page里面有很多prefetch,好像在kernel的时候有问题,所以一般中断都在kernel space中所以就不用了)
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/69528/showart_1814115.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP