免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4954 | 回复: 8

关于mmap,来个猛的. (思一克兄进来看看) [复制链接]

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
发表于 2011-01-07 11:41 |显示全部楼层
5可用积分
有两个进程a和b,两个进程共同操作一个test文件。
其中a进程用mmap调用,b进程用O_DIRECT标识write()。
大家知道:
1.用O_DIRECT来write的时候,是不经过page cache层的
2.mmap调用的话,是在将文件映射到进程虚拟内存区域

步骤:
1.首先a进程先运行,在mmap()调用并打印出其中的文件内容后阻塞
2.启动b进程进行O_DIRECT write(),接着唤醒a进程再次读取文件内容

现象:
1.a进程读取到的文件内容是最新的,也就是b进程写入的内容

问题:
1.步骤1已经进行了mmap()了同时输出了文件内容,说明进程已经做了缺页异常处理,即虚拟地址和物理地址直接建立了
关系,也就是说a进程的虚实映射是不会变化的。那么当步骤2运行完后,内核是怎样重新更新a进程的虚拟地址对应的物理地址的内容?
说的简单一点:就是O_DIRECT write写的时候,内核是怎样更新page cache等其他缓存数据的? 内核哪段代码有体现?
(我一直没有找到)

谢谢!

最佳答案

查看完整内容

O_DIRECT写的时候,检查文件有无page cache(一个文件可以同时被多个地方以多种方式使用), 如果有,及时更新page cahce.而mmap返回的内存其实就是这些page cache组成的。我估计是如此的。

论坛徽章:
0
发表于 2011-01-07 11:41 |显示全部楼层
O_DIRECT写的时候,检查文件有无page cache(一个文件可以同时被多个地方以多种方式使用), 如果有,及时更新page cahce.
而mmap返回的内存其实就是这些page cache组成的。

我估计是如此的。

论坛徽章:
0
发表于 2011-01-07 15:42 |显示全部楼层
mark

论坛徽章:
0
发表于 2011-01-07 16:30 |显示全部楼层
我来献上代码,确实如lz所说

  1. #define _GNU_SOURCE
  2. #include<fcntl.h>
  3. #include <sys/types.h> //open
  4. #include <sys/stat.h>
  5. #include<stdio.h>
  6. #include<error.h>
  7. #include<err.h>
  8. #include<time.h>
  9. #include<string.h>
  10. #include<sys/mman.h>
  11. #include<unistd.h>

  12. int main()
  13. {
  14.     char *buf;
  15.     pid_t pid;
  16.     int fd = open("./test.tmp", O_RDWR|O_CREAT|O_DIRECT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH|S_IWOTH);
  17.     if(fd < 0)
  18.         err(-1,"open fail");
  19.     ftruncate(fd,4096);
  20.     if(0 == (pid = fork()))
  21.     {
  22.         //child
  23.         if( 0 != posix_memalign(&buf, 4096,4096))
  24.             err(-1,"mem alloc");
  25.         sleep(5);
  26.         time_t t = time(0);
  27.         strftime(buf, 4096, "today is a sunnly day, now is %T", localtime(&t));
  28.         int n = 0;
  29.         if(0 > (n = write(fd, buf, 4096)))
  30.             err(-1,"write");
  31.         free(buf);
  32.     }
  33.     else if(pid > 0)
  34.     {
  35.         //parent
  36.         char * maddr = (char *)mmap(NULL, 4096, PROT_READ, MAP_SHARED ,fd, 0);
  37.         if(maddr == MAP_FAILED)
  38.             err(-1,"mmap");
  39.         fprintf(stderr,"before,mmap read:%s\n",maddr);
  40.         waitpid(pid, NULL, 0);
  41.         fprintf(stderr,"after, mmap read:%s\n",maddr);
  42.         munmap(maddr, 4096);
  43.     }
  44.     else
  45.         err(-1,"fork");

  46.     close(fd);
  47.     return 0;
  48. }

复制代码

论坛徽章:
0
发表于 2011-01-08 10:19 |显示全部楼层
为了5分
可不可以这么认为,操作系统负责了对 内存映射页面 保持和文件更新的状态?
也就是说在访问时候,os 会检查页面是否为脏了?

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
发表于 2011-01-09 23:24 |显示全部楼层
为了5分
可不可以这么认为,操作系统负责了对 内存映射页面 保持和文件更新的状态?
也就是说在访问时候, ...
ydfgic 发表于 2011-01-08 10:19



    内核肯定负责了内存映射页面 保持和文件更新的状态,但这里mmap不是通过这种方式,而是采用缺页异常来处理,不好描述

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
发表于 2011-01-09 23:27 |显示全部楼层
O_DIRECT写的时候,检查文件有无page cache(一个文件可以同时被多个地方以多种方式使用), 如果有,及时更 ...
思一克 发表于 2011-01-08 14:05



    恩,mmap映射的确实是page cache中的page,但这个例子中,不是通过这个更新页面来达到完成,而是采用缺页处理来完成

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
发表于 2011-01-09 23:30 |显示全部楼层
本帖最后由 chenzhanyiczy 于 2011-01-09 23:31 编辑

看了源码,基本搞懂。
感谢思一克,ydfgic
还是结了这个帖吧

论坛徽章:
0
发表于 2011-02-16 10:24 |显示全部楼层
采用直接I/O时,当操作类型是 WRITE 的时候,若发现该使用直接 I/O 的文件已经与其他一个或者多个进程存在关联的内存映射,那么就调用 unmap_mapping_range() 函数去取消建立在该文件上的所有的内存映射,并将页缓存中相关的所有 dirty 位被置位的脏页面刷回到磁盘上去。对于直接  I/O  写操作来说,这样做可以保证写到磁盘上的数据是最新的,否则,即将用直接  I/O  方式写入到磁盘上的数据很可能会因为页缓存中已经存在的脏数据而失效。在直接  I/O  写操作完成之后,在页缓存中相关的脏数据就都已经失效了,磁盘与页缓存中的数据内容必须保持同步。

见:http://www.ibm.com/developerwork ... directio/index.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP