Skip to content

Commit 86a46d6

Browse files
eryugeybergwolf
authored andcommitted
linux_session: support set fusermount binary
Use fusermount3 by default, and could set binary path to fusermount if needed. Signed-off-by: Eryu Guan <[email protected]>
1 parent f4293a9 commit 86a46d6

File tree

1 file changed

+48
-16
lines changed

1 file changed

+48
-16
lines changed

src/transport/fusedev/linux_session.rs

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const POLL_EVENTS_CAPACITY: usize = 1024;
3737

3838
const FUSE_DEVICE: &str = "/dev/fuse";
3939
const FUSE_FSTYPE: &str = "fuse";
40+
const FUSERMOUNT_BIN: &str = "fusermount3";
4041

4142
const EXIT_FUSE_EVENT: Token = Token(0);
4243
const FUSE_DEV_EVENT: Token = Token(1);
@@ -54,6 +55,8 @@ pub struct FuseSession {
5455
wakers: Mutex<Vec<Arc<Waker>>>,
5556
auto_unmount: bool,
5657
target_mntns: Option<libc::pid_t>,
58+
// fusermount binary, default to fusermount3
59+
fusermount: String,
5760
}
5861

5962
impl FuseSession {
@@ -93,6 +96,7 @@ impl FuseSession {
9396
wakers: Mutex::new(Vec::new()),
9497
auto_unmount,
9598
target_mntns: None,
99+
fusermount: FUSERMOUNT_BIN.to_string(),
96100
})
97101
}
98102

@@ -102,6 +106,16 @@ impl FuseSession {
102106
self.target_mntns = pid;
103107
}
104108

