顺序访问内核驱动程序中的大页面

gju*_*anm 3 c memory linux-kernel huge-pages

我正在使用使用由大页面支持的缓冲区的驱动程序,但是我发现大页面的顺序性存在一些问题。

在用户空间中,程序使用mmapsyscall 分配由大页面支持的大缓冲区。然后通过ioctl调用将该缓冲区传递给驱动程序。驱动程序使用该get_user_pages函数来获取该缓冲区的内存地址。

这非常适合1 GB(1个大页面)的缓冲区大小。get_user_pages返回很多页面(HUGE_PAGE_SIZE / PAGE_SIZE),但它们都是连续的,因此没有问题。我只是用它来抓取第一页的地址page_address并使用它。remap_pfn_range当另一个程序mmap在char设备上进行调用时,驱动程序还可以将该缓冲区映射回用户空间。

但是,当缓冲区由一个以上的大页作为后备时,事情就会变得复杂。看来内核可以返回由非顺序大页支持的缓冲区。即,如果巨大页面池的布局是这样的

+------+------+------+------+
| HP 1 | HP 2 | HP 3 | HP 4 |
+------+------+------+------+
Run Code Online (Sandbox Code Playgroud)

,可以通过保留HP1和HP4,或者可能是HP3然后是HP2来满足对支持大页的缓冲区的请求。这意味着当我get_user_pages在最后一种情况下获取具有的页面时,页面0的地址实际上是在页面262.144(下一个大页面的头部)的地址之后的1 GB。

有什么办法可以顺序访问这些页面?我尝试对地址进行重新排序以找到较低的地址,以便可以使用整个缓冲区(例如,如果内核为我提供了一个由HP3支持的缓冲区,则我将HP2用作HP2的基址),但似乎会扰乱数据在用户空间中(该重新排序的缓冲区中的偏移量0 可能在用户空间缓冲区中偏移了1GB)。

TL; DR:给定> 1个无序的大页面,是否有任何方法可以在Linux内核驱动程序中顺序访问它们?

顺便说一下,我正在使用3.8.0-29通用内核的Linux机器。

gju*_*anm 5

使用CL建议的功能vm_map_ram,我能够重新映射内存,因此可以按顺序访问内存,而与映射的大页面数无关。我将代码留在这里(不包括错误控制),以防它对任何人有帮助。

struct page** pages;
int retval;
unsigned long npages;
unsigned long buffer_start = (unsigned long) huge->addr; // Address from user-space map.
void* remapped;

npages =  1 + ((bufsize- 1) / PAGE_SIZE); 

pages = vmalloc(npages * sizeof(struct page *));

down_read(&current->mm->mmap_sem);
retval = get_user_pages(current, current->mm, buffer_start, npages,
                     1 /* Write enable */, 0 /* Force */, pages, NULL);
up_read(&current->mm->mmap_sem);    

nid = page_to_nid(pages[0]); // Remap on the same NUMA node.

remapped = vm_map_ram(pages, npages, nid, PAGE_KERNEL);

// Do work on remapped.
Run Code Online (Sandbox Code Playgroud)