summary refs log tree commit diff
diff options
context:
space:
mode:
authorStephen Barber <smbarber@chromium.org>2019-10-02 18:36:21 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-03 19:44:37 +0000
commit28a9d2b70d98e4fd8ce466190a52b85cf270e7bb (patch)
tree2424a3d47f40f3b8feb5d87bf3dd52834ea4b12d
parent82ff397489cc9fcc6bee1cdc98aa5eede18f8978 (diff)
downloadcrosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar.gz
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar.bz2
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar.lz
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar.xz
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.tar.zst
crosvm-28a9d2b70d98e4fd8ce466190a52b85cf270e7bb.zip
devices: virtio_net: avoid busylooping when no rx buffers available
If the guest is unable to return rx queue buffers to the device, we should
temporarily stop polling for reads on the tap fd. Otherwise, we'll spin and
burn CPU needlessly.

BUG=chromium:1010742
TEST=repro from b/141940546

Change-Id: Iac004e870779a8dd39004f44b44e17a2b45bcfa1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1836914
Tested-by: Stephen Barber <smbarber@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
-rw-r--r--devices/src/virtio/net.rs14
1 files changed, 14 insertions, 0 deletions
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index 2a4784c..43fba38 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -38,6 +38,10 @@ pub enum NetError {
     CreatePollContext(SysError),
     /// Cloning kill eventfd failed.
     CloneKillEventFd(SysError),
+    /// Adding the tap fd back to the poll context failed.
+    PollAddTap(SysError),
+    /// Removing the tap fd from the poll context failed.
+    PollDeleteTap(SysError),
     /// Open tap device failed.
     TapOpen(TapError),
     /// Setting tap IP failed.
@@ -66,6 +70,8 @@ impl Display for NetError {
             CreateKillEventFd(e) => write!(f, "failed to create kill eventfd: {}", e),
             CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
             CloneKillEventFd(e) => write!(f, "failed to clone kill eventfd: {}", e),
+            PollAddTap(e) => write!(f, "failed to add tap fd to poll context: {}", e),
+            PollDeleteTap(e) => write!(f, "failed to remove tap fd from poll context: {}", e),
             TapOpen(e) => write!(f, "failed to open tap device: {}", e),
             TapSetIp(e) => write!(f, "failed to set tap IP: {}", e),
             TapSetNetmask(e) => write!(f, "failed to set tap netmask: {}", e),
@@ -231,6 +237,9 @@ where
                             if self.rx_single_frame() {
                                 self.deferred_rx = false;
                             } else {
+                                // The guest has not yet made any buffers available. Remove the
+                                // tapfd from the poll context until more are made available.
+                                poll_ctx.delete(&self.tap).map_err(NetError::PollDeleteTap);
                                 continue;
                             }
                         }
@@ -243,6 +252,11 @@ where
                         }
                         // There should be a buffer available now to receive the frame into.
                         if self.deferred_rx && self.rx_single_frame() {
+                            // The guest has made buffers available, so add the tap back to the
+                            // poll context.
+                            poll_ctx
+                                .add(&self.tap, Token::RxTap)
+                                .map_err(NetError::PollAddTap);
                             self.deferred_rx = false;
                         }
                     }