Skip to content

Commit dadbae4

Browse files
committed
passthrough: turn kernel passthrough off when init() doesn't enable it
init() set `passthrough` when it enabled kernel passthrough, but never cleared it. A takeover that calls init() again on the same instance, with options that no longer allow passthrough, kept registering backing ids for new files. Clear it first. Inodes with handles from before keep sharing their backing ids until their last handle closes. Signed-off-by: Ilan Joselevich <personal@ilanjoselevich.com>
1 parent cf4c814 commit dadbae4

2 files changed

Lines changed: 34 additions & 0 deletions

File tree

‎crates/fuse-backend-passthrough/src/lib.rs‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,6 +2071,36 @@ mod tests {
20712071
.unwrap();
20722072
assert_eq!(*files.closed.lock().unwrap(), vec![7]);
20732073

2074+
// An init() without passthrough turns it off again.
2075+
let tmpdir = TempDir::new().unwrap();
2076+
let files = Files::new(vec![Ok(3)]);
2077+
let fs = passthrough_fs(&tmpdir, files.clone());
2078+
let (entry, h1, opts1, _) = fs.create(&ctx, ROOT_ID, &name, createin).unwrap();
2079+
assert!(opts1.contains(OpenOptions::PASSTHROUGH));
2080+
assert!(!fs
2081+
.init(FsOptions::empty())
2082+
.unwrap()
2083+
.contains(FsOptions::PASSTHROUGH));
2084+
// A new file doesn't pass through.
2085+
let other = CString::new("other").unwrap();
2086+
let (_, _, opts_other, id_other) = fs.create(&ctx, ROOT_ID, &other, createin).unwrap();
2087+
assert!(!opts_other.contains(OpenOptions::PASSTHROUGH));
2088+
assert_eq!(id_other, None);
2089+
assert_eq!(files.calls.load(Ordering::Relaxed), 1);
2090+
// An inode with a handle from before still shares its id, because the kernel fails
2091+
// other opens of it.
2092+
let (h2, opts2, id2) = fs
2093+
.open(&ctx, entry.inode, libc::O_RDONLY as u32, 0)
2094+
.unwrap();
2095+
assert!(opts2.contains(OpenOptions::PASSTHROUGH));
2096+
assert_eq!(id2, Some(3));
2097+
fs.release(&ctx, entry.inode, 0, h1.unwrap(), false, false, None)
2098+
.unwrap();
2099+
assert!(files.closed.lock().unwrap().is_empty());
2100+
fs.release(&ctx, entry.inode, 0, h2.unwrap(), false, false, None)
2101+
.unwrap();
2102+
assert_eq!(*files.closed.lock().unwrap(), vec![3]);
2103+
20742104
// EPERM turns passthrough off, so the next open doesn't try again.
20752105
let tmpdir = TempDir::new().unwrap();
20762106
let files = Files::new(vec![Err(io::Error::from_raw_os_error(libc::EPERM))]);

‎crates/fuse-backend-passthrough/src/sync_io.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,10 @@ impl<S: BitmapSlice + Send + Sync> FileSystem for PassthroughFs<S> {
749749
self.perfile_dax.store(true, Ordering::Relaxed);
750750
}
751751

752+
// A takeover can call init() again with other options, so passthrough stays on only if
753+
// this negotiation enables it again.
754+
#[cfg(target_os = "linux")]
755+
self.passthrough.store(false, Ordering::Relaxed);
752756
#[cfg(target_os = "linux")]
753757
if self.kernel_passthrough.is_some() && capable.contains(FsOptions::PASSTHROUGH) {
754758
// The kernel ignores FUSE_PASSTHROUGH along with FUSE_WRITEBACK_CACHE, and needs open

0 commit comments

Comments
 (0)