77//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
88
99use 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 } ;
1111use crate :: {
1212 bindings, folio:: LockedFolio , init:: PinInit , str:: CStr , time:: Timespec , try_pin_init,
1313 ThisModule ,
@@ -20,6 +20,9 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
2020
2121/// A file system type.
2222pub 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
@@ -165,7 +168,7 @@ impl Registration {
165168 fs. owner = module. 0 ;
166169 fs. name = T :: NAME . as_char_ptr( ) ;
167170 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
168- fs. kill_sb = Some ( Self :: kill_sb_callback) ;
171+ fs. kill_sb = Some ( Self :: kill_sb_callback:: < T > ) ;
169172 fs. fs_flags = 0 ;
170173
171174 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -186,10 +189,22 @@ impl Registration {
186189 } )
187190 }
188191
189- unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
192+ unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
193+ sb_ptr : * mut bindings:: super_block ,
194+ ) {
190195 // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
191196 // the appropriate function to call for cleanup.
192197 unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
198+
199+ // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
200+ let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
201+ if !ptr. is_null ( ) {
202+ // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
203+ // it's initialised with the result of an `into_foreign` call. We checked above that
204+ // `ptr` is non-null because it would be null if we never reached the point where we
205+ // init the field.
206+ unsafe { T :: Data :: from_foreign ( ptr) } ;
207+ }
193208 }
194209}
195210
@@ -417,6 +432,14 @@ pub struct INodeParams {
417432pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
418433
419434impl < T : FileSystem + ?Sized > SuperBlock < T > {
435+ /// Returns the data associated with the superblock.
436+ pub fn data ( & self ) -> <T :: Data as ForeignOwnable >:: Borrowed < ' _ > {
437+ // SAFETY: This method is only available after the `NeedsData` typestate, so `s_fs_info`
438+ // has been initialised initialised with the result of a call to `T::into_foreign`.
439+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
440+ unsafe { T :: Data :: borrow ( ptr) }
441+ }
442+
420443 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
421444 pub fn get_or_create_inode ( & self , ino : u64 ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
422445 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -443,6 +466,14 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
443466 }
444467}
445468
469+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
470+ /// eventually.
471+ pub struct NeedsInit ;
472+
473+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
474+ /// eventually.
475+ pub struct NeedsRoot ;
476+
446477/// Required superblock parameters.
447478///
448479/// This is used in [`NewSuperBlock::init`].
@@ -464,17 +495,19 @@ pub struct SuperParams {
464495
465496/// A superblock that is still being initialised.
466497///
498+ //// It uses type states to ensure that callers use the right sequence of calls.
499+ ///
467500/// # Invariants
468501///
469502/// The superblock is a newly-created one and this is the only active pointer to it.
470- pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized > {
503+ pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized , S = NeedsInit > {
471504 sb : & ' a mut SuperBlock < T > ,
472505
473506 // This also forces `'a` to be invariant.
474- _p : PhantomData < & ' a mut & ' a ( ) > ,
507+ _p : PhantomData < & ' a mut & ' a S > ,
475508}
476509
477- impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T > {
510+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
478511 /// Creates a new instance of [`NewSuperBlock`].
479512 ///
480513 /// # Safety
@@ -490,7 +523,11 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
490523 }
491524
492525 /// Initialises the superblock.
493- pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
526+ pub fn init (
527+ self ,
528+ params : & SuperParams ,
529+ data : T :: Data ,
530+ ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
494531 // SAFETY: Since this is a new super block, we hold the only reference to it.
495532 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
496533
@@ -507,27 +544,42 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
507544 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
508545 sb. s_flags |= bindings:: SB_RDONLY ;
509546
547+ // No failures are allowed beyond this point, otherwise we'll leak `data`.
548+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
549+
550+ Ok ( NewSuperBlock {
551+ sb : self . sb ,
552+ _p : PhantomData ,
553+ } )
554+ }
555+ }
556+
557+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
558+ /// Initialises the root of the superblock.
559+ pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
510560 // Reject root inode if it belongs to a different superblock.
511- if !ptr:: eq ( root . super_block ( ) , self . sb ) {
561+ if !ptr:: eq ( inode . super_block ( ) , self . sb ) {
512562 return Err ( EINVAL ) ;
513563 }
514564
515565 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the case
516566 // for this call.
517567 //
518568 // It takes over the inode, even on failure, so we don't need to clean it up.
519- let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
569+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( inode ) . 0 . get ( ) ) } ;
520570 if dentry. is_null ( ) {
521571 return Err ( ENOMEM ) ;
522572 }
523573
574+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
575+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
524576 sb. s_root = dentry;
525577
526578 Ok ( self . sb )
527579 }
528580}
529581
530- impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
582+ impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
531583 type Target = SuperBlock < T > ;
532584
533585 fn deref ( & self ) -> & Self :: Target {
@@ -939,6 +991,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
939991///
940992/// struct MyFs;
941993/// impl fs::FileSystem for MyFs {
994+ /// type Data = ();
942995/// const NAME: &'static CStr = c_str!("myfs");
943996/// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
944997/// todo!()
0 commit comments