changeset 50180:be019ac8c1e4 stable

dirstate-v2: don't mmap the data file when on NFS `mmap` on NFS will trigger a SIGBUS when the mmap'ed file is deleted, which wouldn't work in our case. Also, the performance advantage of using mmap on NFS is debatable at best.
author Raphaël Gomès <rgomes@octobus.net>
date Mon, 28 Nov 2022 12:33:20 +0100
parents f2e13d8d30e0
children 6515d9a6592d
files rust/hg-core/src/repo.rs rust/hg-core/src/vfs.rs
diffstat 2 files changed, 29 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-core/src/repo.rs	Thu Dec 08 16:38:39 2022 +0100
+++ b/rust/hg-core/src/repo.rs	Mon Nov 28 12:33:20 2022 +0100
@@ -320,7 +320,14 @@
                 .set(Some(docket.uuid.to_owned()));
             let data_size = docket.data_size();
             let metadata = docket.tree_metadata();
-            if let Some(data_mmap) = self
+            if crate::vfs::is_on_nfs_mount(docket.data_filename()) {
+                // Don't mmap on NFS to prevent `SIGBUS` error on deletion
+                OwningDirstateMap::new_v2(
+                    self.hg_vfs().read(docket.data_filename())?,
+                    data_size,
+                    metadata,
+                )
+            } else if let Some(data_mmap) = self
                 .hg_vfs()
                 .mmap_open(docket.data_filename())
                 .io_not_found_as_none()?
--- a/rust/hg-core/src/vfs.rs	Thu Dec 08 16:38:39 2022 +0100
+++ b/rust/hg-core/src/vfs.rs	Mon Nov 28 12:33:20 2022 +0100
@@ -172,3 +172,24 @@
 pub(crate) fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> {
     Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file()))
 }
+
+/// Returns whether the given `path` is on a network file system.
+/// Taken from `cargo`'s codebase.
+#[cfg(target_os = "linux")]
+pub(crate) fn is_on_nfs_mount(path: impl AsRef<Path>) -> bool {
+    use std::ffi::CString;
+    use std::mem;
+    use std::os::unix::prelude::*;
+
+    let path = match CString::new(path.as_ref().as_os_str().as_bytes()) {
+        Ok(path) => path,
+        Err(_) => return false,
+    };
+
+    unsafe {
+        let mut buf: libc::statfs = mem::zeroed();
+        let r = libc::statfs(path.as_ptr(), &mut buf);
+
+        r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
+    }
+}