Sample Header Ad - 728x90

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