Skip to content

Commit d7cfb79

Browse files
committed
rust: fs: introduce FileSystem::read_folio
We also allow the creation of regular file inodes. File systems can now use `read_folio` to expose the file contents via the page cache. Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
1 parent 93d27f3 commit d7cfb79

3 files changed

Lines changed: 122 additions & 23 deletions

File tree

rust/kernel/folio.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ impl LockedFolio<'_> {
6161
/// Callers must ensure that the folio is valid and locked. Additionally, that the
6262
/// responsibility of unlocking is transferred to the new instance of [`LockedFolio`]. Lastly,
6363
/// that the returned [`LockedFolio`] doesn't outlive the refcount that keeps it alive.
64-
#[allow(dead_code)]
6564
pub(crate) unsafe fn from_raw(folio: *const bindings::folio) -> Self {
6665
let ptr = folio.cast();
6766
// SAFETY: The safety requirements ensure that `folio` (from which `ptr` is derived) is

rust/kernel/fs.rs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
99
use crate::error::{code::*, from_result, to_result, Error, Result};
1010
use crate::types::{ARef, AlwaysRefCounted, Either, Opaque};
11-
use crate::{bindings, init::PinInit, str::CStr, time::Timespec, try_pin_init, ThisModule};
11+
use crate::{
12+
bindings, folio::LockedFolio, init::PinInit, str::CStr, time::Timespec, try_pin_init,
13+
ThisModule,
14+
};
1215
use core::{marker::PhantomData, marker::PhantomPinned, mem::ManuallyDrop, pin::Pin, ptr};
1316
use macros::{pin_data, pinned_drop};
1417

@@ -30,6 +33,9 @@ pub trait FileSystem {
3033

3134
/// Returns the inode corresponding to the directory entry with the given name.
3235
fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>>;
36+
37+
/// Reads the contents of the inode into the given folio.
38+
fn read_folio(inode: &INode<Self>, folio: LockedFolio<'_>) -> Result;
3339
}
3440

3541
/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -68,6 +74,7 @@ impl From<INodeType> for DirEntryType {
6874
fn from(value: INodeType) -> Self {
6975
match value {
7076
INodeType::Dir => DirEntryType::Dir,
77+
INodeType::Reg => DirEntryType::Reg,
7178
}
7279
}
7380
}
@@ -220,6 +227,15 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
220227
inode.i_op = &Tables::<T>::DIR_INODE_OPERATIONS;
221228
bindings::S_IFDIR
222229
}
230+
INodeType::Reg => {
231+
// SAFETY: `generic_ro_fops` never changes, it's safe to reference it.
232+
inode.__bindgen_anon_3.i_fop = unsafe { &bindings::generic_ro_fops };
233+
inode.i_data.a_ops = &Tables::<T>::FILE_ADDRESS_SPACE_OPERATIONS;
234+
235+
// SAFETY: The `i_mapping` pointer doesn't change and is valid.
236+
unsafe { bindings::mapping_set_large_folios(inode.i_mapping) };
237+
bindings::S_IFREG
238+
}
223239
};
224240

225241
inode.i_mode = (params.mode & 0o777) | u16::try_from(mode)?;
@@ -256,6 +272,9 @@ impl<T: FileSystem + ?Sized> Drop for NewINode<T> {
256272
pub enum INodeType {
257273
/// Directory type.
258274
Dir,
275+
276+
/// Regular file type.
277+
Reg,
259278
}
260279

261280
/// Required inode parameters.
@@ -604,6 +623,55 @@ impl<T: FileSystem + ?Sized> Tables<T> {
604623
},
605624
}
606625
}
626+
627+
const FILE_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations =
628+
bindings::address_space_operations {
629+
writepage: None,
630+
read_folio: Some(Self::read_folio_callback),
631+
writepages: None,
632+
dirty_folio: None,
633+
readahead: None,
634+
write_begin: None,
635+
write_end: None,
636+
bmap: None,
637+
invalidate_folio: None,
638+
release_folio: None,
639+
free_folio: None,
640+
direct_IO: None,
641+
migrate_folio: None,
642+
launder_folio: None,
643+
is_partially_uptodate: None,
644+
is_dirty_writeback: None,
645+
error_remove_page: None,
646+
swap_activate: None,
647+
swap_deactivate: None,
648+
swap_rw: None,
649+
};
650+
651+
extern "C" fn read_folio_callback(
652+
_file: *mut bindings::file,
653+
folio: *mut bindings::folio,
654+
) -> i32 {
655+
from_result(|| {
656+
// SAFETY: All pointers are valid and stable.
657+
let inode = unsafe {
658+
&*(*(*folio)
659+
.__bindgen_anon_1
660+
.page
661+
.__bindgen_anon_1
662+
.__bindgen_anon_1
663+
.mapping)
664+
.host
665+
.cast::<INode<T>>()
666+
};
667+
668+
// SAFETY: The C contract guarantees that the folio is valid and locked, with ownership
669+
// of the lock transferred to the callee (this function). The folio is also guaranteed
670+
// not to outlive this function.
671+
T::read_folio(inode, unsafe { LockedFolio::from_raw(folio) })?;
672+
Ok(0)
673+
})
674+
}
607675
}
608676

