-/* $OpenBSD: bpf.c,v 1.147 2016/08/15 07:20:14 mpi Exp $ */
+/* $OpenBSD: bpf.c,v 1.148 2016/08/22 10:40:36 mpi Exp $ */
/* $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */
/*
#include <sys/atomic.h>
#include <sys/srp.h>
#include <sys/specdev.h>
+#include <sys/selinfo.h>
+#include <sys/task.h>
#include <net/if.h>
#include <net/bpf.h>
int bpfpoll(dev_t, int, struct proc *);
int bpfkqfilter(dev_t, struct knote *);
void bpf_wakeup(struct bpf_d *);
+void bpf_wakeup_cb(void *);
void bpf_catchpacket(struct bpf_d *, u_char *, size_t, size_t,
void (*)(const void *, void *, size_t), struct timeval *);
void bpf_reset_d(struct bpf_d *);
bd->bd_unit = unit;
bd->bd_bufsize = bpf_bufsize;
bd->bd_sig = SIGIO;
+ task_set(&bd->bd_wake_task, bpf_wakeup_cb, bd);
if (flag & FNONBLOCK)
bd->bd_rtout = -1;
void
bpf_wakeup(struct bpf_d *d)
{
- wakeup((caddr_t)d);
+ /*
+ * As long as csignal() and selwakeup() need to be protected
+ * by the KERNEL_LOCK() we have to delay the wakeup to
+ * another context to keep the hot path KERNEL_LOCK()-free.
+ */
+ bpf_get(d);
+ if (!task_add(systq, &d->bd_wake_task))
+ bpf_put(d);
+}
+
+void
+bpf_wakeup_cb(void *xd)
+{
+ struct bpf_d *d = xd;
+
+ KERNEL_ASSERT_LOCKED();
+
+ wakeup(d);
if (d->bd_async && d->bd_sig)
- csignal(d->bd_pgid, d->bd_sig,
- d->bd_siguid, d->bd_sigeuid);
+ csignal(d->bd_pgid, d->bd_sig, d->bd_siguid, d->bd_sigeuid);
selwakeup(&d->bd_sel);
+ bpf_put(d);
}
int
-/* $OpenBSD: bpfdesc.h,v 1.30 2016/03/30 12:33:10 dlg Exp $ */
+/* $OpenBSD: bpfdesc.h,v 1.31 2016/08/22 10:40:36 mpi Exp $ */
/* $NetBSD: bpfdesc.h,v 1.11 1995/09/27 18:30:42 thorpej Exp $ */
/*
#ifdef _KERNEL
-#include <sys/selinfo.h>
-
/*
* Descriptor associated with each open bpf file.
*/
struct selinfo bd_sel; /* bsd select info */
int bd_unit; /* logical unit number */
LIST_ENTRY(bpf_d) bd_list; /* descriptor list */
+
+ struct task bd_wake_task; /* delay csignal() and selwakeup() */
};
/*