Skip to content

Commit f747b3a

Browse files
committed
rust: fs: introduce FileSystem::lookup
This allows inodes to be created for directory entries. Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
1 parent ec59c28 commit f747b3a

3 files changed

Lines changed: 88 additions & 5 deletions

File tree

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: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/// ```

samples/rust/rust_rofs.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use kernel::fs::{
66
DirEntryType, INode, INodeParams, INodeType, NewSuperBlock, SuperBlock, SuperParams,
77
};
88
use kernel::prelude::*;
9-
use kernel::{c_str, fs, time::UNIX_EPOCH, types::Either};
9+
use kernel::{c_str, fs, time::UNIX_EPOCH, types::ARef, types::Either};
1010

1111
kernel::module_fs! {
1212
type: RoFs,
@@ -93,4 +93,29 @@ impl fs::FileSystem for RoFs {
9393

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

0 commit comments

Comments
 (0)