--- old/usr/src/lib/pkcs11/pkcs11_softtoken/common/softGeneral.c	Fri Jun  6 16:24:05 2014
+++ new/usr/src/lib/pkcs11/pkcs11_softtoken/common/softGeneral.c	Fri Jun  6 16:24:05 2014
@@ -21,6 +21,8 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <strings.h>
@@ -128,6 +130,11 @@
 
 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */
 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * ONLY SET TO TRUE BY softtoken_fork_prepare().
+ * ONLY SET TO FALSE BY softtoken_fork_after().
+ */
+boolean_t fork_prepared = B_FALSE;
 
 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved);
 static void softtoken_init();
@@ -134,6 +141,7 @@
 static void softtoken_fini();
 static void softtoken_fork_prepare();
 static void softtoken_fork_after();
+static void softtoken_fork_after_droplocks(void);
 
 CK_RV
 C_Initialize(CK_VOID_PTR pInitArgs)
@@ -411,17 +419,42 @@
 static void
 softtoken_fini()
 {
-	(void) pthread_mutex_lock(&soft_giant_mutex);
+	int rc;
 
-	/* if we're not initilized, do not attempt to finalize */
-	if (!softtoken_initialized) {
-		(void) pthread_mutex_unlock(&soft_giant_mutex);
-		return;
-	}
+	rc = pthread_mutex_trylock(&soft_giant_mutex);
+	/*
+	 * Check to see if it was acquired by softtoken_fork_prepare().
+	 */
+	if (rc == EBUSY && fork_prepared)
+		rc = 0;
 
-	(void) finalize_common(B_TRUE, NULL_PTR);
+	if (rc != 0) {
+		/*
+		 * I don't know WHAT just happened, but it's pretty bad.  Grab
+		 * the lock for real, even if it means deadlocking here.
+		 */
+		(void) pthread_mutex_lock(&soft_giant_mutex);
+	} /* Else we acquired the lock and life is good. */
 
-	(void) pthread_mutex_unlock(&soft_giant_mutex);
+	/* Only finalize if we're initialized. */
+	if (softtoken_initialized) {
+		/*
+		 * We also have to DROP all of the other locks that
+		 * softtoken_fork_prepare did IF it was prepared, because
+		 * finalize_common() is going to pick them right back up.
+		 */
+		if (fork_prepared)
+			softtoken_fork_after_droplocks();
+		(void) finalize_common(B_TRUE, NULL_PTR);
+		/* ASSERT(!softtoken_initialized); */
+	}
+
+	/*
+	 * If we don't want to drop the lock, we assume softtoken_fork_after()
+	 * will get called.
+	 */
+	if (!fork_prepared)
+		(void) pthread_mutex_unlock(&soft_giant_mutex);
 }
 
 CK_RV
@@ -496,7 +529,7 @@
  * 8. ses_delay_freed.ses_to_be_free_mutex
  */
 void
-softtoken_fork_prepare()
+softtoken_fork_prepare(void)
 {
 	(void) pthread_mutex_lock(&soft_giant_mutex);
 	if (softtoken_initialized) {
@@ -510,25 +543,31 @@
 		(void) pthread_mutex_lock(
 		    &ses_delay_freed.ses_to_be_free_mutex);
 	}
+	fork_prepared = B_TRUE;
 }
 
+static void
+softtoken_fork_after_droplocks(void)
+{
+	/* ASSERT(softtoken_initialized); */
+	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
+	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
+	soft_release_all_session_mutexes(soft_session_list);
+	soft_release_all_session_mutexes(&token_session);
+	(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
+	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
+	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
+}
+
 /*
  * Release in opposite order to softtoken_fork_prepare().
  * Function is used for parent and child.
  */
 void
-softtoken_fork_after()
+softtoken_fork_after(void)
 {
-	if (softtoken_initialized) {
-		(void) pthread_mutex_unlock(
-		    &ses_delay_freed.ses_to_be_free_mutex);
-		(void) pthread_mutex_unlock(
-		    &obj_delay_freed.obj_to_be_free_mutex);
-		soft_release_all_session_mutexes(soft_session_list);
-		soft_release_all_session_mutexes(&token_session);
-		(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
-		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
-		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
-	}
+	if (softtoken_initialized)
+		softtoken_fork_after_droplocks();
+	fork_prepared = B_FALSE;
 	(void) pthread_mutex_unlock(&soft_giant_mutex);
 }
