@@ -12,9 +12,9 @@ pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
1212/// Read-only file systems.
1313pub mod ro {
1414 use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
15- use crate :: types:: { AlwaysRefCounted , Opaque } ;
16- use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
17- use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
15+ use crate :: types:: { ARef , AlwaysRefCounted , Either , Opaque } ;
16+ use crate :: { bindings, init:: PinInit , str:: CStr , time :: Time , try_pin_init, ThisModule } ;
17+ use core:: { marker:: PhantomData , marker:: PhantomPinned , mem :: ManuallyDrop , pin:: Pin , ptr} ;
1818 use macros:: { pin_data, pinned_drop} ;
1919
2020 /// A read-only file system type.
@@ -137,12 +137,138 @@ pub mod ro {
137137 }
138138 }
139139
140+ /// An inode that is locked and hasn't been initialised yet.
141+ #[ repr( transparent) ]
142+ pub struct NewINode < T : Type + ?Sized > ( ARef < INode < T > > ) ;
143+
144+ impl < T : Type + ?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
178+ // called.
179+ Ok ( unsafe { ( & ManuallyDrop :: new ( self ) . 0 as * const ARef < INode < T > > ) . read ( ) } )
180+ }
181+ }
182+
183+ impl < T : Type + ?Sized > Drop for NewINode < T > {
184+ fn drop ( & mut self ) {
185+ // SAFETY: The new inode failed to be turned into an initialised inode, so it's safe
186+ // (and in fact required) to call `iget_failed` on it.
187+ unsafe { bindings:: iget_failed ( self . 0 . 0 . get ( ) ) } ;
188+ }
189+ }
190+
191+ /// The type of the inode.
192+ #[ derive( Copy , Clone ) ]
193+ pub enum INodeType {
194+ /// Directory type.
195+ Dir ,
196+ }
197+
198+ /// Required inode parameters.
199+ ///
200+ /// This is used when creating new inodes.
201+ pub struct INodeParams {
202+ /// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
203+ /// everyone, the owner group, and the owner.
204+ pub mode : u16 ,
205+
206+ /// Type of inode.
207+ ///
208+ /// Also carries additional per-type data.
209+ pub typ : INodeType ,
210+
211+ /// Size of the contents of the inode.
212+ ///
213+ /// Its maximum value is [`super::MAX_LFS_FILESIZE`].
214+ pub size : i64 ,
215+
216+ /// Number of blocks.
217+ pub blocks : u64 ,
218+
219+ /// Number of links to the inode.
220+ pub nlink : u32 ,
221+
222+ /// User id.
223+ pub uid : u32 ,
224+
225+ /// Group id.
226+ pub gid : u32 ,
227+
228+ /// Creation time.
229+ pub ctime : Time ,
230+
231+ /// Last modification time.
232+ pub mtime : Time ,
233+
234+ /// Last access time.
235+ pub atime : Time ,
236+ }
237+
140238 /// A file system super block.
141239 ///
142240 /// Wraps the kernel's `struct super_block`.
143241 #[ repr( transparent) ]
144242 pub struct SuperBlock < T : Type + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
145243
244+ impl < T : Type + ?Sized > SuperBlock < T > {
245+ /// Tries to get an existing inode or create a new one if it doesn't exist yet.
246+ pub fn get_or_create_inode ( & self , ino : u64 ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
247+ // SAFETY: The only initialisation missing from the superblock is the root, and this
248+ // function is needed to create the root, so it's safe to call it.
249+ let inode = ptr:: NonNull :: new ( unsafe { bindings:: iget_locked ( self . 0 . get ( ) , ino) } )
250+ . ok_or ( ENOMEM ) ?;
251+
252+ // SAFETY: `inode` is valid for read, but there could be concurrent writers (e.g., if
253+ // it's an already-initialised inode), so we use `read_volatile` to read its current
254+ // state.
255+ let state = unsafe { ptr:: read_volatile ( ptr:: addr_of!( ( * inode. as_ptr( ) ) . i_state) ) } ;
256+ if state & u64:: from ( bindings:: I_NEW ) == 0 {
257+ // The inode is cached. Just return it.
258+ //
259+ // SAFETY: `inode` had its refcount incremented by `iget_locked`; this increment is
260+ // now owned by `ARef`.
261+ Ok ( Either :: Left ( unsafe { ARef :: from_raw ( inode. cast ( ) ) } ) )
262+ } else {
263+ // SAFETY: The new inode is valid but not fully initialised yet, so it's ok to
264+ // create a `NewINode`.
265+ Ok ( Either :: Right ( NewINode ( unsafe {
266+ ARef :: from_raw ( inode. cast ( ) )
267+ } ) ) )
268+ }
269+ }
270+ }
271+
146272 /// Required superblock parameters.
147273 ///
148274 /// This is used in [`NewSuperBlock::init`].
@@ -191,7 +317,7 @@ pub mod ro {
191317 }
192318
193319 /// Initialises the superblock.
194- pub fn init ( self , params : & SuperParams ) -> Result < & ' a SuperBlock < T > > {
320+ pub fn init ( self , params : & SuperParams , root : ARef < INode < T > > ) -> Result < & ' a SuperBlock < T > > {
195321 // SAFETY: Since this is a new super block, we hold the only reference to it.
196322 let sb = unsafe { & mut * self . sb . 0 . get ( ) } ;
197323
@@ -207,35 +333,16 @@ pub mod ro {
207333 sb. s_blocksize = 1 << sb. s_blocksize_bits ;
208334 sb. s_flags |= bindings:: SB_RDONLY ;
209335
210- // The following is scaffolding code that will be removed in a subsequent patch. It is
211- // needed to build a root dentry, otherwise core code will BUG().
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 } ;
336+ // Reject root inode if it belongs to a different superblock.
337+ if !ptr:: eq ( root. super_block ( ) , self . sb ) {
338+ return Err ( EINVAL ) ;
232339 }
233340
234341 // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
235342 // case for this call.
236343 //
237344 // 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 ) } ;
345+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
239346 if dentry. is_null ( ) {
240347 return Err ( ENOMEM ) ;
241348 }
@@ -246,6 +353,14 @@ pub mod ro {
246353 }
247354 }
248355
356+ impl < T : Type + ?Sized > core:: ops:: Deref for NewSuperBlock < ' _ , T > {
357+ type Target = SuperBlock < T > ;
358+
359+ fn deref ( & self ) -> & Self :: Target {
360+ self . sb
361+ }
362+ }
363+
249364 struct Tables < T : Type + ?Sized > ( T ) ;
250365 impl < T : Type + ?Sized > Tables < T > {
251366 const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
0 commit comments