首页 / 资讯中心 / 文章详情

memory do_page_mkwrite

memory do_page_mkwrite ★ FEATURED ARTICLE
do_page_mkwrite是文件映射写缺页路径中的关键回调封装函数。当用户试图写入一个通过文件映射、但当前 PTE 为只读的页面时内核需要先通知文件系统“这个页面即将变脏”以便文件系统有机会进行必要的准备如分配磁盘块、检查配额do_page_mkwrite正是这一通知机制的调用入口。核心功能与实现根据当前主线的实现已完成 folio 转换其核心逻辑如下static vm_fault_t do_page_mkwrite(struct vm_fault *vmf, struct folio *folio) { vm_fault_t ret; unsigned int old_flags vmf-flags; vmf-flags FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE; if (vmf-vma-vm_file IS_SWAPFILE(vmf-vma-vm_file-f_mapping-host)) return VM_FAULT_SIGBUS; ret vmf-vma-vm_ops-page_mkwrite(vmf); /* Restore original flags so that caller is not surprised */ vmf-flags old_flags; if (unlikely(ret (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) return ret; if (unlikely(!(ret VM_FAULT_LOCKED))) { folio_lock(folio); if (!folio_mapping(folio)) { folio_unlock(folio); return 0; /* retry */ } ret | VM_FAULT_LOCKED; } else VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); return ret; }关键设计点1. 通知文件系统函数通过vmf-vma-vm_ops-page_mkwrite(vmf)调用具体的文件系统回调。这个回调允许文件系统在页面变为可写之前执行必要的准备工作例如实现存储分配或预留以优雅地处理 ENOSPC 错误可能通过生成 SIGBUS。延迟将页面设为可写直到内容被写入后端缓存对 NFS/AFS 结合 FS-Cache/CacheFS 有用。统计和限制脏页数量这是 FUSE 共享可写映射安全工作的关键一环。2. 锁与竞态处理这个回调的一个核心设计约束是调用page_mkwrite时不能持有页表锁PTL因为文件系统实现可能需要睡眠。函数将vmf-flags临时设置为FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE以便文件系统知道这是一个 mkwrite 操作调用完成后再恢复原标志。3. 页面锁定协议文件系统回调的返回值有特定协议如果返回VM_FAULT_LOCKED表示文件系统已经锁定了页面。如果返回 0成功但未锁定do_page_mkwrite会代为锁定页面然后检查folio-mapping是否仍然有效。如果 mapping 已为 NULL说明页面在文件系统回调期间被截断或移除则解锁并返回 0让调用者重试。如果返回错误VM_FAULT_ERROR或VM_FAULT_NOPAGE直接向上传递调用者会向用户进程发送 SIGBUS。4. 交换文件保护如果 VMA 关联的文件是交换文件IS_SWAPFILE直接返回VM_FAULT_SIGBUS。这是因为交换文件不应被用户空间直接映射写入。演进从 page 到 folio该函数在 2023 年的补丁系列中完成了 folio 转换参数从隐式的vmf-page改为显式的struct folio *folio节省了一次隐式的compound_head()调用。内部的lock_page/unlock_page改为folio_lock/folio_unlock。检查page-mapping改为folio_mapping(folio)这里有一个重要的细节如果使用folio-mapping直接访问对于某些特殊类型的 folio如 Movable 类型的页面低位标记会导致误判为 NULL从而进入无限重试循环。使用folio_mapping()辅助函数可以正确过滤这些标记。调用场景do_page_mkwrite由两个上层函数调用wp_page_shared()处理共享映射的写缺页。当页面已经是可共享的但 PTE 是只读时先调用do_page_mkwrite通知文件系统然后重新验证 PTE 并复用页面。do_shared_fault()处理共享文件映射的写缺页调用do_page_mkwrite后继续执行finish_fault完成映射建立。如果文件系统未实现page_mkwrite回调vma-vm_ops-page_mkwrite为 NULL内核会直接标记页面为脏无需通知文件系统。
阅读完成 · 觉得有帮助?
咨询建站