Skip to content

Commit 31d63a6

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 39dc30f commit 31d63a6

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
}
@@ -223,6 +230,15 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
223230
inode.i_op = &Tables::<T>::DIR_INODE_OPERATIONS;
224231
bindings::S_IFDIR
225232
}
233+
INodeType::Reg => {
234+
// SAFETY: `generic_ro_fops` never changes, it's safe to reference it.
235+
inode.__bindgen_anon_3.i_fop = unsafe { &bindings::generic_ro_fops };
236+
inode.i_data.a_ops = &Tables::<T>::FILE_ADDRESS_SPACE_OPERATIONS;
237+
238+
// SAFETY: The `i_mapping` pointer doesn't change and is valid.
239+
unsafe { bindings::mapping_set_large_folios(inode.i_mapping) };
240+
bindings::S_IFREG
241+
}
226242
};
227243

228244
inode.i_mode = (params.mode & 0o777) | u16::try_from(mode)?;
@@ -259,6 +275,9 @@ impl<T: FileSystem + ?Sized> Drop for NewINode<T> {
259275
pub enum INodeType {
260276
/// Directory type.
261277
Dir,
278+
279+
/// Regular file type.
280+
Reg,
262281
}
263282

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

612680
/// Directory entry emitter.
@@ -692,7 +760,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
692760
/// # mod module_ro_fs_sample {
693761
/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock};
694762
/// use kernel::prelude::*;
695-
/// use kernel::{c_str, fs, types::ARef};
763+
/// use kernel::{c_str, folio::LockedFolio, fs, types::ARef};
696764
///
697765
/// kernel::module_fs! {
698766
/// type: MyFs,
@@ -714,6 +782,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
714782
/// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
715783
/// todo!()
716784
/// }
785+
/// fn read_folio(_: &INode<Self>, _: LockedFolio<'_>) -> Result {
786+
/// todo!()
787+
/// }
717788
/// }
718789
/// # }
719790
/// ```

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)