7
7
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
8
8
9
9
use 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 } ;
11
11
use crate :: {
12
12
bindings, folio:: LockedFolio , init:: PinInit , str:: CStr , time:: Timespec , try_pin_init,
13
13
ThisModule ,
@@ -20,11 +20,14 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
20
20
21
21
/// A file system type.
22
22
pub trait FileSystem {
23
+ /// Data associated with each file system instance (super-block).
24
+ type Data : ForeignOwnable + Send + Sync ;
25
+
23
26
/// The name of the file system type.
24
27
const NAME : & ' static CStr ;
25
28
26
29
/// 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 > > ;
28
31
29
32
/// Initialises and returns the root inode of the given superblock.
30
33
///
@@ -174,7 +177,7 @@ impl Registration {
174
177
fs. owner = module. 0 ;
175
178
fs. name = T :: NAME . as_char_ptr( ) ;
176
179
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 > ) ;
178
181
fs. fs_flags = 0 ;
179
182
180
183
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -195,10 +198,22 @@ impl Registration {
195
198
} )
196
199
}
197
200
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
+ ) {
199
204
// SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
200
205
// the appropriate function to call for cleanup.
201
206
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
+ }
202
217
}
203
218
}
204
219
@@ -429,6 +444,14 @@ pub struct INodeParams {
429
444
pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
430
445
431
446
impl < 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
+
432
455
/// Tries to get an existing inode or create a new one if it doesn't exist yet.
433
456
pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
434
457
// SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -458,7 +481,7 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
458
481
/// Required superblock parameters.
459
482
///
460
483
/// This is returned by implementations of [`FileSystem::super_params`].
461
- pub struct SuperParams {
484
+ pub struct SuperParams < T : ForeignOwnable + Send + Sync > {
462
485
/// The magic number of the superblock.
463
486
pub magic : u32 ,
464
487
@@ -472,6 +495,9 @@ pub struct SuperParams {
472
495
473
496
/// Granularity of c/m/atime in ns (cannot be worse than a second).
474
497
pub time_gran : u32 ,
498
+
499
+ /// Data to be associated with the superblock.
500
+ pub data : T ,
475
501
}
476
502
477
503
/// A superblock that is still being initialised.
@@ -522,6 +548,9 @@ impl<T: FileSystem + ?Sized> Tables<T> {
522
548
sb. 0 . s_blocksize = 1 << sb. 0 . s_blocksize_bits ;
523
549
sb. 0 . s_flags |= bindings:: SB_RDONLY ;
524
550
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
+
525
554
// SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
526
555
// newly-created (and initialised above) superblock.
527
556
let sb = unsafe { & mut * sb_ptr. cast ( ) } ;
@@ -934,8 +963,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
934
963
///
935
964
/// struct MyFs;
936
965
/// impl fs::FileSystem for MyFs {
966
+ /// type Data = ();
937
967
/// 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> > {
939
969
/// todo!()
940
970
/// }
941
971
/// fn init_root(_sb: &SuperBlock<Self>) -> Result<ARef<INode<Self>>> {
0 commit comments