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.
@@ -143,12 +143,136 @@ unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
143143 }
144144}
145145
146+ /// An inode that is locked and hasn't been initialised yet.
147+ #[ repr( transparent) ]
148+ pub struct NewINode < T : FileSystem + ?Sized > ( ARef < INode < T > > ) ;
149+
150+ impl < T : FileSystem + ?Sized > NewINode < T > {
151+ /// Initialises the new inode with the given parameters.
152+ pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
153+ // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
154+ let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
155+
156+ let mode = match params. typ {
157+ INodeType :: Dir => {
158+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
159+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
160+
161+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
162+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
163+ bindings:: S_IFDIR
164+ }
165+ } ;
166+
167+ inode. i_mode = ( params. mode & 0o777 ) | u16:: try_from ( mode) ?;
168+ inode. i_size = params. size ;
169+ inode. i_blocks = params. blocks ;
170+
171+ inode. __i_ctime = params. ctime . into ( ) ;
172+ inode. i_mtime = params. mtime . into ( ) ;
173+ inode. i_atime = params. atime . into ( ) ;
174+
175+ // SAFETY: inode is a new inode, so it is valid for write.
176+ unsafe {
177+ bindings:: set_nlink ( inode, params. nlink ) ;
178+ bindings:: i_uid_write ( inode, params. uid ) ;
179+ bindings:: i_gid_write ( inode, params. gid ) ;
180+ bindings:: unlock_new_inode ( inode) ;
181+ }
182+
183+ // SAFETY: We are manually destructuring `self` and preventing `drop` from being called.
184+ Ok ( unsafe { ( & ManuallyDrop :: new ( self ) . 0 as * const ARef < INode < T > > ) . read ( ) } )
185+ }
186+ }
187+
188+ impl < T : FileSystem + ?Sized > Drop for NewINode < T > {
189+ fn drop ( & mut self ) {
190+ // SAFETY: The new inode failed to be turned into an initialised inode, so it's safe (and
191+ // in fact required) to call `iget_failed` on it.
192+ unsafe { bindings:: iget_failed ( self . 0 . 0 . get ( ) ) } ;
193+ }
194+ }
195+
196+ /// The type of the inode.
197+ #[ derive( Copy , Clone ) ]
198+ pub enum INodeType {
199+ /// Directory type.
200+ Dir ,
201+ }
202+
203+ /// Required inode parameters.
204+ ///
205+ /// This is used when creating new inodes.
206+ pub struct INodeParams {
207+ /// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
208+ /// everyone, the owner group, and the owner.
209+ pub mode : u16 ,
210+
211+ /// Type of inode.
212+ ///
213+ /// Also carries additional per-type data.
214+ pub typ : INodeType ,
215+
216+ /// Size of the contents of the inode.
217+ ///
218+ /// Its maximum value is [`MAX_LFS_FILESIZE`].
219+ pub size : i64 ,
220+
221+ /// Number of blocks.
222+ pub blocks : u64 ,
223+
224+ /// Number of links to the inode.
225+ pub nlink : u32 ,
226+
227+ /// User id.
228+ pub uid : u32 ,
229+
230+ /// Group id.
231+ pub gid : u32 ,
232+
233+ /// Creation time.
234+ pub ctime : Timespec ,
235+
236+ /// Last modification time.
237+ pub mtime : Timespec ,
238+
239+ /// Last access time.
240+ pub atime : Timespec ,
241+ }
242+
146243/// A file system super block.
147244///
148245/// Wraps the kernel's `struct super_block`.
149246#[ repr( transparent) ]
150247pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
151248
249+ impl < T : FileSystem + ?Sized > SuperBlock < T > {
250+ /// Tries to get an existing inode or create a new one if it doesn't exist yet.
251+ pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
252+ // SAFETY: The only initialisation missing from the superblock is the root, and this
253+ // function is needed to create the root, so it's safe to call it.
254+ let inode =
255+ ptr:: NonNull :: new ( unsafe { bindings:: iget_locked ( self . 0 . get ( ) , ino) } ) . ok_or ( ENOMEM ) ?;
256+
257+ // SAFETY: `inode` is valid for read, but there could be concurrent writers (e.g., if it's
258+ // an already-initialised inode), so we use `read_volatile` to read its current state.
259+ let state = unsafe { ptr:: read_volatile ( ptr:: addr_of!( ( * inode. as_ptr( ) ) . i_state) ) } ;
260+ if state & u64:: from ( bindings:: I_NEW ) == 0 {
261+ // The inode is cached. Just return it.
262+ //
263+ // SAFETY: `inode` had its refcount incremented by `iget_locked`; this increment is now
264+ // owned by `ARef`.
265+ Ok ( Either :: Left ( unsafe { ARef :: from_raw ( inode. cast ( ) ) } ) )
266+ } else {
267+ // SAFETY: The new inode is valid but not fully initialised yet, so it's ok to create a
268+ // `NewINode`.
269+ Ok ( Either :: Right ( NewINode ( unsafe {
270+ ARef :: from_raw ( inode. cast ( ) )
271+ } ) ) )
272+ }
273+ }
274+ }
275+
152276/// Required superblock parameters.
153277///
154278/// This is used in [`NewSuperBlock::init`].
@@ -196,7 +320,7 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
196320 }
197321
198322 /// Initialises the superblock.
199- pub fn init ( self , params : & SuperParams ) -> Result < & ' a SuperBlock < T > > {
323+ pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
200324 // SAFETY: Since this is a new super block, we hold the only reference to it.
201325 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
202326
@@ -212,36 +336,16 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
212336 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
213337 sb. s_flags |= bindings:: SB_RDONLY ;
214338
215- // The following is scaffolding code that will be removed in a subsequent patch. It is
216- // needed to build a root dentry, otherwise core code will BUG().
217- // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
218- let inode = unsafe { bindings:: new_inode ( sb) } ;
219- if inode. is_null ( ) {
220- return Err ( ENOMEM ) ;
221- }
222-
223- // SAFETY: `inode` is valid for write.
224- unsafe { bindings:: set_nlink ( inode, 2 ) } ;
225-
226- {
227- // SAFETY: This is a newly-created inode. No other references to it exist, so it is
228- // safe to mutably dereference it.
229- let inode = unsafe { & mut * inode } ;
230- inode. i_ino = 1 ;
231- inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
232-
233- // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
234- inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
235-
236- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
237- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
339+ // Reject root inode if it belongs to a different superblock.
340+ if !ptr:: eq ( root. super_block ( ) , self . sb ) {
341+ return Err ( EINVAL ) ;
238342 }
239343
240- // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
241- // case for this call.
344+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the case
345+ // for this call.
242346 //
243347 // It takes over the inode, even on failure, so we don't need to clean it up.
244- let dentry = unsafe { bindings:: d_make_root ( inode ) } ;
348+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
245349 if dentry. is_null ( ) {
246350 return Err ( ENOMEM ) ;
247351 }
@@ -252,6 +356,14 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
252356 }
253357}
254358
359+ impl < T : FileSystem + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
360+ type Target = SuperBlock < T > ;
361+
362+ fn deref ( & self ) -> & Self :: Target {
363+ self . sb
364+ }
365+ }
366+
255367struct Tables < T : FileSystem + ?Sized > ( T ) ;
256368impl < T : FileSystem + ?Sized > Tables < T > {
257369 const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
0 commit comments