@@ -16,10 +16,11 @@ pub mod ro {
1616 use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
1717 use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque } ;
1818 use crate :: {
19- bindings, folio:: LockedFolio , init:: PinInit , str :: CStr , time :: Time , try_pin_init ,
20- ThisModule ,
19+ bindings, container_of , folio:: LockedFolio , init:: PinInit , mem_cache :: MemCache , str :: CStr ,
20+ time :: Time , try_pin_init , ThisModule ,
2121 } ;
22- use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
22+ use core:: mem:: { size_of, ManuallyDrop , MaybeUninit } ;
23+ use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
2324 use macros:: { pin_data, pinned_drop} ;
2425
2526 /// Type of superblock keying.
@@ -38,6 +39,9 @@ pub mod ro {
3839 /// Data associated with each file system instance (super-block).
3940 type Data : ForeignOwnable + Send + Sync ;
4041
42+ /// Type of data associated with each inode.
43+ type INodeData : Send + Sync ;
44+
4145 /// The name of the file system type.
4246 const NAME : & ' static CStr ;
4347
@@ -173,6 +177,7 @@ pub mod ro {
173177 pub struct Registration {
174178 #[ pin]
175179 fs : Opaque < bindings:: file_system_type > ,
180+ inode_cache : Option < MemCache > ,
176181 #[ pin]
177182 _pin : PhantomPinned ,
178183 }
@@ -190,6 +195,14 @@ pub mod ro {
190195 pub fn new < T : Type + ?Sized > ( module : & ' static ThisModule ) -> impl PinInit < Self , Error > {
191196 try_pin_init ! ( Self {
192197 _pin: PhantomPinned ,
198+ inode_cache: if size_of:: <T :: INodeData >( ) == 0 {
199+ None
200+ } else {
201+ Some ( MemCache :: try_new:: <INodeWithData <T :: INodeData >>(
202+ T :: NAME ,
203+ Some ( Self :: inode_init_once_callback:: <T >) ,
204+ ) ?)
205+ } ,
193206 fs <- Opaque :: try_ffi_init( |fs_ptr| {
194207 // SAFETY: `pin_init_from_closure` guarantees that `fs_ptr` is valid for write.
195208 let fs = unsafe { & mut * fs_ptr } ;
@@ -244,6 +257,16 @@ pub mod ro {
244257 unsafe { T :: Data :: from_foreign ( ptr) } ;
245258 }
246259 }
260+
261+ unsafe extern "C" fn inode_init_once_callback < T : Type + ?Sized > (
262+ outer_inode : * mut core:: ffi:: c_void ,
263+ ) {
264+ let ptr = outer_inode. cast :: < INodeWithData < T :: INodeData > > ( ) ;
265+
266+ // SAFETY: This is only used in `new`, so we know that we have a valid `INodeWithData`
267+ // instance whose inode part can be initialised.
268+ unsafe { bindings:: inode_init_once ( ptr:: addr_of_mut!( ( * ptr) . inode) ) } ;
269+ }
247270 }
248271
249272 #[ pinned_drop]
@@ -280,6 +303,15 @@ pub mod ro {
280303 unsafe { & * ( * self . 0 . get ( ) ) . i_sb . cast ( ) }
281304 }
282305
306+ /// Returns the data associated with the inode.
307+ pub fn data ( & self ) -> & T :: INodeData {
308+ let outerp = container_of ! ( self . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
309+ // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference
310+ // (`&self`) to it. Additionally, we know `T::INodeData` is always initialised in an
311+ // `INode`.
312+ unsafe { & * ( * outerp) . data . as_ptr ( ) }
313+ }
314+
283315 /// Returns the size of the inode contents.
284316 pub fn size ( & self ) -> i64 {
285317 // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference.
@@ -300,15 +332,29 @@ pub mod ro {
300332 }
301333 }
302334
335+ struct INodeWithData < T > {
336+ data : MaybeUninit < T > ,
337+ inode : bindings:: inode ,
338+ }
339+
303340 /// An inode that is locked and hasn't been initialised yet.
304341 #[ repr( transparent) ]
305342 pub struct NewINode < T : Type + ?Sized > ( ARef < INode < T > > ) ;
306343
307344 impl < T : Type + ?Sized > NewINode < T > {
308345 /// Initialises the new inode with the given parameters.
309- pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
310- // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
311- let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
346+ pub fn init ( self , params : INodeParams < T :: INodeData > ) -> Result < ARef < INode < T > > > {
347+ let outerp = container_of ! ( self . 0 . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
348+
349+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
350+ // safe to mutably dereference it.
351+ let outer = unsafe { & mut * outerp. cast_mut ( ) } ;
352+
353+ // N.B. We must always write this to a newly allocated inode because the free callback
354+ // expects the data to be initialised and drops it.
355+ outer. data . write ( params. value ) ;
356+
357+ let inode = & mut outer. inode ;
312358
313359 let mode = match params. typ {
314360 INodeType :: Dir => {
@@ -425,7 +471,7 @@ pub mod ro {
425471 /// Required inode parameters.
426472 ///
427473 /// This is used when creating new inodes.
428- pub struct INodeParams {
474+ pub struct INodeParams < T > {
429475 /// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
430476 /// everyone, the owner group, and the owner.
431477 pub mode : u16 ,
@@ -460,6 +506,9 @@ pub mod ro {
460506
461507 /// Last access time.
462508 pub atime : Time ,
509+
510+ /// Value to attach to this node.
511+ pub value : T ,
463512 }
464513
465514 /// A file system super block.
@@ -759,8 +808,12 @@ pub mod ro {
759808 }
760809
761810 const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
762- alloc_inode : None ,
763- destroy_inode : None ,
811+ alloc_inode : if size_of :: < T :: INodeData > ( ) != 0 {
812+ Some ( Self :: alloc_inode_callback)
813+ } else {
814+ None
815+ } ,
816+ destroy_inode : Some ( Self :: destroy_inode_callback) ,
764817 free_inode : None ,
765818 dirty_inode : None ,
766819 write_inode : None ,
@@ -790,6 +843,61 @@ pub mod ro {
790843 shutdown : None ,
791844 } ;
792845
846+ unsafe extern "C" fn alloc_inode_callback (
847+ sb : * mut bindings:: super_block ,
848+ ) -> * mut bindings:: inode {
849+ // SAFETY: The callback contract guarantees that `sb` is valid for read.
850+ let super_type = unsafe { ( * sb) . s_type } ;
851+
852+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
853+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
854+ // superblock associated to it.
855+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
856+
857+ // SAFETY: `sb` and `cache` are guaranteed to be valid by the callback contract and by
858+ // the existence of a superblock respectively.
859+ let ptr = unsafe {
860+ bindings:: alloc_inode_sb ( sb, MemCache :: ptr ( & reg. inode_cache ) , bindings:: GFP_KERNEL )
861+ }
862+ . cast :: < INodeWithData < T :: INodeData > > ( ) ;
863+ if ptr. is_null ( ) {
864+ return ptr:: null_mut ( ) ;
865+ }
866+ ptr:: addr_of_mut!( ( * ptr) . inode)
867+ }
868+
869+ unsafe extern "C" fn destroy_inode_callback ( inode : * mut bindings:: inode ) {
870+ // SAFETY: By the C contrat, inode is a valid pointer.
871+ let is_bad = unsafe { bindings:: is_bad_inode ( inode) } ;
872+
873+ // SAFETY: The inode is guaranteed to be valid by the callback contract. Additionally,
874+ // the superblock is also guaranteed to still be valid by the inode existence.
875+ let super_type = unsafe { ( * ( * inode) . i_sb ) . s_type } ;
876+
877+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
878+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
879+ // superblock associated to it.
880+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
881+ let ptr = container_of ! ( inode, INodeWithData <T :: INodeData >, inode) . cast_mut ( ) ;
882+
883+ if !is_bad {
884+ // SAFETY: The code either initialises the data or marks the inode as bad, since
885+ // it's not bad, it's safey to drop it here.
886+ unsafe { ptr:: drop_in_place ( ( * ptr) . data . as_mut_ptr ( ) ) } ;
887+ }
888+
889+ if size_of :: < T :: INodeData > ( ) == 0 {
890+ // SAFETY: When the size of `INodeData` is zero, we don't use a separate
891+ // mem_cache, so it is allocated from the regular mem_cache, which is what
892+ // `free_inode_nonrcu` uses to free the inode.
893+ unsafe { bindings:: free_inode_nonrcu ( inode) } ;
894+ } else {
895+ // The callback contract guarantees that the inode was previously allocated via the
896+ // `alloc_inode_callback` callback, so it is safe to free it back to the cache.
897+ unsafe { bindings:: kmem_cache_free ( MemCache :: ptr ( & reg. inode_cache ) , ptr. cast ( ) ) } ;
898+ }
899+ }
900+
793901 unsafe extern "C" fn statfs_callback (
794902 dentry : * mut bindings:: dentry ,
795903 buf : * mut bindings:: kstatfs ,
@@ -1089,6 +1197,7 @@ pub mod ro {
10891197 /// impl fs::ro::Type for MyFs {
10901198 /// // ...
10911199 /// # type Data = ();
1200+ /// # type INodeData = ();
10921201 /// # const NAME: &'static CStr = c_str!("myfs");
10931202 /// # fn fill_super(
10941203 /// # _: fs::ro::NewSuperBlock<'_, Self>
0 commit comments