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>