/*
 * DF-2685 trigger: mlock() zero-fill of swapped-out anonymous memory.
 *
 * Mechanism (stock DragonFly):
 *   mlock() -> vm_map_wire() -> vm_fault_wire(user_wire=TRUE)
 *           -> vm_fault(map, va, VM_PROT_READ, VM_FAULT_USER_WIRE)
 *   In vm_fault_object(), TRYPAGER(fs) is FALSE for every fault that has
 *   any VM_FAULT_WIRE_MASK flag set, so the swap/vnode pager is never asked
 *   for the page.  The fault falls through to the terminal-object path and
 *   vm_page_zero_fill()s a freshly allocated page (vm_fault.c:2327).
 *   Result: mlock() returns success and the process observes ZEROS where
 *   its (swapped-out) data was.  Silent memory destruction.
 *
 * Fix validated: TRYPAGER additionally allows VM_FAULT_USER_WIRE faults.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#define CHUNK (4UL<<20)
static unsigned int pat(size_t off, size_t i){ return (unsigned int)(off>>12) ^ (unsigned int)i; }
int main(void){
    size_t total = (size_t)4.6*1024*1024*1024;   /* RAM is 4GB + 4GB swap */
    char *m = mmap(NULL, total, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
    if (m == MAP_FAILED) { perror("mmap"); return 1; }
    for (size_t off = 0; off < total; off += CHUNK) {
        unsigned int *p = (unsigned int *)(m + off);
        for (size_t i = 0; i < CHUNK/4; i++) p[i] = pat(off,i);
    }
    printf("touched %zu MB; sleeping 8s for pageout\n", total>>20); fflush(stdout);
    sleep(8);
    system("swapinfo -h");
    size_t lk = 64UL<<20;                        /* earliest-touched region */
    if (mlock(m, lk) != 0) { printf("mlock: %s\n", strerror(errno)); return 1; }
    long bad = 0;
    for (size_t off = 0; off < lk; off += CHUNK) {
        unsigned int *p = (unsigned int *)(m + off);
        for (size_t i = 0; i < CHUNK/4; i++)
            if (p[i] != pat(off,i)) { bad++; if (bad < 4) printf("mismatch off=%zx i=%zx got=%08x want=%08x\n", off, i, p[i], pat(off,i)); }
    }
    printf("mlock-verify: bad=%ld of %d words\n", bad, (int)(lk/4));
    if (bad) { printf("BUG REPRODUCED: mlock zero-filled swapped pages (silent data destruction)\n"); return 2; }
    printf("OK: data intact after mlock\n");
    return 0;
}
