Experience has shown that it is easier to deal with locks that are either held throughout the execution of a routine, or locks that are both acquired and released in one routine. Avoid nesting like this:
static void
xxfoo(...)
{
mutex_enter(&softc->lock);
...
xxbar();
}
static void
xxbar(...)
{
...
mutex_exit(&softc->lock);
}
This example works, but will almost certainly lead to maintenance problems.
If contention is likely in a particular code path, try to hold locks for a short time. In particular, arrange to drop locks before calling kernel routines that might block. For example:
mutex_enter(&softc->lock); ... softc->foo = bar; softc->thingp = kmem_alloc(sizeof(thing_t), KM_SLEEP); ... mutex_exit(&softc->lock);
This is better coded as:
thingp = kmem_alloc(sizeof(thing_t), KM_SLEEP); mutex_enter(&softc->lock); ... softc->foo = bar; softc->thingp = thingp; ... mutex_exit(&softc->lock);