Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2012 12:36:59 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r236559 - head/sys/net
Message-ID:  <201206041236.q54CaxO1041508@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Mon Jun  4 12:36:58 2012
New Revision: 236559
URL: http://svn.freebsd.org/changeset/base/236559

Log:
  Fix panic introduced by r235745. Panic occurs after first packet traverse renamed interface.
  Add several comments on locking
  
  Found by:         avg
  Approved by:      ae(mentor)
  Tested by:        avg
  MFC after:        1 week

Modified:
  head/sys/net/bpf.c

Modified: head/sys/net/bpf.c
==============================================================================
--- head/sys/net/bpf.c	Mon Jun  4 12:28:56 2012	(r236558)
+++ head/sys/net/bpf.c	Mon Jun  4 12:36:58 2012	(r236559)
@@ -1704,6 +1704,14 @@ bpfioctl(struct cdev *dev, u_long cmd, c
 /*
  * Set d's packet filter program to fp.  If this file already has a filter,
  * free it and replace it.  Returns EINVAL for bogus requests.
+ *
+ * Note we need global lock here to serialize bpf_setf() and bpf_setif() calls
+ * since reading d->bd_bif can't be protected by d or interface lock due to
+ * lock order.
+ *
+ * Additionally, we have to acquire interface write lock due to bpf_mtap() uses
+ * interface read lock to read all filers.
+ *
  */
 static int
 bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
@@ -2535,20 +2543,32 @@ bpfdetach(struct ifnet *ifp)
 }
 
 /*
- * Interface departure handler
+ * Interface departure handler.
+ * Note departure event does not guagantee interface is going down.
  */
 static void
 bpf_ifdetach(void *arg __unused, struct ifnet *ifp)
 {
 	struct bpf_if *bp;
 
-	if ((bp = ifp->if_bpf) == NULL)
+	BPF_LOCK();
+	if ((bp = ifp->if_bpf) == NULL) {
+		BPF_UNLOCK();
+		return;
+	}
+
+	/* Check if bpfdetach() was called previously */
+	if ((bp->flags & BPFIF_FLAG_DYING) == 0) {
+		BPF_UNLOCK();
 		return;
+	}
 
 	CTR3(KTR_NET, "%s: freing BPF instance %p for interface %p",
 	    __func__, bp, ifp);
 
 	ifp->if_bpf = NULL;
+	BPF_UNLOCK();
+
 	rw_destroy(&bp->bif_lock);
 	free(bp, M_BPF);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206041236.q54CaxO1041508>