Below is some example pseudo code, which demonstrates different locking 
strategies. I'd really would like to see a bit feed back to this. Whatever 
locking we choose now, it will change driver APIs in different ways, so 
I'd suggest to carefully think about this now.
First example demonstrates the old locking, as most people should know it. 
I splitted the examples into three phases, each demonstrating a single 
major phase in the live of an object.
init:
	obj = create();
	list_lock();
	register(obj);
	list_unlock();
use:
	list_lock();
	if ((obj = find())) {
		unload_lock();
		if (!deleted(mod))
			inc_ref(mod);
		else
			fail;
		unload_unlock();
	}
	list_unlock();
exit:
	unload_lock();
	if (ref(mod) > 0)
		busy;
	else
		set_deleted(mod);
	unload_unlock();
	list_lock();
	unregister(obj);
	list_unlock();
	delete(obj);
Rusty didn't change very much, it's still the same basic mechanism. 
unload_lock() and inc_ref() are simpler, OTOH ref() has to do _much_ more 
work. deleted() became live() and is now only set after initialization, 
which introduced new problems. This is fixable by splitting the module 
initialization into two phases and inbetween the module becomes live:
init:
	obj = create();
	set_live(mod);
	list_lock();
	register(obj);
	list_unlock();
use:
	list_lock();
	if ((obj = find())) {
		unload_lock();
		if (live(mod))
			inc_ref(mod);
		else
			fail;
		unload_unlock();
	}
	list_unlock();
exit:
	unload_lock();
	if (ref(mod) > 0)
		busy;
	else
		clear_live(mod);
	unload_unlock();
	list_lock();
	unregister(obj);
	list_unlock();
	delete(obj);
Finally I'd like to demonstrate a locking strategy, which I proposed 
already earlier and according to Rusty is "slow, confusing, invasive, 
inflexible *and* buggy".
init:
	obj = create();
	list_lock();
	register(obj);
	list_unlock();
use:
	list_lock();
	if ((obj = find()))
		inc_ref(obj);
	list_unlock();
exit1:
	if (registered(obj)) {
		list_lock();
		unregister(obj);
		list_unlock();
	}
	if (ref(obj) > 0)
		busy;
	else
		delete(obj);
exit2:
	list_lock();
	if (ref(obj) > 0)
		busy;
	else
		unregister(obj);
	list_unlock();
	delete(obj);
There are other variations of the exit phase possible, but the basic idea 
is that the driver tells the module code, whether it's safe to unload or 
not (and not the other way around, but the driver could still use a single 
module count for this).
I have to agree, that this is the most invasive strategy (because it's 
different), but if done correctly it will lead to cleaner, smaller, and 
more flexible code.
Consequences:
The current locking strategy requires that _all_ interfaces which could be 
during module init are split into a allocate and install phase, the use of 
the module ref for every object is mandatory and the module unload should 
rather be avoided, because it really hurts.
My locking strategy requires more care during exit when multiple objects 
have to be unregistered (during install all objects can simply be 
installed when they are ready), but most drivers install only a single 
interface through which the driver can be opened/closed. If multiple 
interfaces are used, it can leave the module in a loaded but unregistered 
state, but there are a few strategies to avoid this.
bye, Roman
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/