Why does remap_file_pages () not work in this example?

The following C code illustrates the problem that I see on Linux 2.6.30.5-43.fc11.x86_64:

#include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { char buf[1024]; void *base; int fd; size_t pagesz = sysconf(_SC_PAGE_SIZE); fd = open("<some file, at least 4*pagesz in length>", O_RDONLY); if (fd < 0) { perror("open"); return 1; } base = mmap(0, 4*pagesz, PROT_READ, MAP_SHARED, fd, 0); if (base < 0) { perror("mmap"); close(fd); return 1; } memcpy(buf, (char*)base + 2*pagesz, 1024); if (remap_file_pages(base, pagesz, 0, 2, 0) < 0) { perror("remap_file_pages"); munmap(base, 4*pagesz); close(fd); return 1; } printf("%d\n", memcmp(buf, base, 1024)); munmap(base, 4*pagesz); close(fd); return 0; } 

This always fails with remap_file_pages () returning -1, and errno is set to EINVAL. If you look at the source of the kernel, I can see all the conditions in the remap_file_pages () file, where it may fail, but none of them seem to be applicable to my example. What's happening?

+4
source share
1 answer

This is caused by opening the O_RDONLY file. If you change the open mode to O_RDWR , it will work (even if mmap() still only indicates PROT_READ ).

This code in do_mmap_pgoff is the main reason - it only marks vma as VM_SHARED if the file was open for writing:

 vm_flags |= VM_SHARED | VM_MAYSHARE; if (!(file->f_mode & FMODE_WRITE)) vm_flags &= ~(VM_MAYWRITE | VM_SHARED); 

So in remap_file_pages() you are not doing the first check:

 if (!vma || !(vma->vm_flags & VM_SHARED)) goto out; 
+5
source

Source: https://habr.com/ru/post/1300620/


All Articles