@@ -12,7 +12,7 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
1212/// Read-only file systems.
1313pub mod ro {
1414 use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
15- use crate :: types:: { ARef , AlwaysRefCounted , Either , Opaque } ;
15+ use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque } ;
1616 use crate :: {
1717 bindings, folio:: LockedFolio , init:: PinInit , str:: CStr , time:: Time , try_pin_init,
1818 ThisModule ,
@@ -22,6 +22,9 @@ pub mod ro {
2222
2323 /// A read-only file system type.
2424 pub trait Type {
25+ /// Data associated with each file system instance (super-block).
26+ type Data : ForeignOwnable + Send + Sync ;
27+
2528 /// The name of the file system type.
2629 const NAME : & ' static CStr ;
2730
@@ -178,7 +181,7 @@ pub mod ro {
178181 fs. owner = module. 0 ;
179182 fs. name = T :: NAME . as_char_ptr( ) ;
180183 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
181- fs. kill_sb = Some ( Self :: kill_sb_callback) ;
184+ fs. kill_sb = Some ( Self :: kill_sb_callback:: < T > ) ;
182185 fs. fs_flags = 0 ;
183186
184187 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -199,10 +202,22 @@ pub mod ro {
199202 } )
200203 }
201204
202- unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
205+ unsafe extern "C" fn kill_sb_callback < T : Type + ?Sized > (
206+ sb_ptr : * mut bindings:: super_block ,
207+ ) {
203208 // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super`
204209 // is the appropriate function to call for cleanup.
205210 unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
211+
212+ // SAFETY: The C api contract guarantees that `sb_ptr` is valid for read.
213+ let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
214+ if !ptr. is_null ( ) {
215+ // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`,
216+ // where it's initialised with the result of an `into_foreign` call. We checked
217+ // above that `ptr` is non-null because it would be null if we never reached the
218+ // point where we init the field.
219+ unsafe { T :: Data :: from_foreign ( ptr) } ;
220+ }
206221 }
207222 }
208223
@@ -429,6 +444,15 @@ pub mod ro {
429444 pub struct SuperBlock < T : Type + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
430445
431446 impl < T : Type + ?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
450+ // `s_fs_info` has been initialised initialised with the result of a call to
451+ // `T::into_foreign`.
452+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
453+ unsafe { T :: Data :: borrow ( ptr) }
454+ }
455+
432456 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
433457 pub fn get_or_create_inode ( & self , ino : u64 ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
434458 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -456,6 +480,14 @@ pub mod ro {
456480 }
457481 }
458482
483+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
484+ /// eventually.
485+ pub struct NeedsInit ;
486+
487+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be
488+ /// called eventually.
489+ pub struct NeedsRoot ;
490+
459491 /// Required superblock parameters.
460492 ///
461493 /// This is used in [`NewSuperBlock::init`].
@@ -477,17 +509,19 @@ pub mod ro {
477509
478510 /// A superblock that is still being initialised.
479511 ///
512+ /// It uses type states to ensure that callers use the right sequence of calls.
513+ ///
480514 /// # Invariants
481515 ///
482516 /// The superblock is a newly-created one and this is the only active pointer to it.
483- pub struct NewSuperBlock < ' a , T : Type + ?Sized > {
517+ pub struct NewSuperBlock < ' a , T : Type + ?Sized , S = NeedsInit > {
484518 sb : & ' a mut SuperBlock < T > ,
485519
486520 // This also forces `'a` to be invariant.
487- _p : PhantomData < & ' a mut & ' a ( ) > ,
521+ _p : PhantomData < & ' a mut & ' a S > ,
488522 }
489523
490- impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T > {
524+ impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
491525 /// Creates a new instance of [`NewSuperBlock`].
492526 ///
493527 /// # Safety
@@ -504,7 +538,11 @@ pub mod ro {
504538 }
505539
506540 /// Initialises the superblock.
507- pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
541+ pub fn init (
542+ self ,
543+ params : & SuperParams ,
544+ data : T :: Data ,
545+ ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
508546 // SAFETY: Since this is a new super block, we hold the only reference to it.
509547 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
510548
@@ -521,27 +559,41 @@ pub mod ro {
521559 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
522560 sb. s_flags |= bindings:: SB_RDONLY ;
523561
562+ // No failures are allowed beyond this point, otherwise we'll leak `data`.
563+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
564+
565+ Ok ( NewSuperBlock {
566+ sb : self . sb ,
567+ _p : PhantomData ,
568+ } )
569+ }
570+ }
571+
572+ impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
573+ /// Initialises the root of the superblock.
574+ pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
524575 // Reject root inode if it belongs to a different superblock.
525- if !ptr:: eq ( root . super_block ( ) , self . sb ) {
576+ if !ptr:: eq ( inode . super_block ( ) , self . sb ) {
526577 return Err ( EINVAL ) ;
527578 }
528579
529580 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
530581 // case for this call.
531582 //
532583 // It takes over the inode, even on failure, so we don't need to clean it up.
533- let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
584+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( inode ) . 0 . get ( ) ) } ;
534585 if dentry. is_null ( ) {
535586 return Err ( ENOMEM ) ;
536587 }
537588
589+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
590+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
538591 sb. s_root = dentry;
539-
540592 Ok ( self . sb )
541593 }
542594 }
543595
544- impl < T : Type + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
596+ impl < T : Type + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
545597 type Target = SuperBlock < T > ;
546598
547599 fn deref ( & self ) -> & Self :: Target {
@@ -909,6 +961,7 @@ pub mod ro {
909961 /// struct MyFs;
910962 /// impl fs::ro::Type for MyFs {
911963 /// // ...
964+ /// # type Data = ();
912965 /// # const NAME: &'static CStr = c_str!("myfs");
913966 /// # fn fill_super(
914967 /// # _: fs::ro::NewSuperBlock<'_, Self>
0 commit comments