在Linux中进行进程的页面表

我正在尝试在linux中浏览一个进程的页表。 在一个内核模块中,我实现了以下function:

static struct page *walk_page_table(unsigned long addr) { pgd_t *pgd; pte_t *ptep, pte; pud_t *pud; pmd_t *pmd; struct page *page = NULL; struct mm_struct *mm = current->mm; pgd = pgd_offset(mm, addr); if (pgd_none(*pgd) || pgd_bad(*pgd)) goto out; printk(KERN_NOTICE "Valid pgd"); pud = pud_offset(pgd, addr); if (pud_none(*pud) || pud_bad(*pud)) goto out; printk(KERN_NOTICE "Valid pud"); pmd = pmd_offset(pud, addr); if (pmd_none(*pmd) || pmd_bad(*pmd)) goto out; printk(KERN_NOTICE "Valid pmd"); ptep = pte_offset_map(pmd, addr); if (!ptep) goto out; pte = *ptep; page = pte_page(pte); if (page) printk(KERN_INFO "page frame struct is @ %p", page); out: return page; } 

这个函数是从ioctl调用的, addr是进程地址空间中的虚拟地址:

 static int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long addr) { struct page *page = walk_page_table(addr); ... return 0; } 

奇怪的是,在用户空间进程中调用ioctl ,这段错误…但似乎我正在寻找页表条目的方式是正确的,因为用dmesg我获得例如每个ioctl调用:

 [ 1721.437104] Valid pgd [ 1721.437108] Valid pud [ 1721.437108] Valid pmd [ 1721.437110] page frame struct is @ c17d9b80 

那么,为什么这个过程不能完成正确的'ioctl'调用呢? 也许我必须在浏览页面表之前locking一些东西?

我正在使用内核2.6.35-22和三级页表。

谢谢你们!

Solutions Collecting From Web of "在Linux中进行进程的页面表"

 pte_unmap(ptep); 

在标签出局之前缺少。 尝试以这种方式更改代码:

  ... page = pte_page(pte); if (page) printk(KERN_INFO "page frame struct is @ %p", page); pte_unmap(ptep); out: 

看看/proc/<pid>/smaps文件系统,你可以看到用户空间的内存:

 cat smaps bfa60000-bfa81000 rw-p 00000000 00:00 0 [stack] Size: 136 kB Rss: 44 kB 

以及如何打印是通过fs/proc/task_mmu.c (来自内核源):

http://lxr.linux.no/linux+v3.0.4/fs/proc/task_mmu.c

  if (vma->vm_mm && !is_vm_hugetlb_page(vma)) walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); show_map_vma(m, vma.....); seq_printf(m, "Size: %8lu kB\n" "Rss: %8lu kB\n" "Pss: %8lu kB\n" 

你的函数有点像walk_page_range()。 看着walk_page_range(),你可以看到smaps_walk结构在走路时不应该改变:

 http://lxr.linux.no/linux+v3.0.4/mm/pagewalk.c#L153 For eg: } 201 if (walk->pgd_entry) 202 err = walk->pgd_entry(pgd, addr, next, walk); 203 if (!err && 204 (walk->pud_entry || walk->pmd_entry || walk->pte_entry 

如果步行是改变的,那么上述所有的检查可能会变得不一致。

所有这些只是意味着在走页面表时必须锁定mmap_sem:

  if (!down_read_trylock(&mm->mmap_sem)) { /* * Activate page so shrink_inactive_list is unlikely to unmap * its ptes while lock is dropped, so swapoff can make progress. */ activate_page(page); unlock_page(page); down_read(&mm->mmap_sem); lock_page(page); } 

然后解锁:

 up_read(&mm->mmap_sem); 

当然,当你在你的内核模块中发布pagetable的printk()时,内核模块会运行在insmod进程的进程上下文中(只需要打印“comm”,你就可以看到“insmod”),这意味着mmap_sem是锁定,这也意味着进程没有运行,因此在进程完成之前没有控制台输出(所有的printk()输出都只进入内存)。

听起来合乎逻辑?