109+
/// Set fusermount binary, default to fusermount3.
110+
pub fn set_fusermount(&mut self, bin: &str) {
111+
self.fusermount = bin.to_string();
112+
}
113+
114+
/// Get current fusermount binary.
115+
pub fn get_fusermount(&self) -> &str {
116+
self.fusermount.as_str()
117+
}
118+
105119
/// Mount the fuse mountpoint, building connection with the in kernel fuse driver.
106120
pub fn mount(&mut self) -> Result<()> {
107121
let mut flags = MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOATIME;
@@ -115,6 +129,7 @@ impl FuseSession {
115129
flags,
116130
self.auto_unmount,
117131
self.target_mntns,
132+
&self.fusermount,
118133
)?;
119134

120135
fcntl(file.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))
@@ -138,10 +153,10 @@ impl FuseSession {
138153
/// Destroy a fuse session.
139154
pub fn umount(&mut self) -> Result<()> {
140155
// If we have a keep_alive socket, just drop it,
141-
// and let fusermount3 do the unmount.
156+
// and let fusermount do the unmount.
142157
if let (None, Some(file)) = (self.keep_alive.take(), self.file.take()) {
143158
if let Some(mountpoint) = self.mountpoint.to_str() {
144-
fuse_kern_umount(mountpoint, file)
159+
fuse_kern_umount(mountpoint, file, self.fusermount.as_str())
145160
} else {
146161
Err(SessionFailure("invalid mountpoint".to_string()))
147162
}
@@ -356,6 +371,7 @@ fn fuse_kern_mount(
356371
flags: MsFlags,
357372
auto_unmount: bool,
358373
target_mntns: Option<libc::pid_t>,
374+
fusermount: &str,
359375
) -> Result<(File, Option<UnixStream>)> {
360376
let file = OpenOptions::new()
361377
.create(false)
@@ -390,7 +406,7 @@ fn fuse_kern_mount(
390406
);
391407
}
392408

393-
// mount in another mntns requires mounting with fusermount3, which is a new process, as
409+
// mount in another mntns requires mounting with fusermount, which is a new process, as
394410
// multithreaded program is not allowed to join to another mntns, and the process running fuse
395411
// session might be multithreaded.
396412
if auto_unmount || target_mntns.is_some() {
@@ -402,6 +418,7 @@ fn fuse_kern_mount(
402418
flags,
403419
auto_unmount,
404420
target_mntns,
421+
fusermount,
405422
)
406423
} else {
407424
match mount(
@@ -420,6 +437,7 @@ fn fuse_kern_mount(
420437
flags,
421438
auto_unmount,
422439
target_mntns,
440+
fusermount,
423441
),
424442
Err(e) => Err(SessionFailure(format!(
425443
"failed to mount {mountpoint:?}: {e}"
@@ -450,6 +468,7 @@ fn msflags_to_string(flags: MsFlags) -> String {
450468
}
451469

452470
/// Mount a fuse file system with fusermount
471+
#[allow(clippy::too_many_arguments)]
453472
fn fuse_fusermount_mount(
454473
mountpoint: &Path,
455474
fsname: &str,
@@ -458,6 +477,7 @@ fn fuse_fusermount_mount(
458477
flags: MsFlags,
459478
auto_unmount: bool,
460479
target_mntns: Option<libc::pid_t>,
480+
fusermount: &str,
461481
) -> Result<(File, Option<UnixStream>)> {
462482
let mut opts = vec![format!("fsname={fsname}"), opts, msflags_to_string(flags)];
463483
if !subtype.is_empty() {
@@ -470,10 +490,10 @@ fn fuse_fusermount_mount(
470490

471491
let (send, recv) = UnixStream::pair().unwrap();
472492

473-
// Keep the sending socket around after exec to pass to fusermount3.
474-
// When its partner recv closes, fusermount3 will unmount.
493+
// Keep the sending socket around after exec to pass to fusermount.
494+
// When its partner recv closes, fusermount will unmount.
475495
// Remove the close-on-exec flag from the socket, so we can pass it to
476-
// fusermount3.
496+
// fusermount.
477497
nix::fcntl::fcntl(send.as_raw_fd(), FcntlArg::F_SETFD(FdFlag::empty()))
478498
.map_err(|e| SessionFailure(format!("Failed to remove close-on-exec flag: {e}")))?;
479499

@@ -483,10 +503,10 @@ fn fuse_fusermount_mount(
483503
c.arg("-t")
484504
.arg(format!("{}", pid))
485505
.arg("-m")
486-
.arg("fusermount3");
506+
.arg(fusermount);
487507
c
488508
}
489-
None => std::process::Command::new("fusermount3"),
509+
None => std::process::Command::new(fusermount),
490510
};
491511
// Old version of fusermount doesn't support long --options, yet.
492512
let mut proc = cmd
@@ -507,7 +527,7 @@ fn fuse_fusermount_mount(
507527
Some(0) => {}
508528
exit_code => {
509529
return Err(SessionFailure(format!(
510-
"Unexpected exit code when running fusermount3: {exit_code:?}"
530+
"Unexpected exit code when running fusermount: {exit_code:?}"
511531
)))
512532
}
513533
}
@@ -517,20 +537,20 @@ fn fuse_fusermount_mount(
517537
match vmm_sys_util::sock_ctrl_msg::ScmSocket::recv_with_fd(&recv, &mut [0u8; 8]).map_err(
518538
|e| {
519539
SessionFailure(format!(
520-
"Unexpected error when receiving fuse file descriptor from fusermount3: {}",
540+
"Unexpected error when receiving fuse file descriptor from fusermount: {}",
521541
e
522542
))
523543
},
524544
)? {
525545
(_recv_bytes, Some(file)) => Ok((file, if auto_unmount { Some(recv) } else { None })),
526546
(recv_bytes, None) => Err(SessionFailure(format!(
527-
"fusermount3 did not send a file descriptor. We received {recv_bytes} bytes."
547+
"fusermount did not send a file descriptor. We received {recv_bytes} bytes."
528548
))),
529549
}
530550
}
531551

532552
/// Umount a fuse file system
533-
fn fuse_kern_umount(mountpoint: &str, file: File) -> Result<()> {
553+
fn fuse_kern_umount(mountpoint: &str, file: File, fusermount: &str) -> Result<()> {
534554
let mut fds = [PollFd::new(file.as_raw_fd(), PollFlags::empty())];
535555

536556
if poll(&mut fds, 0).is_ok() {
@@ -548,16 +568,16 @@ fn fuse_kern_umount(mountpoint: &str, file: File) -> Result<()> {
548568
drop(file);
549569
match umount2(mountpoint, MntFlags::MNT_DETACH) {
550570
Ok(()) => Ok(()),
551-
Err(nix::errno::Errno::EPERM) => fuse_fusermount3_umount(mountpoint),
571+
Err(nix::errno::Errno::EPERM) => fuse_fusermount_umount(mountpoint, fusermount),
552572
Err(e) => Err(SessionFailure(format!(
553573
"failed to umount {mountpoint}: {e}"
554574
))),
555575
}
556576
}
557577

558578
/// Umount a fuse file system
559-
fn fuse_fusermount3_umount(mountpoint: &str) -> Result<()> {
560-
match std::process::Command::new("fusermount3")
579+
fn fuse_fusermount_umount(mountpoint: &str, fusermount: &str) -> Result<()> {
580+
match std::process::Command::new(fusermount)
561581
.arg("--unmount")
562582
.arg("--quiet")
563583
.arg("--lazy")
@@ -569,7 +589,7 @@ fn fuse_fusermount3_umount(mountpoint: &str) -> Result<()> {
569589
{
570590
Some(0) => Ok(()),
571591
exit_code => Err(SessionFailure(format!(
572-
"Unexpected exit code when unmounting via running fusermount3: {exit_code:?}"
592+
"Unexpected exit code when unmounting via running fusermount: {exit_code:?}"
573593
))),
574594
}
575595
}
@@ -598,6 +618,18 @@ mod tests {
598618
let file = unsafe { File::from_raw_fd(fd) };
599619
let _ = FuseChannel::new(file, 3).unwrap();
600620
}
621+
622+
#[test]
623+
fn test_fusermount() {
624+
let dir = TempDir::new().unwrap();
625+
let se = FuseSession::new(dir.as_path(), "foo", "bar", true);
626+
assert!(se.is_ok());
627+
let mut se = se.unwrap();
628+
assert_eq!(se.get_fusermount(), FUSERMOUNT_BIN);
629+
630+
se.set_fusermount("fusermount");
631+
assert_eq!(se.get_fusermount(), "fusermount");
632+
}
601633
}
602634

603635
#[cfg(feature = "async_io")]

0 commit comments

Comments
 (0)