How can I pre-fault and lock memory pages that are mmap'd with MAP_PRIVATE?
1
vote
0
answers
252
views
I am writing a real-time linux application where I need to prevent any page faults from occuring after the initial startup of my application.
My initial thought was just to call
mlockall(MCL_CURRENT | MCL_FUTURE);
. Calling this function returns no error code, but if I inspect my process's pages, it looks like there are still many pages that have the Locked:
size at 0 (which I assume means those pages can still cause a page-fault).
$ cat /proc//smaps | grep -B 21 -A 2 "Locked: 0 kB" | grep -B 1 "^Size:" | grep -v "Size" | grep -v "^\-\-"
7effd0021000-7effd4000000 ---p 00000000 00:00 0
7effd4021000-7effd8000000 ---p 00000000 00:00 0
7effd80c6000-7effdc000000 ---p 00000000 00:00 0
7effddf02000-7effddfa0000 rw-s 00000000 00:05 368 /dev/some_char_device
7effddfa0000-7effde1a0000 rw-s f0000000 00:05 368 /dev/some_char_device
7effde1c1000-7effde1c2000 ---p 00000000 00:00 0
7effde1c6000-7effde1ca000 rw-s f7c00000 00:05 368 /dev/some_char_device
7effde1ca000-7effde1cb000 ---p 00000000 00:00 0
7effe221b000-7effe221c000 ---p 00000000 00:00 0
7effe2220000-7effe2223000 rw-s 00000000 00:05 90 /dev/another_char_device
7effe22df000-7effe22e0000 ---p 00013000 08:02 2234654 //shared_library1.so
7effe22fd000-7effe22fe000 ---p 0000c000 08:02 2231701 //shared_library2.so
7effe23fc000-7effe23fd000 ---p 0001c000 08:02 2234652 //shared_library3.so
7effe2e15000-7effe2e16000 ---p 00215000 08:02 1957 /usr/lib/x86_64-linux-gnu/libc.so.6
7effe2e40000-7effe2e41000 ---p 00011000 08:02 2234649 //shared_library4.so
7effe2f14000-7effe2f15000 ---p 00046000 08:02 2232115 //shared_library5.so
7effe321a000-7effe321b000 ---p 0021a000 08:02 855 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
7effe3258000-7effe3259000 ---p 0001f000 08:02 2234643 //shared_library6.so
7effe327d000-7effe327e000 ---p 00021000 08:02 2234641 //shared_library7.so
7effe328a000-7effe328b000 ---p 00009000 08:02 2232116 //shared_library8.so
7effe348e000-7effe348f000 ---p 00102000 08:02 91759 //shared_library9.so
7effe34c6000-7effe34c8000 r--p 00000000 08:02 175 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7effe34f2000-7effe34fd000 r--p 0002c000 08:02 175 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffc1d1b0000-7ffc1d1b4000 r--p 00000000 00:00 0 [vvar]
7ffc1d1b4000-7ffc1d1b6000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
# Some attempts and some questions...
## Attempt: Move the location of mlockall
in the initialization function
My main function has a bunch of dlopen
calls. Previously the mlockall
call was *after* the calls to dlopen
. Moving the call to mlockall
*before* the dlopen
calls seems to lock in the memory of the shared libraries that are loaded after it. However, it does not lock in the memory of shared libraries loaded *before* the call to mlockall
(those shared libraries are linked at compile-time and specified in the executable).
**Why doesn't MCL_CURRENT lock in already-loaded libraries?**
$ cat /proc//smaps | grep -B 21 -A 2 "Locked: 0 kB" | grep -B 1 "^Size:" | grep -v "Size" | grep -v "^\-\-"
7fef0c021000-7fef10000000 ---p 00000000 00:00 0
7fef10021000-7fef14000000 ---p 00000000 00:00 0
7fef140c6000-7fef18000000 ---p 00000000 00:00 0
7fef1875d000-7fef187fb000 rw-s 00000000 00:05 368 /dev/some_char_device
7fef187fb000-7fef189fb000 rw-s f0000000 00:05 368 /dev/some_char_device
7fef18a0a000-7fef18a0b000 ---p 00000000 00:00 0
7fef1ca2e000-7fef1ca2f000 ---p 00000000 00:00 0
7fef1ca33000-7fef1ca37000 rw-s f7c00000 00:05 368 /dev/some_char_device
7fef1ca37000-7fef1ca38000 ---p 00000000 00:00 0
7fef1ca3c000-7fef1ca3f000 rw-s 00000000 00:05 90 /dev/another_char_device
7fef1d615000-7fef1d616000 ---p 00215000 08:02 1957 /usr/lib/x86_64-linux-gnu/libc.so.6
7fef1da1a000-7fef1da1b000 ---p 0021a000 08:02 855 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30
7fef1dcea000-7fef1dceb000 ---p 00102000 08:02 91760 //shared_library9.so
7fef1dd22000-7fef1dd24000 r--p 00000000 08:02 175 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7fef1dd4e000-7fef1dd59000 r--p 0002c000 08:02 175 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffece1c4000-7ffece1c8000 r--p 00000000 00:00 0 [vvar]
7ffece1c8000-7ffece1ca000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
## Attempt: Use madvise to prefault pages
I tried calling this prefault
function (inspired from here ), but madvise
seems to return a -1
or EPERM
code on the pages with permissions ---p
. If I understand correctly, those pages are mapped with MAP_PRIVATE and are supposed to be allocated in physical memory only when written to (as per the Copy-On-Write pattern). However, madvise
does not seem to trigger the allocation, and just returns an error instead.
**How can I pre-fault pages mapped with MAP_PRIVATE?**
void prefault()
{
const pid_t pid = getpid();
FILE *fp;
char path[PATH_MAX];
char buf;
(void)snprintf(path, sizeof(path), "/proc/%" PRIdMAX "/maps", (intmax_t)pid);
fp = fopen(path, "r");
volatile uint8_t val;
while (fgets(buf, sizeof(buf), fp)) {
void *start, *end, *offset;
int major, minor, n, ret;
uint64_t inode;
char prot;
n = sscanf(buf, "%p-%p %4s %p %x:%x %" PRIu64 " %s\n",
&start, &end, prot, &offset, &major, &minor,
&inode, path);
if (n = end) { continue; /* invalid addresse range */ }
ret = madvise(start, (size_t)((uint8_t *)end - (uint8_t *)start), MADV_POPULATE_WRITE);
}
(void)fclose(fp);
}
Asked by Jay S.
(61 rep)
Oct 2, 2024, 06:19 PM
Last activity: Oct 4, 2024, 08:40 PM
Last activity: Oct 4, 2024, 08:40 PM