5f1c2b
diff -up nss/lib/pk11wrap/pk11util.c.race nss/lib/pk11wrap/pk11util.c
5f1c2b
--- nss/lib/pk11wrap/pk11util.c.race	2017-01-13 17:43:25.829686952 +0100
5f1c2b
+++ nss/lib/pk11wrap/pk11util.c	2017-01-13 17:47:56.374041802 +0100
5f1c2b
@@ -1297,7 +1297,7 @@ SECMOD_HasRemovableSlots(SECMODModule *m
1b6f66
  */
1b6f66
 static SECStatus
5f1c2b
 secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass,
5f1c2b
-                const char *sendSpec)
5f1c2b
+                const char *sendSpec, PRBool needlock)
1b6f66
 {
1b6f66
     CK_OBJECT_HANDLE dummy;
5f1c2b
     CK_ATTRIBUTE template[2];
5f1c2b
@@ -1312,16 +1312,16 @@ secmod_UserDBOp(PK11SlotInfo *slot, CK_O
1b6f66
 
5f1c2b
     PORT_Assert(attrs - template <= 2);
1b6f66
 
1b6f66
-    PK11_EnterSlotMonitor(slot);
1b6f66
+    if (needlock) PK11_EnterSlotMonitor(slot);
1b6f66
     crv = PK11_CreateNewObject(slot, slot->session,
5f1c2b
                                template, attrs - template, PR_FALSE, &dummy);
1b6f66
-    PK11_ExitSlotMonitor(slot);
1b6f66
+    if (needlock) PK11_ExitSlotMonitor(slot);
1b6f66
 
1b6f66
     if (crv != CKR_OK) {
5f1c2b
         PORT_SetError(PK11_MapError(crv));
5f1c2b
         return SECFailure;
1b6f66
     }
1b6f66
-    return SECMOD_UpdateSlotList(slot->module);
1b6f66
+    return SECSuccess;
1b6f66
 }
1b6f66
 
1b6f66
 /*
5f1c2b
@@ -1330,11 +1330,20 @@ secmod_UserDBOp(PK11SlotInfo *slot, CK_O
1b6f66
 static PRBool
5f1c2b
 secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID)
1b6f66
 {
1b6f66
-    PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
1b6f66
+    PK11SlotInfo *slot = SECMOD_FindSlotByID(mod, slotID);
1b6f66
     if (slot) {
5f1c2b
-        PRBool present = PK11_IsPresent(slot);
1b6f66
+	CK_SLOT_INFO slotInfo;
1b6f66
+	CK_RV crv;
1b6f66
+	/* check if the slot is present, skip any slot reinit stuff,
1b6f66
+	 * or cached present values, or locking. (we don't need to lock 
1b6f66
+	 * even if the module is not thread safe because we are already 
1b6f66
+	 * holding the module refLock, which is the same as the slot 
1b6f66
+	 * sessionLock if the module isn't thread safe. */
1b6f66
+	crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo);
5f1c2b
         PK11_FreeSlot(slot);
5f1c2b
-        if (present) {
1b6f66
+	if ((crv == CKR_OK) && 
1b6f66
+		((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT)) {
1b6f66
+	    /* slot is present, so it's not empty */
5f1c2b
             return PR_FALSE;
5f1c2b
         }
1b6f66
     }
5f1c2b
@@ -1390,24 +1399,29 @@ SECMOD_OpenNewSlot(SECMODModule *mod, co
1b6f66
     char *sendSpec;
1b6f66
     SECStatus rv;
1b6f66
 
1b6f66
+    PZ_Lock(mod->refLock);   /* don't reuse a slot on the fly */
1b6f66
     slotID = secmod_FindFreeSlot(mod);
5f1c2b
     if (slotID == (CK_SLOT_ID)-1) {
1b6f66
+	PZ_Unlock(mod->refLock);
5f1c2b
         return NULL;
1b6f66
     }
1b6f66
 
1b6f66
     if (mod->slotCount == 0) {
1b6f66
+	PZ_Unlock(mod->refLock);
5f1c2b
         return NULL;
1b6f66
     }
1b6f66
 
1b6f66
     /* just grab the first slot in the module, any present slot should work */
1b6f66
     slot = PK11_ReferenceSlot(mod->slots[0]);
1b6f66
     if (slot == NULL) {
1b6f66
+	PZ_Unlock(mod->refLock);
5f1c2b
         return NULL;
1b6f66
     }
1b6f66
 
1b6f66
     /* we've found the slot, now build the moduleSpec */
1b6f66
     escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']');
1b6f66
     if (escSpec == NULL) {
1b6f66
+	PZ_Unlock(mod->refLock);
5f1c2b
         PK11_FreeSlot(slot);
5f1c2b
         return NULL;
1b6f66
     }
5f1c2b
@@ -1416,16 +1430,26 @@ SECMOD_OpenNewSlot(SECMODModule *mod, co
1b6f66
 
1b6f66
     if (sendSpec == NULL) {
5f1c2b
         /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
1b6f66
+	PZ_Unlock(mod->refLock);
5f1c2b
         PK11_FreeSlot(slot);
5f1c2b
         PORT_SetError(SEC_ERROR_NO_MEMORY);
5f1c2b
         return NULL;
1b6f66
     }
1b6f66
-    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec);
1b6f66
+    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec, 
1b6f66
+    /* If the module isn't thread safe, the slot sessionLock == mod->refLock
1b6f66
+     * since we already hold the refLock we don't need to lock the sessionLock
1b6f66
+     */
1b6f66
+							mod->isThreadSafe);
1b6f66
+    PZ_Unlock(mod->refLock);
1b6f66
     PR_smprintf_free(sendSpec);
1b6f66
     PK11_FreeSlot(slot);
1b6f66
     if (rv != SECSuccess) {
5f1c2b
         return NULL;
1b6f66
     }
1b6f66
+    rv = SECMOD_UpdateSlotList(mod); /* don't call holding the mod->reflock */
1b6f66
+    if (rv != SECSuccess) {
1b6f66
+	return NULL;
1b6f66
+    }
1b6f66
 
1b6f66
     slot = SECMOD_FindSlotByID(mod, slotID);
1b6f66
     if (slot) {
5f1c2b
@@ -1558,7 +1582,7 @@ SECMOD_CloseUserDB(PK11SlotInfo *slot)
5f1c2b
         PORT_SetError(SEC_ERROR_NO_MEMORY);
5f1c2b
         return SECFailure;
1b6f66
     }
1b6f66
-    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec);
1b6f66
+    rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec, PR_TRUE);
1b6f66
     PR_smprintf_free(sendSpec);
1b6f66
     /* if we are in the delay period for the "isPresent" call, reset
1b6f66
      * the delay since we know things have probably changed... */