process_madvise(2)
madvise() for another process's address space, addressed by pidfd and an iovec of ranges.
- Since
- Linux 5.10check your kernel →
- glibc
- glibc 2.36
- System
- Linux
- Man page
- process_madvise(2)
Synopsis
#include <sys/mman.h>
ssize_t process_madvise(int pidfd, const struct iovec iovec[n],
size_t n, int advice, unsigned int flags);Rod's take
madvise only works on memory you own, which is useless when you're the supervisor staring at someone else's bloated process. process_madvise takes a pidfd and an iovec of ranges inside the target, so a memory daemon or checkpoint tool can say cold or page-this-out from outside. Android's low memory killer does exactly that before it pulls the trigger. The pidfd means PID reuse can't trick you into advising the wrong process. Check the return value; it's bytes advised and it can be partial. And read the permissions section: CAP_SYS_NICE on top of ptrace read access.
Flags and arguments that matter
| Name | What it does |
|---|---|
| MADV_COLD | Deactivate the target's pages so they age toward reclaim. Valid on another process. |
| MADV_PAGEOUT | Reclaim the target's pages now (anon to swap, dirty file pages written back). Valid on another process. |
| MADV_WILLNEED | Expect access soon; read ahead. Valid on another process. |
| MADV_COLLAPSE | Synchronously collapse the range into transparent huge pages. Valid on another process. |
| any advice (self)Linux 6.13 | When pidfd refers to the calling process, any madvise advice is permitted. |
| flags | Reserved; must be 0. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EPERM | No permission: needs PTRACE_MODE_READ_FSCREDS access to the target plus CAP_SYS_NICE (since Linux 5.12). |
| ESRCH | The target process has terminated and been waited on. |
| EBADF | pidfd is not a valid PID file descriptor. |
| EINVAL | flags is not 0, n is too large, or the iov_len sum overflows ssize_t. |
| EFAULT | iovec describes memory outside the target's accessible address space. |
Example
int pidfd = pidfd_open(target_pid, 0);
if (pidfd == -1) err(1, "pidfd_open");
/* one 512 MB anonymous range, taken from /proc/<pid>/maps */
struct iovec range = {
.iov_base = (void *)0x7f0000000000,
.iov_len = 512UL * 1024 * 1024,
};
ssize_t done = process_madvise(pidfd, &range, 1, MADV_PAGEOUT, 0);
if (done < 0) err(1, "process_madvise");
if ((size_t)done < range.iov_len)
warnx("partial: %zd bytes advised", done);Trimmed from the full walkthrough in process_madvise: memory pressure hints across process boundaries.
BSD equivalent
FreeBSD and OpenBSD: none; madvise(2) only works on the caller's own address space.
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
