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