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