Skip to content

Commit fcd6306

Browse files
committed
Rust: Fs: Ramfs in rust
This is still in a early stage. The ultimate goal is to write a complete ram fs in rust. Current status: We can register and mount the fs, and read write some predefined files in the root folder. Signed-off-by: Fox Chen <[email protected]>
1 parent dfaa42f commit fcd6306

File tree

9 files changed

+533
-2
lines changed

9 files changed

+533
-2
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ KBUILD_RUSTCFLAGS := --emit=dep-info,obj,metadata --edition=2018 \
524524
-Cpanic=abort -Cembed-bitcode=n -Clto=n -Crpath=n \
525525
-Cforce-unwind-tables=n -Ccodegen-units=1 \
526526
-Zbinary_dep_depinfo=y -Zsymbol-mangling-version=v0 \
527-
-D unsafe_op_in_unsafe_fn
527+
-D unsafe_op_in_unsafe_fn -Zmacro-backtrace
528528
KBUILD_AFLAGS_KERNEL :=
529529
KBUILD_CFLAGS_KERNEL :=
530530
KBUILD_RUSTCFLAGS_KERNEL :=

rust/kernel/fs.rs

+345
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! File System Interfaces.
4+
5+
use super::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable};
6+
use crate::bindings::{
7+
dentry, file, file_operations, file_system_type, inode, mount_bdev, mount_nodev, mount_single,
8+
register_filesystem, super_block, unregister_filesystem,
9+
};
10+
use crate::str::*;
11+
use crate::{c_str, c_types, error::Error, Result, ThisModule};
12+
use alloc::boxed::Box;
13+
use alloc::vec::Vec;
14+
use core::ptr;
15+
16+
pub const S_IRWXU: i32 = crate::bindings::S_IRWXU as i32;
17+
pub const S_IRUSR: i32 = crate::bindings::S_IRUSR as i32;
18+
pub const S_IWUSR: i32 = crate::bindings::S_IWUSR as i32;
19+
pub const S_IXUSR: i32 = crate::bindings::S_IXUSR as i32;
20+
pub const S_IRWXG: i32 = crate::bindings::S_IRWXG as i32;
21+
pub const S_IRGRP: i32 = crate::bindings::S_IRGRP as i32;
22+
pub const S_IWGRP: i32 = crate::bindings::S_IWGRP as i32;
23+
pub const S_IXGRP: i32 = crate::bindings::S_IXGRP as i32;
24+
pub const S_IRWXO: i32 = crate::bindings::S_IRWXO as i32;
25+
pub const S_IROTH: i32 = crate::bindings::S_IROTH as i32;
26+
pub const S_IWOTH: i32 = crate::bindings::S_IWOTH as i32;
27+
pub const S_IXOTH: i32 = crate::bindings::S_IXOTH as i32;
28+
29+
unsafe extern "C" fn mount_callback<T: FileSystem>(
30+
fs_type: *mut file_system_type,
31+
flags: c_types::c_int,
32+
dev_name: *const c_types::c_char,
33+
data: *mut c_types::c_void,
34+
) -> *mut dentry {
35+
let r_fs_type = FSType::from_c_fs_type(fs_type).unwrap();
36+
let r_dev_name = if dev_name.is_null() {
37+
c_str!("")
38+
} else {
39+
unsafe { CStr::from_char_ptr(dev_name) }
40+
};
41+
let r_data = if data.is_null() {
42+
c_str!("")
43+
} else {
44+
unsafe { CStr::from_char_ptr(data as *const c_types::c_char) }
45+
};
46+
47+
let rt: Result<Dentry> = match T::MOUNT_TYPE {
48+
MountType::Custom => T::mount(&r_fs_type, flags, r_dev_name, r_data),
49+
MountType::Single => Dentry::from_c_dentry(unsafe {
50+
mount_single(fs_type, flags, data, Some(fill_super_callback::<T>))
51+
}),
52+
MountType::BDev => Dentry::from_c_dentry(unsafe {
53+
mount_bdev(
54+
fs_type,
55+
flags,
56+
dev_name,
57+
data,
58+
Some(fill_super_callback::<T>),
59+
)
60+
}),
61+
MountType::NoDev => Dentry::from_c_dentry(unsafe {
62+
mount_nodev(fs_type, flags, data, Some(fill_super_callback::<T>))
63+
}),
64+
};
65+
66+
if let Err(e) = rt {
67+
//TODO wrap ETR_PTR
68+
return e.to_kernel_errno() as *mut dentry;
69+
}
70+
71+
rt.unwrap().to_c_dentry()
72+
}
73+
74+
unsafe extern "C" fn fill_super_callback<T: FileSystem>(
75+
sb: *mut super_block,
76+
data: *mut c_types::c_void,
77+
silent: c_types::c_int,
78+
) -> c_types::c_int {
79+
let r_sb_rs = SuperBlock::from_c_super_block(sb);
80+
if let Err(e) = r_sb_rs {
81+
return e.to_kernel_errno();
82+
}
83+
84+
let mut r_sb = r_sb_rs.unwrap();
85+
let r_data = if data.is_null() {
86+
c_str!("")
87+
} else {
88+
unsafe { CStr::from_char_ptr(data as *const c_types::c_char) }
89+
};
90+
91+
let rs = T::fill_super(&mut r_sb, r_data, silent as i32);
92+
if let Err(e) = rs {
93+
return e.to_kernel_errno();
94+
}
95+
96+
0
97+
}
98+
99+
unsafe extern "C" fn kill_sb_callback<T: FileSystem>(sb: *mut super_block) {
100+
let r_sb_rs = SuperBlock::from_c_super_block(sb);
101+
102+
if let Ok(r_sb) = r_sb_rs {
103+
T::kill_sb(&r_sb);
104+
}
105+
}
106+
107+
pub struct Dentry {
108+
c_dentry: *mut dentry,
109+
}
110+
111+
impl Dentry {
112+
pub fn default() -> Dentry {
113+
Dentry {
114+
c_dentry: ptr::null_mut(),
115+
}
116+
}
117+
118+
pub fn from_c_dentry(c_dentry: *mut dentry) -> Result<Self> {
119+
if c_dentry.is_null() {
120+
return Err(Error::EINVAL);
121+
}
122+
123+
//TODO inc refcnt, and dec in dtor
124+
let mut d = Dentry::default();
125+
d.c_dentry = c_dentry;
126+
127+
Ok(d)
128+
}
129+
130+
pub fn to_c_dentry(&self) -> *mut dentry {
131+
return self.c_dentry;
132+
}
133+
}
134+
135+
pub struct Inode {
136+
c_inode: *mut inode,
137+
}
138+
139+
impl Inode {
140+
pub fn default() -> Inode {
141+
Inode {
142+
c_inode: ptr::null_mut(),
143+
}
144+
}
145+
146+
pub fn from_c_inode(c_inode: *mut inode) -> Result<Self> {
147+
if c_inode.is_null() {
148+
return Err(Error::EINVAL);
149+
}
150+
151+
//TODO inc refcnt, and dec in dtor
152+
let mut i = Inode::default();
153+
i.c_inode = c_inode;
154+
155+
Ok(i)
156+
}
157+
158+
pub fn to_c_inode(&self) -> *mut inode {
159+
return self.c_inode;
160+
}
161+
}
162+
163+
pub struct SuperBlock {
164+
c_sb: *mut super_block,
165+
}
166+
167+
impl SuperBlock {
168+
pub fn default() -> SuperBlock {
169+
SuperBlock {
170+
c_sb: ptr::null_mut(),
171+
}
172+
}
173+
174+
pub fn from_c_super_block(c_sb: *mut super_block) -> Result<Self> {
175+
if c_sb.is_null() {
176+
return Err(Error::EINVAL);
177+
}
178+
179+
let mut sb = SuperBlock::default();
180+
sb.c_sb = c_sb;
181+
182+
Ok(sb)
183+
}
184+
185+
pub fn to_c_super_block(&mut self) -> *mut super_block {
186+
self.c_sb
187+
}
188+
}
189+
190+
pub struct FSType {
191+
c_fs_type: *mut file_system_type,
192+
}
193+
194+
impl FSType {
195+
pub fn default() -> FSType {
196+
FSType {
197+
c_fs_type: ptr::null_mut(),
198+
}
199+
}
200+
201+
pub fn from_c_fs_type(c_fs_type: *mut file_system_type) -> Result<Self> {
202+
if c_fs_type.is_null() {
203+
return Err(Error::EINVAL);
204+
}
205+
206+
let mut fs_type = FSType::default();
207+
fs_type.c_fs_type = c_fs_type;
208+
209+
Ok(fs_type)
210+
}
211+
212+
pub fn to_c_fs_type(&mut self) -> *mut file_system_type {
213+
self.c_fs_type
214+
}
215+
}
216+
217+
pub enum MountType {
218+
// Call user provided mount function instead of [`fill_super()`]
219+
Custom,
220+
221+
// Mount a filesystem residing on a block device
222+
BDev,
223+
224+
// Mount a filesystem that is not backed by a device
225+
NoDev,
226+
227+
// Mount a filesystem which shares the instance between all mounts
228+
Single,
229+
}
230+
231+
impl<T: FileOpener<()>> FileOpenAdapter for T {
232+
type Arg = ();
233+
234+
unsafe fn convert(_inode: *mut inode, _file: *mut file) -> *const Self::Arg {
235+
&()
236+
}
237+
}
238+
239+
pub fn build_fops<A: FileOpenAdapter, T: FileOpener<A::Arg>>() -> &'static file_operations {
240+
return unsafe { FileOperationsVtable::<A, T>::build() };
241+
}
242+
243+
// export tree_descr
244+
pub use crate::bindings::tree_descr;
245+
246+
#[macro_export]
247+
macro_rules! treedescr {
248+
(
249+
$($name:literal,$ops:ident,$mode:expr;)+
250+
) => {
251+
{
252+
let mut v = Vec::<tree_descr>::new();
253+
254+
// Because the root inode is 1, the files array must not contain an
255+
// entry at index 1. We make them start at index 2.
256+
v.push(tree_descr::default()); // index 0 skipped
257+
v.push(tree_descr::default()); // index 1 skipped
258+
259+
$(
260+
let mut tdesc = tree_descr::default();
261+
tdesc.name = c_str!($name).as_char_ptr();
262+
tdesc.ops = build_fops::<$ops, $ops>();
263+
tdesc.mode = $mode;
264+
265+
v.push(tdesc);
266+
)+
267+
268+
// Add ending mark
269+
let mut tdesc = tree_descr::default();
270+
tdesc.name = c_str!("").as_char_ptr();
271+
v.push(tdesc);
272+
273+
v
274+
}
275+
};
276+
() => {
277+
{
278+
let mut v = Vec::<tree_descr>::new();
279+
280+
let mut tdesc = tree_descr::default();
281+
tdesc.name = c_str!("").as_char_ptr();
282+
283+
v.push(tdesc);
284+
v
285+
}
286+
};
287+
}
288+
289+
pub fn simple_fill_super(sb: &mut SuperBlock, magic: usize, vec: &Vec<tree_descr>) -> Result<()> {
290+
let rt = unsafe {
291+
crate::bindings::simple_fill_super(
292+
sb.to_c_super_block(),
293+
magic as c_types::c_ulong,
294+
vec.as_ptr(),
295+
)
296+
};
297+
if rt != 0 {
298+
return Err(Error::from_kernel_errno(rt));
299+
}
300+
301+
Ok(())
302+
}
303+
304+
pub type FSHandle = Box<file_system_type>;
305+
306+
pub trait FileSystem: Sized + Sync {
307+
const MOUNT_TYPE: MountType;
308+
309+
fn mount(_fs_type: &FSType, _flags: i32, _dev_name: &CStr, _data: &CStr) -> Result<Dentry> {
310+
Err(Error::EINVAL)
311+
}
312+
313+
fn fill_super(_sb: &mut SuperBlock, _data: &CStr, _silent: i32) -> Result<()> {
314+
Err(Error::EINVAL)
315+
}
316+
317+
fn kill_sb(_sb: &SuperBlock) {}
318+
319+
fn register_self(name: &'static CStr, owner: &ThisModule) -> Result<FSHandle>
320+
where
321+
Self: Sized,
322+
{
323+
let mut c_fs_type = Box::new(file_system_type::default());
324+
c_fs_type.mount = Some(mount_callback::<Self>);
325+
c_fs_type.kill_sb = Some(kill_sb_callback::<Self>);
326+
c_fs_type.owner = owner.0;
327+
c_fs_type.name = name.as_char_ptr();
328+
329+
let err = unsafe { register_filesystem(c_fs_type.as_mut() as *mut _) };
330+
if err != 0 {
331+
return Err(Error::from_kernel_errno(err));
332+
}
333+
334+
Ok(c_fs_type)
335+
}
336+
337+
fn unregister_self(c_fs_type: &mut FSHandle) -> Result<()> {
338+
let err = unsafe { unregister_filesystem(c_fs_type.as_mut() as *mut _) };
339+
if err != 0 {
340+
return Err(Error::from_kernel_errno(err));
341+
}
342+
343+
Ok(())
344+
}
345+
}

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub mod chrdev;
4848
mod error;
4949
pub mod file;
5050
pub mod file_operations;
51+
pub mod fs;
5152
pub mod miscdev;
5253
pub mod pages;
5354
pub mod str;

rust/kernel/prelude.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use alloc::{borrow::ToOwned, string::String};
1515

1616
pub use super::build_assert;
1717

18-
pub use macros::{module, module_misc_device};
18+
pub use macros::{module, module_fs, module_misc_device};
1919

2020
pub use super::{pr_alert, pr_crit, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
2121

0 commit comments

Comments
 (0)