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);