Date: Sat, 21 Jan 2012 04:24:20 +0000 (UTC) From: Lawrence Stewart <lstewart@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r230417 - stable/7/sys/net Message-ID: <201201210424.q0L4OKmO073869@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: lstewart Date: Sat Jan 21 04:24:19 2012 New Revision: 230417 URL: http://svn.freebsd.org/changeset/base/230417 Log: MFC r229898: Consumers of bpfdetach() expect it to remove all bpf_if structs from the bpf_iflist list which reference the specified ifnet. The existing implementation only removes the first matching bpf_if found in the list, effectively leaking list entries if an ifnet has been bpfattach()ed multiple times with different DLTs. Fix the leak by performing the detach logic in a loop, stopping when all bpf_if structs referencing the specified ifnet have been detached and removed from the bpf_iflist list. Whilst here, also: - Remove the unnecessary "bp->bif_ifp == NULL" check, as a bpf_if should never exist in the list with a NULL ifnet pointer. - Except when INVARIANTS is in the kernel config, silently ignore the case where no bpf_if referencing the specified ifnet is found, as it is harmless and does not require user attention. Reviewed by: csjp Modified: stable/7/sys/net/bpf.c Directory Properties: stable/7/sys/ (props changed) Modified: stable/7/sys/net/bpf.c ============================================================================== --- stable/7/sys/net/bpf.c Sat Jan 21 04:22:19 2012 (r230416) +++ stable/7/sys/net/bpf.c Sat Jan 21 04:24:19 2012 (r230417) @@ -1658,33 +1658,42 @@ bpfdetach(struct ifnet *ifp) { struct bpf_if *bp; struct bpf_d *d; +#ifdef INVARIANTS + int ndetached; - /* Locate BPF interface information */ - mtx_lock(&bpf_mtx); - LIST_FOREACH(bp, &bpf_iflist, bif_next) { - if (ifp == bp->bif_ifp) - break; - } + ndetached = 0; +#endif - /* Interface wasn't attached */ - if ((bp == NULL) || (bp->bif_ifp == NULL)) { + /* Find all bpf_if struct's which reference ifp and detach them. */ + do { + mtx_lock(&bpf_mtx); + LIST_FOREACH(bp, &bpf_iflist, bif_next) { + if (ifp == bp->bif_ifp) + break; + } + if (bp != NULL) + LIST_REMOVE(bp, bif_next); mtx_unlock(&bpf_mtx); - printf("bpfdetach: %s was not attached\n", ifp->if_xname); - return; - } - LIST_REMOVE(bp, bif_next); - mtx_unlock(&bpf_mtx); - - while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { - bpf_detachd(d); - BPFD_LOCK(d); - bpf_wakeup(d); - BPFD_UNLOCK(d); - } + if (bp != NULL) { +#ifdef INVARIANTS + ndetached++; +#endif + while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { + bpf_detachd(d); + BPFD_LOCK(d); + bpf_wakeup(d); + BPFD_UNLOCK(d); + } + mtx_destroy(&bp->bif_mtx); + free(bp, M_BPF); + } + } while (bp != NULL); - mtx_destroy(&bp->bif_mtx); - free(bp, M_BPF); +#ifdef INVARIANTS + if (ndetached == 0) + printf("bpfdetach: %s was not attached\n", ifp->if_xname); +#endif } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201210424.q0L4OKmO073869>