BUG:无法处理内核分页请求
BUG: unable to handle kernel paging request
出于某些特定原因,我需要编辑 2.6.32.65 Linux 内核,以便在内存中分配页面之前从硬盘读取扇区到特定位置。例如,在 mm/filemap.c
中的 do_generic_file_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;
}
然后函数实际上再次读取扇区到分配的页面,如下所示:
error = mapping->a_ops->readpage(filp, page);
当然这不是最佳的,但我只需要它用于测试目的,所以没关系。现在这个工作正常并且可以完成我想要它做的事情。除了 mm/readahead.c
中的 __do_page_cache_readahead
之外,它在其他多个位置也能正常工作。看起来像下面这样:
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);
它调用 read_pages
,它实际上将扇区再次读取到它们分配的页面。据我所知,现在 read_pages
和我一样:
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
struct page *page = list_to_page(pages);
list_del(&page->lru);
if (!add_to_page_cache_lru(page, mapping,
page->index, GFP_KERNEL)) {
mapping->a_ops->readpage(filp, page);
}
page_cache_release(page);
}
ret = 0;
然而 readpage
在 read_pages
中工作正常,但是当我将它添加到 __do_page_cache_readahead
中时它会导致错误 BUG: unable to handle kernel paging request at ffffea0df0668018
。这两行之间的唯一区别是获取数据的页面。在其他情况下对我来说效果很好。为什么会这样?如何解决?
编辑 1
readpage
是指向文件 fs/mpage.c
中的函数 mpage_readpage
的指针,该函数在同一文件中调用 do_mpage_readpage
。使用 printk
s 我发现故障实际上发生在 do_mpage_readpage
的第一行,如下所示:
struct inode *inode = page->mapping->host;
问题是我用来从硬盘读取的页面在启动时被标记为保留(我不希望这个位置被分配给任何进程!)。所以我不确定 page->mapping
会是什么。我猜这是导致错误的原因,但我不知道如何解决!我也不确定它在其他位置是如何工作的,可能是因为 readpage
指向了 mpage_readpage
以外的函数。
根据你的代码,我猜想错误发生在page = page_cache_alloc_cold(mapping);
。我用谷歌搜索了一下:page_cache_alloc_cold
用于在[=15]中找不到想要的页面时分配新页面=] 如果你频繁调用这个函数,内核会oops,因为提供给内核的内存太小了!我遇到过的问题,我的解决方案是在你的module_init()函数中提前分配页面(Pre-allocation)。这样可以避免频繁调用page_cache_alloc_cold
。希望对您有所帮助。
经过一番努力,我发现我的错误非常愚蠢和直截了当。我只是使用了一个无效的页面地址(实际上忘记在某个步骤中在 pfn 和页面之间进行转换)。一旦我解决了它就可以正常工作。
出于某些特定原因,我需要编辑 2.6.32.65 Linux 内核,以便在内存中分配页面之前从硬盘读取扇区到特定位置。例如,在 mm/filemap.c
中的 do_generic_file_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;
}
然后函数实际上再次读取扇区到分配的页面,如下所示:
error = mapping->a_ops->readpage(filp, page);
当然这不是最佳的,但我只需要它用于测试目的,所以没关系。现在这个工作正常并且可以完成我想要它做的事情。除了 mm/readahead.c
中的 __do_page_cache_readahead
之外,它在其他多个位置也能正常工作。看起来像下面这样:
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);
它调用 read_pages
,它实际上将扇区再次读取到它们分配的页面。据我所知,现在 read_pages
和我一样:
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
struct page *page = list_to_page(pages);
list_del(&page->lru);
if (!add_to_page_cache_lru(page, mapping,
page->index, GFP_KERNEL)) {
mapping->a_ops->readpage(filp, page);
}
page_cache_release(page);
}
ret = 0;
然而 readpage
在 read_pages
中工作正常,但是当我将它添加到 __do_page_cache_readahead
中时它会导致错误 BUG: unable to handle kernel paging request at ffffea0df0668018
。这两行之间的唯一区别是获取数据的页面。在其他情况下对我来说效果很好。为什么会这样?如何解决?
编辑 1
readpage
是指向文件 fs/mpage.c
中的函数 mpage_readpage
的指针,该函数在同一文件中调用 do_mpage_readpage
。使用 printk
s 我发现故障实际上发生在 do_mpage_readpage
的第一行,如下所示:
struct inode *inode = page->mapping->host;
问题是我用来从硬盘读取的页面在启动时被标记为保留(我不希望这个位置被分配给任何进程!)。所以我不确定 page->mapping
会是什么。我猜这是导致错误的原因,但我不知道如何解决!我也不确定它在其他位置是如何工作的,可能是因为 readpage
指向了 mpage_readpage
以外的函数。
根据你的代码,我猜想错误发生在page = page_cache_alloc_cold(mapping);
。我用谷歌搜索了一下:page_cache_alloc_cold
用于在[=15]中找不到想要的页面时分配新页面=] 如果你频繁调用这个函数,内核会oops,因为提供给内核的内存太小了!我遇到过的问题,我的解决方案是在你的module_init()函数中提前分配页面(Pre-allocation)。这样可以避免频繁调用page_cache_alloc_cold
。希望对您有所帮助。
经过一番努力,我发现我的错误非常愚蠢和直截了当。我只是使用了一个无效的页面地址(实际上忘记在某个步骤中在 pfn 和页面之间进行转换)。一旦我解决了它就可以正常工作。