summary refs log tree commit diff
diff options
context:
space:
mode:
authorChirantan Ekbote <chirantan@chromium.org>2019-11-15 14:25:36 +0900
committerCommit Bot <commit-bot@chromium.org>2019-11-22 05:54:03 +0000
commit6576091e5623bb64af7076672b4ec4e42923ef3c (patch)
treeddaaeabb0e3359cd8536270939520b71c2c25b8a
parent220605a5fd03d7181d55b59d6bd147c86a4c8bc0 (diff)
downloadcrosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar.gz
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar.bz2
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar.lz
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar.xz
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.tar.zst
crosvm-6576091e5623bb64af7076672b4ec4e42923ef3c.zip
devices: fs: Only resample interrupts on one thread
Having more than one thread watch the interrupt resample event meant
that the threads would race to acknowledge the event: if thread B called
epoll_wait after thread A got a readable event for the resample eventfd
but before thread A called `read()` on the eventfd, then thread B would
also get a readable event for that eventfd. Both threads would then
attempt to acknowledge the event but only one would succeed. This would
leave the other thread blocked on the `read()` call until the resample
event became readable again.

Fix this by having only one worker watch the resample event.

BUG=b:136128319
TEST=`tast run vm.Virtiofs` on kevin

Change-Id: I5cd781a9c79ac718207a944433ea20a967735237
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1923568
Tested-by: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
-rw-r--r--devices/src/virtio/fs/mod.rs7
-rw-r--r--devices/src/virtio/fs/worker.rs22
2 files changed, 21 insertions, 8 deletions
diff --git a/devices/src/virtio/fs/mod.rs b/devices/src/virtio/fs/mod.rs
index ce7739a..0442bad 100644
--- a/devices/src/virtio/fs/mod.rs
+++ b/devices/src/virtio/fs/mod.rs
@@ -236,6 +236,7 @@ impl VirtioDevice for Fs {
         let server = Arc::new(Server::new(fs));
         let irq = Arc::new(interrupt);
 
+        let mut watch_resample_event = true;
         for (idx, (queue, evt)) in queues.into_iter().zip(queue_evts.into_iter()).enumerate() {
             let (self_kill_evt, kill_evt) =
                 match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
@@ -255,9 +256,13 @@ impl VirtioDevice for Fs {
                 .name(format!("virtio-fs worker {}", idx))
                 .spawn(move || {
                     let mut worker = Worker::new(mem, queue, server, irq);
-                    worker.run(evt, kill_evt)
+                    worker.run(evt, kill_evt, watch_resample_event)
                 });
 
+            if watch_resample_event {
+                watch_resample_event = false;
+            }
+
             match worker_result {
                 Ok(worker) => self.workers.push((self_kill_evt, worker)),
                 Err(e) => {
diff --git a/devices/src/virtio/fs/worker.rs b/devices/src/virtio/fs/worker.rs
index ec0ec8a..36b8b69 100644
--- a/devices/src/virtio/fs/worker.rs
+++ b/devices/src/virtio/fs/worker.rs
@@ -56,7 +56,12 @@ impl<F: FileSystem + Sync> Worker<F> {
         Ok(())
     }
 
-    pub fn run(&mut self, queue_evt: EventFd, kill_evt: EventFd) -> Result<()> {
+    pub fn run(
+        &mut self,
+        queue_evt: EventFd,
+        kill_evt: EventFd,
+        watch_resample_event: bool,
+    ) -> Result<()> {
         #[derive(PollToken)]
         enum Token {
             // A request is ready on the queue.
@@ -67,12 +72,15 @@ impl<F: FileSystem + Sync> Worker<F> {
             Kill,
         }
 
-        let poll_ctx = PollContext::build_with(&[
-            (&queue_evt, Token::QueueReady),
-            (&kill_evt, Token::Kill),
-            (self.irq.get_resample_evt(), Token::InterruptResample),
-        ])
-        .map_err(Error::CreatePollContext)?;
+        let poll_ctx =
+            PollContext::build_with(&[(&queue_evt, Token::QueueReady), (&kill_evt, Token::Kill)])
+                .map_err(Error::CreatePollContext)?;
+
+        if watch_resample_event {
+            poll_ctx
+                .add(self.irq.get_resample_evt(), Token::InterruptResample)
+                .map_err(Error::CreatePollContext)?;
+        }
 
         loop {
             let events = poll_ctx.wait().map_err(Error::PollError)?;