static void
foo_buffer_alloc(struct foo *fp)
{
	char *tmpbuf;

	tmpbuf = malloc(BUSSIZE, M_TEMP, M_ZERO|M_WAITOK);
	mtx_lock(&fp->foo_mtx);
	if ((fp->foo_flags & FOO_BUFFERED) == 0) {
		mtx_unlock(&fp->foo_mtx);
		free(tmpbuf, M_TEMP);
		return;
	}
	fp->foo_buffer = tmpbuf;
	mtx_unlock(&fp->foo_mtx);
}

Preallocating memory is a common practice within the kernel. Since dropping
and reacquiring lock generally means you ask for a trouble, picking this way
is easier and less error prone. In a fragment presented above, memory is
always allocated, and action depends on the foo_flags value, whether it'll
be used in the next statements or not. If the former (last one) case is met,
we simply drop the lock giving other threads a chance to start doing their
job with the shared resource and we do some cleanup processing -- freeing
the memory chunk and returning from our function.
