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
@@ -420,6 +435,14 @@ pub struct INodeParams {
420435pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
421436
422437impl < T : FileSystem + ?Sized > SuperBlock < T > {
438+ /// Returns the data associated with the superblock.
439+ pub fn data ( & self ) -> <T :: Data as ForeignOwnable >:: Borrowed < ' _ > {
440+ // SAFETY: This method is only available after the `NeedsData` typestate, so `s_fs_info`
441+ // has been initialised initialised with the result of a call to `T::into_foreign`.
442+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
443+ unsafe { T :: Data :: borrow ( ptr) }
444+ }
445+
423446 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
424447 pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
425448 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -446,6 +469,14 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
446469 }
447470}
448471
472+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
473+ /// eventually.
474+ pub struct NeedsInit ;
475+
476+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
477+ /// eventually.
478+ pub struct NeedsRoot ;
479+
449480/// Required superblock parameters.
450481///
451482/// This is used in [`NewSuperBlock::init`].
@@ -467,17 +498,19 @@ pub struct SuperParams {
467498
468499/// A superblock that is still being initialised.
469500///
501+ //// It uses type states to ensure that callers use the right sequence of calls.
502+ ///
470503/// # Invariants
471504///
472505/// The superblock is a newly-created one and this is the only active pointer to it.
473- pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized > {
506+ pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized , S = NeedsInit > {
474507 sb : & ' a mut SuperBlock < T > ,
475508
476509 // This also forces `'a` to be invariant.
477- _p : PhantomData < & ' a mut & ' a ( ) > ,
510+ _p : PhantomData < & ' a mut & ' a S > ,
478511}
479512
480- impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T > {
513+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
481514 /// Creates a new instance of [`NewSuperBlock`].
482515 ///
483516 /// # Safety
@@ -493,7 +526,11 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
493526 }
494527
495528 /// Initialises the superblock.
496- pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
529+ pub fn init (
530+ self ,
531+ params : & SuperParams ,
532+ data : T :: Data ,
533+ ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
497534 // SAFETY: Since this is a new super block, we hold the only reference to it.
498535 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
499536
@@ -510,27 +547,42 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
510547 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
511548 sb. s_flags |= bindings:: SB_RDONLY ;
512549
550+ // No failures are allowed beyond this point, otherwise we'll leak `data`.
551+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
552+
553+ Ok ( NewSuperBlock {
554+ sb : self . sb ,
555+ _p : PhantomData ,
556+ } )
557+ }
558+ }
559+
560+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
561+ /// Initialises the root of the superblock.
562+ pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
513563 // Reject root inode if it belongs to a different superblock.
514- if !ptr:: eq ( root . super_block ( ) , self . sb ) {
564+ if !ptr:: eq ( inode . super_block ( ) , self . sb ) {
515565 return Err ( EINVAL ) ;
516566 }
517567
518568 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the case
519569 // for this call.
520570 //
521571 // It takes over the inode, even on failure, so we don't need to clean it up.
522- let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
572+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( inode ) . 0 . get ( ) ) } ;
523573 if dentry. is_null ( ) {
524574 return Err ( ENOMEM ) ;
525575 }
526576
577+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
578+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
527579 sb. s_root = dentry;
528580
529581 Ok ( self . sb )
530582 }
531583}
532584
533- impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
585+ impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
534586 type Target = SuperBlock < T > ;
535587
536588 fn deref ( & self ) -> & Self :: Target {
@@ -953,6 +1005,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
9531005///
9541006/// struct MyFs;
9551007/// impl fs::FileSystem for MyFs {
1008+ /// type Data = ();
9561009/// const NAME: &'static CStr = c_str!("myfs");
9571010/// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
9581011/// todo!()
0 commit comments