C 错误:无法处理内核分页请求

C 错误:无法处理内核分页请求,c,linux,linux-kernel,C,Linux,Linux Kernel,出于某种特定的原因,我需要编辑2.6.32.65 Linux内核,以便在内存中分配页面之前,将扇区从硬盘读取到特定位置。例如,在mm/filemap.c中的函数do\u generic\u file\u read中,我执行以下操作: myRet = mapping->a_ops->readpage(filp,myPage); //Added Function_Operates_On_MyPage(); //Added

出于某种特定的原因,我需要编辑2.6.32.65 Linux内核,以便在内存中分配页面之前,将扇区从硬盘读取到特定位置。例如,在
mm/filemap.c
中的函数
do\u generic\u file\u read
中,我执行以下操作:

myRet = mapping->a_ops->readpage(filp,myPage);          //Added
Function_Operates_On_MyPage();                          //Added

page = page_cache_alloc_cold(mapping);
if (!page) {
    desc->error = -ENOMEM;
    goto out;
}
for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
    pgoff_t page_offset = offset + page_idx;

    if (page_offset > end_index)
        break;

    rcu_read_lock();
    page = radix_tree_lookup(&mapping->page_tree, page_offset);
    rcu_read_unlock();
    if (page)
        continue;

    myRet = mapping->a_ops->readpage(filp,myPage);          //Added
    Function_Operates_On_Mypage();                          //Added
    page = page_cache_alloc_cold(mapping);
    if (!page)
        break;
    page->index = page_offset;
    list_add(&page->lru, &page_pool);
    if (page_idx == nr_to_read - lookahead_size)
        SetPageReadahead(page);
    ret++;
}

if (ret)
    read_pages(mapping, filp, &page_pool, ret);
然后,函数实际上会将扇区再次读取到分配的页面,如下所示:

    error = mapping->a_ops->readpage(filp, page);
struct inode *inode = page->mapping->host;
当然,这不是最佳的,但我只需要它的测试目的,所以这并不重要。现在它工作得很好,并且达到了我想要的效果。除了在
mm/readahead.c
中的
\uu do\u page\u cache\u readahead
之外,它还可以在其他多个位置正常工作。如下所示:

myRet = mapping->a_ops->readpage(filp,myPage);          //Added
Function_Operates_On_MyPage();                          //Added

page = page_cache_alloc_cold(mapping);
if (!page) {
    desc->error = -ENOMEM;
    goto out;
}
for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
    pgoff_t page_offset = offset + page_idx;

    if (page_offset > end_index)
        break;

    rcu_read_lock();
    page = radix_tree_lookup(&mapping->page_tree, page_offset);
    rcu_read_unlock();
    if (page)
        continue;

    myRet = mapping->a_ops->readpage(filp,myPage);          //Added
    Function_Operates_On_Mypage();                          //Added
    page = page_cache_alloc_cold(mapping);
    if (!page)
        break;
    page->index = page_offset;
    list_add(&page->lru, &page_pool);
    if (page_idx == nr_to_read - lookahead_size)
        SetPageReadahead(page);
    ret++;
}

if (ret)
    read_pages(mapping, filp, &page_pool, ret);
然而,
readpage
read\u页面
中工作正常,但是当我将它添加到
\uu do\u页面\u cache\u readahead
中时,它会导致错误
错误:无法在ffffea0df0668018处处理内核分页请求。这两行之间的唯一区别是获取数据的页面。这在其他情况下对我很有效。为什么会发生这种情况?如何修复它

编辑1

readpage
是指向文件
fs/mpage.c
中函数
mpage\u readpage
的指针,该函数在同一文件中调用
do\mpage\u readpage
。使用
printk
s,我发现故障实际上发生在
do\mpage\u readpage
的第一行,如下所示:

    error = mapping->a_ops->readpage(filp, page);
struct inode *inode = page->mapping->host;

问题是,我用来从硬盘读取的页面在启动时被标记为保留(我不希望将此位置分配给任何进程!)。所以我不确定什么是
page->mapping
。我猜这就是导致错误的原因,但我不知道如何修复它!我也不确定它在其他位置是如何工作的,可能是因为
readpage
指向的函数不是
mpage\u readpage

根据您的代码,我猜错误发生在
page=page\u cache\u alloc\u cold(映射)
。我已经在谷歌上搜索过了:
页面缓存\u alloc\u cold
用于在缓存中找不到想要的页面时分配新页面。但是如果您经常调用该函数,内核将OOP,因为为内核提供的内存太小了!我遇到的问题是,我的解决方案是在module_init()函数中提前分配页面(预分配)。这样可以避免频繁调用
page\u cache\u alloc\u cold
。我希望这会对你有所帮助。

经过一番努力,我发现我的错误真的很愚蠢和直截了当。我只是使用了一个无效的页面地址(实际上忘记了在某些步骤中在pfn和页面之间进行转换)。有一次我发现它很好用。

这太旧了,我甚至都忘了。你说的很有道理。除了我不经常这么做。事实上,我把页面分配到一个特定的位置,用它做点什么,释放它。我每次都这样做。所以基本上我只占了所有这些分配的一页。在与之斗争了很多之后,我发现我的错误真的很愚蠢。我甚至不想在这里发布答案!我只是使用了一个无效的页面地址(实际上忘记了在某些步骤中在pfn和页面之间进行转换)。一旦我解决了这个问题,它就像一个符咒。如果你的回答真的解释了这个问题,显示了一些代码,等等,你的回答会更有用。这个回答不会帮助其他人来这里看它。