From 0d045c0d0cb001d79480ee33be28514e847f8612 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Tue, 2 Jun 2015 17:12:04 +0000 Subject: [PATCH] 6209 libc mutexes break kernel writers hearts Reviewed by: Jerry Jelinek Reviewed by: Josef 'Jeff' Sipek Reviewed by: Dan McDonald Reviewed by: Garrett D'Amore Approved by: Dan McDonald --- usr/src/head/synch.h | 6 +++ usr/src/lib/libc/inc/thr_uberdata.h | 4 +- usr/src/lib/libc/port/mapfile-vers | 2 + usr/src/lib/libc/port/threads/assfail.c | 10 +++++ usr/src/lib/libc/port/threads/synch.c | 43 +++++++++++++++++++ usr/src/lib/libzpool/common/kernel.c | 4 +- usr/src/lib/libzpool/common/sys/zfs_context.h | 6 ++- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/usr/src/head/synch.h b/usr/src/head/synch.h index c0f68f12f008..dda7fa0a3c7a 100644 --- a/usr/src/head/synch.h +++ b/usr/src/head/synch.h @@ -211,6 +211,12 @@ void smt_pause(void); #endif /* _ASM */ +/* + * Panicking versions of our favorite friends. + */ +void mutex_enter(mutex_t *); +void mutex_exit(mutex_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h index de0d4a6b05a5..4815d11486ce 100644 --- a/usr/src/lib/libc/inc/thr_uberdata.h +++ b/usr/src/lib/libc/inc/thr_uberdata.h @@ -23,7 +23,7 @@ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. */ #ifndef _THR_UBERDATA_H @@ -1229,6 +1229,8 @@ extern void getgregs(ulwp_t *, gregset_t); extern void setgregs(ulwp_t *, gregset_t); extern void thr_panic(const char *); #pragma rarely_called(thr_panic) +extern void mutex_panic(mutex_t *, const char *); +#pragma rarely_called(mutex_panic) extern ulwp_t *find_lwp(thread_t); extern void finish_init(void); extern void update_sched(ulwp_t *); diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index c4571ef2f13f..c6967141b678 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -2915,6 +2915,8 @@ $endif msgctl64; __multi_innetgr; _mutex_destroy { FLAGS = NODYNSORT }; + mutex_enter; + mutex_exit; mutex_held; _mutex_init { FLAGS = NODYNSORT }; _mutex_unlock { FLAGS = NODYNSORT }; diff --git a/usr/src/lib/libc/port/threads/assfail.c b/usr/src/lib/libc/port/threads/assfail.c index 8aebefbe4ac7..b40e6dc02932 100644 --- a/usr/src/lib/libc/port/threads/assfail.c +++ b/usr/src/lib/libc/port/threads/assfail.c @@ -25,6 +25,7 @@ */ /* * Copyright (c) 2012, 2014 by Delphix. All rights reserved. + * Copyright 2015 Joyent, Inc. */ #include "lint.h" @@ -36,6 +37,8 @@ ulwp_t *panic_thread; static mutex_t assert_lock = DEFAULTMUTEX; static ulwp_t *assert_thread = NULL; +mutex_t *panic_mutex = NULL; + /* * Called from __assert() to set panicstr and panic_thread. */ @@ -129,6 +132,13 @@ aio_panic(const char *why) common_panic("*** libc aio system failure: ", why); } +void +mutex_panic(mutex_t *mp, const char *why) +{ + panic_mutex = mp; + common_panic("*** libc mutex system failure: ", why); +} + /* * Utility function for converting a long integer to a string, avoiding stdio. * 'base' must be one of 10 or 16 diff --git a/usr/src/lib/libc/port/threads/synch.c b/usr/src/lib/libc/port/threads/synch.c index a7c4aed9eff4..b4efb58d177f 100644 --- a/usr/src/lib/libc/port/threads/synch.c +++ b/usr/src/lib/libc/port/threads/synch.c @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015, Joyent, Inc. */ #include "lint.h" @@ -2314,6 +2315,29 @@ mutex_lock(mutex_t *mp) return (mutex_lock_impl(mp, NULL)); } +void +mutex_enter(mutex_t *mp) +{ + int ret; + int attr = mp->mutex_type & ALL_ATTRIBUTES; + + /* + * Require LOCK_ERRORCHECK, accept LOCK_RECURSIVE. + */ + if (attr != LOCK_ERRORCHECK && + attr != (LOCK_ERRORCHECK | LOCK_RECURSIVE)) { + mutex_panic(mp, "mutex_enter: bad mutex type"); + } + ret = mutex_lock(mp); + if (ret == EDEADLK) { + mutex_panic(mp, "recursive mutex_enter"); + } else if (ret == EAGAIN) { + mutex_panic(mp, "excessive recursive mutex_enter"); + } else if (ret != 0) { + mutex_panic(mp, "unknown mutex_enter failure"); + } +} + int pthread_mutex_timedlock(pthread_mutex_t *_RESTRICT_KYWD mp, const struct timespec *_RESTRICT_KYWD abstime) @@ -2573,6 +2597,25 @@ mutex_unlock(mutex_t *mp) return (mutex_unlock_internal(mp, 0)); } +void +mutex_exit(mutex_t *mp) +{ + int ret; + int attr = mp->mutex_type & ALL_ATTRIBUTES; + + if (attr != LOCK_ERRORCHECK && + attr != (LOCK_ERRORCHECK | LOCK_RECURSIVE)) { + mutex_panic(mp, "mutex_exit: bad mutex type"); + } + ret = mutex_unlock(mp); + if (ret == EPERM) { + mutex_panic(mp, "mutex_exit: not owner"); + } else if (ret != 0) { + mutex_panic(mp, "unknown mutex_exit failure"); + } + +} + /* * Internally to the library, almost all mutex lock/unlock actions * go through these lmutex_ functions, to protect critical regions. diff --git a/usr/src/lib/libzpool/common/kernel.c b/usr/src/lib/libzpool/common/kernel.c index dd4221deb520..a74276e95e4d 100644 --- a/usr/src/lib/libzpool/common/kernel.c +++ b/usr/src/lib/libzpool/common/kernel.c @@ -156,7 +156,7 @@ zmutex_destroy(kmutex_t *mp) } void -mutex_enter(kmutex_t *mp) +zmutex_enter(kmutex_t *mp) { ASSERT(mp->initialized == B_TRUE); ASSERT(mp->m_owner != (void *)-1UL); @@ -181,7 +181,7 @@ mutex_tryenter(kmutex_t *mp) } void -mutex_exit(kmutex_t *mp) +zmutex_exit(kmutex_t *mp) { ASSERT(mp->initialized == B_TRUE); ASSERT(mutex_owner(mp) == curthread); diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h index 6216006dd487..9e4d8ed0b8ec 100644 --- a/usr/src/lib/libzpool/common/sys/zfs_context.h +++ b/usr/src/lib/libzpool/common/sys/zfs_context.h @@ -225,11 +225,13 @@ extern int _mutex_destroy(mutex_t *mp); #define mutex_init(mp, b, c, d) zmutex_init((kmutex_t *)(mp)) #define mutex_destroy(mp) zmutex_destroy((kmutex_t *)(mp)) +#define mutex_enter(mp) zmutex_enter(mp) +#define mutex_exit(mp) zmutex_exit(mp) extern void zmutex_init(kmutex_t *mp); extern void zmutex_destroy(kmutex_t *mp); -extern void mutex_enter(kmutex_t *mp); -extern void mutex_exit(kmutex_t *mp); +extern void zmutex_enter(kmutex_t *mp); +extern void zmutex_exit(kmutex_t *mp); extern int mutex_tryenter(kmutex_t *mp); extern void *mutex_owner(kmutex_t *mp);