Browse Source

Don't request credit multiple times in a row.

Andrew Walbran 2 years ago
parent
commit
1e0766e329
1 changed files with 20 additions and 5 deletions
  1. 20 5
      src/device/socket/vsock.rs

+ 20 - 5
src/device/socket/vsock.rs

@@ -35,6 +35,11 @@ struct ConnectionInfo {
     tx_cnt: u32,
     /// The number of bytes of packet bodies which we have received from the peer and handled.
     fwd_cnt: u32,
+    /// Whether we have recently requested credit from the peer.
+    ///
+    /// This is set to true when we send a `VIRTIO_VSOCK_OP_CREDIT_REQUEST`, and false when we
+    /// receive a `VIRTIO_VSOCK_OP_CREDIT_UPDATE`.
+    has_pending_credit_request: bool,
 }
 
 impl ConnectionInfo {
@@ -248,9 +253,11 @@ impl<H: Hal, T: Transport> VirtIOSocket<H, T> {
 
     /// Sends the buffer to the destination.
     pub fn send(&mut self, buffer: &[u8]) -> Result {
-        let connection_info = self.connection_info()?;
+        let mut connection_info = self.connection_info()?;
 
-        self.check_peer_buffer_is_sufficient(&connection_info, buffer.len())?;
+        let result = self.check_peer_buffer_is_sufficient(&mut connection_info, buffer.len());
+        self.connection_info = Some(connection_info.clone());
+        result?;
 
         let len = buffer.len() as u32;
         let header = VirtioVsockHdr {
@@ -265,14 +272,18 @@ impl<H: Hal, T: Transport> VirtIOSocket<H, T> {
 
     fn check_peer_buffer_is_sufficient(
         &mut self,
-        connection_info: &ConnectionInfo,
+        connection_info: &mut ConnectionInfo,
         buffer_len: usize,
     ) -> Result {
         if connection_info.peer_free() as usize >= buffer_len {
             Ok(())
         } else {
-            // Request an update of the cached peer credit, and tell the caller to try again later.
-            self.request_credit()?;
+            // Request an update of the cached peer credit, if we haven't already done so, and tell
+            // the caller to try again later.
+            if !connection_info.has_pending_credit_request {
+                self.request_credit()?;
+                connection_info.has_pending_credit_request = true;
+            }
             Err(SocketError::InsufficientBufferSpaceInPeer.into())
         }
     }
@@ -400,6 +411,10 @@ impl<H: Hal, T: Transport> VirtIOSocket<H, T> {
                 }
                 VirtioVsockOp::CreditUpdate => {
                     header.check_data_is_empty()?;
+                    connection_info.has_pending_credit_request = false;
+                    if self.connection_info.is_some() {
+                        self.connection_info = Some(connection_info.clone());
+                    }
 
                     // Virtio v1.1 5.10.6.3
                     // The driver can also receive a VIRTIO_VSOCK_OP_CREDIT_UPDATE packet without previously