Skip to content

Commit 1cf6e5e

Browse files
committed
rust: fs: add per-superblock data
Allow Rust file systems to associate [typed] data to super blocks when they're created. Since we only have a pointer-sized field in which to store the state, it must implement the `ForeignOwnable` trait. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 6032d93 commit 1cf6e5e

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

rust/kernel/fs.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
88
99
use crate::error::{code::*, from_result, to_result, Error, Result};
10-
use crate::types::{ARef, AlwaysRefCounted, Either, Opaque};
10+
use crate::types::{ARef, AlwaysRefCounted, Either, ForeignOwnable, Opaque};
1111
use crate::{
1212
bindings, folio::LockedFolio, init::PinInit, str::CStr, time::Timespec, try_pin_init,
1313
ThisModule,
@@ -20,11 +20,14 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
2020

2121
/// A file system type.
2222
pub trait FileSystem {
23+
/// Data associated with each file system instance (super-block).
24+
type Data: ForeignOwnable + Send + Sync;
25+
2326
/// The name of the file system type.
2427
const NAME: &'static CStr;
2528

2629
/// Returns the parameters to initialise a super block.
27-
fn super_params(sb: &NewSuperBlock<Self>) -> Result<SuperParams>;
30+
fn super_params(sb: &NewSuperBlock<Self>) -> Result<SuperParams<Self::Data>>;
2831

2932
/// Initialises and returns the root inode of the given superblock.
3033
///
@@ -174,7 +177,7 @@ impl Registration {
174177
fs.owner = module.0;
175178
fs.name = T::NAME.as_char_ptr();
176179
fs.init_fs_context = Some(Self::init_fs_context_callback::<T>);
177-
fs.kill_sb = Some(Self::kill_sb_callback);
180+
fs.kill_sb = Some(Self::kill_sb_callback::<T>);
178181
fs.fs_flags = 0;
179182

180183
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -195,10 +198,22 @@ impl Registration {
195198
})
196199
}
197200

198-
unsafe extern "C" fn kill_sb_callback(sb_ptr: *mut bindings::super_block) {
201+
unsafe extern "C" fn kill_sb_callback<T: FileSystem + ?Sized>(
202+
sb_ptr: *mut bindings::super_block,
203+
) {
199204
// SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
200205
// the appropriate function to call for cleanup.
201206
unsafe { bindings::kill_anon_super(sb_ptr) };
207+
208+
// SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
209+
let ptr = unsafe { (*sb_ptr).s_fs_info };
210+
if !ptr.is_null() {
211+
// SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
212+
// it's initialised with the result of an `into_foreign` call. We checked above that
213+
// `ptr` is non-null because it would be null if we never reached the point where we
214+
// init the field.
215+
unsafe { T::Data::from_foreign(ptr) };
216+
}
202217
}
203218
}
204219

@@ -429,6 +444,14 @@ pub struct INodeParams {
429444
pub struct SuperBlock<T: FileSystem + ?Sized>(Opaque<bindings::super_block>, PhantomData<T>);
430445

431446
impl<T: FileSystem + ?Sized> SuperBlock<T> {
447+
/// Returns the data associated with the superblock.
448+
pub fn data(&self) -> <T::Data as ForeignOwnable>::Borrowed<'_> {
449+
// SAFETY: This method is only available after the `NeedsData` typestate, so `s_fs_info`
450+
// has been initialised initialised with the result of a call to `T::into_foreign`.
451+
let ptr = unsafe { (*self.0.get()).s_fs_info };
452+
unsafe { T::Data::borrow(ptr) }
453+
}
454+
432455
/// Tries to get an existing inode or create a new one if it doesn't exist yet.
433456
pub fn get_or_create_inode(&self, ino: Ino) -> Result<Either<ARef<INode<T>>, NewINode<T>>> {
434457
// SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -458,7 +481,7 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
458481
/// Required superblock parameters.
459482
///
460483
/// This is returned by implementations of [`FileSystem::super_params`].
461-
pub struct SuperParams {
484+
pub struct SuperParams<T: ForeignOwnable + Send + Sync> {
462485
/// The magic number of the superblock.
463486
pub magic: u32,
464487

@@ -472,6 +495,9 @@ pub struct SuperParams {
472495

473496
/// Granularity of c/m/atime in ns (cannot be worse than a second).
474497
pub time_gran: u32,
498+
499+
/// Data to be associated with the superblock.
500+
pub data: T,
475501
}
476502

477503
/// A superblock that is still being initialised.
@@ -522,6 +548,9 @@ impl<T: FileSystem + ?Sized> Tables<T> {
522548
sb.0.s_blocksize = 1 << sb.0.s_blocksize_bits;
523549
sb.0.s_flags |= bindings::SB_RDONLY;
524550

551+
// N.B.: Even on failure, `kill_sb` is called and frees the data.
552+
sb.0.s_fs_info = params.data.into_foreign().cast_mut();
553+
525554
// SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
526555
// newly-created (and initialised above) superblock.
527556
let sb = unsafe { &mut *sb_ptr.cast() };
@@ -934,8 +963,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
934963
///
935964
/// struct MyFs;
936965
/// impl fs::FileSystem for MyFs {
966+
/// type Data = ();
937967
/// const NAME: &'static CStr = c_str!("myfs");
938-
/// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
968+
/// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams<Self::Data>> {
939969
/// todo!()
940970
/// }
941971
/// fn init_root(_sb: &SuperBlock<Self>) -> Result<ARef<INode<Self>>> {

samples/rust/rust_rofs.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@ const ENTRIES: [Entry; 4] = [
5252

5353
struct RoFs;
5454
impl fs::FileSystem for RoFs {
55+
type Data = ();
5556
const NAME: &'static CStr = c_str!("rust-fs");
5657

57-
fn super_params(_sb: &NewSuperBlock<Self>) -> Result<SuperParams> {
58+
fn super_params(_sb: &NewSuperBlock<Self>) -> Result<SuperParams<Self::Data>> {
5859
Ok(SuperParams {
5960
magic: 0x52555354,
6061
blocksize_bits: 12,
6162
maxbytes: fs::MAX_LFS_FILESIZE,
6263
time_gran: 1,
64+
data: (),
6365
})
6466
}
6567

0 commit comments

Comments
 (0)