/*
 * DF-3184 root-side mount/unmount driver (harness acceleration).
 * Cycle: mount(); markerA; quiet phase; markerB (immediately before
 * unmount(2)); unmount(MNT_FORCE) -> vflush burst ~258ms after markerB
 * (measured on this guest with a quiet mount; sigma ~3ms).
 *
 * usage: df3184_mountd MOUNTPOINT PHASE_MS RUN_SECONDS MARKER_A MARKER_B
 */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

static double now_s(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return (double)tv.tv_sec + (double)tv.tv_usec / 1e6;
}

static void bump_marker(const char *m)
{
	int fd;
	unlink(m);
	fd = open(m, O_CREAT | O_WRONLY, 0644);
	if (fd >= 0)
		close(fd);
}

int main(int argc, char **argv)
{
	const char *mp = "/procN";
	const char *markA = "/tmp/df3184/cycle.a";
	const char *markB = "/tmp/df3184/cycle.b";
	int phase_ms = 1500, run_s = 300;
	long cycles = 0, ok = 0;

	if (argc > 1) mp = argv[1];
	if (argc > 2) phase_ms = atoi(argv[2]);
	if (argc > 3) run_s = atoi(argv[3]);
	if (argc > 4) markA = argv[4];
	if (argc > 5) markB = argv[5];

	while (run_s <= 0 || cycles < (long)run_s * 4) {
		if (mount("procfs", mp, 0, NULL) == 0) {
			double tB, tU;
			ok++;
			bump_marker(markA);
			usleep(phase_ms * 1000);
			bump_marker(markB);
			tB = now_s();
			if (unmount(mp, MNT_FORCE) < 0)
				fprintf(stderr, "unmount(%s): errno %d "
					"(cycle %ld)\n", mp, errno, cycles);
			tU = now_s();
			printf("cycle %ld: unmount %.3f s\n",
			       cycles, tU - tB);
			fflush(stdout);
		}
		cycles++;
	}
	printf("mountd: %ld cycles, %ld mounts\n", cycles, ok);
	return 0;
}
