Skip to content

Commit 14b32d0

Browse files
committed
rust: fs: introduce FileSystem::lookup
Allow Rust file systems to create inodes that are children of a directory inode when they're looked up by name. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent ac0f637 commit 14b32d0

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

rust/kernel/error.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ impl Error {
131131
}
132132

133133
/// Returns the error encoded as a pointer.
134-
#[allow(dead_code)]
135134
pub(crate) fn to_ptr<T>(self) -> *mut T {
136135
// SAFETY: self.0 is a valid error due to its invariant.
137136
unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ }

rust/kernel/fs.rs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub trait FileSystem {
3333
///
3434
/// [`DirEmitter::pos`] holds the current position of the directory reader.
3535
fn read_dir(inode: &INode<Self>, emitter: &mut DirEmitter) -> Result;
36+
37+
/// Returns the inode corresponding to the directory entry with the given name.
38+
fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>>;
3639
}
3740

3841
/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -226,8 +229,7 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
226229
let mode = match params.typ {
227230
INodeType::Dir => {
228231
inode.__bindgen_anon_3.i_fop = &Tables::<T>::DIR_FILE_OPERATIONS;
229-
// SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
230-
inode.i_op = unsafe { &bindings::simple_dir_inode_operations };
232+
inode.i_op = &Tables::<T>::DIR_INODE_OPERATIONS;
231233
bindings::S_IFDIR
232234
}
233235
};
@@ -530,6 +532,62 @@ impl<T: FileSystem + ?Sized> Tables<T> {
530532
}
531533
})
532534
}
535+
536+
const DIR_INODE_OPERATIONS: bindings::inode_operations = bindings::inode_operations {
537+
lookup: Some(Self::lookup_callback),
538+
get_link: None,
539+
permission: None,
540+
get_inode_acl: None,
541+
readlink: None,
542+
create: None,
543+
link: None,
544+
unlink: None,
545+
symlink: None,
546+
mkdir: None,
547+
rmdir: None,
548+
mknod: None,
549+
rename: None,
550+
setattr: None,
551+
getattr: None,
552+
listxattr: None,
553+
fiemap: None,
554+
update_time: None,
555+
atomic_open: None,
556+
tmpfile: None,
557+
get_acl: None,
558+
set_acl: None,
559+
fileattr_set: None,
560+
fileattr_get: None,
561+
get_offset_ctx: None,
562+
};
563+
564+
extern "C" fn lookup_callback(
565+
parent_ptr: *mut bindings::inode,
566+
dentry: *mut bindings::dentry,
567+
_flags: u32,
568+
) -> *mut bindings::dentry {
569+
// SAFETY: The C API guarantees that `parent_ptr` is a valid inode.
570+
let parent = unsafe { &*parent_ptr.cast::<INode<T>>() };
571+
572+
// SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
573+
// immutable, it's ok to read its length directly.
574+
let len = unsafe { (*dentry).d_name.__bindgen_anon_1.__bindgen_anon_1.len };
575+
let Ok(name_len) = usize::try_from(len) else {
576+
return ENOENT.to_ptr();
577+
};
578+
579+
// SAFETY: The C API guarantees that `dentry` is valid for read. Since the name is
580+
// immutable, it's ok to read it directly.
581+
let name = unsafe { core::slice::from_raw_parts((*dentry).d_name.name, name_len) };
582+
match T::lookup(parent, name) {
583+
Err(e) => e.to_ptr(),
584+
// SAFETY: The returned inode is valid and referenced (by the type invariants), so
585+
// it is ok to transfer this increment to `d_splice_alias`.
586+
Ok(inode) => unsafe {
587+
bindings::d_splice_alias(ManuallyDrop::new(inode).0.get(), dentry)
588+
},
589+
}
590+
}
533591
}
534592

535593
/// Directory entry emitter.
@@ -637,6 +695,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
637695
/// fn read_dir(_: &INode<Self>, _: &mut DirEmitter) -> Result {
638696
/// todo!()
639697
/// }
698+
/// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
699+
/// todo!()
700+
/// }
640701
/// }
641702
/// # }
642703
/// ```

samples/rust/rust_rofs.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,29 @@ impl fs::FileSystem for RoFs {
8989

9090
Ok(())
9191
}
92+
93+
fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>> {
94+
if parent.ino() != 1 {
95+
return Err(ENOENT);
96+
}
97+
98+
match name {
99+
b"subdir" => match parent.super_block().get_or_create_inode(2)? {
100+
Either::Left(existing) => Ok(existing),
101+
Either::Right(new) => new.init(INodeParams {
102+
typ: INodeType::Dir,
103+
mode: 0o555,
104+
size: 0,
105+
blocks: 1,
106+
nlink: 2,
107+
uid: 0,
108+
gid: 0,
109+
atime: UNIX_EPOCH,
110+
ctime: UNIX_EPOCH,
111+
mtime: UNIX_EPOCH,
112+
}),
113+
},
114+
_ => Err(ENOENT),
115+
}
116+
}
92117
}

0 commit comments

Comments
 (0)