Index: sys/net/bpf.c =================================================================== --- sys/net/bpf.c (revision 266306) +++ sys/net/bpf.c (working copy) @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include @@ -643,6 +643,20 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp) } /* + * Check if filter looks like 'set snaplen' + * program used by pcap-bpf.c:pcap_activate_bpf() + */ +static void +bpf_check_upgrade(u_long cmd, struct bpf_insn *fcode, u_int flen, int *is_snap) +{ + + if (cmd == BIOCSETF && flen == 1 && fcode[0].code == (BPF_RET | BPF_K)) + *is_snap = 1; + else + *is_snap = 0; +} + +/* * Add d to the list of active bp filters. * Reuqires bpf_attachd() to be called before */ @@ -1728,7 +1742,7 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, #endif size_t size; u_int flen; - int need_upgrade; + int is_snaplen, need_upgrade; #ifdef COMPAT_FREEBSD32 switch (cmd) { @@ -1755,6 +1769,7 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, #ifdef BPF_JITTER jfunc = ofunc = NULL; #endif + is_snaplen = 0; need_upgrade = 0; /* @@ -1773,6 +1788,8 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, free(fcode, M_BPF); return (EINVAL); } + /* Try to guess if this is snaplen cmd */ + bpf_check_upgrade(cmd, fcode, flen, &is_snaplen); #ifdef BPF_JITTER /* Filter is copied inside fcode and is perfectly valid. */ jfunc = bpf_jitter(fcode, flen); @@ -1807,11 +1824,27 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, * Do not require upgrade by first BIOCSETF * (used to set snaplen) by pcap_open_live(). */ - if (d->bd_writer != 0 && --d->bd_writer == 0) - need_upgrade = 1; - CTR4(KTR_NET, "%s: filter function set by pid %d, " - "bd_writer counter %d, need_upgrade %d", - __func__, d->bd_pid, d->bd_writer, need_upgrade); + if (d->bd_writer != 0) { + if (is_snaplen == 0) { + /* + * We're probably using bpf directly. + * Upgrade immediately. + */ + need_upgrade = 1; + } else if (--d->bd_writer == 0) { + /* + * First snaplen filter has already + * been set. This is probably catch-all + * filter + */ + need_upgrade = 1; + } + CTR5(KTR_NET, + "%s: filter function set by pid %d, " + "bd_writer counter %d, snap %d upgrade %d", + __func__, d->bd_pid, d->bd_writer, + is_snaplen, need_upgrade); + } } } BPFD_UNLOCK(d); @@ -1842,6 +1875,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp; struct ifnet *theywant; + BPFIF_TRACKER; BPF_LOCK_ASSERT(); @@ -2038,6 +2072,7 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktl #endif u_int slen; int gottime; + BPFIF_TRACKER; gottime = BPF_TSTAMP_NONE; @@ -2105,6 +2140,7 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) #endif u_int pktlen, slen; int gottime; + BPFIF_TRACKER; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -2158,6 +2194,7 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dle struct bpf_d *d; u_int pktlen, slen; int gottime; + BPFIF_TRACKER; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -2477,7 +2514,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdr LIST_INIT(&bp->bif_wlist); bp->bif_ifp = ifp; bp->bif_dlt = dlt; - rw_init(&bp->bif_lock, "bpf interface lock"); + rm_init(&bp->bif_lock, "bpf interface lock"); KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); *driverp = bp; @@ -2582,7 +2619,7 @@ bpf_ifdetach(void *arg __unused, struct ifnet *ifp LIST_REMOVE(bp, bif_next); - rw_destroy(&bp->bif_lock); + rm_destroy(&bp->bif_lock); free(bp, M_BPF); nmatched++; @@ -2696,6 +2733,7 @@ bpf_zero_counters(void) { struct bpf_if *bp; struct bpf_d *bd; + BPFIF_TRACKER; BPF_LOCK(); LIST_FOREACH(bp, &bpf_iflist, bif_next) { @@ -2760,6 +2798,7 @@ bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) int index, error; struct bpf_if *bp; struct bpf_d *bd; + BPFIF_TRACKER; /* * XXX This is not technically correct. It is possible for non Index: sys/net/bpf.h =================================================================== --- sys/net/bpf.h (revision 266306) +++ sys/net/bpf.h (working copy) @@ -1260,7 +1260,7 @@ struct bpf_if { u_int bif_dlt; /* link layer type */ u_int bif_hdrlen; /* length of link header */ struct ifnet *bif_ifp; /* corresponding interface */ - struct rwlock bif_lock; /* interface lock */ + struct rmlock bif_lock; /* interface lock */ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */ int flags; /* Interface flags */ #endif Index: sys/net/bpfdesc.h =================================================================== --- sys/net/bpfdesc.h (revision 266306) +++ sys/net/bpfdesc.h (working copy) @@ -152,10 +152,11 @@ struct xbpf_d { u_int64_t bd_spare[4]; }; -#define BPFIF_RLOCK(bif) rw_rlock(&(bif)->bif_lock) -#define BPFIF_RUNLOCK(bif) rw_runlock(&(bif)->bif_lock) -#define BPFIF_WLOCK(bif) rw_wlock(&(bif)->bif_lock) -#define BPFIF_WUNLOCK(bif) rw_wunlock(&(bif)->bif_lock) +#define BPFIF_TRACKER struct rm_priotracker tracker +#define BPFIF_RLOCK(bif) rm_rlock(&(bif)->bif_lock, &tracker) +#define BPFIF_RUNLOCK(bif) rm_runlock(&(bif)->bif_lock, &tracker) +#define BPFIF_WLOCK(bif) rm_wlock(&(bif)->bif_lock) +#define BPFIF_WUNLOCK(bif) rm_wunlock(&(bif)->bif_lock) #define BPFIF_FLAG_DYING 1 /* Reject new bpf consumers */ Index: sys/kern/subr_witness.c =================================================================== --- sys/kern/subr_witness.c (revision 266306) +++ sys/kern/subr_witness.c (working copy) @@ -550,7 +550,7 @@ static struct witness_order_list_entry order_lists * BPF */ { "bpf global lock", &lock_class_mtx_sleep }, - { "bpf interface lock", &lock_class_rw }, + { "bpf interface lock", &lock_class_rm }, { "bpf cdev lock", &lock_class_mtx_sleep }, { NULL, NULL }, /*