if_bridge crash
Andrew Thompson
thompsa at FreeBSD.org
Sat Jul 21 21:08:39 UTC 2007
On Sun, Jul 22, 2007 at 09:07:59AM +1200, Andrew Thompson wrote:
> On Sat, Jul 21, 2007 at 08:38:59PM +0200, Attilio Rao wrote:
> > Doug Rabson wrote:
> > >I've been using if_bridge and if_tap to join various qemu virtual
> > >machines onto my local network. I use this script to set up the bridge:
> > >
> > > ifconfig bridge0 create
> > > ifconfig tap0 create
> > > ifconfig bridge0 addm vr0 addm tap0 up
> > >
> > >I had forgotten what stupid mac address qemu had made up for its
> > >interface and I needed to adjust my dhcpd config so I typed 'ifconfig
> > >bridge addr' to list the addresses on the bridge and got an instant
> > >panic. Qemu was not running at this point. The kernel address where it
> > >crashed was good - it was the userland address which faulted.
> > >
> > >The crash was in generic_copyout+0x36 called from bridge_ioctl+0x1ae. I
> > >took a look at the code and as far as I can make out, trap() got a bit
> > >confused and managed to ignore the pcb_onfault marker left by copyout.
> > >Its hard to tell exactly what happened since the damn compiler has
> > >optimised the crap out of the code there.
> > >
> > >As far as I can see, the bridge code is calling copyout with a mutex
> > >held. Is that allowed? It doesn't sound like it should be allowed but
> > >I'm not quite up-to-date on that aspect of the current kernel api.
> >
> > Since a copyout() can generate a page fault (which can let the thread
> > sleep) it is not allowed to mantain neither a blockable lock (mutex,
> > rwlock) or a spinlock over a copyout.
>
>
> Please test this patch.
One more time with the file attached.
-------------- next part --------------
Index: if_bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_bridge.c,v
retrieving revision 1.100
diff -u -p -r1.100 if_bridge.c
--- if_bridge.c 13 Jun 2007 18:58:04 -0000 1.100
+++ if_bridge.c 21 Jul 2007 21:05:55 -0000
@@ -668,8 +668,6 @@ bridge_ioctl(struct ifnet *ifp, u_long c
const struct bridge_control *bc;
int error = 0;
- BRIDGE_LOCK(sc);
-
switch (cmd) {
case SIOCADDMULTI:
@@ -714,7 +712,9 @@ bridge_ioctl(struct ifnet *ifp, u_long c
break;
}
+ BRIDGE_LOCK(sc);
error = (*bc->bc_func)(sc, &args);
+ BRIDGE_UNLOCK(sc);
if (error)
break;
@@ -730,14 +730,15 @@ bridge_ioctl(struct ifnet *ifp, u_long c
* If interface is marked down and it is running,
* then stop and disable it.
*/
+ BRIDGE_LOCK(sc);
bridge_stop(ifp, 1);
+ BRIDGE_UNLOCK(sc);
} else if ((ifp->if_flags & IFF_UP) &&
!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
/*
* If interface is marked up and it is stopped, then
* start it.
*/
- BRIDGE_UNLOCK(sc);
(*ifp->if_init)(sc);
}
break;
@@ -752,14 +753,10 @@ bridge_ioctl(struct ifnet *ifp, u_long c
* drop the lock as ether_ioctl() will call bridge_start() and
* cause the lock to be recursed.
*/
- BRIDGE_UNLOCK(sc);
error = ether_ioctl(ifp, cmd, data);
break;
}
- if (BRIDGE_LOCKED(sc))
- BRIDGE_UNLOCK(sc);
-
return (error);
}
Index: if_bridgevar.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_bridgevar.h,v
retrieving revision 1.21
diff -u -p -r1.21 if_bridgevar.h
--- if_bridgevar.h 13 Jun 2007 18:58:04 -0000 1.21
+++ if_bridgevar.h 21 Jul 2007 21:06:08 -0000
@@ -272,7 +272,6 @@ struct ifbpstpconf {
} while (0)
#define BRIDGE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define BRIDGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
-#define BRIDGE_LOCKED(_sc) mtx_owned(&(_sc)->sc_mtx)
#define BRIDGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
#define BRIDGE_LOCK2REF(_sc, _err) do { \
mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
More information about the freebsd-current
mailing list