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:: { AlwaysRefCounted , Opaque } ;
11- use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
12- use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
10+ use crate :: types:: { ARef , AlwaysRefCounted , Either , Opaque } ;
11+ use crate :: { bindings, init:: PinInit , str:: CStr , time :: Timespec , try_pin_init, ThisModule } ;
12+ use core:: { marker:: PhantomData , marker:: PhantomPinned , mem :: ManuallyDrop , pin:: Pin , ptr} ;
1313use macros:: { pin_data, pinned_drop} ;
1414
1515/// Maximum size of an inode.
@@ -22,6 +22,12 @@ pub trait FileSystem {
2222
2323 /// Returns the parameters to initialise a super block.
2424 fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams > ;
25+
26+ /// Initialises and returns the root inode of the given superblock.
27+ ///
28+ /// This is called during initialisation of a superblock after [`FileSystem::super_params`] has
29+ /// completed successfully.
30+ fn init_root ( sb : & SuperBlock < Self > ) -> Result < ARef < INode < Self > > > ;
2531}
2632
2733/// A registration of a file system.
@@ -143,12 +149,136 @@ unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
143149 }
144150}
145151
152+ /// An inode that is locked and hasn't been initialised yet.
153+ #[ repr( transparent) ]
154+ pub struct NewINode < T : FileSystem + ?Sized > ( ARef < INode < T > > ) ;
155+
156+ impl < T : FileSystem + ?Sized > NewINode < T > {
157+ /// Initialises the new inode with the given parameters.
158+ pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
159+ // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
160+ let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
161+
162+ let mode = match params. typ {
163+ INodeType :: Dir => {
164+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
165+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
166+
167+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
168+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
169+ bindings:: S_IFDIR
170+ }
171+ } ;
172+
173+ inode. i_mode = ( params. mode & 0o777 ) | u16:: try_from ( mode) ?;
174+ inode. i_size = params. size ;
175+ inode. i_blocks = params. blocks ;
176+
177+ inode. __i_ctime = params. ctime . into ( ) ;
178+ inode. i_mtime = params. mtime . into ( ) ;
179+ inode. i_atime = params. atime . into ( ) ;
180+
181+ // SAFETY: inode is a new inode, so it is valid for write.
182+ unsafe {
183+ bindings:: set_nlink ( inode, params. nlink ) ;
184+ bindings:: i_uid_write ( inode, params. uid ) ;
185+ bindings:: i_gid_write ( inode, params. gid ) ;
186+ bindings:: unlock_new_inode ( inode) ;
187+ }
188+
189+ // SAFETY: We are manually destructuring `self` and preventing `drop` from being called.
190+ Ok ( unsafe { ( & ManuallyDrop :: new ( self ) . 0 as * const ARef < INode < T > > ) . read ( ) } )
191+ }
192+ }
193+
194+ impl < T : FileSystem + ?Sized > Drop for NewINode < T > {
195+ fn drop ( & mut self ) {
196+ // SAFETY: The new inode failed to be turned into an initialised inode, so it's safe (and
197+ // in fact required) to call `iget_failed` on it.
198+ unsafe { bindings:: iget_failed ( self . 0 . 0 . get ( ) ) } ;
199+ }
200+ }
201+
202+ /// The type of the inode.
203+ #[ derive( Copy , Clone ) ]
204+ pub enum INodeType {
205+ /// Directory type.
206+ Dir ,
207+ }
208+
209+ /// Required inode parameters.
210+ ///
211+ /// This is used when creating new inodes.
212+ pub struct INodeParams {
213+ /// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
214+ /// everyone, the owner group, and the owner.
215+ pub mode : u16 ,
216+
217+ /// Type of inode.
218+ ///
219+ /// Also carries additional per-type data.
220+ pub typ : INodeType ,
221+
222+ /// Size of the contents of the inode.
223+ ///
224+ /// Its maximum value is [`MAX_LFS_FILESIZE`].
225+ pub size : i64 ,
226+
227+ /// Number of blocks.
228+ pub blocks : u64 ,
229+
230+ /// Number of links to the inode.
231+ pub nlink : u32 ,
232+
233+ /// User id.
234+ pub uid : u32 ,
235+
236+ /// Group id.
237+ pub gid : u32 ,
238+
239+ /// Creation time.
240+ pub ctime : Timespec ,
241+
242+ /// Last modification time.
243+ pub mtime : Timespec ,
244+
245+ /// Last access time.
246+ pub atime : Timespec ,
247+ }
248+
146249/// A file system super block.
147250///
148251/// Wraps the kernel's `struct super_block`.
149252#[ repr( transparent) ]
150253pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
151254
255+ impl < T : FileSystem + ?Sized > SuperBlock < T > {
256+ /// Tries to get an existing inode or create a new one if it doesn't exist yet.
257+ pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
258+ // SAFETY: The only initialisation missing from the superblock is the root, and this
259+ // function is needed to create the root, so it's safe to call it.
260+ let inode =
261+ ptr:: NonNull :: new ( unsafe { bindings:: iget_locked ( self . 0 . get ( ) , ino) } ) . ok_or ( ENOMEM ) ?;
262+
263+ // SAFETY: `inode` is valid for read, but there could be concurrent writers (e.g., if it's
264+ // an already-initialised inode), so we use `read_volatile` to read its current state.
265+ let state = unsafe { ptr:: read_volatile ( ptr:: addr_of!( ( * inode. as_ptr( ) ) . i_state) ) } ;
266+ if state & u64:: from ( bindings:: I_NEW ) == 0 {
267+ // The inode is cached. Just return it.
268+ //
269+ // SAFETY: `inode` had its refcount incremented by `iget_locked`; this increment is now
270+ // owned by `ARef`.
271+ Ok ( Either :: Left ( unsafe { ARef :: from_raw ( inode. cast ( ) ) } ) )
272+ } else {
273+ // SAFETY: The new inode is valid but not fully initialised yet, so it's ok to create a
274+ // `NewINode`.
275+ Ok ( Either :: Right ( NewINode ( unsafe {
276+ ARef :: from_raw ( inode. cast ( ) )
277+ } ) ) )
278+ }
279+ }
280+ }
281+
152282/// Required superblock parameters.
153283///
154284/// This is returned by implementations of [`FileSystem::super_params`].
@@ -215,41 +345,28 @@ impl<T: FileSystem + ?Sized> Tables<T> {
215345 sb. 0 . s_blocksize = 1 << sb. 0 . s_blocksize_bits ;
216346 sb. 0 . s_flags |= bindings:: SB_RDONLY ;
217347
218- // The following is scaffolding code that will be removed in a subsequent patch. It is
219- // needed to build a root dentry, otherwise core code will BUG().
220- // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
221- let inode = unsafe { bindings:: new_inode ( & mut sb. 0 ) } ;
222- if inode. is_null ( ) {
223- return Err ( ENOMEM ) ;
224- }
225-
226- // SAFETY: `inode` is valid for write.
227- unsafe { bindings:: set_nlink ( inode, 2 ) } ;
228-
229- {
230- // SAFETY: This is a newly-created inode. No other references to it exist, so it is
231- // safe to mutably dereference it.
232- let inode = unsafe { & mut * inode } ;
233- inode. i_ino = 1 ;
234- inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
235-
236- // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
237- inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
348+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
349+ // newly-created (and initialised above) superblock.
350+ let sb = unsafe { & mut * sb_ptr. cast ( ) } ;
351+ let root = T :: init_root ( sb) ?;
238352
239- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
240- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
353+ // Reject root inode if it belongs to a different superblock.
354+ if !ptr:: eq ( root. super_block ( ) , sb) {
355+ return Err ( EINVAL ) ;
241356 }
242357
243358 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
244359 // case for this call.
245360 //
246361 // It takes over the inode, even on failure, so we don't need to clean it up.
247- let dentry = unsafe { bindings:: d_make_root ( inode ) } ;
362+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
248363 if dentry. is_null ( ) {
249364 return Err ( ENOMEM ) ;
250365 }
251366
252- sb. 0 . s_root = dentry;
367+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
368+ // newly-created (and initialised above) superblock.
369+ unsafe { ( * sb_ptr) . s_root = dentry } ;
253370
254371 Ok ( 0 )
255372 } )
@@ -314,9 +431,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
314431///
315432/// ```
316433/// # mod module_fs_sample {
317- /// use kernel::fs::{NewSuperBlock, SuperParams};
434+ /// use kernel::fs::{INode, NewSuperBlock, SuperBlock , SuperParams};
318435/// use kernel::prelude::*;
319- /// use kernel::{c_str, fs};
436+ /// use kernel::{c_str, fs, types::ARef };
320437///
321438/// kernel::module_fs! {
322439/// type: MyFs,
@@ -332,6 +449,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
332449/// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
333450/// todo!()
334451/// }
452+ /// fn init_root(_sb: &SuperBlock<Self>) -> Result<ARef<INode<Self>>> {
453+ /// todo!()
454+ /// }
335455/// }
336456/// # }
337457/// ```
0 commit comments