On 13/09/16(Tue) 12:23, Martin Pieuchot wrote: > Here's the big scary diff I've been using for some months now to stop > grabbing the KERNEL_LOCK() in bpf_mtap(9). This has been originally > written to prevent lock ordering inside pf_test(). Now that we're > heading toward using a rwlock, we won't have this problem, but fewer > usages of KERNEL_LOCK() is still interesting. > > I'm going to split this diff in small chunks to ease the review. But > I'd appreciate if people could try to break it, test & report back. > > Some notes: > > - Now that selwakeup() is called in a thread context (task) we only > rely on the KERNEL_LOCK() to serialize access to kqueue(9) data. > > - The reference counting is here to make sure a descriptor is not > freed during a sleep. That's why the KERNEL_LOCK() is still > necessary in the slow path. On the other hand bpf_catchpacket() > relies on the reference guaranteed by the SRP list. > > - A mutex now protects the rotating buffers and their associated > fields. It is dropped before calling ifpromisc() because USB > devices sleep. > > - The dance around uiomove(9) is here to check that buffers aren't > rotated while data is copied to userland. Setting ``b->bd_fbuf'' > to NULL should be enough to let bpf_catchpacket() to drop the > patcket. But I added ``__in_uiomove'' to be able to have usable > panic if something weird happen. > > Comments?
I've got many test reports but no actual review... anyone? Here's another extracted diff to move forward. Let bpf_allocbufs() fail when allocating memory, this way we can call it while holding a mutex. ok? Index: net/bpf.c =================================================================== RCS file: /cvs/src/sys/net/bpf.c,v retrieving revision 1.150 diff -u -p -r1.150 bpf.c --- net/bpf.c 16 Oct 2016 18:05:41 -0000 1.150 +++ net/bpf.c 14 Nov 2016 09:02:51 -0000 @@ -92,7 +92,7 @@ int bpf_maxbufsize = BPF_MAXBUFSIZE; struct bpf_if *bpf_iflist; LIST_HEAD(, bpf_d) bpf_d_list; -void bpf_allocbufs(struct bpf_d *); +int bpf_allocbufs(struct bpf_d *); void bpf_ifname(struct ifnet *, struct ifreq *); int _bpf_mtap(caddr_t, const struct mbuf *, u_int, void (*)(const void *, void *, size_t)); @@ -996,6 +996,7 @@ int bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp, *candidate = NULL; + int error = 0; int s; /* @@ -1012,30 +1013,33 @@ bpf_setif(struct bpf_d *d, struct ifreq candidate = bp; } - if (candidate != NULL) { - /* - * Allocate the packet buffers if we need to. - * If we're already attached to requested interface, - * just flush the buffer. - */ - if (d->bd_sbuf == NULL) - bpf_allocbufs(d); - s = splnet(); - if (candidate != d->bd_bif) { - if (d->bd_bif) - /* - * Detach if attached to something else. - */ - bpf_detachd(d); + /* Not found. */ + if (candidate == NULL) + return (ENXIO); - bpf_attachd(d, candidate); - } - bpf_reset_d(d); - splx(s); - return (0); + /* + * Allocate the packet buffers if we need to. + * If we're already attached to requested interface, + * just flush the buffer. + */ + s = splnet(); + if (d->bd_sbuf == NULL) { + if ((error = bpf_allocbufs(d))) + goto out; } - /* Not found. */ - return (ENXIO); + if (candidate != d->bd_bif) { + if (d->bd_bif) + /* + * Detach if attached to something else. + */ + bpf_detachd(d); + + bpf_attachd(d, candidate); + } + bpf_reset_d(d); +out: + splx(s); + return (error); } /* @@ -1434,13 +1438,23 @@ bpf_catchpacket(struct bpf_d *d, u_char /* * Initialize all nonzero fields of a descriptor. */ -void +int bpf_allocbufs(struct bpf_d *d) { - d->bd_fbuf = malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); - d->bd_sbuf = malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); + d->bd_fbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT); + if (d->bd_fbuf == NULL) + return (ENOMEM); + + d->bd_sbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT); + if (d->bd_sbuf == NULL) { + free(d->bd_fbuf, M_DEVBUF, d->bd_bufsize); + return (ENOMEM); + } + d->bd_slen = 0; d->bd_hlen = 0; + + return (0); } void