欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Linux 深入了解脏页面(dirty page)-2.2 脏页面回写

最编程 2024-03-30 18:07:35
...
 1 /mm/page_writeback.c
 2  
 3 write_cache_pages
 4  
 5     ->clear_page_dirty_for_io  //对于回写的每一个页
 6  
 7         |->page_mkclean  //清脏标记  mm/rmap.c 
 8  
 9         |   ->page_mkclean_one  //反向映射查找这个页的每个vma,调用清脏标记和写保护处理
10  
11         |        ->entry = pmdp_invalidate(vma, address, pmd);
12         |          entry = pmd_wrprotect(entry);  //写保护处理,设置只读
13         |           entry = pmd_mkclean(entry);  //清脏标记 set_pte_at(vma->vm_mm, address, pte, entry) //设置到页表项中
14  
15         |->set_page_dirty

2.3 第二次写访问文件页
1)脏页还没有回写时(确切的说是调用clear_page_dirty_for_io之前),页描述符已经设置了脏标记,页表项已经设置了脏标记、可写。

这时可以直接写访问文件页,不会发生缺页。

2)脏页已经回写时(确切的说是调用clear_page_dirty_for_io之后),页描述符已经清除了脏标记,页表项已经清除了脏标记,且只读。

这时写访问文件页会发生写时复制缺页异常(访问权限错误缺页)。

调用链如下:

 1 /mm/memory.c
 2  
 3 handle_pte_fault
 4  
 5     ->if (vmf->flags & FAULT_FLAG_WRITE) {  //vma可写
 6           if (!pte_write(entry))  //页表项没有可写属性
 7               do_wp_page(vmf)  //写时复制缺页异常处理
 8  
 9                   ->if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED))  //是共享可写的文件映射vma
10                         wp_page_shared
11  
12                             |->do_page_mkwrite
13  
14                             |    ->vmf->vma->vm_ops->page_mkwrite
15  
16                             |        ->filemap_page_mkwrite /mm/filemap.c
17  
18                             |            ->set_page_dirty
19  
20                             |                ->__set_page_dirty_buffers
21  
22                             |                    ->TestSetPageDirty  //设置页描述符脏标记
23  
24                             |                    ->__set_page_dirty  //page cache中标记页为脏 
25                             |->finish_mkwrite_fault
26  
27                                  ->wp_page_reuse
28  
29                                      ->entry = maybe_mkwrite(pte_mkdirty(entry), vma);  //重新设置页表项脏、可写

2.4 再次写访问
重复上面步骤

3. write 接口操作的文件页
由于通过write接口访问文件页时,会读取文件页到page cache,不会映射到任何进程地址空间,所有这种方式跟踪脏页是通过设置/清除页描述符脏标记来实现。

3.1 第一次写访问文件页
会首先读文件页到page cache,然后将用户空间写缓冲区数据写到page cache,调用链如下:

 1 /fs/ext4/file.c
 2  
 3 ext4_file_write_iter
 4  
 5     ->__generic_file_write_iter
 6  
 7         ->generic_perform_write
 8  
 9             ->a_ops->write_begin   //写之前处理 分配page cache页
10  
11                 ->__block_commit_write
12  
13                     ->mark_buffer_dirty
14  
15                         ->__set_page_dirty  //设置页为脏(设置页描述符脏标记)
16  
17             ->iov_iter_copy_from_user_atomic  //用户空间写缓冲区数据写到page cache页