609677
/// Directory entry emitter.
@@ -678,7 +746,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
678746
/// # mod module_ro_fs_sample {
679747
/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock};
680748
/// use kernel::prelude::*;
681-
/// use kernel::{c_str, fs, types::ARef};
749+
/// use kernel::{c_str, folio::LockedFolio, fs, types::ARef};
682750
///
683751
/// kernel::module_fs! {
684752
/// type: MyFs,
@@ -700,6 +768,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
700768
/// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
701769
/// todo!()
702770
/// }
771+
/// fn read_folio(_: &INode<Self>, _: LockedFolio<'_>) -> Result {
772+
/// todo!()
773+
/// }
703774
/// }
704775
/// # }
705776
/// ```

samples/rust/rust_rofs.rs

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use kernel::fs::{
66
DirEmitter, INode, INodeParams, INodeType, NewSuperBlock, SuperBlock, SuperParams,
77
};
88
use kernel::prelude::*;
9-
use kernel::{c_str, fs, time::UNIX_EPOCH, types::ARef, types::Either};
9+
use kernel::{c_str, folio::LockedFolio, fs, time::UNIX_EPOCH, types::ARef, types::Either};
1010

1111
kernel::module_fs! {
1212
type: RoFs,
@@ -20,23 +20,27 @@ struct Entry {
2020
name: &'static [u8],
2121
ino: u64,
2222
etype: INodeType,
23+
contents: &'static [u8],
2324
}
2425

2526
const ENTRIES: [Entry; 3] = [
2627
Entry {
2728
name: b".",
2829
ino: 1,
2930
etype: INodeType::Dir,
31+
contents: b"",
3032
},
3133
Entry {
3234
name: b"..",
3335
ino: 1,
3436
etype: INodeType::Dir,
37+
contents: b"",
3538
},
3639
Entry {
37-
name: b"subdir",
40+
name: b"test.txt",
3841
ino: 2,
39-
etype: INodeType::Dir,
42+
etype: INodeType::Reg,
43+
contents: b"hello\n",
4044
},
4145
];
4246

@@ -95,23 +99,48 @@ impl fs::FileSystem for RoFs {
9599
return Err(ENOENT);
96100
}
97101

98-
match name {
99-
b"subdir" => match parent.super_block().get_or_create_inode(2)? {
100-
Either::Left(existing) => Ok(existing),
101-
Either::Right(new) => new.init(INodeParams {
102-
typ: INodeType::Dir,
103-
mode: 0o555,
104-
size: 0,
105-
blocks: 1,
106-
nlink: 2,
107-
uid: 0,
108-
gid: 0,
109-
atime: UNIX_EPOCH,
110-
ctime: UNIX_EPOCH,
111-
mtime: UNIX_EPOCH,
112-
}),
113-
},
114-
_ => Err(ENOENT),
102+
for e in &ENTRIES {
103+
if name == e.name {
104+
return match parent.super_block().get_or_create_inode(e.ino)? {
105+
Either::Left(existing) => Ok(existing),
106+
Either::Right(new) => new.init(INodeParams {
107+
typ: e.etype,
108+
mode: 0o444,
109+
size: e.contents.len().try_into()?,
110+
blocks: 1,
111+
nlink: 1,
112+
uid: 0,
113+
gid: 0,
114+
atime: UNIX_EPOCH,
115+
ctime: UNIX_EPOCH,
116+
mtime: UNIX_EPOCH,
117+
}),
118+
};
119+
}
115120
}
121+
122+
Err(ENOENT)
123+
}
124+
125+
fn read_folio(inode: &INode<Self>, mut folio: LockedFolio<'_>) -> Result {
126+
let data = match inode.ino() {
127+
2 => ENTRIES[2].contents,
128+
_ => return Err(EINVAL),
129+
};
130+
131+
let pos = usize::try_from(folio.pos()).unwrap_or(usize::MAX);
132+
let copied = if pos >= data.len() {
133+
0
134+
} else {
135+
let to_copy = core::cmp::min(data.len() - pos, folio.size());
136+
folio.write(0, &data[pos..][..to_copy])?;
137+
to_copy
138+
};
139+
140+
folio.zero_out(copied, folio.size() - copied)?;
141+
folio.mark_uptodate();
142+
folio.flush_dcache();
143+
144+
Ok(())
116145
}
117146
}

0 commit comments

Comments
 (0)