@@ -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`].
@@ -214,8 +217,7 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
214217 let mode = match params. typ {
215218 INodeType :: Dir => {
216219 inode. __bindgen_anon_3 . i_fop = & Tables :: < T > :: DIR_FILE_OPERATIONS ;
217- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
218- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
220+ inode. i_op = & Tables :: < T > :: DIR_INODE_OPERATIONS ;
219221 bindings:: S_IFDIR
220222 }
221223 } ;
@@ -546,6 +548,62 @@ impl<T: FileSystem + ?Sized> Tables<T> {
546548 }
547549 } )
548550 }
551+
552+ const DIR_INODE_OPERATIONS : bindings:: inode_operations = bindings:: inode_operations {
553+ lookup : Some ( Self :: lookup_callback) ,
554+ get_link : None ,
555+ permission : None ,
556+ get_inode_acl : None ,
557+ readlink : None ,
558+ create : None ,
559+ link : None ,
560+ unlink : None ,
561+ symlink : None ,
562+ mkdir : None ,
563+ rmdir : None ,
564+ mknod : None ,
565+ rename : None ,
566+ setattr : None ,
567+ getattr : None ,
568+ listxattr : None ,
569+ fiemap : None ,
570+ update_time : None ,
571+ atomic_open : None ,
572+ tmpfile : None ,
573+ get_acl : None ,
574+ set_acl : None ,
575+ fileattr_set : None ,
576+ fileattr_get : None ,
577+ get_offset_ctx : None ,
578+ } ;
579+
580+ extern "C" fn lookup_callback (
581+ parent_ptr : * mut bindings:: inode ,
582+ dentry : * mut bindings:: dentry ,
583+ _flags : u32 ,
584+ ) -> * mut bindings:: dentry {
585+ // SAFETY: The C API guarantees that `parent_ptr` is a valid inode.
586+ let parent = unsafe { & * parent_ptr. cast :: < INode < T > > ( ) } ;
587+
588+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
589+ // immutable, it's ok to read its length directly.
590+ let len = unsafe { ( * dentry) . d_name . __bindgen_anon_1 . __bindgen_anon_1 . len } ;
591+ let Ok ( name_len) = usize:: try_from ( len) else {
592+ return ENOENT . to_ptr ( ) ;
593+ } ;
594+
595+ // SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
596+ // immutable, it's ok to read it directly.
597+ let name = unsafe { core:: slice:: from_raw_parts ( ( * dentry) . d_name . name , name_len) } ;
598+ match T :: lookup ( parent, name) {
599+ Err ( e) => e. to_ptr ( ) ,
600+ // SAFETY: The returned inode is valid and referenced (by the type invariants), so
601+ // it is ok to transfer this increment to `d_splice_alias`.
602+ Ok ( inode) => unsafe {
603+ bindings:: d_splice_alias ( ManuallyDrop :: new ( inode) . 0 . get ( ) , dentry)
604+ } ,
605+ }
606+ }
549607}
550608
551609/// Directory entry emitter.
@@ -620,7 +678,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
620678/// # mod module_ro_fs_sample {
621679/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock};
622680/// use kernel::prelude::*;
623- /// use kernel::{c_str, fs};
681+ /// use kernel::{c_str, fs, types::ARef };
624682///
625683/// kernel::module_fs! {
626684/// type: MyFs,
@@ -639,6 +697,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
639697/// fn read_dir(_: &INode<Self>, _: &mut DirEmitter) -> Result {
640698/// todo!()
641699/// }
700+ /// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
701+ /// todo!()
702+ /// }
642703/// }
643704/// # }
644705/// ```
0 commit comments