77//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
88
99use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
10- use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque } ;
11- use crate :: {
12- bindings, folio:: LockedFolio , init:: PinInit , str:: CStr , time:: Timespec , try_pin_init,
13- ThisModule ,
14- } ;
10+ use crate :: folio:: { LockedFolio , UniqueFolio } ;
11+ use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque , ScopeGuard } ;
12+ use crate :: { bindings, init:: PinInit , str:: CStr , time:: Timespec , try_pin_init, ThisModule } ;
1513use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
1614use macros:: { pin_data, pinned_drop} ;
1715
@@ -21,6 +19,17 @@ pub mod buffer;
2119/// Maximum size of an inode.
2220pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
2321
22+ /// Type of superblock keying.
23+ ///
24+ /// It determines how C's `fs_context_operations::get_tree` is implemented.
25+ pub enum Super {
26+ /// Multiple independent superblocks may exist.
27+ Independent ,
28+
29+ /// Uses a block device.
30+ BlockDev ,
31+ }
32+
2433/// A file system type.
2534pub trait FileSystem {
2635 /// Data associated with each file system instance (super-block).
@@ -29,6 +38,9 @@ pub trait FileSystem {
2938 /// The name of the file system type.
3039 const NAME : & ' static CStr ;
3140
41+ /// Determines how superblocks for this file system type are keyed.
42+ const SUPER_TYPE : Super = Super :: Independent ;
43+
3244 /// Returns the parameters to initialise a super block.
3345 fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams < Self :: Data > > ;
3446
@@ -181,7 +193,9 @@ impl Registration {
181193 fs. name = T :: NAME . as_char_ptr( ) ;
182194 fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
183195 fs. kill_sb = Some ( Self :: kill_sb_callback:: <T >) ;
184- fs. fs_flags = 0 ;
196+ fs. fs_flags = if let Super :: BlockDev = T :: SUPER_TYPE {
197+ bindings:: FS_REQUIRES_DEV as i32
198+ } else { 0 } ;
185199
186200 // SAFETY: Pointers stored in `fs` are static so will live for as long as the
187201 // registration is active (it is undone in `drop`).
@@ -204,9 +218,16 @@ impl Registration {
204218 unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
205219 sb_ptr : * mut bindings:: super_block ,
206220 ) {
207- // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
208- // the appropriate function to call for cleanup.
209- unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
221+ match T :: SUPER_TYPE {
222+ // SAFETY: In `get_tree_callback` we always call `get_tree_bdev` for
223+ // `Super::BlockDev`, so `kill_block_super` is the appropriate function to call
224+ // for cleanup.
225+ Super :: BlockDev => unsafe { bindings:: kill_block_super ( sb_ptr) } ,
226+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev` for
227+ // `Super::Independent`, so `kill_anon_super` is the appropriate function to call
228+ // for cleanup.
229+ Super :: Independent => unsafe { bindings:: kill_anon_super ( sb_ptr) } ,
230+ }
210231
211232 // SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
212233 let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
@@ -479,6 +500,65 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
479500 } ) ) )
480501 }
481502 }
503+
504+ /// Reads a block from the block device.
505+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
506+ pub fn bread ( & self , block : u64 ) -> Result < ARef < buffer:: Head > > {
507+ // Fail requests for non-blockdev file systems. This is a compile-time check.
508+ match T :: SUPER_TYPE {
509+ Super :: BlockDev => { }
510+ _ => return Err ( EIO ) ,
511+ }
512+
513+ // SAFETY: This function is only valid after the `NeedsInit` typestate, so the block size
514+ // is known and the superblock can be used to read blocks.
515+ let ptr =
516+ ptr:: NonNull :: new ( unsafe { bindings:: sb_bread ( self . 0 . get ( ) , block) } ) . ok_or ( EIO ) ?;
517+ // SAFETY: `sb_bread` returns a referenced buffer head. Ownership of the increment is
518+ // passed to the `ARef` instance.
519+ Ok ( unsafe { ARef :: from_raw ( ptr. cast ( ) ) } )
520+ }
521+
522+ /// Reads `size` bytes starting from `offset` bytes.
523+ ///
524+ /// Returns an iterator that returns slices based on blocks.
525+ #[ cfg( CONFIG_BUFFER_HEAD ) ]
526+ pub fn read (
527+ & self ,
528+ offset : u64 ,
529+ size : u64 ,
530+ ) -> Result < impl Iterator < Item = Result < buffer:: View > > + ' _ > {
531+ struct BlockIter < ' a , T : FileSystem + ?Sized > {
532+ sb : & ' a SuperBlock < T > ,
533+ next_offset : u64 ,
534+ end : u64 ,
535+ }
536+ impl < ' a , T : FileSystem + ?Sized > Iterator for BlockIter < ' a , T > {
537+ type Item = Result < buffer:: View > ;
538+
539+ fn next ( & mut self ) -> Option < Self :: Item > {
540+ if self . next_offset >= self . end {
541+ return None ;
542+ }
543+
544+ // SAFETY: The superblock is valid and has had its block size initialised.
545+ let block_size = unsafe { ( * self . sb . 0 . get ( ) ) . s_blocksize } ;
546+ let bh = match self . sb . bread ( self . next_offset / block_size) {
547+ Ok ( bh) => bh,
548+ Err ( e) => return Some ( Err ( e) ) ,
549+ } ;
550+ let boffset = self . next_offset & ( block_size - 1 ) ;
551+ let bsize = core:: cmp:: min ( self . end - self . next_offset , block_size - boffset) ;
552+ self . next_offset += bsize;
553+ Some ( Ok ( buffer:: View :: new ( bh, boffset as usize , bsize as usize ) ) )
554+ }
555+ }
556+ Ok ( BlockIter {
557+ sb : self ,
558+ next_offset : offset,
559+ end : offset. checked_add ( size) . ok_or ( ERANGE ) ?,
560+ } )
561+ }
482562}
483563
484564/// Required superblock parameters.
@@ -511,6 +591,70 @@ pub struct SuperParams<T: ForeignOwnable + Send + Sync> {
511591#[ repr( transparent) ]
512592pub struct NewSuperBlock < T : FileSystem + ?Sized > ( bindings:: super_block , PhantomData < T > ) ;
513593
594+ impl < T : FileSystem + ?Sized > NewSuperBlock < T > {
595+ /// Reads sectors.
596+ ///
597+ /// `count` must be such that the total size doesn't exceed a page.
598+ pub fn sread ( & self , sector : u64 , count : usize , folio : & mut UniqueFolio ) -> Result {
599+ // Fail requests for non-blockdev file systems. This is a compile-time check.
600+ match T :: SUPER_TYPE {
601+ // The superblock is valid and given that it's a blockdev superblock it must have a
602+ // valid `s_bdev`.
603+ Super :: BlockDev => { }
604+ _ => return Err ( EIO ) ,
605+ }
606+
607+ crate :: build_assert!( count * ( bindings:: SECTOR_SIZE as usize ) <= bindings:: PAGE_SIZE ) ;
608+
609+ // Read the sectors.
610+ let mut bio = bindings:: bio:: default ( ) ;
611+ let bvec = Opaque :: < bindings:: bio_vec > :: uninit ( ) ;
612+
613+ // SAFETY: `bio` and `bvec` are allocated on the stack, they're both valid.
614+ unsafe {
615+ bindings:: bio_init (
616+ & mut bio,
617+ self . 0 . s_bdev ,
618+ bvec. get ( ) ,
619+ 1 ,
620+ bindings:: req_op_REQ_OP_READ,
621+ )
622+ } ;
623+
624+ // SAFETY: `bio` was just initialised with `bio_init` above, so it's safe to call
625+ // `bio_uninit` on the way out.
626+ let mut bio =
627+ ScopeGuard :: new_with_data ( bio, |mut b| unsafe { bindings:: bio_uninit ( & mut b) } ) ;
628+
629+ // SAFETY: We have one free `bvec` (initialsied above). We also know that size won't exceed
630+ // a page size (build_assert above).
631+ unsafe {
632+ bindings:: bio_add_folio_nofail (
633+ & mut * bio,
634+ folio. 0 . 0 . get ( ) ,
635+ count * ( bindings:: SECTOR_SIZE as usize ) ,
636+ 0 ,
637+ )
638+ } ;
639+ bio. bi_iter . bi_sector = sector;
640+
641+ // SAFETY: The bio was fully initialised above.
642+ to_result ( unsafe { bindings:: submit_bio_wait ( & mut * bio) } ) ?;
643+ Ok ( ( ) )
644+ }
645+
646+ /// Returns the number of sectors in the underlying block device.
647+ pub fn sector_count ( & self ) -> Result < u64 > {
648+ // Fail requests for non-blockdev file systems. This is a compile-time check.
649+ match T :: SUPER_TYPE {
650+ // The superblock is valid and given that it's a blockdev superblock it must have a
651+ // valid `s_bdev`.
652+ Super :: BlockDev => Ok ( unsafe { bindings:: bdev_nr_sectors ( self . 0 . s_bdev ) } ) ,
653+ _ => Err ( EIO ) ,
654+ }
655+ }
656+ }
657+
514658struct Tables < T : FileSystem + ?Sized > ( T ) ;
515659impl < T : FileSystem + ?Sized > Tables < T > {
516660 const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
@@ -523,9 +667,18 @@ impl<T: FileSystem + ?Sized> Tables<T> {
523667 } ;
524668
525669 unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
526- // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
527- // the right type and is a valid callback.
528- unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
670+ match T :: SUPER_TYPE {
671+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
672+ // the right type and is a valid callback.
673+ Super :: BlockDev => unsafe {
674+ bindings:: get_tree_bdev ( fc, Some ( Self :: fill_super_callback) )
675+ } ,
676+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
677+ // the right type and is a valid callback.
678+ Super :: Independent => unsafe {
679+ bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) )
680+ } ,
681+ }
529682 }
530683
531684 unsafe extern "C" fn fill_super_callback (
0 commit comments