@@ -27,6 +27,9 @@ pub trait FileSystem {
2727 ///
2828 /// [`DirEmitter::pos`] holds the current position of the directory reader.
2929 fn read_dir ( inode : & INode < Self > , emitter : & mut DirEmitter ) -> Result ;
30+
31+ /// Returns the inode corresponding to the directory entry with the given name.
32+ fn lookup ( parent : & INode < Self > , name : & [ u8 ] ) -> Result < ARef < INode < Self > > > ;
3033}
3134
3235/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -217,8 +220,7 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
217220 let mode = match params. typ {
218221 INodeType :: Dir => {
219222 inode. __bindgen_anon_3 . i_fop = & Tables :: < T > :: DIR_FILE_OPERATIONS ;
220- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
221- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
223+ inode. i_op = & Tables :: < T > :: DIR_INODE_OPERATIONS ;
222224 bindings:: S_IFDIR
223225 }
224226 } ;
@@ -549,6 +551,62 @@ impl<T: FileSystem + ?Sized> Tables<T> {
549551 }
550552 } )
551553 }
554+
555+ const DIR_INODE_OPERATIONS : bindings:: inode_operations = bindings:: inode_operations {
556+ lookup : Some ( Self :: lookup_callback) ,
557+ get_link : None ,
558+ permission : None ,
559+ get_inode_acl : None ,
560+ readlink : None ,
561+ create : None ,
562+ link : None ,
563+ unlink : None ,
564+ symlink : None ,
565+ mkdir : None ,
566+ rmdir : None ,
567+ mknod : None ,
568+ rename : None ,
569+ setattr : None ,
570+ getattr : None ,
571+ listxattr : None ,
572+ fiemap : None ,
573+ update_time : None ,
574+ atomic_open : None ,
575+ tmpfile : None ,
576+ get_acl : None ,
577+ set_acl : None ,
578+ fileattr_set : None ,
579+ fileattr_get : None ,
580+ get_offset_ctx : None ,
581+ } ;
582+
583+ extern "C" fn lookup_callback (
584+ parent_ptr : * mut bindings:: inode ,
585+ dentry : * mut bindings:: dentry ,
586+ _flags : u32 ,
587+ ) -> * mut bindings:: dentry {
588+ // SAFETY: The C API guarantees that `parent_ptr` is a valid inode.
589+ let parent = unsafe { & * parent_ptr. cast :: < INode < T > > ( ) } ;
590+
591+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
592+ // immutable, it's ok to read its length directly.
593+ let len = unsafe { ( * dentry) . d_name . __bindgen_anon_1 . __bindgen_anon_1 . len } ;
594+ let Ok ( name_len) = usize:: try_from ( len) else {
595+ return ENOENT . to_ptr ( ) ;
596+ } ;
597+
598+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
599+ // immutable, it's ok to read it directly.
600+ let name = unsafe { core:: slice:: from_raw_parts ( ( * dentry) . d_name . name , name_len) } ;
601+ match T :: lookup ( parent, name) {
602+ Err ( e) => e. to_ptr ( ) ,
603+ // SAFETY: The returned inode is valid and referenced (by the type invariants), so
604+ // it is ok to transfer this increment to `d_splice_alias`.
605+ Ok ( inode) => unsafe {
606+ bindings:: d_splice_alias ( ManuallyDrop :: new ( inode) . 0 . get ( ) , dentry)
607+ } ,
608+ }
609+ }
552610}
553611
554612/// Directory entry emitter.
@@ -634,7 +692,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
634692/// # mod module_ro_fs_sample {
635693/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock};
636694/// use kernel::prelude::*;
637- /// use kernel::{c_str, fs};
695+ /// use kernel::{c_str, fs, types::ARef };
638696///
639697/// kernel::module_fs! {
640698/// type: MyFs,
@@ -653,6 +711,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
653711/// fn read_dir(_: &INode<Self>, _: &mut DirEmitter) -> Result {
654712/// todo!()
655713/// }
714+ /// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
715+ /// todo!()
716+ /// }
656717/// }
657718/// # }
658719/// ```
0 commit comments