Skip to content

Commit 46bf8e0

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

3 files changed

Lines changed: 92 additions & 4 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: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub mod ro {
4040
pos: i64,
4141
report: impl FnMut(&[u8], i64, u64, DirEntryType) -> bool,
4242
) -> Result<i64>;
43+
44+
/// Returns the inode corresponding to the directory entry with the given name.
45+
fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>>;
4346
}
4447

4548
/// The types of directory entries reported by [`Type::read_dir`].
@@ -225,8 +228,7 @@ pub mod ro {
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
};
@@ -559,6 +561,62 @@ pub mod ro {
559561
Ok(0)
560562
})
561563
}
564+
565+
const DIR_INODE_OPERATIONS: bindings::inode_operations = bindings::inode_operations {
566+
lookup: Some(Self::lookup_callback),
567+
get_link: None,
568+
permission: None,
569+
get_inode_acl: None,
570+
readlink: None,
571+
create: None,
572+
link: None,
573+
unlink: None,
574+
symlink: None,
575+
mkdir: None,
576+
rmdir: None,
577+
mknod: None,
578+
rename: None,
579+
setattr: None,
580+
getattr: None,
581+
listxattr: None,
582+
fiemap: None,
583+
update_time: None,
584+
atomic_open: None,
585+
tmpfile: None,
586+
get_acl: None,
587+
set_acl: None,
588+
fileattr_set: None,
589+
fileattr_get: None,
590+
get_offset_ctx: None,
591+
};
592+
593+
extern "C" fn lookup_callback(
594+
parent_ptr: *mut bindings::inode,
595+
dentry: *mut bindings::dentry,
596+
_flags: u32,
597+
) -> *mut bindings::dentry {
598+
// SAFETY: The C api guarantees that `parent_ptr` is a valid inode.
599+
let parent = unsafe { &*parent_ptr.cast::<INode<T>>() };
600+
601+
// SAFETY: The C api guarantees that `dentry` is valid for read. Since the name is
602+
// immutable, it's ok to read its length directly.
603+
let Ok(name_len) = usize::try_from(unsafe { (*dentry).d_name.__bindgen_anon_1.__bindgen_anon_1.len}
604+
) else {
605+
return ENOENT.to_ptr();
606+
};
607+
608+
// SAFETY: The C api guarantees that `dentry` is valid for read. Since the name is
609+
// immutable, it's ok to read it directly.
610+
let name = unsafe { core::slice::from_raw_parts((*dentry).d_name.name, name_len) };
611+
match T::lookup(parent, name) {
612+
Err(e) => e.to_ptr(),
613+
// SAFETY: The returned inode is valid and referenced (by the type invariants), so
614+
// it is ok to transfer this increment to `d_splice_alias`.
615+
Ok(inode) => unsafe {
616+
bindings::d_splice_alias(ManuallyDrop::new(inode).0.get(), dentry)
617+
},
618+
}
619+
}
562620
}
563621

564622
/// Kernel module that exposes a single read-only file system implemented by `T`.
@@ -614,6 +672,12 @@ pub mod ro {
614672
/// # ) -> Result<i64> {
615673
/// # todo!()
616674
/// # }
675+
/// # fn lookup(
676+
/// # _: &fs::ro::INode<Self>,
677+
/// # _: &[u8],
678+
/// # ) -> Result<kernel::types::ARef<fs::ro::INode<Self>>> {
679+
/// # todo!()
680+
/// # }
617681
/// }
618682
/// ```
619683
#[macro_export]

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::ro::{
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_ro_fs! {
1212
type: RoFs,
@@ -93,4 +93,29 @@ impl fs::ro::Type 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)