免费注册 查看新帖 |

Chinaunix

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

内核和应用程序通过mmap共享的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-03 18:30 |只看该作者 |倒序浏览
内核和应用程序需要进行大量数据的实时传输, 所以选用mmap来进行内存共享。

内核:
1.  调用kmalloc申请一页内存
2.  注册一字符设备,这里称为/dev/test_device
3.  在注册该字符设备时的缺页处理函数,将1中申请的一页内存关联到该设备。
4.  内核每隔一定时间产生一次中断,将采集来的数据写入该页内存。
5.  发送netlink 事件通知应用程序。

应用程序:
1. open 注册的字符设备
2. 通过mmap映射该设备
3. 监听内核netlink事件
4. 收到内核事件,通过访问mmap返回的地址空间,获得采集数据。

问题:
应用程序访问到的数据经常不是内核写入的数据。如果把内核中断间隔设长,比如10秒, 应用访问的数据是正确的。
如果把中断时间设成5秒,应用程序访问的数据有时正确,有时错误。按道理,内核将数据写入内存后,应该很快会更新应用程序映射的地址空间,
不应该很慢啊。 我做了一个实验,在应用程序读完数据后,将该段空间清0, 在下次读取数据时,发现有时只有一部分数据被内核更新了,其余仍然是0。
这是为什么了?虚心求教。

论坛徽章:
0
2 [报告]
发表于 2010-11-03 21:20 |只看该作者
做好页对齐,做好互斥

论坛徽章:
0
3 [报告]
发表于 2010-11-04 08:50 |只看该作者
做好页对齐,做好互斥
sep 发表于 2010-11-03 21:20



我就分配了一页内存,应该是对齐的吧。 请问互斥怎么做了,能具体点吗? 谢谢

论坛徽章:
0
4 [报告]
发表于 2010-11-04 10:59 |只看该作者
本帖最后由 snail_314 于 2010-11-04 11:17 编辑

回复 1# langfanyun


    kernel访问bus address和user space访问同一个bus address的虚拟地址->页表是不一样的.x86上控制页表可以控制指定的虚拟地址要不要被cache,如果你希望kernel写的数据能被user space看见,那么这两个页表都不应该是cachable的.也就是说,x86是virtual address cache的.
kmalloc分配出来的页面都是固定映射的,其页表的内容早在init的时候就定好了,默认是cachable的,所以,我觉得你至少要将其这一部分页面改成uncachable的

论坛徽章:
0
5 [报告]
发表于 2010-11-04 11:29 |只看该作者
回复 3# langfanyun


    kmalloc分配的内存是页对齐的吗?我不确定。我之前的做法都是手动对齐。

互斥操作是驱动的基本功,如果不了解的话,最好恶补一下。

忘记说一点:要mmap用kmalloc分配的内存的话,要置该内存的所有page为保留。不知你已经做了这个工作。

论坛徽章:
0
6 [报告]
发表于 2010-11-04 11:38 |只看该作者
回复  langfanyun


    kernel访问bus address和user space访问同一个bus address的虚拟地址->页表是不 ...
snail_314 发表于 2010-11-04 10:59



    嗯,这也是一个重点。不过这个在驱动的mmap函数里实现吧?对vma设置nocache标志。

论坛徽章:
0
7 [报告]
发表于 2010-11-04 13:49 |只看该作者
贴出我的代码,应该设置Reserved 和 nocache了,帮忙看看是否有问题

pdata=(char *)kmalloc(256, GFP_KERNEL);

static int test_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    struct page *page;

    if(pdata) {
        page=virt_to_page(pdata);
        get_page(page);
        vmf->page = page;
    } else
        return VM_FAULT_SIGBUS;

    return 0;
}

struct vm_operations_struct test_vm_ops =
{
    .open  = test_vm_open,
    .close = test_vm_close,
    .fault = test_vm_fault,
};

static int test_mmap(struct file *flip,struct vm_area_struct *vma)
{
    vma->vm_ops = &test_vm_ops;
    vma->vm_flags |= VM_RESERVED;
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); //no cache

    return 0;
}

论坛徽章:
0
8 [报告]
发表于 2010-11-04 14:02 |只看该作者
/*内核模块加载函数*/
int __init kmalloc_map_init(void)
{
    //申请设备号,添加cdev结构体
    buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
    for (page = virt_to_page(buffer); page < virt_to_page(buffer + BUFFER_SIZE); page++)
    {
        mem_map_reserve(page);//置页为保留,virt_to_page()将内核虚拟地址转化为页
    }
}
/*mmap()函数*/
static int kmalloc_map_mmap(struct file *filp, struct vm_area_struct *vma)
{
    unsigned long page, pos;
    unsigned long start = (unsigned long)vma->vm_start;
    unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);
    if (size > BUFFER_SIZE)
    {
        return - EINVAL;
    }
    pos = (unsigned long)buffer;
    /*映射buffer中的所有页*/
    while (size > 0)
    {
        page = virt_to_phys((void *)pos);
        if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
            return - EAGAIN;
        start += PAGE_SIZE;
        pos += PAGE_SIZE;
        size -= PAGE_SIZE;
    }

/*

**可否用io_remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)buffer) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, PAGE_SHARED)来替代remap_page_range?

**在Linux kernel 2.6.27中,已经找不到remap_page_range的实现,见Linux kernel change log: Changes remap_page_range to remap_pfn_range for 2.6.10 and above kernels

*/
    return 0;
}

论坛徽章:
0
9 [报告]
发表于 2010-11-04 14:09 |只看该作者
回复 7# langfanyun


    你的代码应该只是把mmap出去的页表设为nocache了,你kmalloc出来的页面对kernel来说也不能是cache的

论坛徽章:
0
10 [报告]
发表于 2010-11-04 15:52 |只看该作者
回复  langfanyun


    你的代码应该只是把mmap出去的页表设为nocache了,你kmalloc出来的页面对kernel ...
snail_314 发表于 2010-11-04 14:09



    那怎么nocache kmalloc的页面了?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP