oldQPair = *qpair;
result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint);
- if (result >= VMCI_SUCCESS) {
-#ifdef DEBUG
- oldQPair->handle = VMCI_INVALID_HANDLE;
- oldQPair->produceQ = NULL;
- oldQPair->consumeQ = NULL;
- oldQPair->produceQSize = 0;
- oldQPair->consumeQSize = 0;
- oldQPair->flags = 0;
- oldQPair->privFlags = 0;
- oldQPair->peer = VMCI_INVALID_ID;
-#endif
-
- VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair);
-
- *qpair = NULL;
- }
+ /*
+ * The guest can fail to detach for a number of reasons, and if it does so,
+ * it will cleanup the entry (if there is one). The host can fail too, but
+ * it won't cleanup the entry immediately, it will do that later when the
+ * context is freed. Either way, we need to release the qpair struct here;
+ * there isn't much the caller can do, and we don't want to leak.
+ */
+
+ memset(oldQPair, 0, sizeof *oldQPair);
+ oldQPair->handle = VMCI_INVALID_HANDLE;
+ oldQPair->peer = VMCI_INVALID_ID;
+ VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair);
+ *qpair = NULL;
return result;
}
entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, handle);
if (!entry) {
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
+ VMCIQPLock_Release(&qpGuestEndpoints.lock);
+ return VMCI_ERROR_NOT_FOUND;
}
ASSERT(entry->qp.refCount >= 1);
if (entry->qp.refCount > 1) {
result = QueuePairNotifyPeerLocal(FALSE, handle);
- if (result < VMCI_SUCCESS) {
- goto out;
- }
+ /*
+ * We can fail to notify a local queuepair because we can't allocate.
+ * We still want to release the entry if that happens, so don't bail
+ * out yet.
+ */
}
} else {
result = VMCIQueuePairDetachHypercall(handle);
VMCIQPUnmarkHibernateFailed(entry);
}
}
+ if (result < VMCI_SUCCESS) {
+ /*
+ * We failed to notify a non-local queuepair. That other queuepair
+ * might still be accessing the shared memory, so don't release the
+ * entry yet. It will get cleaned up by VMCIQueuePair_Exit()
+ * if necessary (assuming we are going away, otherwise why did this
+ * fail?).
+ */
+
+ VMCIQPLock_Release(&qpGuestEndpoints.lock);
+ return result;
+ }
}
-out:
- if (result >= VMCI_SUCCESS) {
- entry->qp.refCount--;
+ /*
+ * If we get here then we either failed to notify a local queuepair, or
+ * we succeeded in all cases. Release the entry if required.
+ */
- if (entry->qp.refCount == 0) {
- QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp);
- }
+ entry->qp.refCount--;
+ if (entry->qp.refCount == 0) {
+ QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp);
}
/* If we didn't remove the entry, this could change once we unlock. */
VMCIQPLock_Release(&qpGuestEndpoints.lock);
- if (result >= VMCI_SUCCESS && refCount == 0) {
+ if (refCount == 0) {
QPGuestEndpointDestroy(entry);
}
return result;