thread: detect spinlocks that are not initialized

If spdk_spin_lock() is called on an uninitialized spinlock, it will
deadlock. This commit detects whether a lock is initialized and aborts
instead of deadlocking.

Signed-off-by: Mike Gerdts <mgerdts@nvidia.com>
Change-Id: Ie7497633091edd4127c06ca0530e9a1dff530d1b
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16002
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Mike Gerdts 2022-12-16 21:11:40 -06:00 committed by David Ko
parent 4077eff3ae
commit 80ab43ae97
2 changed files with 18 additions and 0 deletions

View File

@ -905,6 +905,8 @@ struct spdk_spinlock {
pthread_spinlock_t spinlock; pthread_spinlock_t spinlock;
struct spdk_thread *thread; struct spdk_thread *thread;
struct spdk_spinlock_internal *internal; struct spdk_spinlock_internal *internal;
bool initialized;
bool destroyed;
}; };
/** /**

View File

@ -185,6 +185,11 @@ enum spin_error {
* deadlock when another SPDK thread on the same pthread tries to take that lock. * deadlock when another SPDK thread on the same pthread tries to take that lock.
*/ */
SPIN_ERR_HOLD_DURING_SWITCH, SPIN_ERR_HOLD_DURING_SWITCH,
/* Trying to use a lock that was destroyed (but not re-initialized) */
SPIN_ERR_DESTROYED,
/* Trying to use a lock that is not initialized */
SPIN_ERR_NOT_INITIALIZED,
/* Must be last, not an actual error code */ /* Must be last, not an actual error code */
SPIN_ERR_LAST SPIN_ERR_LAST
}; };
@ -198,6 +203,8 @@ static const char *spin_error_strings[] = {
[SPIN_ERR_LOCK_HELD] = "Destroying a held spinlock", [SPIN_ERR_LOCK_HELD] = "Destroying a held spinlock",
[SPIN_ERR_LOCK_COUNT] = "Lock count is invalid", [SPIN_ERR_LOCK_COUNT] = "Lock count is invalid",
[SPIN_ERR_HOLD_DURING_SWITCH] = "Lock(s) held while SPDK thread going off CPU", [SPIN_ERR_HOLD_DURING_SWITCH] = "Lock(s) held while SPDK thread going off CPU",
[SPIN_ERR_DESTROYED] = "Lock has been destroyed",
[SPIN_ERR_NOT_INITIALIZED] = "Lock has not been initialized",
}; };
#define SPIN_ERROR_STRING(err) (err < 0 || err >= SPDK_COUNTOF(spin_error_strings)) \ #define SPIN_ERROR_STRING(err) (err < 0 || err >= SPDK_COUNTOF(spin_error_strings)) \
@ -2971,6 +2978,7 @@ spdk_spin_init(struct spdk_spinlock *sspin)
SPIN_ASSERT_LOG_STACKS(rc == 0, SPIN_ERR_PTHREAD, sspin); SPIN_ASSERT_LOG_STACKS(rc == 0, SPIN_ERR_PTHREAD, sspin);
sspin_init_internal(sspin); sspin_init_internal(sspin);
SSPIN_GET_STACK(sspin, init); SSPIN_GET_STACK(sspin, init);
sspin->initialized = true;
} }
void void
@ -2978,12 +2986,16 @@ spdk_spin_destroy(struct spdk_spinlock *sspin)
{ {
int rc; int rc;
SPIN_ASSERT_LOG_STACKS(!sspin->destroyed, SPIN_ERR_DESTROYED, sspin);
SPIN_ASSERT_LOG_STACKS(sspin->initialized, SPIN_ERR_NOT_INITIALIZED, sspin);
SPIN_ASSERT_LOG_STACKS(sspin->thread == NULL, SPIN_ERR_LOCK_HELD, sspin); SPIN_ASSERT_LOG_STACKS(sspin->thread == NULL, SPIN_ERR_LOCK_HELD, sspin);
rc = pthread_spin_destroy(&sspin->spinlock); rc = pthread_spin_destroy(&sspin->spinlock);
SPIN_ASSERT_LOG_STACKS(rc == 0, SPIN_ERR_PTHREAD, sspin); SPIN_ASSERT_LOG_STACKS(rc == 0, SPIN_ERR_PTHREAD, sspin);
sspin_fini_internal(sspin); sspin_fini_internal(sspin);
sspin->initialized = false;
sspin->destroyed = true;
} }
void void
@ -2992,6 +3004,8 @@ spdk_spin_lock(struct spdk_spinlock *sspin)
struct spdk_thread *thread = spdk_get_thread(); struct spdk_thread *thread = spdk_get_thread();
int rc; int rc;
SPIN_ASSERT_LOG_STACKS(!sspin->destroyed, SPIN_ERR_DESTROYED, sspin);
SPIN_ASSERT_LOG_STACKS(sspin->initialized, SPIN_ERR_NOT_INITIALIZED, sspin);
SPIN_ASSERT_LOG_STACKS(thread != NULL, SPIN_ERR_NOT_SPDK_THREAD, sspin); SPIN_ASSERT_LOG_STACKS(thread != NULL, SPIN_ERR_NOT_SPDK_THREAD, sspin);
SPIN_ASSERT_LOG_STACKS(thread != sspin->thread, SPIN_ERR_DEADLOCK, sspin); SPIN_ASSERT_LOG_STACKS(thread != sspin->thread, SPIN_ERR_DEADLOCK, sspin);
@ -3010,6 +3024,8 @@ spdk_spin_unlock(struct spdk_spinlock *sspin)
struct spdk_thread *thread = spdk_get_thread(); struct spdk_thread *thread = spdk_get_thread();
int rc; int rc;
SPIN_ASSERT_LOG_STACKS(!sspin->destroyed, SPIN_ERR_DESTROYED, sspin);
SPIN_ASSERT_LOG_STACKS(sspin->initialized, SPIN_ERR_NOT_INITIALIZED, sspin);
SPIN_ASSERT_LOG_STACKS(thread != NULL, SPIN_ERR_NOT_SPDK_THREAD, sspin); SPIN_ASSERT_LOG_STACKS(thread != NULL, SPIN_ERR_NOT_SPDK_THREAD, sspin);
SPIN_ASSERT_LOG_STACKS(thread == sspin->thread, SPIN_ERR_WRONG_THREAD, sspin); SPIN_ASSERT_LOG_STACKS(thread == sspin->thread, SPIN_ERR_WRONG_THREAD, sspin);