How do I know if a copy on a recording page is an actual copy?

When I create a copy-to-write mapping (MAP_PRIVATE) using mmap, some pages of this mapping will be copied as soon as I write to specific addresses. At some point in my program, I would like to find out which pages were actually copied. There is a call called "mincore", but it only tells you if the page is in memory or not, which does not match the page being copied or not.

Is there any way to find out which pages were copied?

+7
source share
6 answers

Well, following MarkR's advice, I gave him a chance to go through the pagemap and kpageflags interface. Below is a quick test to check if the page is in the "SWAPBACKED" memory, as it is called. Of course, one problem remains: the problem is that kpageflags is only available for the root.

int main(int argc, char* argv[]) { unsigned long long pagesize=getpagesize(); assert(pagesize>0); int pagecount=4; int filesize=pagesize*pagecount; int fd=open("test.dat", O_RDWR); if (fd<=0) { fd=open("test.dat", O_CREAT|O_RDWR,S_IRUSR|S_IWUSR); printf("Created test.dat testfile\n"); } assert(fd); int err=ftruncate(fd,filesize); assert(!err); char* M=(char*)mmap(NULL, filesize, PROT_READ|PROT_WRITE, MAP_PRIVATE,fd,0); assert(M!=(char*)-1); assert(M); printf("Successfully create private mapping\n"); 

Test setup contains 4 pages. pages 0 and 2 are dirty

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

page 3 read.

  char t=M[pagesize*3]; 

page 1 will not be available

The pagemap file maps its virtual memory process to actual pages, which can then be extracted from the global kpageflags file later. Read the file /usr/src/linux/Documentation/vm/pagemap.txt

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

Here we read page numbers for each of our virtual pages.

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

Now we are going to read for each virtual frame, the actual page flags

  int pageflags=open("/proc/kpageflags",O_RDONLY); assert(pageflags>0); for(int i = 0 ; i < pagecount; i++) { unsigned long long v2a=page2pfn[i]; printf("Page: %d, flag %llx\n",i,page2pfn[i]); if(v2a&0x8000000000000000LL) // Is the virtual page present ? { unsigned long long pfn=v2a&0x3fffffffffffffLL; err=lseek64(pageflags,pfn*8,SEEK_SET); assert(err==pfn*8); unsigned long long pf; err=read(pageflags,&pf,8); assert(err==8); printf("pageflags are %llx with SWAPBACKED: %d\n",pf,(pf>>14)&1); } } } 

In general, I am not very happy with this approach, since it requires access to a file that we cannot get at all, and it is very complicated (how about a simple kernel call to retrieve the page flags?).

+9
source

I usually use mprotect to set the monitored copy-write read-only pages, and then process the resulting SIGSEGVs, putting this page dirty and allowing writing.

This is not ideal, but the overhead is quite manageable and can be used in combination with mincore , etc. to perform more complex optimizations, for example, to control the size of the working set or to approximate the index information for the expected pages to replace, which allows the run-time system to interact with the kernel, rather than fight it.

+3
source

It is not easy, but it can be determined. To find out if a page is a copy of another page (maybe another process), you need to do the following (latest kernels):

  • Read the entry in / proc / pid / pagemap for the relevant pages of the process (s)
  • Poll / proc / kpageflags

You can then determine that the two pages are actually the same page in memory.

This is quite difficult to do, you need to be root, and everything you do will probably have some race conditions, but it is possible.

+2
source

Copy-on-write is implemented using a virtual memory hardware memory protection circuit.

When a read-only page is written, a page error occurs. The error handler of the page checks whether the page carries a copy-to-write flag: if so, a new page is assigned, the contents of the old page are copied, and the record is repeated.

The new page is not available for reading or copying to the record, the link to the original page is completely broken.

So, all you have to do is check the memory protection flags for the page.

In the Windows API GetWorkingSet , see the explanation in VirtualQueryEx . I do not know what the corresponding linux API is.

+2
source

I gave an answer to someone for a similar purpose and referred to a question similar to yours.

I think the bmargulies answer to this question matches what you need when two ideas are combined.

+2
source

I do not remember that such an API is exported. Why do you want to do such a thing (what is the root of the problem you are solving?)

You might want to take a look at / proc / [pid] / smaps (which provides some detailed statistics on the pages used / copy / save).

Again, why do you need to do this? If you are sure that this approach is the only one (as a rule, virtual memory is used and forgotten), you may want to write a kernel module that processes such functions.

+1
source

All Articles