【发布时间】:2017-05-11 14:50:38
【问题描述】:
在 Linux 机器上,尝试编写驱动程序并尝试将一些内核内存映射到应用程序以获得性能提升。 在线检查 mmap 的驱动程序实现,找到不同的实现方式。 根据手册页,mmap - 在调用进程的虚拟地址空间中创建新映射。
1) 在 mmap 调用期间谁分配物理地址空间?内核还是设备驱动?
见过以下各种驱动程序 mmap 实现。
a) 驱动程序创建连续的物理内核内存并将其映射到进程地址空间。
static int driver_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
pos = kmalloc(size); //allocate contiguous physical memory.
while (size > 0) {
unsigned long pfn;
pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT; // Get Page frame number
if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) // creates mapping
return -EAGAIN;
start += PAGE_SIZE;
pos += PAGE_SIZE;
size -= PAGE_SIZE;
}
}
b) 驱动程序创建虚拟内核内存并将其映射到进程地址空间。
static struct vm_operations_struct dr_vm_ops = {
.open = dr_vma_open,
.close = dr_vma_close,
};
static int driver_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
void *kp = vmalloc(size);
unsigned long up;
for (up = vma->vm_start; up < vma->vm_end; up += PAGE_SIZE) {
struct page *page = vmalloc_to_page(kp); //Finding physical page from virtual address
err = vm_insert_page(vma, up, page); //How is it different from remap_pfn_range?
if (err)
break;
kp += PAGE_SIZE;
}
vma->vm_ops = &dr_vm_ops;
ps_vma_open(vma);
}
c) 不确定在这种情况下谁分配内存。
static int driver_mmap(struct file *filp, struct vm_area_struct *vma)
{
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) // creates mapping
return -EAGAIN;
}
2)如果内核为mmap分配内存,在a&b情况下是不是内存浪费了?
3) remap_pfn_range 用于映射多个页面,而 vm_insert_page 仅用于单页面映射。这是这两个 API 的唯一区别吗?
谢谢,
戈皮纳特。
【问题讨论】:
标签: memory-management linux-kernel linux-device-driver mmap