@@ -38,6 +38,9 @@ pub trait FileSystem {
3838 pos : i64 ,
3939 report : impl FnMut ( & [ u8 ] , i64 , u64 , DirEntryType ) -> bool ,
4040 ) -> Result < i64 > ;
41+
42+ /// Returns the inode corresponding to the directory entry with the given name.
43+ fn lookup ( parent : & INode < Self > , name : & [ u8 ] ) -> Result < ARef < INode < Self > > > ;
4144}
4245
4346/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -225,8 +228,7 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
225228 let mode = match params. typ {
226229 INodeType :: Dir => {
227230 inode. __bindgen_anon_3 . i_fop = & Tables :: < T > :: DIR_FILE_OPERATIONS ;
228- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
229- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
231+ inode. i_op = & Tables :: < T > :: DIR_INODE_OPERATIONS ;
230232 bindings:: S_IFDIR
231233 }
232234 } ;
@@ -556,6 +558,60 @@ impl<T: FileSystem + ?Sized> Tables<T> {
556558 Ok ( 0 )
557559 } )
558560 }
561+
562+ const DIR_INODE_OPERATIONS : bindings:: inode_operations = bindings:: inode_operations {
563+ lookup : Some ( Self :: lookup_callback) ,
564+ get_link : None ,
565+ permission : None ,
566+ get_inode_acl : None ,
567+ readlink : None ,
568+ create : None ,
569+ link : None ,
570+ unlink : None ,
571+ symlink : None ,
572+ mkdir : None ,
573+ rmdir : None ,
574+ mknod : None ,
575+ rename : None ,
576+ setattr : None ,
577+ getattr : None ,
578+ listxattr : None ,
579+ fiemap : None ,
580+ update_time : None ,
581+ atomic_open : None ,
582+ tmpfile : None ,
583+ get_acl : None ,
584+ set_acl : None ,
585+ fileattr_set : None ,
586+ fileattr_get : None ,
587+ get_offset_ctx : None ,
588+ } ;
589+
590+ extern "C" fn lookup_callback (
591+ parent_ptr : * mut bindings:: inode ,
592+ dentry : * mut bindings:: dentry ,
593+ _flags : u32 ,
594+ ) -> * mut bindings:: dentry {
595+ // SAFETY: The C API guarantees that `parent_ptr` is a valid inode.
596+ let parent = unsafe { & * parent_ptr. cast :: < INode < T > > ( ) } ;
597+
598+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
599+ // immutable, it's ok to read its length directly.
600+ let len = unsafe { ( * dentry) . d_name . __bindgen_anon_1 . __bindgen_anon_1 . len } ;
601+ let Ok ( name_len) = usize:: try_from ( len) else { return ENOENT . to_ptr ( ) } ;
602+
603+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
604+ // immutable, it's ok to read it directly.
605+ let name = unsafe { core:: slice:: from_raw_parts ( ( * dentry) . d_name . name , name_len) } ;
606+ match T :: lookup ( parent, name) {
607+ Err ( e) => e. to_ptr ( ) ,
608+ // SAFETY: The returned inode is valid and referenced (by the type invariants), so
609+ // it is ok to transfer this increment to `d_splice_alias`.
610+ Ok ( inode) => unsafe {
611+ bindings:: d_splice_alias ( ManuallyDrop :: new ( inode) . 0 . get ( ) , dentry)
612+ } ,
613+ }
614+ }
559615}
560616
561617/// Kernel module that exposes a single file system implemented by `T`.
@@ -586,7 +642,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
586642/// # mod module_ro_fs_sample {
587643/// use kernel::fs::{DirEntryType, INode, NewSuperBlock, SuperBlock};
588644/// use kernel::prelude::*;
589- /// use kernel::{c_str, fs};
645+ /// use kernel::{c_str, fs, types::ARef };
590646///
591647/// kernel::module_fs! {
592648/// type: MyFs,
@@ -609,6 +665,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
609665/// ) -> Result<i64> {
610666/// todo!()
611667/// }
668+ /// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
669+ /// todo!()
670+ /// }
612671/// }
613672/// # }
614673/// ```
0 commit comments