From 94da3ddd336a308cc6e1c42d7124c8f417a66597 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Mon, 13 Oct 2025 16:35:20 +0200 Subject: [PATCH] fs: Allow multiple Uhyve mounts at arbitrary paths given by fdt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin Kröning --- src/fs/mod.rs | 13 +++++++++++ src/fs/uhyve.rs | 57 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 78eb630ed4..9b7a9245d3 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -404,6 +404,19 @@ pub fn create_dir(path: &str, mode: AccessPermission) -> io::Result<()> { }) } +/// Creates a directory and creates all missing parent directories as well. +fn create_dir_recursive(path: &str, mode: AccessPermission) -> io::Result<()> { + trace!("create_dir_recursive: {path}"); + create_dir(path, mode).or_else(|errno| { + if errno != Errno::Badf { + return Err(errno); + } + let (parent_path, _file_name) = path.rsplit_once('/').unwrap(); + create_dir_recursive(parent_path, mode)?; + create_dir(path, mode) + }) +} + /// Returns an vector with all the entries within a directory. pub fn readdir(name: &str) -> io::Result> { debug!("Read directory {name}"); diff --git a/src/fs/uhyve.rs b/src/fs/uhyve.rs index 58c0afe607..dce0a4fe58 100644 --- a/src/fs/uhyve.rs +++ b/src/fs/uhyve.rs @@ -1,3 +1,4 @@ +use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::ffi::CString; use alloc::string::{String, ToString}; @@ -14,9 +15,11 @@ use uhyve_interface::parameters::{ use uhyve_interface::{GuestPhysAddr, GuestVirtAddr, Hypercall}; use crate::arch::mm::paging; +use crate::env::fdt; use crate::errno::Errno; use crate::fs::{ self, AccessPermission, FileAttr, NodeKind, ObjectInterface, OpenOption, SeekWhence, VfsNode, + create_dir_recursive, }; use crate::io; use crate::syscalls::interfaces::uhyve::uhyve_hypercall; @@ -229,14 +232,48 @@ impl VfsNode for UhyveDirectory { pub(crate) fn init() { info!("Try to initialize uhyve filesystem"); - let mount_point = hermit_var_or!("UHYVE_MOUNT", "/root").to_string(); - info!("Mounting uhyve filesystem at {mount_point}"); - fs::FILESYSTEM - .get() - .unwrap() - .mount( - &mount_point, - Box::new(UhyveDirectory::new(Some(mount_point.clone()))), - ) - .expect("Mount failed. Duplicate mount_point?"); + let mount_str = fdt().and_then(|fdt| { + fdt.find_node("/uhyve,mounts") + .and_then(|node| node.property("mounts")) + .and_then(|property| property.as_str()) + }); + if let Some(mount_str) = mount_str { + assert_ne!(mount_str.len(), 0, "Invalid /uhyve,mounts node in FDT"); + for mount_point in mount_str.split('\0') { + info!("Mounting uhyve filesystem at {mount_point}"); + + if let Err(errno) = fs::FILESYSTEM.get().unwrap().mount( + mount_point, + Box::new(UhyveDirectory::new(Some(mount_point.to_owned()))), + ) { + assert_eq!(errno, Errno::Badf); + debug!( + "Mounting of {mount_point} failed with {errno:?}. Creating missing parent folders" + ); + let (parent_path, _file_name) = mount_point.rsplit_once('/').unwrap(); + create_dir_recursive(parent_path, AccessPermission::S_IRWXU).unwrap(); + + fs::FILESYSTEM + .get() + .unwrap() + .mount( + mount_point, + Box::new(UhyveDirectory::new(Some(mount_point.to_owned()))), + ) + .unwrap(); + } + } + } else { + // No FDT -> Uhyve legacy mounting (to /root) + let mount_point = hermit_var_or!("UHYVE_MOUNT", "/root").to_string(); + info!("Mounting uhyve filesystem at {mount_point}"); + fs::FILESYSTEM + .get() + .unwrap() + .mount( + &mount_point, + Box::new(UhyveDirectory::new(Some(mount_point.clone()))), + ) + .expect("Mount failed. Duplicate mount_point?"); + } }