Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Aug 2006 08:15:30 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-hackers@freebsd.org
Cc:        Hans Petter Selasky <hselasky@c2i.net>
Subject:   Re: miibus + USB = problem
Message-ID:  <200608090815.31152.jhb@freebsd.org>
In-Reply-To: <200608091022.02584.hselasky@c2i.net>
References:  <200608021437.55500.hselasky@c2i.net> <20060809.000719.-432838874.imp@bsdimp.com> <200608091022.02584.hselasky@c2i.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wednesday 09 August 2006 04:22, Hans Petter Selasky wrote:
> > The aue driver takes out the AUE_LOCK in these routines, and in
> > detach, it unregisters the timeout.  Alas, it is stupid, and does this
> > with the lock held, thus ensuring deadlock if the timeout fires after
> > the lock is acquired, but before the untimeout can complete (meaning
> > that the timeout routine would sleep forever waiting for the lock,
> > oops).  This is why you can't run the detach routine locked in most
> > cases.  
> 
> Yes, all of that is gone now. I use "callout_init_mtx()" and that solves the 
> problem, except it does not wait for the last mtx_lock()/mtx_unlock(), in 
> case of a race :-(
> 
> You need to hold a lock during detach. Else you can risk that the callbacks 
> will re-start functions you have already shut down, like USB transfers, and 
> then you never get detached.

This is the model that other drivers follow:

	FOO_LOCK(sc);
	foo_stop(sc);
	FOO_UNLOCK(sc);
	callout_drain(...);
	taskqueue_drain(...);
	bus_teardown_intr(...);
	ether_ifdetach(...);

in foo_lock() you do things like a callout_stop() with the lock held and
disable interrupts from the device.  You can also mark it as dying, etc.
in that function.  Then after you drop the lock you perform several
operations to wait for any other threads that might be in the driver to
be out of the driver.  callout_drain() should be called on each callout.
If you have any task's, call taskqueue_drain() on those.
bus_teardown_intr() won't return until your handler is both deregistered
and finished executing if it was currently in progress.
ether_ifdetach() should guarantee that any other threads coming into your
driver via the if_*() routines are all gone.  (This last one doesn't
actually do that yet, but eventually it will, and other drivers depend
on it to do so.. that is a problem to be solved in the ifnet layer, not
in your driver.)

-- 
John Baldwin



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