diff --git a/src/api/server/sync_io.rs b/src/api/server/sync_io.rs index 20268dba..3e1c9dcb 100644 --- a/src/api/server/sync_io.rs +++ b/src/api/server/sync_io.rs @@ -57,7 +57,36 @@ impl Server { .map_err(Error::FailedToWrite)?; buffer_writer.commit(None).map_err(Error::InvalidMessage) } + /// Notify the kernel that an inode's data has been invalidated. + #[cfg(feature = "fusedev")] + pub fn notify_inval_inode( + &self, + mut w: FuseDevWriter<'_, S>, + ino: u64, + off: u64, + len: u64, + ) -> Result { + let mut buffer_writer = w.split_at(0).map_err(Error::FailedToSplitWriter)?; + let mut header = OutHeader::default(); + let mut inode = NotifyInvalInodeOut::default(); + + header.unique = 0; + header.error = NotifyOpcode::InvalInode as i32; + header.len = std::mem::size_of::() as u32 + + std::mem::size_of::() as u32; + inode.ino = ino; + inode.off = off as i64; + inode.len = len as i64; + + buffer_writer + .write_obj(header) + .map_err(Error::FailedToWrite)?; + buffer_writer + .write_obj(inode) + .map_err(Error::FailedToWrite)?; + buffer_writer.commit(None).map_err(Error::InvalidMessage) + } #[cfg(feature = "fusedev")] /// Send a resend notification message to the kernel via FUSE. This function should be invoked as part of /// the crash recovery routine. Given that FUSE initialization does not occur again during recovery, diff --git a/src/api/vfs/mod.rs b/src/api/vfs/mod.rs index b1c36970..9ede7b08 100644 --- a/src/api/vfs/mod.rs +++ b/src/api/vfs/mod.rs @@ -496,8 +496,8 @@ impl Vfs { Ok((inode, parent)) } - /// Get the mounted backend file system alongside the path if there's one. - pub fn get_rootfs(&self, path: &str) -> VfsResult>> { + /// Get the mounted backend file system and its fs_idx alongside the path if there's one. + pub fn get_rootfs(&self, path: &str) -> VfsResult, u8)>> { // Serialize mount operations. Do not expect poisoned lock here. let _guard = self.lock.lock().unwrap(); let inode = match self.root.path_walk(path).map_err(VfsError::PathWalk)? { @@ -506,9 +506,10 @@ impl Vfs { }; if let Some(mnt) = self.mountpoints.load().get(&inode) { - Ok(Some(self.get_fs_by_idx(mnt.fs_idx).map_err(|e| { - VfsError::NotFound(format!("fs index {}, {:?}", mnt.fs_idx, e)) - })?)) + let fs = self + .get_fs_by_idx(mnt.fs_idx) + .map_err(|e| VfsError::NotFound(format!("fs index {}, {:?}", mnt.fs_idx, e)))?; + Ok(Some((fs, mnt.fs_idx))) } else { // Pseudo fs dir inode exists, but that no backend is ever mounted // is a normal case. @@ -1582,9 +1583,9 @@ mod tests { assert!(vfs.mount(Box::new(fs1), "/x/y/z").is_ok()); assert!(vfs.mount(Box::new(fs2), "/x/y").is_ok()); - let m1 = vfs.get_rootfs("/x/y/z").unwrap().unwrap(); + let (m1, _) = vfs.get_rootfs("/x/y/z").unwrap().unwrap(); assert!(m1.as_any().is::()); - let m2 = vfs.get_rootfs("/x/y").unwrap().unwrap(); + let (m2, _) = vfs.get_rootfs("/x/y").unwrap().unwrap(); assert!(m2.as_any().is::()); assert!(vfs.umount("/x/y/z").is_ok()); @@ -1605,7 +1606,7 @@ mod tests { assert!(vfs.mount(Box::new(fs1), "/x/y").is_ok()); assert!(vfs.mount(Box::new(fs2), "/x/y").is_ok()); - let m1 = vfs.get_rootfs("/x/y").unwrap().unwrap(); + let (m1, _) = vfs.get_rootfs("/x/y").unwrap().unwrap(); assert!(m1.as_any().is::()); assert!(vfs.umount("/x/y").is_ok()); diff --git a/src/passthrough/mod.rs b/src/passthrough/mod.rs index 075bfcb0..0f0e5408 100644 --- a/src/passthrough/mod.rs +++ b/src/passthrough/mod.rs @@ -1032,7 +1032,7 @@ mod tests { fs.import().unwrap(); vfs.mount(Box::new(fs), "/submnt/A").unwrap(); - let p_fs = vfs.get_rootfs("/submnt/A").unwrap().unwrap(); + let (p_fs, _) = vfs.get_rootfs("/submnt/A").unwrap().unwrap(); let any_fs = p_fs.deref().as_any(); any_fs .downcast_ref::()