swap: wake the faulting process on conflict

userfaultfd does not wake the thread if zero operation fails with
EEXIST.

minor change: An unexpected page fault event is critical error because
it blocks the faulting thread forever.

BUG=b:215093219
TEST=none

Change-Id: I5326878018f825024c7a5ceaf8daec5792547cb6
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4125076
Commit-Queue: Shin Kawamura <kawasin@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: David Stevens <stevensd@chromium.org>
diff --git a/swap/src/lib.rs b/swap/src/lib.rs
index c9bbdc4..388f0c3 100644
--- a/swap/src/lib.rs
+++ b/swap/src/lib.rs
@@ -448,7 +448,7 @@
                                         .handle_page_fault(uffd, addr as usize)
                                         .context("handle fault")?;
                                 } else {
-                                    warn!("page fault event while handler is none");
+                                    bail!("page fault event while handler is none");
                                 }
                             }
                             UffdEvent::Fork { uffd } => {
diff --git a/swap/src/page_handler.rs b/swap/src/page_handler.rs
index 77338b2..4d65a4d 100644
--- a/swap/src/page_handler.rs
+++ b/swap/src/page_handler.rs
@@ -245,6 +245,7 @@
                     Err(UffdError::ZeropageFailed(errno)) if errno as i32 == libc::EEXIST => {
                         // zeroing fails with EEXIST if the page is already filled. This case can
                         // happen if page faults on the same page happen on different processes.
+                        uffd.wake(page_addr, page_size)?;
                         Ok(())
                     }
                     Err(e) => Err(e.into()),
diff --git a/swap/src/userfaultfd.rs b/swap/src/userfaultfd.rs
index dd627f7..410bc26 100644
--- a/swap/src/userfaultfd.rs
+++ b/swap/src/userfaultfd.rs
@@ -129,6 +129,18 @@
         }
     }
 
+    /// Wake the faulting thread blocked by the page(s).
+    ///
+    /// If the page is not initialized, the thread causes a page fault again.
+    ///
+    /// # Arguments
+    ///
+    /// * `addr` - the starting address of the page(s).
+    /// * `len` - the length in bytes of the page(s).
+    pub fn wake(&self, addr: usize, len: usize) -> Result<()> {
+        self.uffd.wake(addr as *mut libc::c_void, len)
+    }
+
     /// Read an event from the userfaultfd.
     ///
     /// Return `None` immediately if no events is ready to read.