BUG:无法处理内核分页请求

时间:2015-04-21 00:19:05

标签: c linux linux-kernel

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

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);

当然这不是最佳选择,但我只需将其用于测试目的,因此无关紧要。现在这很好用,做我想做的事。它在多个其他位置也可以正常工作,__do_page_cache_readahead中的mm/readahead.c除外。它看起来如下:

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;

然而readpageread_pages中正常工作,但当我在__do_page_cache_readahead中添加时,会导致错误BUG: unable to handle kernel paging request at ffffea0df0668018。两行之间的唯一区别是获取数据的页面。在其他情况下,我和我一起工作得很好。为什么会这样?如何解决?

修改1

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

struct inode *inode = page->mapping->host;

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

2 个答案:

答案 0 :(得分:2)

从您的代码中,我猜到了/** * Create rounded corner bitmap from given bitmap. The given bitmap will be * recycle after createing round image. * * @param bitmap * in {@link Bitmap} to parse * @param corner * in {@link Integer} the corner of round rect image * @return rounded corner bitmap in {@link Bitmap} */ public static Bitmap parseBitmapToRoundedBitmap(Bitmap bitmap) { final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); int size = Math.min(width, height); Bitmap output = Bitmap.createBitmap(size, size, Config.ARGB_8888); Canvas canvas = new Canvas(output); final Paint paint = new Paint(); // Rect of bitmap paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); // This is how we draw round rect image or circle image // Round rect image // canvas.drawRoundRect(new RectF(rect), roundPx, roundPx, paint); // Circle image final float radius = size / 2; canvas.drawCircle(size / 2, size / 2, radius, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); Rect srcRect = new Rect(width / 2 - size / 2, height / 2 - size / 2, size, size); canvas.drawBitmap(bitmap, srcRect, new Rect(0, 0, size, size), paint); // Recycle bitmap if need. if (hasHoneycomb()) { bitmap = null; } else { bitmap.recycle(); bitmap = null; } return output; } 中发生的错误。我用Google搜索了它:page = page_cache_alloc_cold(mapping);用于在缓存中找不到想要的页面时分配新页面。但是如果你经常调用函数,内核会因为为内核提供的内存太小而oops!我遇到的问题,我的解决方案是在你的module_init()函数中预先分配页面(预分配)。它会避免经常调用page_cache_alloc_cold。我希望这会对你有所帮助。

答案 1 :(得分:-1)

经过多次努力,我发现我的错误真的很愚蠢和直截了当。我只是使用了一个无效的页面地址(实际上忘了在某个步骤之间在pfn和页面之间进行转换)。一旦我解决了它,它工作正常。