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页