linux – 如何知道写时复制页面是否是实际的副本?

前端之家收集整理的这篇文章主要介绍了linux – 如何知道写时复制页面是否是实际的副本?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
当我使用mmap创建写时复制映射(MAP_PRIVATE)时,只要我写入特定地址,就会复制此映射的某些页面.在我的程序中的某个点,我想弄清楚哪些页面实际上已被复制.有一个名为’mincore’的调用,但它只报告页面是否在内存中,这与正在复制的页面不同.

有没有办法弄清楚哪些页面被复制了?

解决方法

很好,按照 MarkR的建议,我给了它一个镜头来浏览页面地图和kpageflags界面.下面是一个快速测试,用于检查页面是否在调用内存时“SWAPBACKED”.当然还存在一个问题,即kpageflags只能被root访问.
  1. int main(int argc,char* argv[])
  2. {
  3. unsigned long long pagesize=getpagesize();
  4. assert(pagesize>0);
  5. int pagecount=4;
  6. int filesize=pagesize*pagecount;
  7. int fd=open("test.dat",O_RDWR);
  8. if (fd<=0)
  9. {
  10. fd=open("test.dat",O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
  11. printf("Created test.dat testfile\n");
  12. }
  13. assert(fd);
  14. int err=ftruncate(fd,filesize);
  15. assert(!err);
  16.  
  17. char* M=(char*)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
  18. assert(M!=(char*)-1);
  19. assert(M);
  20. printf("Successfully create private mapping\n");

测试设置包含4页.第0页和第2页很脏

  1. strcpy(M,"I feel so dirty\n");
  2. strcpy(M+pagesize*2,"Christ on crutches\n");

第3页已被阅读.

  1. char t=M[pagesize*3];

第1页将无法访问

页面映射文件将进程的虚拟内存映射到实际页面,然后可以从全局kpageflags文件中检索该页面.阅读文件/usr/src/linux/Documentation/vm/pagemap.txt

  1. int mapfd=open("/proc/self/pagemap",O_RDONLY);
  2. assert(mapfd>0);
  3. unsigned long long target=((unsigned long)(void*)M)/pagesize;
  4. err=lseek64(mapfd,target*8,SEEK_SET);
  5. assert(err==target*8);
  6. assert(sizeof(long long)==8);

在这里,我们读取每个虚拟页面页面框架编号

  1. unsigned long long page2pfn[pagecount];
  2. err=read(mapfd,page2pfn,sizeof(long long)*pagecount);
  3. if (err<0)
  4. perror("Reading pagemap");
  5. if(err!=pagecount*8)
  6. printf("Could only read %d bytes\n",err);

现在我们将要读取每个虚拟帧,即实际的页面标志

  1. int pageflags=open("/proc/kpageflags",O_RDONLY);
  2. assert(pageflags>0);
  3. for(int i = 0 ; i < pagecount; i++)
  4. {
  5. unsigned long long v2a=page2pfn[i];
  6. printf("Page: %d,flag %llx\n",i,page2pfn[i]);
  7.  
  8. if(v2a&0x8000000000000000LL) // Is the virtual page present ?
  9. {
  10. unsigned long long pfn=v2a&0x3fffffffffffffLL;
  11. err=lseek64(pageflags,pfn*8,SEEK_SET);
  12. assert(err==pfn*8);
  13. unsigned long long pf;
  14. err=read(pageflags,&pf,8);
  15. assert(err==8);
  16. printf("pageflags are %llx with SWAPBACKED: %d\n",pf,(pf>>14)&1);
  17. }
  18. }
  19. }

总而言之,我对这种方法并不是特别满意,因为它需要访问我们通常无法访问的文件,而且它很复杂(如何通过简单的内核调用来检索页面标记?).

猜你在找的Linux相关文章