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,11 +20,14 @@ 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
2629 /// Returns the parameters to initialise a super block.
27- fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams > ;
30+ fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams < Self :: Data > > ;
2831
2932 /// Initialises and returns the root inode of the given superblock.
3033 ///
@@ -174,7 +177,7 @@ impl Registration {
174177 fs. owner = module. 0 ;
175178 fs. name = T :: NAME . as_char_ptr( ) ;
176179 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
177- fs. kill_sb = Some ( Self :: kill_sb_callback) ;
180+ fs. kill_sb = Some ( Self :: kill_sb_callback:: < T > ) ;
178181 fs. fs_flags = 0 ;
179182
180183 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -195,10 +198,22 @@ impl Registration {
195198 } )
196199 }
197200
198- unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
201+ unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
202+ sb_ptr : * mut bindings:: super_block ,
203+ ) {
199204 // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
200205 // the appropriate function to call for cleanup.
201206 unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
207+
208+ // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
209+ let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
210+ if !ptr. is_null ( ) {
211+ // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
212+ // it's initialised with the result of an `into_foreign` call. We checked above that
213+ // `ptr` is non-null because it would be null if we never reached the point where we
214+ // init the field.
215+ unsafe { T :: Data :: from_foreign ( ptr) } ;
216+ }
202217 }
203218}
204219
@@ -429,6 +444,14 @@ pub struct INodeParams {
429444pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
430445
431446impl < T : FileSystem + ?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 `s_fs_info`
450+ // has been initialised initialised with the result of a call to `T::into_foreign`.
451+ let ptr = unsafe { ( * self . 0 . get ( ) ) . s_fs_info } ;
452+ unsafe { T :: Data :: borrow ( ptr) }
453+ }
454+
432455 /// Tries to get an existing inode or create a new one if it doesn't exist yet.
433456 pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
434457 // SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -458,7 +481,7 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
458481/// Required superblock parameters.
459482///
460483/// This is returned by implementations of [`FileSystem::super_params`].
461- pub struct SuperParams {
484+ pub struct SuperParams < T : ForeignOwnable + Send + Sync > {
462485 /// The magic number of the superblock.
463486 pub magic : u32 ,
464487
@@ -472,6 +495,9 @@ pub struct SuperParams {
472495
473496 /// Granularity of c/m/atime in ns (cannot be worse than a second).
474497 pub time_gran : u32 ,
498+
499+ /// Data to be associated with the superblock.
500+ pub data : T ,
475501}
476502
477503/// A superblock that is still being initialised.
@@ -522,6 +548,9 @@ impl<T: FileSystem + ?Sized> Tables<T> {
522548 sb. 0 . s_blocksize = 1 << sb. 0 . s_blocksize_bits ;
523549 sb. 0 . s_flags |= bindings:: SB_RDONLY ;
524550
551+ // N.B.: Even on failure, `kill_sb` is called and frees the data.
552+ sb. 0 . s_fs_info = params. data . into_foreign ( ) . cast_mut ( ) ;
553+
525554 // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
526555 // newly-created (and initialised above) superblock.
527556 let sb = unsafe { & mut * sb_ptr. cast ( ) } ;
@@ -934,8 +963,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
934963///
935964/// struct MyFs;
936965/// impl fs::FileSystem for MyFs {
966+ /// type Data = ();
937967/// const NAME: &'static CStr = c_str!("myfs");
938- /// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
968+ /// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams<Self::Data> > {
939969/// todo!()
940970/// }
941971/// fn init_root(_sb: &SuperBlock<Self>) -> Result<ARef<INode<Self>>> {
0 commit comments