调用 mmap() 时如何获取 Linux 中设备内字段的偏移量

How to get the offset of a field within a device in Linux when calling mmap()

我目前正在 Linux 设备驱动程序中实现 mmap()

基本上,假设已经定义了一个名为 data 的结构。我的设备的结构定义如下,

struct test_dev{
    struct cdev cdev;
    struct mutex lock;
    struct data *data;
};

在设备的open()方法中,data是通过调用vmalloc()分配的。假设我想让用户调用mmap()映射到数据字段,用户需要知道data字段的offset

int fd = open("/dev/testdev", O_RDWR);
int ret = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);

我在尝试找到 data 的偏移量时卡住了。

我查看了 mmap() 的联机帮助页,它说

The contents of a file mapping (as opposed to an anonymous mapping; see MAP_ANONYMOUS below), are initialized using length bytes starting at offset offset in the file (or other object) referred to by the file descriptor fd.

Q1:由于data字段是使用vmalloc()分配的,它在高端内存中,但是test_dev结构是使用kmalloc()分配的,它在低内存中memory, addr(data) - addr(test_dev) 小于0。因此,我们不能以这种方式计算偏移量。我可以知道是否有另一种方法来获取 offset,以便用户可以使用此 offsetmmap()data 字段?

Q2:如果 data 字段是使用 kmalloc() 分配的,vmalloc() 方法之间会有什么区别吗?

Linux Device Drivers中声明kmalloc()返回的内存地址也是虚拟地址,位于低位内存。我不确定使用“addr(data) - addr(test_dev)”是否有效。以我自己的理解,不太可能行得通。

此外,由于kmalloc() manpagekmalloc()是内核中为小于页面大小的对象分配内存的正常方法,因此在实现mmap()时,我们可能不会选择映射到 kmalloc() 返回的地址,因为 mmap() 映射到页面边界。

偏移量被传递给您在设备驱动程序中编写的 mmap 处理程序。你可以把它当作一个任意的 off_t 参数,这意味着你想要的任何东西。忽略它并始终 mmap data。或者将它用作从 data 开始的偏移量,这可能是您的驱动程序最正确的语义。

驱动程序初始化时 kmalloc() 调用的结构与 mmap 无关。 offset 不是距此结构开头的偏移量。

要映射 vmalloc 内存,您需要获取每个页面,因为它们不连续,并将其添加到 vma。参见 vmalloc_to_pagevm_insert_page