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