7
7
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
8
8
9
9
use 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 } ;
15
13
use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
16
14
use macros:: { pin_data, pinned_drop} ;
17
15
@@ -21,6 +19,17 @@ pub mod buffer;
21
19
/// Maximum size of an inode.
22
20
pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
23
21
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
+
24
33
/// A file system type.
25
34
pub trait FileSystem {
26
35
/// Data associated with each file system instance (super-block).
@@ -29,6 +38,9 @@ pub trait FileSystem {
29
38
/// The name of the file system type.
30
39
const NAME : & ' static CStr ;
31
40
41
+ /// Determines how superblocks for this file system type are keyed.
42
+ const SUPER_TYPE : Super = Super :: Independent ;
43
+
32
44
/// Returns the parameters to initialise a super block.
33
45
fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams < Self :: Data > > ;
34
46
@@ -181,7 +193,9 @@ impl Registration {
181
193
fs. name = T :: NAME . as_char_ptr( ) ;
182
194
fs. init_fs_context = Some ( Self :: init_fs_context_callback:: <T >) ;
183
195
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 } ;
185
199
186
200
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
187
201
// registration is active (it is undone in `drop`).
@@ -204,9 +218,16 @@ impl Registration {
204
218
unsafe extern "C" fn kill_sb_callback < T : FileSystem + ?Sized > (
205
219
sb_ptr : * mut bindings:: super_block ,
206
220
) {
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
+ }
210
231
211
232
// SAFETY: The C API contract guarantees that `sb_ptr` is valid for read.
212
233
let ptr = unsafe { ( * sb_ptr) . s_fs_info } ;
@@ -479,6 +500,65 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
479
500
} ) ) )
480
501
}
481
502
}
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
+ }
482
562
}
483
563
484
564
/// Required superblock parameters.
@@ -511,6 +591,70 @@ pub struct SuperParams<T: ForeignOwnable + Send + Sync> {
511
591
#[ repr( transparent) ]
512
592
pub struct NewSuperBlock < T : FileSystem + ?Sized > ( bindings:: super_block , PhantomData < T > ) ;
513
593
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
+
514
658
struct Tables < T : FileSystem + ?Sized > ( T ) ;
515
659
impl < T : FileSystem + ?Sized > Tables < T > {
516
660
const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
@@ -523,9 +667,18 @@ impl<T: FileSystem + ?Sized> Tables<T> {
523
667
} ;
524
668
525
669
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
+ }
529
682
}
530
683
531
684
unsafe extern "C" fn fill_super_callback (
0 commit comments