@@ -22,6 +22,17 @@ pub mod ro {
22
22
use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
23
23
use macros:: { pin_data, pinned_drop} ;
24
24
25
+ /// Type of superblock keying.
26
+ ///
27
+ /// It determines how C's `fs_context_operations::get_tree` is implemented.
28
+ pub enum Super {
29
+ /// Multiple independent superblocks may exist.
30
+ Independent ,
31
+
32
+ /// Uses a block device.
33
+ BlockDev ,
34
+ }
35
+
25
36
/// A read-only file system type.
26
37
pub trait Type {
27
38
/// Data associated with each file system instance (super-block).
@@ -30,6 +41,9 @@ pub mod ro {
30
41
/// The name of the file system type.
31
42
const NAME : & ' static CStr ;
32
43
44
+ /// Determines how superblocks for this file system type are keyed.
45
+ const SUPER_TYPE : Super = Super :: Independent ;
46
+
33
47
/// Initialises a super block for this file system type.
34
48
fn fill_super ( sb : NewSuperBlock < ' _ , Self > ) -> Result < & SuperBlock < Self > > ;
35
49
@@ -184,7 +198,9 @@ pub mod ro {
184
198
fs. name = T :: NAME . as_char_ptr( ) ;
185
199
fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
186
200
fs. kill_sb = Some ( Self :: kill_sb_callback:: <T >) ;
187
- fs. fs_flags = 0 ;
201
+ fs. fs_flags = if let Super :: BlockDev = T :: SUPER_TYPE {
202
+ bindings:: FS_REQUIRES_DEV as i32
203
+ } else { 0 } ;
188
204
189
205
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
190
206
// registration is active (it is undone in `drop`).
@@ -207,9 +223,16 @@ pub mod ro {
207
223
unsafe extern "C" fn kill_sb_callback < T : Type + ?Sized > (
208
224
sb_ptr : * mut bindings:: super_block ,
209
225
) {
210
- // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super`
211
- // is the appropriate function to call for cleanup.
212
- unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
226
+ match T :: SUPER_TYPE {
227
+ // SAFETY: In `get_tree_callback` we always call `get_tree_bdev` for
228
+ // `Super::BlockDev`, so `kill_block_super` is the appropriate function to call
229
+ // for cleanup.
230
+ Super :: BlockDev => unsafe { bindings:: kill_block_super ( sb_ptr) } ,
231
+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev` for
232
+ // `Super::Independent`, so `kill_anon_super` is the appropriate function to call
233
+ // for cleanup.
234
+ Super :: Independent => unsafe { bindings:: kill_anon_super ( sb_ptr) } ,
235
+ }
213
236
214
237
// SAFETY: The C api contract guarantees that `sb_ptr` is valid for read.
215
238
let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
@@ -480,12 +503,88 @@ pub mod ro {
480
503
} ) ) )
481
504
}
482
505
}
506
+
507
+ /// Reads a block from the block device.
508
+ pub fn bread ( & self , block : u64 ) -> Result < ARef < super :: buffer:: Head > > {
509
+ // Fail requests for non-blockdev file systems. This is a compile-time check.
510
+ match T :: SUPER_TYPE {
511
+ Super :: BlockDev => { }
512
+ _ => return Err ( EIO ) ,
513
+ }
514
+
515
+ // SAFET: This function is only valid after the `NeedsInit` typestate, so the block
516
+ // size is known and the superblock can be used to read blocks.
517
+ let ptr =
518
+ ptr:: NonNull :: new ( unsafe { bindings:: sb_bread ( self . 0 . get ( ) , block) } ) . ok_or ( EIO ) ?;
519
+ // SAFETY: `sb_bread` returns a referenced buffer head. Ownership of the increment is
520
+ // passed to the `ARef` instance.
521
+ Ok ( unsafe { ARef :: from_raw ( ptr. cast ( ) ) } )
522
+ }
523
+
524
+ /// Reads `size` bytes starting from `offset` bytes.
525
+ ///
526
+ /// Returns an iterator that returns slices based on blocks.
527
+ pub fn read (
528
+ & self ,
529
+ offset : u64 ,
530
+ size : u64 ,
531
+ ) -> Result < impl Iterator < Item = Result < super :: buffer:: View > > + ' _ > {
532
+ struct BlockIter < ' a , T : Type + ?Sized > {
533
+ sb : & ' a SuperBlock < T > ,
534
+ next_offset : u64 ,
535
+ end : u64 ,
536
+ }
537
+ impl < ' a , T : Type + ?Sized > Iterator for BlockIter < ' a , T > {
538
+ type Item = Result < super :: buffer:: View > ;
539
+
540
+ fn next ( & mut self ) -> Option < Self :: Item > {
541
+ if self . next_offset >= self . end {
542
+ return None ;
543
+ }
544
+
545
+ // SAFETY: The superblock is valid and has had its block size initialised.
546
+ let block_size = unsafe { ( * self . sb . 0 . get ( ) ) . s_blocksize } ;
547
+ let bh = match self . sb . bread ( self . next_offset / block_size) {
548
+ Ok ( bh) => bh,
549
+ Err ( e) => return Some ( Err ( e) ) ,
550
+ } ;
551
+ let boffset = self . next_offset & ( block_size - 1 ) ;
552
+ let bsize = core:: cmp:: min ( self . end - self . next_offset , block_size - boffset) ;
553
+ self . next_offset += bsize;
554
+ Some ( Ok ( super :: buffer:: View :: new (
555
+ bh,
556
+ boffset as usize ,
557
+ bsize as usize ,
558
+ ) ) )
559
+ }
560
+ }
561
+ Ok ( BlockIter {
562
+ sb : self ,
563
+ next_offset : offset,
564
+ end : offset. checked_add ( size) . ok_or ( ERANGE ) ?,
565
+ } )
566
+ }
567
+
568
+ /// Returns the number of sectors in the underlying block device.
569
+ pub fn sector_count ( & self ) -> Result < u64 > {
570
+ // Fail requests for non-blockdev file systems. This is a compile-time check.
571
+ match T :: SUPER_TYPE {
572
+ // The superblock is valid and given that it's a blockdev superblock it must have a
573
+ // valid `s_bdev`.
574
+ Super :: BlockDev => Ok ( unsafe { bindings:: bdev_nr_sectors ( ( * self . 0 . get ( ) ) . s_bdev ) } ) ,
575
+ _ => Err ( EIO ) ,
576
+ }
577
+ }
483
578
}
484
579
485
580
/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
486
581
/// eventually.
487
582
pub struct NeedsInit ;
488
583
584
+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_data`] needs to be
585
+ /// called eventually.
586
+ pub struct NeedsData ;
587
+
489
588
/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be
490
589
/// called eventually.
491
590
pub struct NeedsRoot ;
@@ -540,11 +639,7 @@ pub mod ro {
540
639
}
541
640
542
641
/// Initialises the superblock.
543
- pub fn init (
544
- self ,
545
- params : & SuperParams ,
546
- data : T :: Data ,
547
- ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
642
+ pub fn init ( self , params : & SuperParams ) -> Result < NewSuperBlock < ' a , T , NeedsData > > {
548
643
// SAFETY: Since this is a new super block, we hold the only reference to it.
549
644
let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
550
645
@@ -561,16 +656,37 @@ pub mod ro {
561
656
sb. s_blocksize = 1 << sb. s_blocksize_bits ;
562
657
sb. s_flags |= bindings:: SB_RDONLY ;
563
658
564
- // No failures are allowed beyond this point, otherwise we'll leak `data`.
565
- sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
566
-
567
659
Ok ( NewSuperBlock {
568
660
sb : self . sb ,
569
661
_p : PhantomData ,
570
662
} )
571
663
}
572
664
}
573
665
666
+ impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T , NeedsData > {
667
+ /// Initialises the superblock data.
668
+ pub fn init_data ( self , data : T :: Data ) -> NewSuperBlock < ' a , T , NeedsRoot > {
669
+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
670
+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
671
+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
672
+
673
+ NewSuperBlock {
674
+ sb : self . sb ,
675
+ _p : PhantomData ,
676
+ }
677
+ }
678
+
679
+ /// Reads a block from the block device.
680
+ pub fn bread ( & self , block : u64 ) -> Result < ARef < super :: buffer:: Head > > {
681
+ self . sb . bread ( block)
682
+ }
683
+
684
+ /// Returns the number of sectors in the underlying block device.
685
+ pub fn sector_count ( & self ) -> Result < u64 > {
686
+ self . sb . sector_count ( )
687
+ }
688
+ }
689
+
574
690
impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
575
691
/// Initialises the root of the superblock.
576
692
pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
@@ -615,9 +731,18 @@ pub mod ro {
615
731
} ;
616
732
617
733
unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
618
- // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
619
- // the right type and is a valid callback.
620
- unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
734
+ match T :: SUPER_TYPE {
735
+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
736
+ // the right type and is a valid callback.
737
+ Super :: BlockDev => unsafe {
738
+ bindings:: get_tree_bdev ( fc, Some ( Self :: fill_super_callback) )
739
+ } ,
740
+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
741
+ // the right type and is a valid callback.
742
+ Super :: Independent => unsafe {
743
+ bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) )
744
+ } ,
745
+ }
621
746
}
622
747
623
748
unsafe extern "C" fn fill_super_callback (
0 commit comments