问题描述
编写内核驱动,使用mmap
共享内存。发现读取到的数据不对。
联想到mmap
的length
会自动调整为PAGE_SIZE
的倍数,猜测是因为mmap
返回的是对应page
的起始地址,导致存在偏移。
修复方式:初始化时,单独申请一块大小为PAGE_SIZE
的内存,不使用数组。
并调用SetPageReserved
,保留该页。
问题代码
内核驱动
结构体
1 2 3 4 5
| struct ShareData{ bool isCompleted; int data[20]; } ShareData * g_ShareData;
|
初始化
1
| g_ShareData = kmalloc(sizeof(struct ShareData), GFP_KERNEL);
|
mmap
1 2 3 4
| if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(g_ShareData->data) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { return -EAGAIN; }
|
应用层
1
| (int *) data_mapped = (int *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
测试
计算偏移值:offset = (uint64_t)g_ShareData->data % PAGE_SIZE
加上该偏移值后,读取data_mapped + offset/4
,发现确实是要读取的数据。
修复
结构体
1 2 3 4 5
| struct ShareData{ bool isCompleted; int* data; } ShareData * g_ShareData;
|
初始化
1 2 3
| g_ShareData = kmalloc(sizeof(struct ShareData), GFP_KERNEL); g_ShareData->data = kmalloc(PAGE_SIZE, GFP_KERNEL); SetPageReserved(virt_to_page(g_ShareData->data));
|
参考
例说linux内核与应用数据通信(四):映射设备内核空间到用户态
例說核心層與使用層通訊/4_memdev/drv/chr_memdev.c
linux/memory/mmap/kernel/hello.c