mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Add support for mounting OverlayFS
This commit is contained in:
parent
914237e9ca
commit
f38f476c3b
@ -6,6 +6,7 @@ use crate::{
|
|||||||
exfat::{ExfatFS, ExfatMountOptions},
|
exfat::{ExfatFS, ExfatMountOptions},
|
||||||
ext2::Ext2,
|
ext2::Ext2,
|
||||||
fs_resolver::{FsPath, AT_FDCWD},
|
fs_resolver::{FsPath, AT_FDCWD},
|
||||||
|
overlayfs::OverlayFS,
|
||||||
path::Dentry,
|
path::Dentry,
|
||||||
utils::{FileSystem, InodeType},
|
utils::{FileSystem, InodeType},
|
||||||
},
|
},
|
||||||
@ -63,7 +64,7 @@ pub fn sys_mount(
|
|||||||
} else if mount_flags.contains(MountFlags::MS_MOVE) {
|
} else if mount_flags.contains(MountFlags::MS_MOVE) {
|
||||||
do_move_mount_old(devname, dst_dentry, ctx)?;
|
do_move_mount_old(devname, dst_dentry, ctx)?;
|
||||||
} else {
|
} else {
|
||||||
do_new_mount(devname, fstype_addr, dst_dentry, ctx)?;
|
do_new_mount(devname, fstype_addr, dst_dentry, data, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
@ -136,6 +137,7 @@ fn do_new_mount(
|
|||||||
devname: CString,
|
devname: CString,
|
||||||
fs_type: Vaddr,
|
fs_type: Vaddr,
|
||||||
target_dentry: Dentry,
|
target_dentry: Dentry,
|
||||||
|
data: Vaddr,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if target_dentry.type_() != InodeType::Dir {
|
if target_dentry.type_() != InodeType::Dir {
|
||||||
@ -146,32 +148,93 @@ fn do_new_mount(
|
|||||||
if fs_type.is_empty() {
|
if fs_type.is_empty() {
|
||||||
return_errno_with_message!(Errno::EINVAL, "fs_type is empty");
|
return_errno_with_message!(Errno::EINVAL, "fs_type is empty");
|
||||||
}
|
}
|
||||||
let fs = get_fs(fs_type, devname)?;
|
let fs = get_fs(fs_type, devname, data, ctx)?;
|
||||||
target_dentry.mount(fs)?;
|
target_dentry.mount(fs)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the filesystem by fs_type and devname.
|
/// Get the filesystem by fs_type and devname.
|
||||||
fn get_fs(fs_type: CString, devname: CString) -> Result<Arc<dyn FileSystem>> {
|
fn get_fs(
|
||||||
let devname = devname.to_str().unwrap();
|
fs_type: CString,
|
||||||
let device = match aster_block::get_device(devname) {
|
devname: CString,
|
||||||
Some(device) => device,
|
data: Vaddr,
|
||||||
None => return_errno_with_message!(Errno::ENOENT, "Device does not exist"),
|
ctx: &Context,
|
||||||
};
|
) -> Result<Arc<dyn FileSystem>> {
|
||||||
|
let user_space = ctx.user_space();
|
||||||
|
let data = user_space.read_cstring(data, MAX_FILENAME_LEN)?;
|
||||||
|
let data = data.to_string_lossy();
|
||||||
|
|
||||||
let fs_type = fs_type.to_str().unwrap();
|
let fs_type = fs_type.to_str().unwrap();
|
||||||
match fs_type {
|
match fs_type {
|
||||||
"ext2" => {
|
"ext2" => {
|
||||||
|
let device = aster_block::get_device(devname.to_str().unwrap()).ok_or(
|
||||||
|
Error::with_message(Errno::ENOENT, "device for ext2 does not exist"),
|
||||||
|
)?;
|
||||||
let ext2_fs = Ext2::open(device)?;
|
let ext2_fs = Ext2::open(device)?;
|
||||||
Ok(ext2_fs)
|
Ok(ext2_fs)
|
||||||
}
|
}
|
||||||
"exfat" => {
|
"exfat" => {
|
||||||
|
let device = aster_block::get_device(devname.to_str().unwrap()).ok_or(
|
||||||
|
Error::with_message(Errno::ENOENT, "device for exfat does not exist"),
|
||||||
|
)?;
|
||||||
let exfat_fs = ExfatFS::open(device, ExfatMountOptions::default())?;
|
let exfat_fs = ExfatFS::open(device, ExfatMountOptions::default())?;
|
||||||
Ok(exfat_fs)
|
Ok(exfat_fs)
|
||||||
}
|
}
|
||||||
|
"overlay" => {
|
||||||
|
let overlay_fs = create_overlayfs(data.as_ref(), ctx)?;
|
||||||
|
Ok(overlay_fs)
|
||||||
|
}
|
||||||
_ => return_errno_with_message!(Errno::EINVAL, "Invalid fs type"),
|
_ => return_errno_with_message!(Errno::EINVAL, "Invalid fs type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Support read-only mount (no upper) and customized features
|
||||||
|
fn create_overlayfs(data: &str, ctx: &Context) -> Result<Arc<OverlayFS>> {
|
||||||
|
let mut lower = Vec::new();
|
||||||
|
let mut upper = "";
|
||||||
|
let mut work = "";
|
||||||
|
|
||||||
|
for entry in data.split(',') {
|
||||||
|
let mut parts = entry.split('=');
|
||||||
|
match (parts.next(), parts.next()) {
|
||||||
|
// Handle lowerdir, split by ':'
|
||||||
|
(Some("upperdir"), Some(path)) => {
|
||||||
|
if path.is_empty() {
|
||||||
|
return_errno_with_message!(Errno::ENOENT, "upperdir is empty");
|
||||||
|
}
|
||||||
|
upper = path;
|
||||||
|
}
|
||||||
|
(Some("lowerdir"), Some(paths)) => {
|
||||||
|
for path in paths.split(':') {
|
||||||
|
if path.is_empty() {
|
||||||
|
return_errno_with_message!(Errno::ENOENT, "lowerdir is empty");
|
||||||
|
}
|
||||||
|
lower.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some("workdir"), Some(path)) => {
|
||||||
|
if path.is_empty() {
|
||||||
|
return_errno_with_message!(Errno::ENOENT, "workdir is empty");
|
||||||
|
}
|
||||||
|
work = path;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fs = ctx.posix_thread.fs().resolver().read();
|
||||||
|
|
||||||
|
let upper = fs.lookup(&FsPath::new(AT_FDCWD, upper)?)?;
|
||||||
|
let lower = lower
|
||||||
|
.iter()
|
||||||
|
.map(|lower| fs.lookup(&FsPath::new(AT_FDCWD, lower).unwrap()).unwrap())
|
||||||
|
.collect();
|
||||||
|
let work = fs.lookup(&FsPath::new(AT_FDCWD, work)?)?;
|
||||||
|
|
||||||
|
let overlayfs = OverlayFS::new(upper, lower, work)?;
|
||||||
|
Ok(overlayfs)
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct MountFlags: u32 {
|
struct MountFlags: u32 {
|
||||||
const MS_RDONLY = 1 << 0; // Mount read-only.
|
const MS_RDONLY = 1 << 0; // Mount read-only.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user