starnix_modules_erofs/
lib.rs1use fidl_fuchsia_erofs::{ErofsMarker, ErofsServeRequest};
6use fidl_fuchsia_io as fio;
7use fuchsia_component::client::connect_to_protocol_sync;
8use starnix_core::fs::fuchsia::RemoteFs;
9use starnix_core::mm::ProtectionFlags;
10use starnix_core::task::CurrentTask;
11use starnix_core::vfs::{CacheMode, FileSystem, FileSystemHandle, FileSystemOptions};
12use starnix_logging::{impossible_error, log_error, log_info};
13use starnix_uapi::errors::Errno;
14use starnix_uapi::mount_flags::FileSystemFlags;
15use starnix_uapi::open_flags::OpenFlags;
16use starnix_uapi::{errno, from_status_like_fdio};
17use std::sync::atomic::Ordering;
18use zx::{MonotonicInstant, VmoChildOptions};
19
20pub fn new_fs(
21 current_task: &CurrentTask,
22 options: FileSystemOptions,
23) -> Result<FileSystemHandle, Errno> {
24 let kernel = current_task.kernel();
25
26 if !options.flags.load(Ordering::Relaxed).contains(FileSystemFlags::RDONLY) {
28 return Err(errno!(EROFS));
29 }
30
31 let fsoffset = options.params.get_as::<u64>(b"fsoffset")?;
32
33 let source_device = current_task.open_file(options.source.as_ref(), OpenFlags::RDONLY)?;
34 let memory = source_device.get_memory(current_task, None, ProtectionFlags::READ)?;
35 let backing_vmo = memory
36 .as_vmo()
37 .ok_or_else(|| errno!(EINVAL))?
38 .duplicate_handle(zx::Rights::SAME_RIGHTS)
39 .map_err(impossible_error)?;
40
41 let backing_vmo = match fsoffset {
42 None => {
43 log_info!("mounting erofs image source={:?}", options.source);
44 backing_vmo
45 }
46 Some(fsoffset) if fsoffset > 0 => {
47 let page_size = zx::system_get_page_size() as u64;
48 if fsoffset % page_size != 0 {
49 log_error!("fsoffset {} is not page-aligned (page size {})", fsoffset, page_size);
50 return Err(errno!(EINVAL));
51 }
52 let vmo_size = backing_vmo.get_size().map_err(impossible_error)?;
53 let clone_len = vmo_size.checked_sub(fsoffset).ok_or_else(|| {
54 log_error!("fsoffset {} exceeds vmo size {}", fsoffset, vmo_size);
55 errno!(EINVAL)
56 })?;
57 log_info!("mounting erofs image with fsoffset={}, len={}", fsoffset, clone_len);
58 backing_vmo.create_child(VmoChildOptions::SLICE, fsoffset, clone_len).map_err(|e| {
59 log_error!("Failed to create child VMO slice for fsoffset {}: {:?}", fsoffset, e);
60 errno!(EINVAL)
61 })?
62 }
63 Some(_) => {
64 log_info!("mounting erofs image with fsoffset of zero");
65 backing_vmo
66 }
67 };
68
69 let erofs_provider = connect_to_protocol_sync::<ErofsMarker>().map_err(|_| errno!(ENOENT))?;
70
71 let (root_client, root_server) = fidl::endpoints::create_endpoints();
72 erofs_provider
73 .serve(
74 ErofsServeRequest {
75 backing_vmo: Some(backing_vmo),
76 root: Some(root_server),
77 ..Default::default()
78 },
79 MonotonicInstant::INFINITE,
80 )
81 .map_err(|e| {
82 log_error!("FIDL error on Erofs.Serve: {e:?}");
83 errno!(EIO)
84 })?
85 .map_err(|e| {
86 log_error!("Erofs.Serve failed: {e:?}");
87 from_status_like_fdio!(zx::Status::err_from_raw(e))
88 })?;
89
90 let (remotefs, root_node, info, node_id) =
91 RemoteFs::new(root_client.into_channel(), fio::PERM_READABLE, "erofs")?;
92
93 let fs =
94 FileSystem::new(kernel, CacheMode::Cached(kernel.fs_cache_config()), remotefs, options)?;
95
96 fs.create_root_with_info(node_id, root_node, info);
97
98 Ok(fs)
99}