内核驱动读取/proc/<pid>/pagemap失败及大页DMA内存分配咨询
内核读取pagemap失败与大页DMA内存分配解决方案
一、解决内核读取/proc//pagemap失败的问题
内核态无法通过kernel_read读取pagemap文件,核心原因是/proc/<pid>/pagemap的文件操作接口未实现内核态read方法,仅支持用户态pread64调用,直接调用kernel_read会触发*EINVAL(无效参数)*错误。
无需依赖/proc文件系统,直接通过进程页表获取虚拟地址对应的物理页是更高效安全的方案,还能规避sudo权限需求:
- 通过PID获取目标进程的
struct task_struct(使用pid_task(find_vpid(pid), PIDTYPE_PID),注意加锁保护); - 调用
get_user_pages_fast或get_user_pages函数,传入用户态虚拟地址、页数和标志位,获取对应的struct page指针; - 用
page_to_phys(page)将页结构转换为物理地址; - 操作完成后调用
put_page释放页引用。
示例代码片段:
struct task_struct *task = pid_task(find_vpid(19030), PIDTYPE_PID); if (!task) return -ESRCH; mmap_read_lock(task->mm); struct page *page = NULL; int ret = get_user_pages_fast(0x7FFD1BF46530, 1, 0, &page); mmap_read_unlock(task->mm); if (ret == 1) { phys_addr_t phys_addr = page_to_phys(page); // 使用物理地址做DMA操作 put_page(page); } else { // 处理页获取失败的情况 }
二、分配大页物理连续DMA内存的方案
dma_alloc_coherent受限于伙伴系统内存碎片化,无法支持数百MB到GB级的连续内存分配,可采用以下几种可行方案:
1. 使用HugeTLB大页分配
内核态直接分配HugeTLB大页作为DMA内存,需提前在系统中预留足够大页:
- 系统层面:通过
sysctl vm.nr_hugepages设置预留数量,或启动参数hugepages=N指定; - 内核代码中:调用
hugetlb_alloc_pages分配大页,再用dma_map_page映射为DMA地址; - 若需要用户态访问,通过
remap_pfn_range将物理页映射到用户态虚拟地址空间。
核心流程示例:
// 分配2MB大页(根据系统大页大小调整,如1GB大页则用HPAGE_SIZE_1GB) struct page *page = hugetlb_alloc_pages(HPAGE_SIZE, GFP_KERNEL | GFP_DMA); if (!page) return -ENOMEM; // 映射为DMA地址 dma_addr_t dma_addr = dma_map_page(dev, page, 0, HPAGE_SIZE, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, dma_addr)) { hugetlb_free_pages(page, HPAGE_SIZE); return -EIO; } // 映射到用户态(若需要) unsigned long pfn = page_to_pfn(page); int ret = remap_pfn_range(vma, vma->vm_start, pfn, HPAGE_SIZE, vma->vm_page_prot);
2. 利用连续内存分配器(CMA)
若系统启用了CMA,可通过dma_alloc_from_contiguous分配大段连续物理内存:
- 系统层面:通过启动参数
cma=2G(按需调整大小)预留CMA区域; - 内核代码中:调用
dma_alloc_from_contiguous分配指定大小的连续内存,支持更大尺寸的分配,且天然适配DMA操作; - 同样可通过
remap_pfn_range映射到用户态。
3. 优化用户态mmap的物理连续性
若坚持使用用户态分配,可通过以下方式提升物理连续性:
- 用
mmap的MAP_HUGETLB标志直接申请HugeTLB大页,而非依赖THP自动转换; - 提前设置
sysctl vm.nr_overcommit_hugepages预留足够大页; - 内核态通过
get_user_pages获取这些大页的物理地址用于DMA操作。
注意:GB级连续内存分配高度依赖系统内存布局和碎片化程度,建议在系统启动时通过启动参数或CMA预留内存,避免运行时因碎片化导致分配失败。
内容的提问来源于stack exchange,提问作者aku
相关产品推荐
相关产品推荐

