"get_user_pages"是如何工作的(针对Linux驱动程序)

8

我正在处理一个Linux PCI驱动程序,现在我正在尝试使用分散/聚集编写DMA代码。

目前为止,我已经学到了要直接从用户空间访问DMA数据,我们需要将用户空间页面固定到内核空间。

而要做到这一点,我们有一个叫做get_user_pages的函数,其完整定义如下:

int get_user_pages(struct task_struct * tsk,  
    struct mm_struct * mm,  
    unsigned long start,  
    int nr_pages,  
    int write,  
    int force,  
    struct page ** pages,  
    struct vm_area_struct ** vmas);

我的第一个问题是关于 struct page ** pages。在调用 get_user_pages 之前,我们需要为 pages 分配内存(例如使用 kcalloc)吗?

我的第二个问题是关于 unsigned long start,在手册页上,它说“起始用户地址”,这是否意味着,如果我在用户空间声明一个指针,如 int *p,那么我应该将传递给内核空间的“起始用户地址”设为 p

我的第三个问题也与 unsigned long start 相关。如果我正确理解了第二个问题,那么我们如何确保该地址恰好从页面开头开始?

以上是三个问题,谢谢。


使用 posix_memalign(),您可以确保指针对齐,或者在 malloc()/mmap() MAP_ANONYMOUS 之后检查它。如果没有对齐,您可以过度分配并自行对齐指针。(保留原始指针以释放内存) - Alexis
1个回答

5
我的第一个问题是关于结构体页面 ** 页面。在调用 get_user_pages 之前,我们需要为页面分配内存(例如使用 kcalloc)吗?
您可以这样做,但这不是必需的,数组就足够了(其大小取决于 nr_pages)。
如果您想固定4页,则 struct page *pages [4]; 就足够了。
我的第二个问题是关于无符号长整型 start,man 手册上说“开始用户地址”,这是否意味着,如果我声明像 int *p 这样的指针,“开始用户地址”我应该传递到内核空间的是 p?
此参数应指向您的用户进程拥有的内存(如 malloc 后)。
我的第三个问题也是关于无符号长整型 start,如果我正确理解了第二个问题,那么我们如何确保此地址恰好从页面开头开始?
我认为您可以使用 getpagesize 函数来实现。
我认为这篇博客文章:"get_user_pages example" 可能会对你有所帮助。

那个“get_user_pages example”并不是很好,因为它假设用户的缓冲区是页面对齐的。 - Ian Abbott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接