我正在使用一个由大页支持的缓冲区的驱动程序,并且我发现了一些问题顺序性大页。
在用户空间中,程序使用大页分配一个大缓冲区mmap
系统调用。然后缓冲区通过一个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 |
+------+------+------+------+
,对大页支持的缓冲区的请求可以通过保留 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-generic 内核的 Linux 机器上工作。
使用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(¤t->mm->mmap_sem);
retval = get_user_pages(current, current->mm, buffer_start, npages,
1 /* Write enable */, 0 /* Force */, pages, NULL);
up_read(¤t->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.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)