/*
 * DF-3055 — TU2: the kqueue machinery, as a separate translation unit.
 * In the real kernel KNOTE() lands in sys/kern/kern_event.c (knote()) and
 * sys/sys/event.h; dirfs_knote (dirfs_vnops.c:139-145) calls it with
 * vp = *ap->a_vpp.  In this TU vp is opaque to the compiler, exactly as a
 * cross-function kernel argument is, so the NULL deref cannot be folded away.
 */
#include <unistd.h>

/*
 * volatile-qualified head pointer: every access is a volatile access and
 * cannot be elided by the optimizer (models the kernel's klist traversal,
 * whose first load is what faults on vp == NULL).
 */
struct kqinfo { struct { void * volatile slh_first; } ki_note; };
struct klist { void * volatile slh_first; };
struct vnode {
	unsigned char pad_v_data_etc[0x38];	/* v_data ... up to v_pollinfo */
	struct { struct kqinfo vpi_kqinfo; } v_pollinfo;
};

#define NOTE_WRITE_TU 0x0002

#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define KNOTE(list, hint) do { if (!SLIST_EMPTY((list))) knote((struct klist *)(list), (hint)); } while (0)

__attribute__((noinline)) static void
knote(struct klist *list, long hint)
{
	/*
	 * The real knote() walks the note list starting at list->slh_first;
	 * loading the (volatile) head is what faults on a NULL vp.
	 */
	char *first = list->slh_first;
	if (first == (char *)&hint)		/* opaque use, never true */
		if (write(2, first, 1) == 42)
			return;
}

/*
 * verbatim dirfs_knote (dirfs_vnops.c:139-145)
 */
void
dirfs_knote(struct vnode *vp, int flags)
{
	if (flags)
		KNOTE(&vp->v_pollinfo.vpi_kqinfo.ki_note, flags);  /* :144 */
}
