From: VMware, Inc <> Date: Wed, 26 Jan 2011 02:04:35 +0000 (-0800) Subject: Handle VMCI device shutdown when clients are still attached. X-Git-Tag: 2011.01.24-354108~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8697043e1d5bbec2a07753c461f7a6f5594ffcf7;p=thirdparty%2Fopen-vm-tools.git Handle VMCI device shutdown when clients are still attached. 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 --- diff --git a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h index 9bd207025..57b663374 100644 --- a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h +++ b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h @@ -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_ diff --git a/open-vm-tools/modules/linux/vmci/vmciDatagram.c b/open-vm-tools/modules/linux/vmci/vmciDatagram.c index 2afded28c..8e7f58578 100644 --- a/open-vm-tools/modules/linux/vmci/vmciDatagram.c +++ b/open-vm-tools/modules/linux/vmci/vmciDatagram.c @@ -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); +} diff --git a/open-vm-tools/modules/linux/vmci/vmciDatagram.h b/open-vm-tools/modules/linux/vmci/vmciDatagram.h index 299f64456..7661823c5 100644 --- a/open-vm-tools/modules/linux/vmci/vmciDatagram.h +++ b/open-vm-tools/modules/linux/vmci/vmciDatagram.h @@ -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); diff --git a/open-vm-tools/modules/linux/vmci/vmciEvent.c b/open-vm-tools/modules/linux/vmci/vmciEvent.c index 1870fccaa..ff053a901 100644 --- a/open-vm-tools/modules/linux/vmci/vmciEvent.c +++ b/open-vm-tools/modules/linux/vmci/vmciEvent.c @@ -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 } diff --git a/open-vm-tools/modules/linux/vmci/vmciEvent.h b/open-vm-tools/modules/linux/vmci/vmciEvent.h index fb075d924..3eeef29df 100644 --- a/open-vm-tools/modules/linux/vmci/vmciEvent.h +++ b/open-vm-tools/modules/linux/vmci/vmciEvent.h @@ -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); diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.c b/open-vm-tools/modules/linux/vmci/vmciNotifications.c index 81975712e..3e61ce145 100644 --- a/open-vm-tools/modules/linux/vmci/vmciNotifications.c +++ b/open-vm-tools/modules/linux/vmci/vmciNotifications.c @@ -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; diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.h b/open-vm-tools/modules/linux/vmci/vmciNotifications.h index 6c39ff81a..43bc5d610 100644 --- a/open-vm-tools/modules/linux/vmci/vmciNotifications.h +++ b/open-vm-tools/modules/linux/vmci/vmciNotifications.h @@ -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); diff --git a/open-vm-tools/modules/linux/vmci/vmciQueuePair.c b/open-vm-tools/modules/linux/vmci/vmciQueuePair.c index 3d8bf95a1..f138d869e 100644 --- a/open-vm-tools/modules/linux/vmci/vmciQueuePair.c +++ b/open-vm-tools/modules/linux/vmci/vmciQueuePair.c @@ -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))) { diff --git a/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h b/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h index df155e8bb..24db38d02 100644 --- a/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h +++ b/open-vm-tools/modules/linux/vmci/vmciQueuePairInt.h @@ -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); diff --git a/open-vm-tools/modules/linux/vmci/vmci_version.h b/open-vm-tools/modules/linux/vmci/vmci_version.h index 74dcf0e5a..bc50a6b76 100644 --- a/open-vm-tools/modules/linux/vmci/vmci_version.h +++ b/open-vm-tools/modules/linux/vmci/vmci_version.h @@ -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_ */