]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Handle VMCI device shutdown when clients are still attached.
authorVMware, Inc <>
Wed, 26 Jan 2011 02:04:35 +0000 (18:04 -0800)
committerMarcelo Vanzin <mvanzin@vmware.com>
Wed, 26 Jan 2011 02:04:35 +0000 (18:04 -0800)
When Windows reboots/halts, it sends the VMCI device
a shutdown PnP event.  This event is sent even if the
device is still referenced.  Clients are supposed to
handle IRP_MJ_SHUTDOWN (or similar) and detach, but if
they don't, then it's possible for them to call us
after the device is gone, at which point we can
explode.

Fixed so that we gracefully handle this.  On a shutdown
event:

1) Fail VMCI handle creation from this point on, but
   allow other calls, so that handles can be closed.
2) Inform vsock that the device is going away.
3) VSock fails DGRAM/STREAM creation from this point on.
4) VSock informs all open sockets that the device
   is going away.  The sockets close their handles
   and their wait list is kicked so that they wakeup
   from recv() etc.
5) VSock closes the control channel.
6) VSock fails all creation calls from this point on,
   but allows other calls, so that sockets can be
   closed etc.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/modules/linux/shared/vmci_kernel_if.h
open-vm-tools/modules/linux/vmci/vmciDatagram.c
open-vm-tools/modules/linux/vmci/vmciDatagram.h
open-vm-tools/modules/linux/vmci/vmciEvent.c
open-vm-tools/modules/linux/vmci/vmciEvent.h
open-vm-tools/modules/linux/vmci/vmciNotifications.c
open-vm-tools/modules/linux/vmci/vmciNotifications.h
open-vm-tools/modules/linux/vmci/vmciQueuePair.c
open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h
open-vm-tools/modules/linux/vmci/vmci_version.h

index 9bd20702562d4ef944bd0b0763334927c7a5173d..57b6633741702f6bbe40077f09e4136be616f4e1 100644 (file)
@@ -280,11 +280,6 @@ Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event,
 int VMCI_CopyFromUser(void *dst, VA64 src, size_t len);
 #endif
 
-#if defined(_WIN32)
-void VMCI_InitHelperQueue(void);
-void VMCI_ExitHelperQueue(void);
-#endif // _WIN32
-
 typedef void (VMCIWorkFn)(void *data);
 Bool VMCI_CanScheduleDelayedWork(void);
 int VMCI_ScheduleDelayedWork(VMCIWorkFn  *workFn,
@@ -295,10 +290,10 @@ void VMCIMutex_Destroy(VMCIMutex *mutex);
 void VMCIMutex_Acquire(VMCIMutex *mutex);
 void VMCIMutex_Release(VMCIMutex *mutex);
 
-#if defined(SOLARIS)
+#if defined(SOLARIS) || defined(_WIN32)
 int VMCIKernelIf_Init(void);
 void VMCIKernelIf_Exit(void);
-#endif         /* SOLARIS  */
+#endif // SOLARIS || _WIN32
 
 #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
                            defined(SOLARIS) || defined(__APPLE__))
