66//!
77//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
88
9- use crate :: error:: { code:: * , from_result, to_result, Error } ;
9+ use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
1010use crate :: types:: Opaque ;
1111use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
1212use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin } ;
1313use macros:: { pin_data, pinned_drop} ;
1414
15+ /// Maximum size of an inode.
16+ pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
17+
1518/// A file system type.
1619pub trait FileSystem {
1720 /// The name of the file system type.
1821 const NAME : & ' static CStr ;
22+
23+ /// Initialises a super block for this file system type.
24+ fn fill_super ( sb : NewSuperBlock < ' _ , Self > ) -> Result < & SuperBlock < Self > > ;
1925}
2026
2127/// A registration of a file system.
@@ -49,7 +55,7 @@ impl Registration {
4955 let fs = unsafe { & mut * fs_ptr } ;
5056 fs. owner = module. 0 ;
5157 fs. name = T :: NAME . as_char_ptr( ) ;
52- fs. init_fs_context = Some ( Self :: init_fs_context_callback) ;
58+ fs. init_fs_context = Some ( Self :: init_fs_context_callback:: < T > ) ;
5359 fs. kill_sb = Some ( Self :: kill_sb_callback) ;
5460 fs. fs_flags = 0 ;
5561
@@ -60,13 +66,22 @@ impl Registration {
6066 } )
6167 }
6268
63- unsafe extern "C" fn init_fs_context_callback (
64- _fc_ptr : * mut bindings:: fs_context ,
69+ unsafe extern "C" fn init_fs_context_callback < T : FileSystem + ? Sized > (
70+ fc_ptr : * mut bindings:: fs_context ,
6571 ) -> core:: ffi:: c_int {
66- from_result ( || Err ( ENOTSUPP ) )
72+ from_result ( || {
73+ // SAFETY: The C callback API guarantees that `fc_ptr` is valid.
74+ let fc = unsafe { & mut * fc_ptr } ;
75+ fc. ops = & Tables :: < T > :: CONTEXT ;
76+ Ok ( 0 )
77+ } )
6778 }
6879
69- unsafe extern "C" fn kill_sb_callback ( _sb_ptr : * mut bindings:: super_block ) { }
80+ unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
81+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
82+ // the appropriate function to call for cleanup.
83+ unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
84+ }
7085}
7186
7287#[ pinned_drop]
@@ -79,6 +94,178 @@ impl PinnedDrop for Registration {
7994 }
8095}
8196
97+ /// A file system super block.
98+ ///
99+ /// Wraps the kernel's `struct super_block`.
100+ #[ repr( transparent) ]
101+ pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
102+
103+ /// Required superblock parameters.
104+ ///
105+ /// This is used in [`NewSuperBlock::init`].
106+ pub struct SuperParams {
107+ /// The magic number of the superblock.
108+ pub magic : u32 ,
109+
110+ /// The size of a block in powers of 2 (i.e., for a value of `n`, the size is `2^n`).
111+ pub blocksize_bits : u8 ,
112+
113+ /// Maximum size of a file.
114+ ///
115+ /// The maximum allowed value is [`MAX_LFS_FILESIZE`].
116+ pub maxbytes : i64 ,
117+
118+ /// Granularity of c/m/atime in ns (cannot be worse than a second).
119+ pub time_gran : u32 ,
120+ }
121+
122+ /// A superblock that is still being initialised.
123+ ///
124+ /// # Invariants
125+ ///
126+ /// The superblock is a newly-created one and this is the only active pointer to it.
127+ pub struct NewSuperBlock < ' a , T : FileSystem + ?Sized > {
128+ sb : & ' a mut SuperBlock < T > ,
129+
130+ // This also forces `'a` to be invariant.
131+ _p : PhantomData < & ' a mut & ' a ( ) > ,
132+ }
133+
134+ impl < ' a , T : FileSystem + ?Sized > NewSuperBlock < ' a , T > {
135+ /// Creates a new instance of [`NewSuperBlock`].
136+ ///
137+ /// # Safety
138+ ///
139+ /// `sb` must point to a newly-created superblock and it must be the only active pointer to 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+ // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
169+ let inode = unsafe { bindings:: new_inode ( sb) } ;
170+ if inode. is_null ( ) {
171+ return Err ( ENOMEM ) ;
172+ }
173+
174+ // SAFETY: `inode` is valid for write.
175+ unsafe { bindings:: set_nlink ( inode, 2 ) } ;
176+
177+ {
178+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
179+ // safe to mutably dereference it.
180+ let inode = unsafe { & mut * inode } ;
181+ inode. i_ino = 1 ;
182+ inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
183+
184+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
185+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
186+
187+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
188+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
189+ }
190+
191+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
192+ // case for this call.
193+ //
194+ // It takes over the inode, even on failure, so we don't need to clean it up.
195+ let dentry = unsafe { bindings:: d_make_root ( inode) } ;
196+ if dentry. is_null ( ) {
197+ return Err ( ENOMEM ) ;
198+ }
199+
200+ sb. s_root = dentry;
201+
202+ Ok ( self . sb )
203+ }
204+ }
205+
206+ struct Tables < T : FileSystem + ?Sized > ( T ) ;
207+ impl < T : FileSystem + ?Sized > Tables < T > {
208+ const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
209+ free : None ,
210+ parse_param : None ,
211+ get_tree : Some ( Self :: get_tree_callback) ,
212+ reconfigure : None ,
213+ parse_monolithic : None ,
214+ dup : None ,
215+ } ;
216+
217+ unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
218+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
219+ // the right type and is a valid callback.
220+ unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
221+ }
222+
223+ unsafe extern "C" fn fill_super_callback (
224+ sb_ptr : * mut bindings:: super_block ,
225+ _fc : * mut bindings:: fs_context ,
226+ ) -> core:: ffi:: c_int {
227+ from_result ( || {
228+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
229+ // newly-created superblock.
230+ let newsb = unsafe { NewSuperBlock :: new ( sb_ptr) } ;
231+ T :: fill_super ( newsb) ?;
232+ Ok ( 0 )
233+ } )
234+ }
235+
236+ const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
237+ alloc_inode : None ,
238+ destroy_inode : None ,
239+ free_inode : None ,
240+ dirty_inode : None ,
241+ write_inode : None ,
242+ drop_inode : None ,
243+ evict_inode : None ,
244+ put_super : None ,
245+ sync_fs : None ,
246+ freeze_super : None ,
247+ freeze_fs : None ,
248+ thaw_super : None ,
249+ unfreeze_fs : None ,
250+ statfs : None ,
251+ remount_fs : None ,
252+ umount_begin : None ,
253+ show_options : None ,
254+ show_devname : None ,
255+ show_path : None ,
256+ show_stats : None ,
257+ #[ cfg( CONFIG_QUOTA ) ]
258+ quota_read : None ,
259+ #[ cfg( CONFIG_QUOTA ) ]
260+ quota_write : None ,
261+ #[ cfg( CONFIG_QUOTA ) ]
262+ get_dquots : None ,
263+ nr_cached_objects : None ,
264+ free_cached_objects : None ,
265+ shutdown : None ,
266+ } ;
267+ }
268+
82269/// Kernel module that exposes a single file system implemented by `T`.
83270#[ pin_data]
84271pub struct Module < T : FileSystem + ?Sized > {
@@ -98,13 +285,14 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
98285
99286/// Declares a kernel module that exposes a single file system.
100287///
101- /// The `type` argument must be a type which implements the [`FileSystem`] trait. Also accepts
102- /// various forms of kernel metadata.
288+ /// The `type` argument must be a type which implements the [`FileSystem`] trait. Also accepts various
289+ /// forms of kernel metadata.
103290///
104291/// # Examples
105292///
106293/// ```
107- /// # mod module_fs_sample {
294+ /// # mod module_ro_fs_sample {
295+ /// use kernel::fs::{NewSuperBlock, SuperBlock};
108296/// use kernel::prelude::*;
109297/// use kernel::{c_str, fs};
110298///
@@ -119,6 +307,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
119307/// struct MyFs;
120308/// impl fs::FileSystem for MyFs {
121309/// const NAME: &'static CStr = c_str!("myfs");
310+ /// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
311+ /// todo!()
312+ /// }
122313/// }
123314/// # }
124315/// ```
0 commit comments