如何避免find_get_entries返回无效页引发Linux内核崩溃?
解决
find_get_entries()返回无效页面导致put_page()崩溃的问题 针对你遇到的find_get_entries()竞态导致页面指针无效、调用put_page()触发内核崩溃的问题,可以通过以下实操方案规避:
1. 严格验证页面有效性
在调用put_page()前,必须对返回的struct page *做有效性校验,核心检查点包括:
- 校验页面的
page->mapping是否与目标文件的address_space(即file->f_mapping)一致,不匹配则说明页面已被回收或复用。 - 校验
page->index是否对应你请求的文件偏移索引(计算逻辑:目标偏移 >> PAGE_SHIFT),避免页面被重新分配后索引不符的情况。 - 检查页面引用计数:通过
page_ref_count(page)确认计数大于0,若为0则页面已被释放,绝对不能调用put_page()。
2. 安全的页面遍历与释放流程
对find_get_entries()返回的页面逐个处理,无效页面直接跳过,不要调用put_page(),示例代码如下:
struct page **pages; unsigned int nr_pages = find_get_entries(mapping, start, nr, &pages); unsigned int i; for (i = 0; i < nr_pages; i++) { struct page *page = pages[i]; bool valid = true; if (!page) { valid = false; } else if (page->mapping != mapping) { valid = false; } else if (page->index != (start + i) >> PAGE_SHIFT) { valid = false; } if (valid) { // 执行你的页面业务逻辑 // ... put_page(page); } } kfree(pages);
3. 替换为更安全的遍历函数
如果业务场景允许,优先使用内核提供的、已处理竞态的页面遍历函数:
filemap_read():内部封装了页面有效性校验与引用计数管理,无需手动处理竞态。walk_page_range():通过回调函数遍历页面,内核会保证回调执行期间页面的有效性。
4. 加锁缩小竞态窗口
若必须使用find_get_entries(),可通过加锁减少页面被回收的概率:
- 持有文件的
i_mutex锁,或地址空间的mapping->tree_lock(注意:tree_lock是自旋锁,需在原子上下文使用,且持有时间不宜过长),加锁后页面不会被回收或复用,确保遍历期间的有效性。
内容的提问来源于stack exchange,提问作者TheAhmad
相关产品推荐
相关产品推荐