@@ -360,6 +355,9 @@ int VMCI_ConvertToLocalQueue(struct VMCIQueue *queueInfo,
 void VMCI_RevertToNonLocalQueue(struct VMCIQueue *queueInfo,
                                 void *nonLocalQueue, uint64 size);
 void VMCI_FreeQueueBuffer(void *queue, uint64 size);
+void VMCI_DeviceShutdownBegin(void);
+void VMCI_DeviceShutdownEnd(void);
+Bool VMCI_DeviceShutdown(void);
 #else // _WIN32
 #  define VMCI_InitQueueMutex(_pq, _cq)
 #  define VMCI_AcquireQueueMutex(_q)
@@ -368,6 +366,8 @@ void VMCI_FreeQueueBuffer(void *queue, uint64 size);
 #  define VMCI_ConvertToLocalQueue(_pq, _cq, _s, _oq, _kc) VMCI_ERROR_UNAVAILABLE
 #  define VMCI_RevertToNonLocalQueue(_q, _nlq, _s)
 #  define VMCI_FreeQueueBuffer(_q, _s)
+#  define VMCI_DeviceShutdown() FALSE
 #endif // !_WIN32
 
+
 #endif // _VMCI_KERNEL_IF_H_
index 2afded28cff6e8d995974d44b167f63cc7e36a0e..8e7f58578064fb376fc14f4a034745093b87789e 100644 (file)
@@ -144,6 +144,13 @@ DatagramHashAddEntry(DatagramHashEntry *entry, // IN:
    ASSERT(entry);
 
    VMCI_GrabLock_BH(&hashTable.lock, &flags);
+
+   /* Do not allow addition of a new handle if the device is being shutdown. */
+   if (VMCI_DeviceShutdown()) {
+      VMCI_ReleaseLock_BH(&hashTable.lock, flags);
+      return VMCI_ERROR_DEVICE_NOT_FOUND;
+   }
+
    if (!VMCI_HANDLE_INVALID(entry->handle) &&
        !DatagramHandleUniqueLockedAnyCid(entry->handle)) {
       VMCI_ReleaseLock_BH(&hashTable.lock, flags);
@@ -433,7 +440,6 @@ VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN
       }
    }
 
-
    if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
       VMCIDatagramWellKnownMapMsg wkMsg;
       if (resourceID == VMCI_INVALID_ID) {
@@ -795,3 +801,27 @@ VMCIDatagram_CheckHostCapabilities(void)
 {
    return TRUE;
 }
+
+
+/*
+ * VMCIDatagram_Sync --
+ *
+ *      Use this as a synchronization point when setting globals, for example,
+ *      during device shutdown.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIDatagram_Sync(void)
+{
+   VMCILockFlags flags;
+   VMCI_GrabLock_BH(&hashTable.lock, &flags);
+   VMCI_ReleaseLock_BH(&hashTable.lock, flags);
+}
index 299f64456c91bb3103b5528c5f38d1540d5f8579..7661823c504e01767c63516eaeebcb2adfab500b 100644 (file)
@@ -35,6 +35,7 @@
 #include "vmci_iocontrols.h"
 
 void VMCIDatagram_Init(void);
+void VMCIDatagram_Sync(void);
 Bool VMCIDatagram_CheckHostCapabilities(void);
 int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *msg);
 
index 1870fccaadffe9b061a44c2b8b98d1913a7e29c3..ff053a90124c6d23ee94075528f73a2f2b865eb2 100644 (file)
@@ -169,6 +169,33 @@ VMCIEvent_Exit(void)
    VMCI_CleanupLock(&subscriberLock);
 }
 
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIEvent_Sync --
+ *
+ *      Use this as a synchronization point when setting globals, for example,
+ *      during device shutdown.
+ *
+ * Results:
+ *      TRUE.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIEvent_Sync(void)
+{
+   VMCILockFlags lockFlags;
+   VMCIEventGrabLock(&subscriberLock, &lockFlags);
+   VMCIEventReleaseLock(&subscriberLock, lockFlags);
+}
+
+
 #ifdef VMX86_TOOLS
 /*
  *-----------------------------------------------------------------------------
@@ -545,6 +572,13 @@ VMCIEventRegisterSubscription(VMCISubscription *sub,   // IN
    sub->callbackData = callbackData;
 
    VMCIEventGrabLock(&subscriberLock, &lockFlags);
+
+   /* Do not allow a new subscription if the device is being shutdown. */
+   if (VMCI_DeviceShutdown()) {
+      result = VMCI_ERROR_DEVICE_NOT_FOUND;
+      goto exit;
+   }
+
    for (success = FALSE, attempts = 0;
         success == FALSE && attempts < VMCI_EVENT_MAX_ATTEMPTS;
         attempts++) {
@@ -573,8 +607,9 @@ VMCIEventRegisterSubscription(VMCISubscription *sub,   // IN
    } else {
       result = VMCI_ERROR_NO_RESOURCES;
    }
-   VMCIEventReleaseLock(&subscriberLock, lockFlags);
 
+exit:
+   VMCIEventReleaseLock(&subscriberLock, lockFlags);
    return result;
 #  undef VMCI_EVENT_MAX_ATTEMPTS
 }
index fb075d924a81853393123431738c850a7ae4a24f..3eeef29df9e4f14810f7bef4dc858bddeb6cb615 100644 (file)
@@ -36,6 +36,7 @@
 
 void VMCIEvent_Init(void);
 void VMCIEvent_Exit(void);
+void VMCIEvent_Sync(void);
 int  VMCIEvent_Dispatch(VMCIDatagram *msg);
 #ifdef VMX86_TOOLS
 Bool VMCIEvent_CheckHostCapabilities(void);
index 81975712e615ca3d45e3d6269b91e5aa3c69e8e3..3e61ce14526fc98a15e3dc77600104f6a3fde242 100644 (file)
@@ -210,6 +210,32 @@ VMCINotifications_Exit(void)
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCINotifications_Sync --
+ *
+ *      Use this as a synchronization point when setting globals, for example,
+ *      during device shutdown.
+ *
+ * Results:
+ *      TRUE.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCINotifications_Sync(void)
+{
+   VMCILockFlags flags;
+   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
+   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -301,6 +327,12 @@ VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry) // IN
 
    VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
 
+   /* Do not allow addition of a new handle if the device is being shutdown. */
+   if (VMCI_DeviceShutdown()) {
+      result = VMCI_ERROR_DEVICE_NOT_FOUND;
+      goto out;
+   }
+
    if (VMCI_HANDLE_INVALID(entry->handle)) {
       VMCIHandle newHandle;
       VMCIId oldRID = notifyRID;
index 6c39ff81a284365aa390a383b2d229c83b7d5aa6..43bc5d610f5833458b0348e9380a0a6f619ceee1 100644 (file)
@@ -31,6 +31,7 @@
 
 void VMCINotifications_Init(void);
 void VMCINotifications_Exit(void);
+void VMCINotifications_Sync(void);
 
 Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN);
 void VMCI_ScanNotificationBitmap(uint8 *bitmap);
index 3d8bf95a137033be62e95336641f1cbf3989d945..f138d869e2ec3fbb985fba4746d48ae2f6b11a63 100644 (file)
@@ -274,6 +274,31 @@ VMCIQueuePair_Exit(void)
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueuePair_Sync --
+ *
+ *      Use this as a synchronization point when setting globals, for example,
+ *      during device shutdown.
+ *
+ * Results:
+ *      TRUE.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIQueuePair_Sync(void)
+{
+   QueuePairList_Lock();
+   QueuePairList_Unlock();
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -708,6 +733,12 @@ VMCIQueuePairAllocHelper(VMCIHandle *handle,   // IN/OUT:
 
    QueuePairList_Lock();
 
+   /* Do not allow alloc/attach if the device is being shutdown. */
+   if (VMCI_DeviceShutdown()) {
+      result = VMCI_ERROR_DEVICE_NOT_FOUND;
+      goto error;
+   }
+
    if ((Atomic_Read(&queuePairList.hibernate) == 1) &&
        !(flags & VMCI_QPFLAG_LOCAL)) {
       /*
@@ -717,8 +748,8 @@ VMCIQueuePairAllocHelper(VMCIHandle *handle,   // IN/OUT:
        * ones.
        */
 
-      QueuePairList_Unlock();
-      return VMCI_ERROR_UNAVAILABLE;
+      result = VMCI_ERROR_UNAVAILABLE;
+      goto error;
    }
 
    if ((queuePairEntry = QueuePairList_FindEntry(*handle))) {
index df155e8bb5f9319104dfd5c38c6c6444fc6913ff..24db38d02f5d79e776cd43a2d346718cbc5125dc 100644 (file)
@@ -30,6 +30,7 @@
 
 void VMCIQueuePair_Init(void);
 void VMCIQueuePair_Exit(void);
+void VMCIQueuePair_Sync(void);
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
                         uint64 consumeSize, VMCIId peer, uint32 flags);
index 74dcf0e5a02312d97e9930c3fdc2d4cdb30062ae..bc50a6b760ad8cacdcbd6c4dbf2b749ac690f004 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMCI_VERSION_H_
 #define _VMCI_VERSION_H_
 
-#define VMCI_DRIVER_VERSION          9.1.3.0
-#define VMCI_DRIVER_VERSION_COMMAS   9,1,3,0
-#define VMCI_DRIVER_VERSION_STRING   "9.1.3.0"
+#define VMCI_DRIVER_VERSION          9.1.4.0
+#define VMCI_DRIVER_VERSION_COMMAS   9,1,4,0
+#define VMCI_DRIVER_VERSION_STRING   "9.1.4.0"
 
 #endif /* _VMCI_VERSION_H_ */