66//!
77//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
88
9+ /// Maximum size of an inode.
10+ pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
11+
912/// Read-only file systems.
1013pub mod ro {
11- use crate :: error:: { code:: * , from_result, to_result, Error } ;
14+ use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
1215 use crate :: types:: Opaque ;
1316 use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
1417 use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin } ;
@@ -18,6 +21,9 @@ pub mod ro {
1821 pub trait Type {
1922 /// The name of the file system type.
2023 const NAME : & ' static CStr ;
24+
25+ /// Initialises a super block for this file system type.
26+ fn fill_super ( sb : NewSuperBlock < ' _ , Self > ) -> Result < & SuperBlock < Self > > ;
2127 }
2228
2329 /// A registration of a read-only file system.
@@ -48,7 +54,7 @@ pub mod ro {
4854 * fs = bindings:: file_system_type:: default ( ) ;
4955 fs. owner = module. 0 ;
5056 fs. name = T :: NAME . as_char_ptr( ) ;
51- fs. init_fs_context = Some ( Self :: init_fs_context_callback) ;
57+ fs. init_fs_context = Some ( Self :: init_fs_context_callback:: < T > ) ;
5258 fs. kill_sb = Some ( Self :: kill_sb_callback) ;
5359 fs. fs_flags = 0 ;
5460
@@ -59,13 +65,22 @@ pub mod ro {
5965 } )
6066 }
6167
62- unsafe extern "C" fn init_fs_context_callback (
63- _fc_ptr : * mut bindings:: fs_context ,
68+ unsafe extern "C" fn init_fs_context_callback < T : Type + ? Sized > (
69+ fc_ptr : * mut bindings:: fs_context ,
6470 ) -> core:: ffi:: c_int {
65- from_result ( || Err ( ENOTSUPP ) )
71+ from_result ( || {
72+ // SAFETY: The C callback API guarantees that `fc_ptr` is valid.
73+ let fc = unsafe { & mut * fc_ptr } ;
74+ fc. ops = & Tables :: < T > :: CONTEXT ;
75+ Ok ( 0 )
76+ } )
6677 }
6778
68- unsafe extern "C" fn kill_sb_callback ( _sb_ptr : * mut bindings:: super_block ) { }
79+ unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
80+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super`
81+ // is the appropriate function to call for cleanup.
82+ unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
83+ }
6984 }
7085
7186 #[ pinned_drop]
@@ -78,6 +93,178 @@ pub mod ro {
7893 }
7994 }
8095
96+ /// A file system super block.
97+ ///
98+ /// Wraps the kernel's `struct super_block`.
99+ #[ repr( transparent) ]
100+ pub struct SuperBlock < T : Type + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
101+
102+ /// Required superblock parameters.
103+ ///
104+ /// This is used in [`NewSuperBlock::init`].
105+ pub struct SuperParams {
106+ /// The magic number of the superblock.
107+ pub magic : u32 ,
108+
109+ /// The size of a block in powers of 2 (i.e., for a value of `n`, the size is `2^n`).
110+ pub blocksize_bits : u8 ,
111+
112+ /// Maximum size of a file.
113+ ///
114+ /// The maximum allowed value is [`super::MAX_LFS_FILESIZE`].
115+ pub maxbytes : i64 ,
116+
117+ /// Granularity of c/m/atime in ns (cannot be worse than a second).
118+ pub time_gran : u32 ,
119+ }
120+
121+ /// A superblock that is still being initialised.
122+ ///
123+ /// # Invariants
124+ ///
125+ /// The superblock is a newly-created one and this is the only active pointer to it.
126+ pub struct NewSuperBlock < ' a , T : Type + ?Sized > {
127+ sb : & ' a mut SuperBlock < T > ,
128+
129+ // This also forces `'a` to be invariant.
130+ _p : PhantomData < & ' a mut & ' a ( ) > ,
131+ }
132+
133+ impl < ' a , T : Type + ?Sized > NewSuperBlock < ' a , T > {
134+ /// Creates a new instance of [`NewSuperBlock`].
135+ ///
136+ /// # Safety
137+ ///
138+ /// `sb` must point to a newly-created superblock and it must be the only active pointer to
139+ /// it.
140+ unsafe fn new ( sb : * mut bindings:: super_block ) -> Self {
141+ // INVARIANT: The invariants are satisfied by the safety requirements of this function.
142+ Self {
143+ // SAFETY: The safety requirements ensure that `sb` is valid for read and write.
144+ sb : unsafe { & mut * sb. cast ( ) } ,
145+ _p : PhantomData ,
146+ }
147+ }
148+
149+ /// Initialises the superblock.
150+ pub fn init ( self , params : & SuperParams ) -> Result < & ' a SuperBlock < T > > {
151+ // SAFETY: Since this is a new super block, we hold the only reference to it.
152+ let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
153+
154+ sb. s_magic = params. magic as _ ;
155+ sb. s_op = & Tables :: < T > :: SUPER_BLOCK ;
156+ sb. s_maxbytes = params. maxbytes ;
157+ sb. s_time_gran = params. time_gran ;
158+ sb. s_blocksize_bits = params. blocksize_bits ;
159+ sb. s_blocksize = 1 ;
160+ if sb. s_blocksize . leading_zeros ( ) < params. blocksize_bits . into ( ) {
161+ return Err ( EINVAL ) ;
162+ }
163+ sb. s_blocksize = 1 << sb. s_blocksize_bits ;
164+ sb. s_flags |= bindings:: SB_RDONLY ;
165+
166+ // The following is scaffolding code that will be removed in a subsequent patch. It is
167+ // needed to build a root dentry, otherwise core code will BUG().
168+ let inode = unsafe { bindings:: new_inode ( sb) } ;
169+ if inode. is_null ( ) {
170+ return Err ( ENOMEM ) ;
171+ }
172+
173+ // SAFETY: `inode` is valid for write.
174+ unsafe { bindings:: set_nlink ( inode, 2 ) } ;
175+
176+ {
177+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
178+ // safe to mutably dereference it.
179+ let inode = unsafe { & mut * inode } ;
180+ inode. i_ino = 1 ;
181+ inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
182+
183+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
184+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
185+
186+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
187+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
188+ }
189+
190+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
191+ // case for this call.
192+ //
193+ // It takes over the inode, even on failure, so we don't need to clean it up.
194+ let dentry = unsafe { bindings:: d_make_root ( inode) } ;
195+ if dentry. is_null ( ) {
196+ return Err ( ENOMEM ) ;
197+ }
198+
199+ sb. s_root = dentry;
200+
201+ Ok ( self . sb )
202+ }
203+ }
204+
205+ struct Tables < T : Type + ?Sized > ( T ) ;
206+ impl < T : Type + ?Sized > Tables < T > {
207+ const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
208+ free : None ,
209+ parse_param : None ,
210+ get_tree : Some ( Self :: get_tree_callback) ,
211+ reconfigure : None ,
212+ parse_monolithic : None ,
213+ dup : None ,
214+ } ;
215+
216+ unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
217+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
218+ // the right type and is a valid callback.
219+ unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
220+ }
221+
222+ unsafe extern "C" fn fill_super_callback (
223+ sb_ptr : * mut bindings:: super_block ,
224+ _fc : * mut bindings:: fs_context ,
225+ ) -> core:: ffi:: c_int {
226+ from_result ( || {
227+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
228+ // newly-created superblock.
229+ let newsb = unsafe { NewSuperBlock :: new ( sb_ptr) } ;
230+ T :: fill_super ( newsb) ?;
231+ Ok ( 0 )
232+ } )
233+ }
234+
235+ const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
236+ alloc_inode : None ,
237+ destroy_inode : None ,
238+ free_inode : None ,
239+ dirty_inode : None ,
240+ write_inode : None ,
241+ drop_inode : None ,
242+ evict_inode : None ,
243+ put_super : None ,
244+ sync_fs : None ,
245+ freeze_super : None ,
246+ freeze_fs : None ,
247+ thaw_super : None ,
248+ unfreeze_fs : None ,
249+ statfs : None ,
250+ remount_fs : None ,
251+ umount_begin : None ,
252+ show_options : None ,
253+ show_devname : None ,
254+ show_path : None ,
255+ show_stats : None ,
256+ #[ cfg( CONFIG_QUOTA ) ]
257+ quota_read : None ,
258+ #[ cfg( CONFIG_QUOTA ) ]
259+ quota_write : None ,
260+ #[ cfg( CONFIG_QUOTA ) ]
261+ get_dquots : None ,
262+ nr_cached_objects : None ,
263+ free_cached_objects : None ,
264+ shutdown : None ,
265+ } ;
266+ }
267+
81268 /// Kernel module that exposes a single read-only file system implemented by `T`.
82269 #[ pin_data]
83270 pub struct Module < T : Type + ?Sized > {
@@ -119,6 +306,11 @@ pub mod ro {
119306 /// impl fs::ro::Type for MyFs {
120307 /// // ...
121308 /// # const NAME: &'static CStr = c_str!("myfs");
309+ /// # fn fill_super(
310+ /// # _: fs::ro::NewSuperBlock<'_, Self>
311+ /// # ) -> Result<&fs::ro::SuperBlock<Self>> {
312+ /// # todo!()
313+ /// # }
122314 /// }
123315 /// ```
124316 #[ macro_export]
0 commit comments