/* squeeze.c -- wire memory (root setup tool for DF-5015 verification):
 * mlocks 32MB chunks until free page count drops to the target floor,
 * then holds. Exit/unlink releases everything (kernel unlocks on close). */
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/resource.h>

static long
free_pages(void)
{
	size_t len;
	u_int v = 0;
	static int real_mib[CTL_MAXNAME];
	static size_t real_len;

	if (real_len == 0) {
		real_len = CTL_MAXNAME;
		if (sysctlnametomib("vm.stats.vm.v_free_count", real_mib,
		    &real_len))
			return -1;
	}
	len = sizeof(v);
	if (sysctl(real_mib, real_len, &v, &len, NULL, 0))
		return -1;
	return v;
}

int
main(int argc, char **argv)
{
	long target = atol(argv[1]);	/* target free pages floor */
	long chunk = 32 << 20;
	void *p;

	if (argc < 2)
		return 64;
	{
		struct rlimit rl;
		rl.rlim_cur = RLIM_INFINITY;
		rl.rlim_max = RLIM_INFINITY;
		if (setrlimit(RLIMIT_MEMLOCK, &rl))
			printf("squeeze: setrlimit: %s\n", strerror(errno));
	}
	for (;;) {
		if (free_pages() <= target)
			break;
		p = mmap(NULL, chunk, PROT_READ | PROT_WRITE,
		    MAP_ANON | MAP_PRIVATE, -1, 0);
		if (p == MAP_FAILED) {
			printf("squeeze: mmap failed at free=%ld\n",
			    free_pages());
			break;
		}
		memset(p, 1, chunk);
		if (mlock(p, chunk)) {
			printf("squeeze: mlock failed at free=%ld: %s\n",
			    free_pages(), strerror(errno));
			munmap(p, chunk);
			break;
		}
	}
	printf("squeeze: holding at free=%ld (target %ld)\n",
	    free_pages(), target);
	fflush(stdout);
	pause();
	return 0;
}
