@@ -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`].
@@ -220,8 +223,7 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
220223 let mode = match params. typ {
221224 INodeType :: Dir => {
222225 inode. __bindgen_anon_3 . i_fop = & Tables :: < T > :: DIR_FILE_OPERATIONS ;
223- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
224- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
226+ inode. i_op = & Tables :: < T > :: DIR_INODE_OPERATIONS ;
225227 bindings:: S_IFDIR
226228 }
227229 } ;
@@ -552,6 +554,62 @@ impl<T: FileSystem + ?Sized> Tables<T> {
552554 }
553555 } )
554556 }
557+
558+ const DIR_INODE_OPERATIONS : bindings:: inode_operations = bindings:: inode_operations {
559+ lookup : Some ( Self :: lookup_callback) ,
560+ get_link : None ,
561+ permission : None ,
562+ get_inode_acl : None ,
563+ readlink : None ,
564+ create : None ,
565+ link : None ,
566+ unlink : None ,
567+ symlink : None ,
568+ mkdir : None ,
569+ rmdir : None ,
570+ mknod : None ,
571+ rename : None ,
572+ setattr : None ,
573+ getattr : None ,
574+ listxattr : None ,
575+ fiemap : None ,
576+ update_time : None ,
577+ atomic_open : None ,
578+ tmpfile : None ,
579+ get_acl : None ,
580+ set_acl : None ,
581+ fileattr_set : None ,
582+ fileattr_get : None ,
583+ get_offset_ctx : None ,
584+ } ;
585+
586+ extern "C" fn lookup_callback (
587+ parent_ptr : * mut bindings:: inode ,
588+ dentry : * mut bindings:: dentry ,
589+ _flags : u32 ,
590+ ) -> * mut bindings:: dentry {
591+ // SAFETY: The C API guarantees that `parent_ptr` is a valid inode.
592+ let parent = unsafe { & * parent_ptr. cast :: < INode < T > > ( ) } ;
593+
594+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
595+ // immutable, it's ok to read its length directly.
596+ let len = unsafe { ( * dentry) . d_name . __bindgen_anon_1 . __bindgen_anon_1 . len } ;
597+ let Ok ( name_len) = usize:: try_from ( len) else {
598+ return ENOENT . to_ptr ( ) ;
599+ } ;
600+
601+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
602+ // immutable, it's ok to read it directly.
603+ let name = unsafe { core:: slice:: from_raw_parts ( ( * dentry) . d_name . name , name_len) } ;
604+ match T :: lookup ( parent, name) {
605+ Err ( e) => e. to_ptr ( ) ,
606+ // SAFETY: The returned inode is valid and referenced (by the type invariants), so
607+ // it is ok to transfer this increment to `d_splice_alias`.
608+ Ok ( inode) => unsafe {
609+ bindings:: d_splice_alias ( ManuallyDrop :: new ( inode) . 0 . get ( ) , dentry)
610+ } ,
611+ }
612+ }
555613}
556614
557615/// Directory entry emitter.
@@ -637,7 +695,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
637695/// # mod module_ro_fs_sample {
638696/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock};
639697/// use kernel::prelude::*;
640- /// use kernel::{c_str, fs};
698+ /// use kernel::{c_str, fs, types::ARef };
641699///
642700/// kernel::module_fs! {
643701/// type: MyFs,
@@ -656,6 +714,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
656714/// fn read_dir(_: &INode<Self>, _: &mut DirEmitter) -> Result {
657715/// todo!()
658716/// }
717+ /// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
718+ /// todo!()
719+ /// }
659720/// }
660721/// # }
661722/// ```
0 commit comments