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
@@ -176,7 +179,7 @@ impl Registration {
176179 fs. owner = module. 0 ;
177180 fs. name = T :: NAME . as_char_ptr( ) ;
178181 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
179- fs. kill_sb = Some ( Self :: kill_sb_callback) ;
182+ fs. kill_sb = Some ( Self :: kill_sb_callback:: < T > ) ;
180183 fs. fs_flags = 0 ;
181184
182185 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -197,10 +200,22 @@ impl Registration {
197200 } )
198201 }
199202
200- unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
203+ unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
204+ sb_ptr : * mut bindings:: super_block ,
205+ ) {
201206 // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
202207 // the appropriate function to call for cleanup.
203208 unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
209+
210+ // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
211+ let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
212+ if !ptr. is_null ( ) {
213+ // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
214+ // it's initialised with the result of an `into_foreign` call. We checked above that
215+ // `ptr` is non-null because it would be null if we never reached the point where we
216+ // init the field.
217+ unsafe { T :: Data :: from_foreign ( ptr) } ;
218+ }
204219 }
205220}
206221
@@ -428,6 +443,14 @@ pub struct INodeParams {
428443pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
429444
430445impl < T : FileSystem + ?Sized > SuperBlock < T > {
446+ /// Returns the data associated with the superblock.
447+ pub fn data ( & self ) -> <T :: Data as ForeignOwnable >:: Borrowed < ' _ > {
448+ // SAFETY: This method is only available after the `NeedsData` typestate, so `s_fs_info`
449+ // has been initialised initialised with the result of a call to `T::into_foreign`.
450+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
451+ unsafe { T :: Data :: borrow ( ptr) }
452+ }
453+
431454 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
432455 pub fn get_or_create_inode ( & self , ino : u64 ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
433456 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -454,6 +477,14 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
454477 }
455478}
456479
480+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
481+ /// eventually.
482+ pub struct NeedsInit ;
483+
484+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
485+ /// eventually.
486+ pub struct NeedsRoot ;
487+
457488/// Required superblock parameters.
458489///
459490/// This is used in [`NewSuperBlock::init`].
@@ -475,17 +506,19 @@ pub struct SuperParams {
475506
476507/// A superblock that is still being initialised.
477508///
509+ //// It uses type states to ensure that callers use the right sequence of calls.
510+ ///
478511/// # Invariants
479512///
480513/// The superblock is a newly-created one and this is the only active pointer to it.
481- pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized > {
514+ pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized , S = NeedsInit > {
482515 sb : & ' a mut SuperBlock < T > ,
483516
484517 // This also forces `'a` to be invariant.
485- _p : PhantomData < & ' a mut & ' a ( ) > ,
518+ _p : PhantomData < & ' a mut & ' a S > ,
486519}
487520
488- impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T > {
521+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
489522 /// Creates a new instance of [`NewSuperBlock`].
490523 ///
491524 /// # Safety
@@ -501,7 +534,11 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
501534 }
502535
503536 /// Initialises the superblock.
504- pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
537+ pub fn init (
538+ self ,
539+ params : & SuperParams ,
540+ data : T :: Data ,
541+ ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
505542 // SAFETY: Since this is a new super block, we hold the only reference to it.
506543 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
507544
@@ -518,27 +555,42 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
518555 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
519556 sb. s_flags |= bindings:: SB_RDONLY ;
520557
558+ // No failures are allowed beyond this point, otherwise we'll leak `data`.
559+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
560+
561+ Ok ( NewSuperBlock {
562+ sb : self . sb ,
563+ _p : PhantomData ,
564+ } )
565+ }
566+ }
567+
568+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
569+ /// Initialises the root of the superblock.
570+ pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
521571 // Reject root inode if it belongs to a different superblock.
522- if !ptr:: eq ( root . super_block ( ) , self . sb ) {
572+ if !ptr:: eq ( inode . super_block ( ) , self . sb ) {
523573 return Err ( EINVAL ) ;
524574 }
525575
526576 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the case
527577 // for this call.
528578 //
529579 // It takes over the inode, even on failure, so we don't need to clean it up.
530- let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
580+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( inode ) . 0 . get ( ) ) } ;
531581 if dentry. is_null ( ) {
532582 return Err ( ENOMEM ) ;
533583 }
534584
585+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
586+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
535587 sb. s_root = dentry;
536588
537589 Ok ( self . sb )
538590 }
539591}
540592
541- impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
593+ impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
542594 type Target = SuperBlock < T > ;
543595
544596 fn deref ( & self ) -> & Self :: Target {
@@ -903,6 +955,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
903955///
904956/// struct MyFs;
905957/// impl fs::FileSystem for MyFs {
958+ /// type Data = ();
906959/// const NAME: &'static CStr = c_str!("myfs");
907960/// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
908961/// todo!()
0 commit comments