【发布时间】:2012-01-23 23:38:25
【问题描述】:
我正在尝试为 linux 中的进程导航页表。在一个内核模块中,我实现了以下功能:
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' 调用呢?也许我必须在导航页表之前锁定一些东西?
我正在使用内核 2.6.35-22 和三级页表。
谢谢大家!
【问题讨论】:
-
是否有可能ioctl syscall成功返回,之后代码出现segfaulting?
-
否,因为 ioctl 系统调用是
main中return之前的最后一条指令。如果我评论ioctl该过程不会出现段错误。 -
为什么隐藏了使用
struct page地址的部分?你确定你的段错误不是来自这里吗?你试过在 qemu 上调试这个吗? -
在调用
walk-page_table之后,如果page是NULL,我只执行printk。我还尝试只保留对walk_page_table的调用,但该过程仍然存在段错误。也许是的,发现问题的最快方法是调试。谢谢昆汀。 -
通过调试编译代码并在转储期间强制进行堆栈跟踪,以便您绝对知道发生了什么。或者使用kgdb。此外,您确定您没有使用最新内核的新 unlocked_ioctl 功能吗?
标签: linux linux-kernel kernel