⬢ DragonFlyBSD Kernel Audit
DF-5436 / hx5436_race.c
← back to finding ↓ download raw
/*
 * DF-5436 racer -- two CPU-pinned processes hammer open()/close() on the
 * two cdevs of one softc (the /dev/ulpt0 vs /dev/unlpt0 pair), same
 * direction (O_RDONLY -- the direction unprivileged users can reach on
 * the 0644 production nodes).
 *
 * The barrier/threaded variant serializes on one CPU under the DFly
 * scheduler; two pinned free-running processes give true concurrency
 * through the production gate window (gate check -> kmalloc(2x32KB) ->
 * sc_fflags |= at ulpt.c:427-456).
 *
 * The authoritative anomaly oracle is the KERNEL counter
 * hw.hx5436.opens_while_open ("successful open of a direction that is
 * already open" -- impossible when the gate is correct) plus
 * double_open_simul (both opens inside the race window simultaneously).
 *
 * usage: hx5436_race [seconds]
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/usched.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>

#define	DEVA	"/dev/hx5436a"
#define	DEVB	"/dev/hx5436b"
#define	STOPF	"/tmp/hx5436.stop"

static double
now_sec(void)
{
	struct timespec ts;

	clock_gettime(CLOCK_MONOTONIC, &ts);
	return (ts.tv_sec + ts.tv_nsec / 1e9);
}

static int
sysctl_int(const char *name)
{
	int v = 0;
	size_t l = sizeof(v);

	if (sysctlbyname(name, &v, &l, NULL, 0) != 0)
		return (-1);
	return (v);
}

static void
pin_cpu(int cpu)
{
	if (usched_set(0, USCHED_SET_CPU, &cpu, sizeof(cpu)) != 0)
		fprintf(stderr, "[pin %d] usched_set: %s\n", cpu,
		    strerror(errno));
}

static void
hammer(const char *dev, int cpu)
{
	long opens = 0, ebusy = 0, other = 0;

	pin_cpu(cpu);
	while (access(STOPF, F_OK) != 0) {
		int fd = open(dev, O_RDONLY);

		if (fd >= 0) {
			opens++;
			close(fd);
		} else if (errno == EBUSY) {
			ebusy++;
		} else {
			other++;
		}
	}
	printf("[hammer %s cpu%d] opens=%ld ebusy=%ld other=%ld\n",
	    dev, cpu, opens, ebusy, other);
	_exit(0);
}

int
main(int argc, char **argv)
{
	double secs = 10.0, t0;
	pid_t pa, pb;
	int st;

	if (argc > 1)
		secs = atof(argv[1]);
	setvbuf(stdout, NULL, _IOLBF, 0);
	unlink(STOPF);

	printf("[*] DF-5436 racer: free-running pinned processes, %.1f s\n",
	    secs);
	printf("[*] baseline kernel counters: opens_while_open=%d "
	    "double_simul=%d polls=%d resets=%d a=%d b=%d ebusy=%d\n",
	    sysctl_int("hw.hx5436.opens_while_open"),
	    sysctl_int("hw.hx5436.double_open_simul"),
	    sysctl_int("hw.hx5436.polls_while_open"),
	    sysctl_int("hw.hx5436.resets_while_open"),
	    sysctl_int("hw.hx5436.a_opens"),
	    sysctl_int("hw.hx5436.b_opens"),
	    sysctl_int("hw.hx5436.ebusy"));

	pb = fork();
	if (pb == 0)
		hammer(DEVB, 1);		/* /dev/unlpt0 role */
	pa = fork();
	if (pa == 0)
		hammer(DEVA, 0);		/* /dev/ulpt0 role */

	t0 = now_sec();
	while (now_sec() - t0 < secs)
		usleep(100000);
	close(open(STOPF, O_CREAT | O_WRONLY, 0644));

	waitpid(pa, &st, 0);
	waitpid(pb, &st, 0);
	unlink(STOPF);

	printf("[R] kernel: opens_while_open=%d double_simul=%d "
	    "polls_while_open=%d resets_while_open=%d a=%d b=%d ebusy=%d\n",
	    sysctl_int("hw.hx5436.opens_while_open"),
	    sysctl_int("hw.hx5436.double_open_simul"),
	    sysctl_int("hw.hx5436.polls_while_open"),
	    sysctl_int("hw.hx5436.resets_while_open"),
	    sysctl_int("hw.hx5436.a_opens"),
	    sysctl_int("hw.hx5436.b_opens"),
	    sysctl_int("hw.hx5436.ebusy"));
	return (0);
}