@@ -12,7 +12,7 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
12
12
/// Read-only file systems.
13
13
pub mod ro {
14
14
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 } ;
16
16
use crate :: {
17
17
bindings, folio:: LockedFolio , init:: PinInit , str:: CStr , time:: Time , try_pin_init,
18
18
ThisModule ,
@@ -22,6 +22,9 @@ pub mod ro {
22
22
23
23
/// A read-only file system type.
24
24
pub trait Type {
25
+ /// Data associated with each file system instance (super-block).
26
+ type Data : ForeignOwnable + Send + Sync ;
27
+
25
28
/// The name of the file system type.
26
29
const NAME : & ' static CStr ;
27
30
@@ -178,7 +181,7 @@ pub mod ro {
178
181
fs. owner = module. 0 ;
179
182
fs. name = T :: NAME . as_char_ptr( ) ;
180
183
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 > ) ;
182
185
fs. fs_flags = 0 ;
183
186
184
187
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
@@ -199,10 +202,22 @@ pub mod ro {
199
202
} )
200
203
}
201
204
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
+ ) {
203
208
// SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super`
204
209
// is the appropriate function to call for cleanup.
205
210
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
+ }
206
221
}
207
222
}
208
223
@@ -429,6 +444,15 @@ pub mod ro {
429
444
pub struct SuperBlock < T : Type + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
430
445
431
446
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
+
432
456
/// Tries to get an existing inode or create a new one if it doesn't exist yet.
433
457
pub fn get_or_create_inode ( & self , ino : u64 ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
434
458
// SAFETY: The only initialisation missing from the superblock is the root, and this
@@ -456,6 +480,14 @@ pub mod ro {
456
480
}
457
481
}
458
482
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
+
459
491
/// Required superblock parameters.
460
492
///
461
493
/// This is used in [`NewSuperBlock::init`].
@@ -477,17 +509,19 @@ pub mod ro {
477
509
478
510
/// A superblock that is still being initialised.
479
511
///
512
+ /// It uses type states to ensure that callers use the right sequence of calls.
513
+ ///
480
514
/// # Invariants
481
515
///
482
516
/// 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 > {
484
518
sb : & ' a mut SuperBlock < T > ,
485
519
486
520
// This also forces `'a` to be invariant.
487
- _p : PhantomData < & ' a mut & ' a ( ) > ,
521
+ _p : PhantomData < & ' a mut & ' a S > ,
488
522
}
489
523
490
- impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T > {
524
+ impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T , NeedsInit > {
491
525
/// Creates a new instance of [`NewSuperBlock`].
492
526
///
493
527
/// # Safety
@@ -504,7 +538,11 @@ pub mod ro {
504
538
}
505
539
506
540
/// 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 > > {
508
546
// SAFETY: Since this is a new super block, we hold the only reference to it.
509
547
let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
510
548
@@ -521,27 +559,41 @@ pub mod ro {
521
559
sb. s_blocksize = 1 << sb. s_blocksize_bits ;
522
560
sb. s_flags |= bindings:: SB_RDONLY ;
523
561
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 > > {
524
575
// 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 ) {
526
577
return Err ( EINVAL ) ;
527
578
}
528
579
529
580
// SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
530
581
// case for this call.
531
582
//
532
583
// 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 ( ) ) } ;
534
585
if dentry. is_null ( ) {
535
586
return Err ( ENOMEM ) ;
536
587
}
537
588
589
+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
590
+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
538
591
sb. s_root = dentry;
539
-
540
592
Ok ( self . sb )
541
593
}
542
594
}
543
595
544
- impl < T : Type + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
596
+ impl < T : Type + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T , NeedsRoot > {
545
597
type Target = SuperBlock < T > ;
546
598
547
599
fn deref ( & self ) -> & Self :: Target {
@@ -909,6 +961,7 @@ pub mod ro {
909
961
/// struct MyFs;
910
962
/// impl fs::ro::Type for MyFs {
911
963
/// // ...
964
+ /// # type Data = ();
912
965
/// # const NAME: &'static CStr = c_str!("myfs");
913
966
/// # fn fill_super(
914
967
/// # _: fs::ro::NewSuperBlock<'_, Self>
0 commit comments