C 错误:无法处理内核分页请求
出于某种特定的原因,我需要编辑2.6.32.65 Linux内核,以便在内存中分配页面之前,将扇区从硬盘读取到特定位置。例如,在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
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和页面之间进行转换)。一旦我解决了这个问题,它就像一个符咒。如果你的回答真的解释了这个问题,显示了一些代码,等等,你的回答会更有用。这个回答不会帮助其他人来这里看它。