Skip to content

Commit a29fec8

Browse files
committed
add notify_inval_inode and extend get_rootfs to return fs_idx for unmount
- Add notify_inval_inode method to fusedev to explicitly invalidate inode caches in the kernel, ensuring cache coherence when backend files change outside guest VFS. - Extend get_rootfs to return both Arc<BackFileSystem> and u8 fs_idx. This is necessary for correct unmount handling and cache invalidation. The implementation follows fuse kernel and libfuse protocols and maintains compatibility with existing patterns like notify_inval_entry. Signed-off-by: sidneychang <[email protected]>
1 parent 0edf34e commit a29fec8

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

src/api/server/sync_io.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,36 @@ impl<F: FileSystem + Sync> Server<F> {
5757
.map_err(Error::FailedToWrite)?;
5858
buffer_writer.commit(None).map_err(Error::InvalidMessage)
5959
}
60+
/// Notify the kernel that an inode's data has been invalidated.
61+
#[cfg(feature = "fusedev")]
62+
pub fn notify_inval_inode<S: BitmapSlice>(
63+
&self,
64+
mut w: FuseDevWriter<'_, S>,
65+
ino: u64,
66+
off: u64,
67+
len: u64,
68+
) -> Result<usize> {
69+
let mut buffer_writer = w.split_at(0).map_err(Error::FailedToSplitWriter)?;
70+
let mut header = OutHeader::default();
71+
let mut inode = NotifyInvalInodeOut::default();
72+
73+
header.unique = 0;
74+
header.error = NotifyOpcode::InvalInode as i32;
75+
header.len = std::mem::size_of::<OutHeader>() as u32
76+
+ std::mem::size_of::<NotifyInvalInodeOut>() as u32;
6077

78+
inode.ino = ino;
79+
inode.off = off as i64;
80+
inode.len = len as i64;
81+
82+
buffer_writer
83+
.write_obj(header)
84+
.map_err(Error::FailedToWrite)?;
85+
buffer_writer
86+
.write_obj(inode)
87+
.map_err(Error::FailedToWrite)?;
88+
buffer_writer.commit(None).map_err(Error::InvalidMessage)
89+
}
6190
#[cfg(feature = "fusedev")]
6291
/// Send a resend notification message to the kernel via FUSE. This function should be invoked as part of
6392
/// the crash recovery routine. Given that FUSE initialization does not occur again during recovery,

src/api/vfs/mod.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,8 @@ impl Vfs {
496496
Ok((inode, parent))
497497
}
498498

499-
/// Get the mounted backend file system alongside the path if there's one.
500-
pub fn get_rootfs(&self, path: &str) -> VfsResult<Option<Arc<BackFileSystem>>> {
499+
/// Get the mounted backend file system and its fs_idx alongside the path if there's one.
500+
pub fn get_rootfs(&self, path: &str) -> VfsResult<Option<(Arc<BackFileSystem>, u8)>> {
501501
// Serialize mount operations. Do not expect poisoned lock here.
502502
let _guard = self.lock.lock().unwrap();
503503
let inode = match self.root.path_walk(path).map_err(VfsError::PathWalk)? {
@@ -506,9 +506,10 @@ impl Vfs {
506506
};
507507

508508
if let Some(mnt) = self.mountpoints.load().get(&inode) {
509-
Ok(Some(self.get_fs_by_idx(mnt.fs_idx).map_err(|e| {
510-
VfsError::NotFound(format!("fs index {}, {:?}", mnt.fs_idx, e))
511-
})?))
509+
let fs = self
510+
.get_fs_by_idx(mnt.fs_idx)
511+
.map_err(|e| VfsError::NotFound(format!("fs index {}, {:?}", mnt.fs_idx, e)))?;
512+
Ok(Some((fs, mnt.fs_idx)))
512513
} else {
513514
// Pseudo fs dir inode exists, but that no backend is ever mounted
514515
// is a normal case.
@@ -1582,9 +1583,9 @@ mod tests {
15821583
assert!(vfs.mount(Box::new(fs1), "/x/y/z").is_ok());
15831584
assert!(vfs.mount(Box::new(fs2), "/x/y").is_ok());
15841585

1585-
let m1 = vfs.get_rootfs("/x/y/z").unwrap().unwrap();
1586+
let (m1, _) = vfs.get_rootfs("/x/y/z").unwrap().unwrap();
15861587
assert!(m1.as_any().is::<FakeFileSystemOne>());
1587-
let m2 = vfs.get_rootfs("/x/y").unwrap().unwrap();
1588+
let (m2, _) = vfs.get_rootfs("/x/y").unwrap().unwrap();
15881589
assert!(m2.as_any().is::<FakeFileSystemTwo>());
15891590

15901591
assert!(vfs.umount("/x/y/z").is_ok());
@@ -1605,7 +1606,7 @@ mod tests {
16051606
assert!(vfs.mount(Box::new(fs1), "/x/y").is_ok());
16061607
assert!(vfs.mount(Box::new(fs2), "/x/y").is_ok());
16071608

1608-
let m1 = vfs.get_rootfs("/x/y").unwrap().unwrap();
1609+
let (m1, _) = vfs.get_rootfs("/x/y").unwrap().unwrap();
16091610
assert!(m1.as_any().is::<FakeFileSystemTwo>());
16101611

16111612
assert!(vfs.umount("/x/y").is_ok());

src/passthrough/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ mod tests {
10321032
fs.import().unwrap();
10331033
vfs.mount(Box::new(fs), "/submnt/A").unwrap();
10341034

1035-
let p_fs = vfs.get_rootfs("/submnt/A").unwrap().unwrap();
1035+
let (p_fs, _) = vfs.get_rootfs("/submnt/A").unwrap().unwrap();
10361036
let any_fs = p_fs.deref().as_any();
10371037
any_fs
10381038
.downcast_ref::<PassthroughFs>()

0 commit comments

Comments
 (0)