@@ -21,6 +21,17 @@ pub mod buffer;
21
21
/// Maximum size of an inode.
22
22
pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
23
23
24
+ /// Type of superblock keying.
25
+ ///
26
+ /// It determines how C's `fs_context_operations::get_tree` is implemented.
27
+ pub enum Super {
28
+ /// Multiple independent superblocks may exist.
29
+ Independent ,
30
+
31
+ /// Uses a block device.
32
+ BlockDev ,
33
+ }
34
+
24
35
/// A file system type.
25
36
pub trait FileSystem {
26
37
/// Data associated with each file system instance (super-block).
@@ -29,6 +40,9 @@ pub trait FileSystem {
29
40
/// The name of the file system type.
30
41
const NAME : & ' static CStr ;
31
42
43
+ /// Determines how superblocks for this file system type are keyed.
44
+ const SUPER_TYPE : Super = Super :: Independent ;
45
+
32
46
/// Initialises a super block for this file system type.
33
47
fn fill_super ( sb : NewSuperBlock < ' _ , Self > ) -> Result < & SuperBlock < Self > > ;
34
48
@@ -172,7 +186,9 @@ impl Registration {
172
186
fs. name = T :: NAME . as_char_ptr( ) ;
173
187
fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
174
188
fs. kill_sb = Some ( Self :: kill_sb_callback:: <T >) ;
175
- fs. fs_flags = 0 ;
189
+ fs. fs_flags = if let Super :: BlockDev = T :: SUPER_TYPE {
190
+ bindings:: FS_REQUIRES_DEV as i32
191
+ } else { 0 } ;
176
192
177
193
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
178
194
// registration is active (it is undone in `drop`).
@@ -195,9 +211,16 @@ impl Registration {
195
211
unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
196
212
sb_ptr : * mut bindings:: super_block ,
197
213
) {
198
- // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
199
- // the appropriate function to call for cleanup.
200
- unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
214
+ match T :: SUPER_TYPE {
215
+ // SAFETY: In `get_tree_callback` we always call `get_tree_bdev` for
216
+ // `Super::BlockDev`, so `kill_block_super` is the appropriate function to call
217
+ // for cleanup.
218
+ Super :: BlockDev => unsafe { bindings:: kill_block_super ( sb_ptr) } ,
219
+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev` for
220
+ // `Super::Independent`, so `kill_anon_super` is the appropriate function to call
221
+ // for cleanup.
222
+ Super :: Independent => unsafe { bindings:: kill_anon_super ( sb_ptr) } ,
223
+ }
201
224
202
225
// SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
203
226
let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
@@ -467,12 +490,86 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
467
490
} ) ) )
468
491
}
469
492
}
493
+
494
+ /// Reads a block from the block device.
495
+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
496
+ pub fn bread ( & self , block : u64 ) -> Result < ARef < buffer:: Head > > {
497
+ // Fail requests for non-blockdev file systems. This is a compile-time check.
498
+ match T :: SUPER_TYPE {
499
+ Super :: BlockDev => { }
500
+ _ => return Err ( EIO ) ,
501
+ }
502
+
503
+ // SAFETY: This function is only valid after the `NeedsInit` typestate, so the block size
504
+ // is known and the superblock can be used to read blocks.
505
+ let ptr =
506
+ ptr:: NonNull :: new ( unsafe { bindings:: sb_bread ( self . 0 . get ( ) , block) } ) . ok_or ( EIO ) ?;
507
+ // SAFETY: `sb_bread` returns a referenced buffer head. Ownership of the increment is
508
+ // passed to the `ARef` instance.
509
+ Ok ( unsafe { ARef :: from_raw ( ptr. cast ( ) ) } )
510
+ }
511
+
512
+ /// Reads `size` bytes starting from `offset` bytes.
513
+ ///
514
+ /// Returns an iterator that returns slices based on blocks.
515
+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
516
+ pub fn read (
517
+ & self ,
518
+ offset : u64 ,
519
+ size : u64 ,
520
+ ) -> Result < impl Iterator < Item = Result < buffer:: View > > + ' _ > {
521
+ struct BlockIter < ' a , T : FileSystem + ?Sized > {
522
+ sb : & ' a SuperBlock < T > ,
523
+ next_offset : u64 ,
524
+ end : u64 ,
525
+ }
526
+ impl < ' a , T : FileSystem + ?Sized > Iterator for BlockIter < ' a , T > {
527
+ type Item = Result < buffer:: View > ;
528
+
529
+ fn next ( & mut self ) -> Option < Self :: Item > {
530
+ if self . next_offset >= self . end {
531
+ return None ;
532
+ }
533
+
534
+ // SAFETY: The superblock is valid and has had its block size initialised.
535
+ let block_size = unsafe { ( * self . sb . 0 . get ( ) ) . s_blocksize } ;
536
+ let bh = match self . sb . bread ( self . next_offset / block_size) {
537
+ Ok ( bh) => bh,
538
+ Err ( e) => return Some ( Err ( e) ) ,
539
+ } ;
540
+ let boffset = self . next_offset & ( block_size - 1 ) ;
541
+ let bsize = core:: cmp:: min ( self . end - self . next_offset , block_size - boffset) ;
542
+ self . next_offset += bsize;
543
+ Some ( Ok ( buffer:: View :: new ( bh, boffset as usize , bsize as usize ) ) )
544
+ }
545
+ }
546
+ Ok ( BlockIter {
547
+ sb : self ,
548
+ next_offset : offset,
549
+ end : offset. checked_add ( size) . ok_or ( ERANGE ) ?,
550
+ } )
551
+ }
552
+
553
+ /// Returns the number of sectors in the underlying block device.
554
+ pub fn sector_count ( & self ) -> Result < u64 > {
555
+ // Fail requests for non-blockdev file systems. This is a compile-time check.
556
+ match T :: SUPER_TYPE {
557
+ // The superblock is valid and given that it's a blockdev superblock it must have a
558
+ // valid `s_bdev`.
559
+ Super :: BlockDev => Ok ( unsafe { bindings:: bdev_nr_sectors ( ( * self . 0 . get ( ) ) . s_bdev ) } ) ,
560
+ _ => Err ( EIO ) ,
561
+ }
562
+ }
470
563
}
471
564
472
565
/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
473
566
/// eventually.
474
567
pub struct NeedsInit ;
475
568
569
+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_data`] needs to be called
570
+ /// eventually.
571
+ pub struct NeedsData ;
572
+
476
573
/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
477
574
/// eventually.
478
575
pub struct NeedsRoot ;
@@ -526,11 +623,7 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
526
623
}
527
624
528
625
/// Initialises the superblock.
529
- pub fn init (
530
- self ,
531
- params : & SuperParams ,
532
- data : T :: Data ,
533
- ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
626
+ pub fn init ( self , params : & SuperParams ) -> Result < NewSuperBlock < ' a , T , NeedsData > > {
534
627
// SAFETY: Since this is a new super block, we hold the only reference to it.
535
628
let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
536
629
@@ -547,16 +640,38 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
547
640
sb. s_blocksize = 1 << sb. s_blocksize_bits ;
548
641
sb. s_flags |= bindings:: SB_RDONLY ;
549
642
550
- // No failures are allowed beyond this point, otherwise we'll leak `data`.
551
- sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
552
-
553
643
Ok ( NewSuperBlock {
554
644
sb : self . sb ,
555
645
_p : PhantomData ,
556
646
} )
557
647
}
558
648
}
559
649
650
+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsData > {
651
+ /// Initialises the superblock data.
652
+ pub fn init_data ( self , data : T :: Data ) -> NewSuperBlock < ' a , T , NeedsRoot > {
653
+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
654
+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
655
+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
656
+
657
+ NewSuperBlock {
658
+ sb : self . sb ,
659
+ _p : PhantomData ,
660
+ }
661
+ }
662
+
663
+ /// Reads a block from the block device.
664
+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
665
+ pub fn bread ( & self , block : u64 ) -> Result < ARef < buffer:: Head > > {
666
+ self . sb . bread ( block)
667
+ }
668
+
669
+ /// Returns the number of sectors in the underlying block device.
670
+ pub fn sector_count ( & self ) -> Result < u64 > {
671
+ self . sb . sector_count ( )
672
+ }
673
+ }
674
+
560
675
impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
561
676
/// Initialises the root of the superblock.
562
677
pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
@@ -602,9 +717,18 @@ impl<T: FileSystem + ?Sized> Tables<T> {
602
717
} ;
603
718
604
719
unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
605
- // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
606
- // the right type and is a valid callback.
607
- unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
720
+ match T :: SUPER_TYPE {
721
+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
722
+ // the right type and is a valid callback.
723
+ Super :: BlockDev => unsafe {
724
+ bindings:: get_tree_bdev ( fc, Some ( Self :: fill_super_callback) )
725
+ } ,
726
+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
727
+ // the right type and is a valid callback.
728
+ Super :: Independent => unsafe {
729
+ bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) )
730
+ } ,
731
+ }
608
732
}
609
733
610
734
unsafe extern "C" fn fill_super_callback (
0 commit comments