Make kmutex_t typesafe in all cases.

When HAVE_MUTEX_OWNER and CONFIG_SMP are defined, kmutex_t is just
a typedef for struct mutex.

This is generally OK but has the downside that it can make mistakes
such as mutex_lock(&kmutex_var) to pass by unnoticed until someone
compiles the code without HAVE_MUTEX_OWNER or CONFIG_SMP (in which
case kmutex_t is a real struct). Note that the correct API to call
should have been mutex_enter() rather than mutex_lock().

We prevent these kind of mistakes by making kmutex_t a real structure
with only one field. This makes kmutex_t typesafe and it shouldn't
have any impact on the generated assembly code.

Signed-off-by: Ricardo M. Correia <ricardo.correia@oracle.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Ricardo M. Correia 2010-11-22 00:20:58 -08:00 committed by Brian Behlendorf
parent 058de03caa
commit c2f997b0b3

View File

@ -37,14 +37,20 @@ typedef enum {
#if defined(HAVE_MUTEX_OWNER) && defined(CONFIG_SMP) #if defined(HAVE_MUTEX_OWNER) && defined(CONFIG_SMP)
typedef struct mutex kmutex_t; /*
* We define a 1-field struct rather than a straight typedef to enforce type
* safety.
*/
typedef struct {
struct mutex m;
} kmutex_t;
static inline kthread_t * static inline kthread_t *
mutex_owner(kmutex_t *mp) mutex_owner(kmutex_t *mp)
{ {
struct thread_info *owner; struct thread_info *owner;
owner = ACCESS_ONCE(mp->owner); owner = ACCESS_ONCE(mp->m.owner);
if (owner) if (owner)
return owner->task; return owner->task;
@ -54,7 +60,7 @@ mutex_owner(kmutex_t *mp)
static inline int static inline int
mutex_owned(kmutex_t *mp) mutex_owned(kmutex_t *mp)
{ {
return (ACCESS_ONCE(mp->owner) == current_thread_info()); return (ACCESS_ONCE(mp->m.owner) == current_thread_info());
} }
#define MUTEX_HELD(mp) mutex_owned(mp) #define MUTEX_HELD(mp) mutex_owned(mp)
@ -65,31 +71,31 @@ mutex_owned(kmutex_t *mp)
static struct lock_class_key __key; \ static struct lock_class_key __key; \
ASSERT(type == MUTEX_DEFAULT); \ ASSERT(type == MUTEX_DEFAULT); \
\ \
__mutex_init((mp), #mp, &__key); \ __mutex_init(&(mp)->m, #mp, &__key); \
}) })
#undef mutex_destroy #undef mutex_destroy
#define mutex_destroy(mp) \ #define mutex_destroy(mp) \
({ \ ({ \
VERIFY3P(mutex_owner(mp), ==, NULL); \ VERIFY3P(mutex_owner(mp), ==, NULL); \
}) })
#define mutex_tryenter(mp) mutex_trylock(mp) #define mutex_tryenter(mp) mutex_trylock(&(mp)->m)
#define mutex_enter(mp) mutex_lock(mp) #define mutex_enter(mp) mutex_lock(&(mp)->m)
/* mutex->owner is not cleared when CONFIG_DEBUG_MUTEXES is set */ /* mutex->owner is not cleared when CONFIG_DEBUG_MUTEXES is set */
#ifdef CONFIG_DEBUG_MUTEXES #ifdef CONFIG_DEBUG_MUTEXES
# define mutex_exit(mp) \ # define mutex_exit(mp) \
({ \ ({ \
mutex_unlock(mp); \ mutex_unlock(&(mp)->m); \
(mp)->owner = NULL; \ (mp)->m.owner = NULL; \
}) })
#else #else
# define mutex_exit(mp) mutex_unlock(mp) # define mutex_exit(mp) mutex_unlock(&(mp)->m)
#endif /* CONFIG_DEBUG_MUTEXES */ #endif /* CONFIG_DEBUG_MUTEXES */
#ifdef HAVE_GPL_ONLY_SYMBOLS #ifdef HAVE_GPL_ONLY_SYMBOLS
# define mutex_enter_nested(mp, sc) mutex_lock_nested(mp, sc) # define mutex_enter_nested(mp, sc) mutex_lock_nested(&(mp)->m, sc)
#else #else
# define mutex_enter_nested(mp, sc) mutex_enter(mp) # define mutex_enter_nested(mp, sc) mutex_enter(mp)
#endif /* HAVE_GPL_ONLY_SYMBOLS */ #endif /* HAVE_GPL_ONLY_SYMBOLS */
@ -172,7 +178,7 @@ mutex_owner(kmutex_t *mp)
#undef mutex_destroy #undef mutex_destroy
#define mutex_destroy(mp) \ #define mutex_destroy(mp) \
({ \ ({ \
VERIFY3P(mutex_owner(mp), ==, NULL); \ VERIFY3P(mutex_owner(mp), ==, NULL); \
}) })
#define mutex_tryenter(mp) \ #define mutex_tryenter(mp) \