DF-5815 / df5815_hog.c
/* * DF-5815 trigger — unprivileged anonymous-memory hog. * * With vm.max_launder set to a negative value (root-writable sysctl), * vm_pageout_scan_inactive()'s max_launder computation * (sys/vm/vm_pageout.c:828-836) evaluates to a NEGATIVE per-queue * launder budget: * * max_launder = vm_max_launder / PQ_L2_SIZE; (negative) * ... * if (max_launder >= vm_max_launder / 16) (always true * max_launder = vm_max_launder / 16 + 1; for vm<0) * * so vm_pageout_page()'s laundering branch (vm_pageout.c:1171 * `else if (*max_launderp > 0)') is never taken: dirty pages are never * paged out, the pagedaemon can never rebuild free+cache, and the * system livelocks (continuous-paging warning, memory waiters stuck). * * This hog allocates and dirties anonymous memory until it is told to * stop or the system starves. With the stock vm.max_launder the same * hog simply forces swapping and the system survives (baseline). * * build: cc -O2 -o df5815_hog df5815_hog.c * run: ./df5815_hog <MB> [touch-loop-seconds] */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> int main(int argc, char **argv) { unsigned long mb = 3072, i, sz; int loop = 60; char *p; time_t t0; if (argc > 1) mb = strtoul(argv[1], NULL, 0); if (argc > 2) loop = atoi(argv[2]); sz = mb * 1024 * 1024; p = malloc(sz); if (p == NULL) { fprintf(stderr, "malloc %lu MB failed\n", mb); return (1); } fprintf(stderr, "hog %lu MB, touching (pid %d)\n", mb, (int)getpid()); t0 = time(NULL); i = 0; while (time(NULL) - t0 < (time_t)loop) { /* dirty every page, forever */ for (i = 0; i < sz; i += 4096) p[i] = (char)(i >> 12); } fprintf(stderr, "hog done (%lds)\n", (long)(time(NULL) - t0)); free(p); return (0); } |