@@ -21,6 +21,17 @@ pub mod buffer;
2121/// Maximum size of an inode.
2222pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
2323
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+
2435/// A file system type.
2536pub trait FileSystem {
2637 /// Data associated with each file system instance (super-block).
@@ -29,6 +40,9 @@ pub trait FileSystem {
2940 /// The name of the file system type.
3041 const NAME : & ' static CStr ;
3142
43+ /// Determines how superblocks for this file system type are keyed.
44+ const SUPER_TYPE : Super = Super :: Independent ;
45+
3246 /// Initialises a super block for this file system type.
3347 fn fill_super ( sb : NewSuperBlock < ' _ , Self > ) -> Result < & SuperBlock < Self > > ;
3448
@@ -175,7 +189,9 @@ impl Registration {
175189 fs. name = T :: NAME . as_char_ptr( ) ;
176190 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
177191 fs. kill_sb = Some ( Self :: kill_sb_callback:: <T >) ;
178- fs. fs_flags = 0 ;
192+ fs. fs_flags = if let Super :: BlockDev = T :: SUPER_TYPE {
193+ bindings:: FS_REQUIRES_DEV as i32
194+ } else { 0 } ;
179195
180196 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
181197 // registration is active (it is undone in `drop`).
@@ -198,9 +214,16 @@ impl Registration {
198214 unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
199215 sb_ptr : * mut bindings:: super_block ,
200216 ) {
201- // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
202- // the appropriate function to call for cleanup.
203- unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
217+ match T :: SUPER_TYPE {
218+ // SAFETY: In `get_tree_callback` we always call `get_tree_bdev` for
219+ // `Super::BlockDev`, so `kill_block_super` is the appropriate function to call
220+ // for cleanup.
221+ Super :: BlockDev => unsafe { bindings:: kill_block_super ( sb_ptr) } ,
222+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev` for
223+ // `Super::Independent`, so `kill_anon_super` is the appropriate function to call
224+ // for cleanup.
225+ Super :: Independent => unsafe { bindings:: kill_anon_super ( sb_ptr) } ,
226+ }
204227
205228 // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
206229 let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
@@ -473,12 +496,86 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
473496 } ) ) )
474497 }
475498 }
499+
500+ /// Reads a block from the block device.
501+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
502+ pub fn bread ( & self , block : u64 ) -> Result < ARef < buffer:: Head > > {
503+ // Fail requests for non-blockdev file systems. This is a compile-time check.
504+ match T :: SUPER_TYPE {
505+ Super :: BlockDev => { }
506+ _ => return Err ( EIO ) ,
507+ }
508+
509+ // SAFETY: This function is only valid after the `NeedsInit` typestate, so the block size
510+ // is known and the superblock can be used to read blocks.
511+ let ptr =
512+ ptr:: NonNull :: new ( unsafe { bindings:: sb_bread ( self . 0 . get ( ) , block) } ) . ok_or ( EIO ) ?;
513+ // SAFETY: `sb_bread` returns a referenced buffer head. Ownership of the increment is
514+ // passed to the `ARef` instance.
515+ Ok ( unsafe { ARef :: from_raw ( ptr. cast ( ) ) } )
516+ }
517+
518+ /// Reads `size` bytes starting from `offset` bytes.
519+ ///
520+ /// Returns an iterator that returns slices based on blocks.
521+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
522+ pub fn read (
523+ & self ,
524+ offset : u64 ,
525+ size : u64 ,
526+ ) -> Result < impl Iterator < Item = Result < buffer:: View > > + ' _ > {
527+ struct BlockIter < ' a , T : FileSystem + ?Sized > {
528+ sb : & ' a SuperBlock < T > ,
529+ next_offset : u64 ,
530+ end : u64 ,
531+ }
532+ impl < ' a , T : FileSystem + ?Sized > Iterator for BlockIter < ' a , T > {
533+ type Item = Result < buffer:: View > ;
534+
535+ fn next ( & mut self ) -> Option < Self :: Item > {
536+ if self . next_offset >= self . end {
537+ return None ;
538+ }
539+
540+ // SAFETY: The superblock is valid and has had its block size initialised.
541+ let block_size = unsafe { ( * self . sb . 0 . get ( ) ) . s_blocksize } ;
542+ let bh = match self . sb . bread ( self . next_offset / block_size) {
543+ Ok ( bh) => bh,
544+ Err ( e) => return Some ( Err ( e) ) ,
545+ } ;
546+ let boffset = self . next_offset & ( block_size - 1 ) ;
547+ let bsize = core:: cmp:: min ( self . end - self . next_offset , block_size - boffset) ;
548+ self . next_offset += bsize;
549+ Some ( Ok ( buffer:: View :: new ( bh, boffset as usize , bsize as usize ) ) )
550+ }
551+ }
552+ Ok ( BlockIter {
553+ sb : self ,
554+ next_offset : offset,
555+ end : offset. checked_add ( size) . ok_or ( ERANGE ) ?,
556+ } )
557+ }
558+
559+ /// Returns the number of sectors in the underlying block device.
560+ pub fn sector_count ( & self ) -> Result < u64 > {
561+ // Fail requests for non-blockdev file systems. This is a compile-time check.
562+ match T :: SUPER_TYPE {
563+ // The superblock is valid and given that it's a blockdev superblock it must have a
564+ // valid `s_bdev`.
565+ Super :: BlockDev => Ok ( unsafe { bindings:: bdev_nr_sectors ( ( * self . 0 . get ( ) ) . s_bdev ) } ) ,
566+ _ => Err ( EIO ) ,
567+ }
568+ }
476569}
477570
478571/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
479572/// eventually.
480573pub struct NeedsInit ;
481574
575+ /// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_data`] needs to be called
576+ /// eventually.
577+ pub struct NeedsData ;
578+
482579/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
483580/// eventually.
484581pub struct NeedsRoot ;
@@ -532,11 +629,7 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
532629 }
533630
534631 /// Initialises the superblock.
535- pub fn init (
536- self ,
537- params : & SuperParams ,
538- data : T :: Data ,
539- ) -> Result < NewSuperBlock < ' a , T , NeedsRoot > > {
632+ pub fn init ( self , params : & SuperParams ) -> Result < NewSuperBlock < ' a , T , NeedsData > > {
540633 // SAFETY: Since this is a new super block, we hold the only reference to it.
541634 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
542635
@@ -553,16 +646,38 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
553646 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
554647 sb. s_flags |= bindings:: SB_RDONLY ;
555648
556- // No failures are allowed beyond this point, otherwise we'll leak `data`.
557- sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
558-
559649 Ok ( NewSuperBlock {
560650 sb : self . sb ,
561651 _p : PhantomData ,
562652 } )
563653 }
564654}
565655
656+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsData > {
657+ /// Initialises the superblock data.
658+ pub fn init_data ( self , data : T :: Data ) -> NewSuperBlock < ' a , T , NeedsRoot > {
659+ // SAFETY: Since this is a new superblock, we hold the only reference to it.
660+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
661+ sb. s_fs_info = data. into_foreign ( ) . cast_mut ( ) ;
662+
663+ NewSuperBlock {
664+ sb : self . sb ,
665+ _p : PhantomData ,
666+ }
667+ }
668+
669+ /// Reads a block from the block device.
670+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
671+ pub fn bread ( & self , block : u64 ) -> Result < ARef < buffer:: Head > > {
672+ self . sb . bread ( block)
673+ }
674+
675+ /// Returns the number of sectors in the underlying block device.
676+ pub fn sector_count ( & self ) -> Result < u64 > {
677+ self . sb . sector_count ( )
678+ }
679+ }
680+
566681impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T , NeedsRoot > {
567682 /// Initialises the root of the superblock.
568683 pub fn init_root ( self , inode : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
@@ -608,9 +723,18 @@ impl<T: FileSystem + ?Sized> Tables<T> {
608723 } ;
609724
610725 unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
611- // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
612- // the right type and is a valid callback.
613- unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
726+ match T :: SUPER_TYPE {
727+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
728+ // the right type and is a valid callback.
729+ Super :: BlockDev => unsafe {
730+ bindings:: get_tree_bdev ( fc, Some ( Self :: fill_super_callback) )
731+ } ,
732+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
733+ // the right type and is a valid callback.
734+ Super :: Independent => unsafe {
735+ bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) )
736+ } ,
737+ }
614738 }
615739
616740 unsafe extern "C" fn fill_super_callback (
0 commit comments