]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Hang in VMCISockets caused by uninitialized notification state.
authorVMware, Inc <>
Thu, 24 Feb 2011 22:04:22 +0000 (14:04 -0800)
committerMarcelo Vanzin <mvanzin@vmware.com>
Thu, 24 Feb 2011 22:04:22 +0000 (14:04 -0800)
It turns out that a recent unload/shutdown fix broke the
notification code.

We don't call the notification functions when the qpair
is invalid, to guard against touching the qpair after
the device has shutdown, but some of those functions
need to be called *before* a qpair is actually attached.
There are actually a few of them, so rather than introduce
a new macro for notifications that don't need qpairs,
I've removed the qpair check from the macros and embedded
it as necessary in the notification code.

We also uncovered a problem where if the notification
write window is less than a page we can underflow.
Fixed on all platforms.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/modules/linux/vsock/linux/notify.c
open-vm-tools/modules/linux/vsock/linux/notifyQState.c

index a6e61bc3db8e296010f7df8496010f956eed5994..4fbe5b4c632a6d94239496781a8604f7a558a9e1 100644 (file)
@@ -77,11 +77,16 @@ VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk)    // IN
 
    if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) {
       PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE;
-      PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
-      if (PKT_FIELD(vsk, writeNotifyWindow) <
-                    PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      if (PKT_FIELD(vsk, writeNotifyWindow) < PAGE_SIZE) {
          PKT_FIELD(vsk, writeNotifyWindow) =
             PKT_FIELD(vsk, writeNotifyMinWindow);
+      } else {
+         PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
+         if (PKT_FIELD(vsk, writeNotifyWindow) <
+             PKT_FIELD(vsk, writeNotifyMinWindow)) {
+            PKT_FIELD(vsk, writeNotifyWindow) =
+               PKT_FIELD(vsk, writeNotifyMinWindow);
+         }
       }
    }
    notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow);
@@ -538,7 +543,7 @@ VSockVmciNotifyPktSocketInit(struct sock *sk) // IN
    VSockVmciSock *vsk;
    vsk = vsock_sk(sk);
 
-   PKT_FIELD(vsk, writeNotifyWindow) = 0;
+   PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, peerWaitingRead) = FALSE;
    PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
@@ -1151,6 +1156,9 @@ VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
    vsk = vsock_sk(sk);
 
    PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+   if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize;
+   }
 }
 
 
@@ -1180,6 +1188,9 @@ VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
    vsk = vsock_sk(sk);
 
    PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+   if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize;
+   }
 }
 
 
index 59f2f760e08fc3b03b0e217f5bb65cb0c98d6d27..5b1cb60665e5121a0e6fb6507ef6cbc113d87bc8 100644 (file)
@@ -74,11 +74,16 @@ VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk)    // IN
 
    if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) {
       PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE;
-      PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
-      if (PKT_FIELD(vsk, writeNotifyWindow) <
-                    PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      if (PKT_FIELD(vsk, writeNotifyWindow) < PAGE_SIZE) {
          PKT_FIELD(vsk, writeNotifyWindow) =
             PKT_FIELD(vsk, writeNotifyMinWindow);
+      } else {
+         PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
+         if (PKT_FIELD(vsk, writeNotifyWindow) <
+             PKT_FIELD(vsk, writeNotifyMinWindow)) {
+            PKT_FIELD(vsk, writeNotifyWindow) =
+               PKT_FIELD(vsk, writeNotifyMinWindow);
+         }
       }
    }
    notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow);
@@ -278,7 +283,7 @@ VSockVmciNotifyPktSocketInit(struct sock *sk) // IN
    VSockVmciSock *vsk;
    vsk = vsock_sk(sk);
 
-   PKT_FIELD(vsk, writeNotifyWindow) = 0;
+   PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
    PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
@@ -307,11 +312,10 @@ VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN
    VSockVmciSock *vsk;
    vsk = vsock_sk(sk);
 
-   PKT_FIELD(vsk, writeNotifyWindow) = 0;
+   PKT_FIELD(vsk, writeNotifyWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
    PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
    PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
-   return;
 }
 
 
@@ -731,6 +735,9 @@ VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
    vsk = vsock_sk(sk);
 
    PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+   if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize;
+   }
 }
 
 
@@ -760,6 +767,9 @@ VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
    vsk = vsock_sk(sk);
 
    PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+   if (vsk->consumeSize < PKT_FIELD(vsk, writeNotifyMinWindow)) {
+      PKT_FIELD(vsk, writeNotifyMinWindow) = vsk->consumeSize;
+   }
 }