免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 8116 | 回复: 40
打印 上一主题 下一主题

[内核模块] 内存映射内核和用户读写数据不同步 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-09-11 09:28 |只看该作者 |倒序浏览
我使用mmap将内核空间内存映射到用户空间,然后由用户层的write函数让内核向这块内存写数据,写完之后用户层立即将从这块内存获得的数据与写入的比较。
内核源码如下:
  1. #define MMAP_PAGE_SIZE 4096
  2. static unsigned char *buffer;

  3. ssize_t mmap_write(struct file *file, const char __user *buf, size_t len, loff_t *ofs)
  4. {
  5.         copy_from_user(buffer, buf, len);
  6.        
  7.         printk("data1 is=%x\n",buffer[0]);
  8.         printk("data2 is=%x\n",buffer[1]);
  9.         printk("data3 is=%x\n",buffer[2]);
  10.         printk("data4 is=%x\n",buffer[3]);
  11.         printk("data5 is=%x\n",buffer[4]);
  12.         printk("data6 is=%x\n",buffer[5]);
  13.         printk("data7 is=%x\n",buffer[6]);
  14.         printk("data8 is=%x\n",buffer[7]);
  15.         printk("data9 is=%x\n",buffer[8]);
  16.         printk("dataA is=%x\n",buffer[9]);
  17.         printk("dataB is=%x\n",buffer[10]);
  18.         printk("dataC is=%x\n",buffer[11]);
  19.         printk("dataD is=%x\n",buffer[12]);
  20.         printk("dataE is=%x\n",buffer[13]);
  21.         printk("dataF is=%x\n",buffer[14]);
  22.         printk("\n");

  23.         return len;
  24. }

  25. static int mmap_map(struct file *filp, struct vm_area_struct *vma)
  26. {     
  27.         unsigned long page;
  28.         unsigned long start = (unsigned long)vma->vm_start;
  29.         unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);

  30.         page = virt_to_phys(buffer);
  31.     vma->vm_flags |= VM_LOCKED | VM_SHARED | VM_IO | VM_RESERVED;;
  32.         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

  33.         if(remap_pfn_range(vma,start,page>>PAGE_SHIFT,size,vma->vm_page_prot))
  34.                 return -1;
  35.        
  36.         return 0;
  37. }
复制代码
用户源码如下:
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. #include <linux/fb.h>
  7. #include <sys/mman.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/mman.h>

  10. #define PAGE_SIZE 4096

  11. unsigned char buf1[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
  12.                                         0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};

  13. unsigned char buf2[] = {0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9,
  14.                                         0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1};

  15. int main(int argc , char *argv[])
  16. {
  17.         int fd;
  18.         int i;
  19.         unsigned char *p_map;

  20.         fd = open("/dev/mmap-dev",O_RDWR);
  21.         if(fd < 0)
  22.         {
  23.                 printf("open failn");
  24.                 exit(1);
  25.         }

  26.         p_map = (unsigned char *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,fd, 0);
  27.         if(p_map < 0)
  28.         {
  29.                 printf("mmap failn");
  30.                 goto here;
  31.         }

  32.         while(1)
  33.         {
  34.                 for(i=0; i<100; i++)
  35.                 {
  36.                         write(fd, buf1,15);
  37.                         msync(p_map, PAGE_SIZE, MS_SYNC);
  38.                         //sleep(1);
  39.                         for(i=0; i<15; i++)
  40.                                 if(buf1[i] != p_map[i]){
  41.                                         printf("data %x is=%x\n", i+1, p_map[i]);
  42.                                         printf("mmap error buff1 !!!!!! \n");
  43.                                 }

  44.                         write(fd, buf2,15);
  45.                         msync(p_map, PAGE_SIZE, MS_SYNC);
  46.                         //sleep(1);
  47.                         for(i=0; i<15; i++)
  48.                                 if(buf2[i] != p_map[i]){
  49.                                         printf("data %x is=%x\n", i+1, p_map[i]);
  50.                                         printf("mmap error buff2 !!!!!! \n");

  51.                                 }
  52.                 }

  53.                 sleep(1);
  54.         }

  55.         here:
  56.                 munmap(p1_map, PAGE_SIZE);
  57.                
  58.         return 0;
  59. }
复制代码
如果我把mmap_write函数里的printk都注销,出错的概率会非常低,可能几十小时才出一次,但加上printk会立即出现上层读到的数据与写入的不一致,再接着读取,大部分时候就是正确的了。如果在把上层程序的sleep加上,则完全不会出错。从现象来看,好像是用户层读到的数据滞后了内核一点时间,不知道具体是内核写入产生的滞后还是用户读取产生的滞后,或者哪里设置不对,请大神们帮忙!我用的ARM平台

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
2 [报告]
发表于 2014-09-11 09:47 |只看该作者
本帖最后由 arm-linux-gcc 于 2014-09-14 15:21 编辑

多半是cache alias的问题

是arm9吗?vivt的cache就是蛋疼

论坛徽章:
0
3 [报告]
发表于 2014-09-11 10:15 |只看该作者
回复 2# arm-linux-gcc
是arm9,映射时已经设置了nocache了啊,怎么还会有这类问题,可以详细一点吗

   

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
4 [报告]
发表于 2014-09-11 13:14 |只看该作者
你只是把映射到app的虚拟地址设置成了uncache,但是你的write方法是直接写的buffer代表的虚拟地址,这个虚拟地址有设置为uncache吗?

论坛徽章:
0
5 [报告]
发表于 2014-09-11 13:49 |只看该作者
回复 4# arm-linux-gcc
我之前也才猜想读写只设置了一个为nocache,但不确定是哪个,通过这句设置的“vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);”,如果把这个设置去掉,更容易出错,请问怎么把读写都设置为nocache?

   

论坛徽章:
0
6 [报告]
发表于 2014-09-11 14:33 |只看该作者
回复 5# 枫露清愁


    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 指的就是把這塊vma弄成non-cache

如果拿掉這個更容易出錯救代表你需要在某些地方作flush cache的動作

如果要知道是不是真的是cache問題,建議直接從kernel config那邊把L1,2的cache關掉即可

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
7 [报告]
发表于 2014-09-11 14:34 |只看该作者
本帖最后由 arm-linux-gcc 于 2014-09-11 14:38 编辑

回复 5# 枫露清愁


    pgprot_noncached保留

在copy_from_user后面做clean cache

你这个buffer是调用哪个API分配的?

论坛徽章:
0
8 [报告]
发表于 2014-09-11 15:07 |只看该作者
回复 7# arm-linux-gcc
那个buffer是内核调用malloc分配的,clean cache是指调用那个函数吗?cleancache_flush_page?cleancache_put_page?

   

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
9 [报告]
发表于 2014-09-11 15:23 |只看该作者
本帖最后由 arm-linux-gcc 于 2014-09-11 15:35 编辑

回复 8# 枫露清愁


方法1:   
是kmalloc吧,建议换成__get_free_pages
然后在copy_from_user后面调用dma_map_single和dma_unmap_single(方向使用DMA_TO_DEVICE)





方法2:
如果你的buffer size不大,那么可以直接调用dma_alloc_coherent来分配内存,这种方法就无需做dma_map/unmap_xxx了,
这样改动也是最小的,但是性能就不及方法1





论坛徽章:
0
10 [报告]
发表于 2014-09-11 15:32 |只看该作者
回复 9# arm-linux-gcc
是kmalloc,为什么调用这两个函数?我想能不能调用某个函数直接把cache刷到内存里面

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP