64位Linux中用户进程页面换入换出时虚拟地址归属疑问
用户进程页面换入/换出时的虚拟地址归属(64位Linux)
核心结论:用户进程的页面本身的虚拟地址始终属于用户空间,但内核在处理换入/换出操作时,会使用内核空间的虚拟地址来访问对应的物理页。
换入场景(对应linux-6.5.1/mm/memory.c代码)
当发生缺页需要换入页面时,mm_account_fault函数中的address参数是触发缺页的用户态虚拟地址,完全落在你给出的用户态地址范围(0x0000000000000000-0x00007FFFFFFFFFFF)内。virt_to_pfn(address)通过进程的页表将用户虚拟地址转换为物理页帧号(PFN),内核完成页换入后,会把这个用户虚拟地址和物理页重新建立映射,用户进程后续访问该地址时,依然使用的是用户空间的虚拟地址。
对应的代码片段:
mm_account_fault() if (major) { struct major_page_fault_hash_entry *temp = NULL; unsigned long pfn = virt_to_pfn(address); printk("[%lu][i][%lu]", pfn, address); perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); }
其中printk输出的第二个%lu就是用户空间的虚拟地址,对应换入操作的目标用户地址。
换出场景(对应linux-6.5.1/mm/swap_state.c代码)
当页面被换出到交换分区时,内核需要直接访问物理页的内容。page_to_virt(current_page)返回的是内核空间的虚拟地址,落在你给出的内核态地址范围(0xFFFF800000000000-0xFFFFFFFFFFFFFFFF)内——这是因为内核拥有所有物理页的线性映射,通过内核虚拟地址可以直接操作物理页。
但这个内核虚拟地址只是内核操作页的临时地址,用户进程对该页的认知始终是原来的用户空间虚拟地址,换出后用户访问该地址会触发缺页,内核再从交换分区换入并重新建立用户虚拟地址到物理页的映射。
对应的代码片段:
bool add_to_swap(struct folio *folio) long pages_number = folio_nr_pages(folio); unsigned long start_pfn = folio_pfn(folio); for (int i = 0; i < pages_number; i++) { struct page *current_page = pfn_to_page(start_pfn + i); unsigned long current_virt_addr = (unsigned long)page_to_virt(current_page); printk("[%lu][o][%lu]\n",start_pfn + i, current_virt_addr); }
这里printk输出的第二个%lu就是内核空间的虚拟地址,用于内核写入交换分区时访问物理页。
内容的提问来源于stack exchange,提问作者Mia8Cew
相关产品推荐
相关产品推荐

