Rework r348303 to reduce the time of holding global BPF lock.

It appeared that using NET_EPOCH_WAIT() while holding global BPF lock
can lead to another panic:

spin lock 0xfffff800183c9840 (turnstile lock) held by 0xfffff80018e2c5a0 (tid 100325) too long
panic: spin lock held too long
...
#0  sched_switch (td=0xfffff80018e2c5a0, newtd=0xfffff8000389e000, flags=<optimized out>) at /usr/src/sys/kern/sched_ule.c:2133
#1  0xffffffff80bf9912 in mi_switch (flags=256, newtd=0x0) at /usr/src/sys/kern/kern_synch.c:439
#2  0xffffffff80c21db7 in sched_bind (td=<optimized out>, cpu=<optimized out>) at /usr/src/sys/kern/sched_ule.c:2704
#3  0xffffffff80c34c33 in epoch_block_handler_preempt (global=<optimized out>, cr=0xfffffe00005a1a00, arg=<optimized out>)
    at /usr/src/sys/kern/subr_epoch.c:394
#4  0xffffffff803c741b in epoch_block (global=<optimized out>, cr=<optimized out>, cb=<optimized out>, ct=<optimized out>)
    at /usr/src/sys/contrib/ck/src/ck_epoch.c:416
#5  ck_epoch_synchronize_wait (global=0xfffff8000380cd80, cb=<optimized out>, ct=<optimized out>) at /usr/src/sys/contrib/ck/src/ck_epoch.c:465
#6  0xffffffff80c3475e in epoch_wait_preempt (epoch=0xfffff8000380cd80) at /usr/src/sys/kern/subr_epoch.c:513
#7  0xffffffff80ce970b in bpf_detachd_locked (d=0xfffff801d309cc00, detached_ifp=<optimized out>) at /usr/src/sys/net/bpf.c:856
#8  0xffffffff80ced166 in bpf_detachd (d=<optimized out>) at /usr/src/sys/net/bpf.c:836
#9  bpf_dtor (data=0xfffff801d309cc00) at /usr/src/sys/net/bpf.c:914

To fix this add the check to the catchpacket() that BPF descriptor was
not detached just before we acquired BPFD_LOCK().

Reported by:	slavash
Tested by:	slavash
MFC after:	1 week
This commit is contained in:
Andrey V. Elsukov 2019-05-28 11:45:00 +00:00
parent 51db930589
commit de25327313
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=348324

View File

@ -850,15 +850,10 @@ bpf_detachd_locked(struct bpf_d *d, bool detached_ifp)
/* Check if descriptor is attached */
if ((bp = d->bd_bif) == NULL)
return;
/*
* Remove d from the interface's descriptor list.
* And wait until bpf_[m]tap*() will finish their possible work
* with descriptor.
*/
CK_LIST_REMOVE(d, bd_next);
NET_EPOCH_WAIT();
BPFD_LOCK(d);
/* Remove d from the interface's descriptor list. */
CK_LIST_REMOVE(d, bd_next);
/* Save bd_writer value */
error = d->bd_writer;
ifp = bp->bif_ifp;
@ -2494,6 +2489,11 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
int tstype;
BPFD_LOCK_ASSERT(d);
if (d->bd_bif == NULL) {
/* Descriptor was detached in concurrent thread */
counter_u64_add(d->bd_dcount, 1);
return;
}
/*
* Detect whether user space has released a buffer back to us, and if