Subject: Re: nesting simple_lock and spl*?
To: Jason R Thorpe <thorpej@wasabisystems.com>
From: David Laight <david@l8s.co.uk>
List: tech-kern
Date: 05/25/2002 20:59:20
> 
> In a perfect world, things would work like this (this is how mutexes work
> in the "newlock" branch):
> 
> 	...
> 	mutex_init(&vp->v_interlock, MUTEX_SPIN, IPL_BIO);
> 	...
> 	mutex_init(&vnode_free_list_mutex, MUTEX_SPIN, IPL_BIO);
> 	...
> 
> 	mutex_enter(&vp->v_interlock);
> 	vp->v_usecount--;
> 	if (vp->v_usecount > 0) {
> 		mutex_exit(&vp->v_interlock);
> 		return;
> 	}
> 
> 	mutex_enter(&vnode_free_list_mutex);
> 	if (vp->v_holdcnt > 0)
> 		TAILQ_INSERT_TAIL(&vnode_hold_list, vp, v_freelist);
> 	else
> 		TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
> 	mutex_exit(&vnode_free_list_mutex);
> 
> 	mutex_exit(&vp->v_interlock);
> 
> It's probably easiest to think about the current spl/simple_lock stuff
> in this way.  And, it might not hurt to create macros for acquiring/releasing
> these kinds of locks now (UVM currently has such a macro for dealing with
> the fpageq lock, for example).

I found some problems with the 'solaris' semantics of saving the spl
level within the mutex, the 'SVR4' semantics where the spl level
is returned to the user are more flexible.
In particular it allows you to release locks in a different order
that you required them.  This is particularly useful for code
that searches a table for an entry as you can then do:

	pl1 = read_lock( table_lock )
	entry = search_table( key );
	pl2 = lock( entry->lock );
	unlock( table_lock, pl2 );
	.....
	unlock( entry->lock, pl1 );

Updates to the table (probably some form of binary tree) are
done with the table write locked.

If you are forced to release the locks in the order you acquire
them you have to have a reference count on the 'entry' which
complicates things somewhat if it isn't otherwise required.

	David

-- 
David Laight: david@l8s.co.uk