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
@@ -168,7 +171,7 @@ impl Registration {
168171 fs. owner = module. 0 ;
169172 fs. name = T :: NAME . as_char_ptr( ) ;
170173 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
171- fs. kill_sb = Some ( Self :: kill_sb_callback) ;
174+ fs. kill_sb = Some ( Self :: kill_sb_callback:: < T > ) ;
172175 fs. fs_flags = 0 ;
173176
174177 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -189,10 +192,22 @@ impl Registration {
189192 } )
190193 }
191194
192- unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
195+ unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
196+ sb_ptr : * mut bindings:: super_block ,
197+ ) {
193198 // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
194199 // the appropriate function to call for cleanup.
195200 unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
201+
202+ // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
203+ let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
204+ if !ptr. is_null ( ) {
205+ // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
206+ // it's initialised with the result of an `into_foreign` call. We checked above that
207+ // `ptr` is non-null because it would be null if we never reached the point where we
208+ // init the field.
209+ unsafe { T :: Data :: from_foreign ( ptr) } ;
210+ }
196211 }
197212}
198213
@@ -423,6 +438,14 @@ pub struct INodeParams {
423438pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
424439
425440impl < T : FileSystem + ?Sized > SuperBlock < T > {
441+ /// Returns the data associated with the superblock.
442+ pub fn data ( & self ) -> <T :: Data as ForeignOwnable >:: Borrowed < ' _ > {
443+ // SAFETY: This method is only available after the `NeedsData` typestate, so `s_fs_info`
444+ // has been initialised initialised with the result of a call to `T::into_foreign`.
445+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
446+ unsafe { T :: Data :: borrow ( ptr) }
447+ }
448+
426449 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
427450 pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
428451 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -449,6 +472,14 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
449472 }
450473}
451474
475+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
476+ /// eventually.
477+ pub struct NeedsInit ;
478+
479+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
480+ /// eventually.
481+ pub struct NeedsRoot ;
482+
452483/// Required superblock parameters.
453484///
454485/// This is used in [`NewSuperBlock::init`].
@@ -470,17 +501,19 @@ pub struct SuperParams {
470501
471502/// A superblock that is still being initialised.
472503///
504+ //// It uses type states to ensure that callers use the right sequence of calls.
505+ ///
473506/// # Invariants
474507///
475508/// The superblock is a newly-created one and this is the only active pointer to it.
476- pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized > {
509+ pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized , S = NeedsInit > {
477510 sb : & ' a mut SuperBlock < T > ,
478511
479512 // This also forces `'a` to be invariant.
480- _p : PhantomData < & ' a mut & ' a ( ) > ,
513+ _p : PhantomData < & ' a mut & ' a S > ,
481514}
482515
483- impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T > {
516+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
484517 /// Creates a new instance of [`NewSuperBlock`].
485518 ///
486519 /// # Safety
@@ -496,7 +529,11 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
496529 }
497530
498531 /// Initialises the superblock.
499- pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
532+ pub fn init (
533+ self ,
534+ params : & SuperParams ,
535+ data : T :: Data ,
536+ ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
500537 // SAFETY: Since this is a new super block, we hold the only reference to it.
501538 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
502539
@@ -513,27 +550,42 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
513550 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
514551 sb. s_flags |= bindings:: SB_RDONLY ;
515552
553+ // No failures are allowed beyond this point, otherwise we'll leak `data`.
554+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
555+
556+ Ok ( NewSuperBlock {
557+ sb : self . sb ,
558+ _p : PhantomData ,
559+ } )
560+ }
561+ }
562+
563+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
564+ /// Initialises the root of the superblock.
565+ pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
516566 // Reject root inode if it belongs to a different superblock.
517- if !ptr:: eq ( root . super_block ( ) , self . sb ) {
567+ if !ptr:: eq ( inode . super_block ( ) , self . sb ) {
518568 return Err ( EINVAL ) ;
519569 }
520570
521571 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the case
522572 // for this call.
523573 //
524574 // It takes over the inode, even on failure, so we don't need to clean it up.
525- let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
575+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( inode ) . 0 . get ( ) ) } ;
526576 if dentry. is_null ( ) {
527577 return Err ( ENOMEM ) ;
528578 }
529579
580+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
581+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
530582 sb. s_root = dentry;
531583
532584 Ok ( self . sb )
533585 }
534586}
535587
536- impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
588+ impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
537589 type Target = SuperBlock < T > ;
538590
539591 fn deref ( & self ) -> & Self :: Target {
@@ -956,6 +1008,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
9561008///
9571009/// struct MyFs;
9581010/// impl fs::FileSystem for MyFs {
1011+ /// type Data = ();
9591012/// const NAME: &'static CStr = c_str!("myfs");
9601013/// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
9611014/// todo!()
0 commit comments