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?).