MLOCK(2)

๐Ÿ’– MLOCK(2) โ€” the "pin it down, bestie" page ๐Ÿ’–

okay so this is the manual page for mlock, munlock from the System Calls Manual, and honestly? it's giving "I need these pages to STAY PUT" energy. let's get into it ๐Ÿซถ


โœจ NAME โœจ

mlock, munlock โ€” lock (unlock) physical pages in memory ๐Ÿ”’๐Ÿ”“


๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C Library (libc, -lc)


๐ŸŒธ SYNOPSIS ๐ŸŒธ

#include <sys/mman.h>

int
mlock(const void *addr, size_t len);

int
munlock(const void *addr, size_t len);

๐Ÿ’… DESCRIPTION ๐Ÿ’…

so the mlock() system call locks into memory the physical pages associated with the virtual address range starting at addr for len bytes. it's literally grabbing those pages and going "you're not going anywhere, babe." โœ‹

and munlock()? it unlocks pages that were previously locked by one or more mlock() calls. the release, the letting go, the moving on ๐Ÿฆ‹

for both of them, the addr argument should be aligned to a multiple of the page size. and if len isn't a multiple of the page size, bestie, it gets rounded up to be so. the entire range must be allocated โ€” no phantom pages, no cap. โœจ

After an mlock() system call, the indicated pages will cause neither a non-resident page nor address-translation fault until they are unlocked. (iconic behaviour, honestly.) they may still cause protection-violation faults or TLB-miss faults on architectures with software-managed TLBs โ€” so like, mostly immune, not fully immune, iykyk ๐Ÿ’€

the physical pages remain in memory until all locked mappings for the pages are removed. multiple processes may have the same physical pages locked via their own virtual address mappings. a single process may likewise have pages multiply-locked via different virtual mappings of the same physical pages. the way that one physical page can be living its main character life in like five different address spaces at once ๐Ÿ˜ญ

Unlocking is performed explicitly by munlock() or implicitly by a call to munmap() which deallocates the unmapped address range. and locked mappings are not inherited by the child process after fork(2) โ€” sorry to that child, they get nothing ๐Ÿ™ˆ


โš ๏ธ scarcity alert โš ๏ธ Since physical memory is a potentially scarce resource, processes are limited in how much they can lock down.

The amount of memory that a single process can mlock() is limited by both:

  • the per-process RLIMIT_MEMLOCK resource limit, and
  • the system-wide "wired pages" limit vm.max_user_wired.

and here's the tea: vm.max_user_wired applies to the system as a whole, so the amount available to a single process at any given time is the difference between vm.max_user_wired and vm.stats.vm.v_user_wire_count. math is math, bestie ๐Ÿงฎ

If security.bsd.unprivileged_mlock is set to 0 these calls are only available to the super-user. ๐Ÿ‘‘ so like... know your power level before you try.


๐ŸŒˆ RETURN VALUES ๐ŸŒˆ

Upon successful completion, the value 0 is returned; otherwise the value -1 is returned and the global variable errno is set to indicate the error.

If the call succeeds, all pages in the range become locked (unlocked); otherwise the locked status of all pages in the range remains unchanged. it's all-or-nothing, no partial credit, no half-sending the vibe ๐Ÿ’…


๐Ÿ”ฅ ERRORS ๐Ÿ”ฅ

The mlock() system call will fail if:

  • [EPERM] โ€” security.bsd.unprivileged_mlock is set to 0 and the caller is not the super-user. (no key, no entry ๐Ÿšซ)
  • [EINVAL] โ€” The address range given wraps around zero. (wrapping around zero is not the serve you think it is ๐Ÿ’€)
  • [ENOMEM] โ€” Some portion of the indicated address range is not allocated. There was an error faulting/mapping a page. Locking the indicated range would exceed the per-process or system-wide limits for locked memory.

The munlock() system call will fail if:

  • [EPERM] โ€” security.bsd.unprivileged_mlock is set to 0 and the caller is not the super-user.
  • [EINVAL] โ€” The address range given wraps around zero.
  • [ENOMEM] โ€” Some or all of the address range specified by the addr and len arguments does not correspond to valid mapped pages in the address space of the process.
  • [ENOMEM] โ€” Locking the pages mapped by the specified range would exceed a limit on the amount of memory that the process may lock.

๐Ÿฆ‹ SEE ALSO ๐Ÿฆ‹

fork(2), mincore(2), minherit(2), mlockall(2), mmap(2), munlockall(2), munmap(2), setrlimit(2), getpagesize(3)

(the whole friend group, fr fr ๐Ÿซถ)


๐ŸŽ€ HISTORY ๐ŸŽ€

The mlock() and munlock() system calls first appeared in 4.4BSD. old money, vintage, classic ๐Ÿ’œ


๐Ÿ˜ญ BUGS ๐Ÿ˜ญ

  • Allocating too much wired memory can lead to a memory-allocation deadlock which requires a reboot to recover from. ๐Ÿšจ not a vibe. not the moment. be careful out there bestie.
  • The per-process and system-wide resource limits of locked memory apply to the amount of virtual memory locked, not the amount of locked physical pages. Hence two distinct locked mappings of the same physical page counts as 2 pages aginst the system limit, and also against the per-process limit if both mappings belong to the same physical map. (yes, double-counted. the audacity ๐Ÿ˜ค)
  • The per-process resource limit is not currently supported.

and that's the whole page, bestie!! this one's from the Debian crew, dated May 13, 2019 โ€” so like, it's been serving this exact energy for a minute. lock your pages, respect the limits, and stay hydrated ๐Ÿ’–โœจ๐ŸŽ€

๐Ÿ“ฆ where this page comes from