9
9
use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
10
10
use crate :: folio:: { LockedFolio , UniqueFolio } ;
11
11
use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque , ScopeGuard } ;
12
- use crate :: { bindings, init:: PinInit , str:: CStr , time:: Timespec , try_pin_init, ThisModule } ;
13
- use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
12
+ use crate :: {
13
+ bindings, container_of, init:: PinInit , mem_cache:: MemCache , str:: CStr , time:: Timespec ,
14
+ try_pin_init, ThisModule ,
15
+ } ;
16
+ use core:: mem:: { size_of, ManuallyDrop , MaybeUninit } ;
17
+ use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
14
18
use macros:: { pin_data, pinned_drop} ;
15
19
16
20
#[ cfg( CONFIG_BUFFER_HEAD ) ]
@@ -35,6 +39,9 @@ pub trait FileSystem {
35
39
/// Data associated with each file system instance (super-block).
36
40
type Data : ForeignOwnable + Send + Sync ;
37
41
42
+ /// Type of data associated with each inode.
43
+ type INodeData : Send + Sync ;
44
+
38
45
/// The name of the file system type.
39
46
const NAME : & ' static CStr ;
40
47
@@ -165,6 +172,7 @@ impl core::convert::TryFrom<u32> for DirEntryType {
165
172
pub struct Registration {
166
173
#[ pin]
167
174
fs : Opaque < bindings:: file_system_type > ,
175
+ inode_cache : Option < MemCache > ,
168
176
#[ pin]
169
177
_pin : PhantomPinned ,
170
178
}
@@ -182,6 +190,14 @@ impl Registration {
182
190
pub fn new < T : FileSystem + ?Sized > ( module : & ' static ThisModule ) -> impl PinInit < Self , Error > {
183
191
try_pin_init ! ( Self {
184
192
_pin: PhantomPinned ,
193
+ inode_cache: if size_of:: <T :: INodeData >( ) == 0 {
194
+ None
195
+ } else {
196
+ Some ( MemCache :: try_new:: <INodeWithData <T :: INodeData >>(
197
+ T :: NAME ,
198
+ Some ( Self :: inode_init_once_callback:: <T >) ,
199
+ ) ?)
200
+ } ,
185
201
fs <- Opaque :: try_ffi_init( |fs_ptr: * mut bindings:: file_system_type| {
186
202
// SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write.
187
203
unsafe { fs_ptr. write( bindings:: file_system_type:: default ( ) ) } ;
@@ -239,6 +255,16 @@ impl Registration {
239
255
unsafe { T :: Data :: from_foreign ( ptr) } ;
240
256
}
241
257
}
258
+
259
+ unsafe extern "C" fn inode_init_once_callback < T : FileSystem + ?Sized > (
260
+ outer_inode : * mut core:: ffi:: c_void ,
261
+ ) {
262
+ let ptr = outer_inode. cast :: < INodeWithData < T :: INodeData > > ( ) ;
263
+
264
+ // SAFETY: This is only used in `new`, so we know that we have a valid `INodeWithData`
265
+ // instance whose inode part can be initialised.
266
+ unsafe { bindings:: inode_init_once ( ptr:: addr_of_mut!( ( * ptr) . inode) ) } ;
267
+ }
242
268
}
243
269
244
270
#[ pinned_drop]
@@ -280,6 +306,15 @@ impl<T: FileSystem + ?Sized> INode<T> {
280
306
unsafe { & * ( * self . 0 . get ( ) ) . i_sb . cast ( ) }
281
307
}
282
308
309
+ /// Returns the data associated with the inode.
310
+ pub fn data ( & self ) -> & T :: INodeData {
311
+ let outerp = container_of ! ( self . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
312
+ // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference
313
+ // (`&self`) to it. Additionally, we know `T::INodeData` is always initialised in an
314
+ // `INode`.
315
+ unsafe { & * ( * outerp) . data . as_ptr ( ) }
316
+ }
317
+
283
318
/// Returns the size of the inode contents.
284
319
pub fn size ( & self ) -> i64 {
285
320
// SAFETY: `self` is guaranteed to be valid by the existence of a shared reference.
@@ -300,15 +335,29 @@ unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
300
335
}
301
336
}
302
337
338
+ struct INodeWithData < T > {
339
+ data : MaybeUninit < T > ,
340
+ inode : bindings:: inode ,
341
+ }
342
+
303
343
/// An inode that is locked and hasn't been initialised yet.
304
344
#[ repr( transparent) ]
305
345
pub struct NewINode < T : FileSystem + ?Sized > ( ARef < INode < T > > ) ;
306
346
307
347
impl < T : FileSystem + ?Sized > NewINode < T > {
308
348
/// 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 ( ) } ;
349
+ pub fn init ( self , params : INodeParams < T :: INodeData > ) -> Result < ARef < INode < T > > > {
350
+ let outerp = container_of ! ( self . 0 . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
351
+
352
+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
353
+ // safe to mutably dereference it.
354
+ let outer = unsafe { & mut * outerp. cast_mut ( ) } ;
355
+
356
+ // N.B. We must always write this to a newly allocated inode because the free callback
357
+ // expects the data to be initialised and drops it.
358
+ outer. data . write ( params. value ) ;
359
+
360
+ let inode = & mut outer. inode ;
312
361
313
362
let mode = match params. typ {
314
363
INodeType :: Dir => {
@@ -424,7 +473,7 @@ pub enum INodeType {
424
473
/// Required inode parameters.
425
474
///
426
475
/// This is used when creating new inodes.
427
- pub struct INodeParams {
476
+ pub struct INodeParams < T > {
428
477
/// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
429
478
/// everyone, the owner group, and the owner.
430
479
pub mode : u16 ,
@@ -459,6 +508,9 @@ pub struct INodeParams {
459
508
460
509
/// Last access time.
461
510
pub atime : Timespec ,
511
+
512
+ /// Value to attach to this node.
513
+ pub value : T ,
462
514
}
463
515
464
516
/// A file system super block.
@@ -735,8 +787,12 @@ impl<T: FileSystem + ?Sized> Tables<T> {
735
787
}
736
788
737
789
const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
738
- alloc_inode : None ,
739
- destroy_inode : None ,
790
+ alloc_inode : if size_of :: < T :: INodeData > ( ) != 0 {
791
+ Some ( Self :: alloc_inode_callback)
792
+ } else {
793
+ None
794
+ } ,
795
+ destroy_inode : Some ( Self :: destroy_inode_callback) ,
740
796
free_inode : None ,
741
797
dirty_inode : None ,
742
798
write_inode : None ,
@@ -766,6 +822,61 @@ impl<T: FileSystem + ?Sized> Tables<T> {
766
822
shutdown : None ,
767
823
} ;
768
824
825
+ unsafe extern "C" fn alloc_inode_callback (
826
+ sb : * mut bindings:: super_block ,
827
+ ) -> * mut bindings:: inode {
828
+ // SAFETY: The callback contract guarantees that `sb` is valid for read.
829
+ let super_type = unsafe { ( * sb) . s_type } ;
830
+
831
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
832
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
833
+ // superblock associated to it.
834
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
835
+
836
+ // SAFETY: `sb` and `cache` are guaranteed to be valid by the callback contract and by
837
+ // the existence of a superblock respectively.
838
+ let ptr = unsafe {
839
+ bindings:: alloc_inode_sb ( sb, MemCache :: ptr ( & reg. inode_cache ) , bindings:: GFP_KERNEL )
840
+ }
841
+ . cast :: < INodeWithData < T :: INodeData > > ( ) ;
842
+ if ptr. is_null ( ) {
843
+ return ptr:: null_mut ( ) ;
844
+ }
845
+ ptr:: addr_of_mut!( ( * ptr) . inode)
846
+ }
847
+
848
+ unsafe extern "C" fn destroy_inode_callback ( inode : * mut bindings:: inode ) {
849
+ // SAFETY: By the C contract, `inode` is a valid pointer.
850
+ let is_bad = unsafe { bindings:: is_bad_inode ( inode) } ;
851
+
852
+ // SAFETY: The inode is guaranteed to be valid by the callback contract. Additionally, the
853
+ // superblock is also guaranteed to still be valid by the inode existence.
854
+ let super_type = unsafe { ( * ( * inode) . i_sb ) . s_type } ;
855
+
856
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
857
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
858
+ // superblock associated to it.
859
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
860
+ let ptr = container_of ! ( inode, INodeWithData <T :: INodeData >, inode) . cast_mut ( ) ;
861
+
862
+ if !is_bad {
863
+ // SAFETY: The code either initialises the data or marks the inode as bad. Since the
864
+ // inode is not bad, the data is initialised, and thus safe to drop.
865
+ unsafe { ptr:: drop_in_place ( ( * ptr) . data . as_mut_ptr ( ) ) } ;
866
+ }
867
+
868
+ if size_of :: < T :: INodeData > ( ) == 0 {
869
+ // SAFETY: When the size of `INodeData` is zero, we don't use a separate mem_cache, so
870
+ // it is allocated from the regular mem_cache, which is what `free_inode_nonrcu` uses
871
+ // to free the inode.
872
+ unsafe { bindings:: free_inode_nonrcu ( inode) } ;
873
+ } else {
874
+ // The callback contract guarantees that the inode was previously allocated via the
875
+ // `alloc_inode_callback` callback, so it is safe to free it back to the cache.
876
+ unsafe { bindings:: kmem_cache_free ( MemCache :: ptr ( & reg. inode_cache ) , ptr. cast ( ) ) } ;
877
+ }
878
+ }
879
+
769
880
unsafe extern "C" fn statfs_callback (
770
881
dentry : * mut bindings:: dentry ,
771
882
buf : * mut bindings:: kstatfs ,
@@ -1120,6 +1231,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
1120
1231
/// struct MyFs;
1121
1232
/// impl fs::FileSystem for MyFs {
1122
1233
/// type Data = ();
1234
+ /// type INodeData =();
1123
1235
/// const NAME: &'static CStr = c_str!("myfs");
1124
1236
/// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams<Self::Data>> {
1125
1237
/// todo!()
0 commit comments