This patch introduce erofs_readdir_rust as an alternative for erofs_readdir written in Rust. Signed-off-by: Yiyang Wu <toolmanp@xxxxxxx> --- fs/erofs/Makefile | 2 +- fs/erofs/dir.c | 2 ++ fs/erofs/dir_rs.rs | 57 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/internal.h | 1 + fs/erofs/rust_bindings.h | 1 + 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 fs/erofs/dir_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 0f748f3e0ff6..e086487971b6 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +9,4 @@ erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o -erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o dir_rs.o rust_helpers.o diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index c3b90abdee37..0f5df8a4169b 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -6,6 +6,7 @@ */ #include "internal.h" +#ifndef CONFIG_EROFS_FS_RUST static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, void *dentry_blk, struct erofs_dirent *de, unsigned int nameoff0, unsigned int maxsize) @@ -92,6 +93,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx) erofs_put_metabuf(&buf); return err < 0 ? err : 0; } +#endif const struct file_operations erofs_dir_fops = { .llseek = generic_file_llseek, diff --git a/fs/erofs/dir_rs.rs b/fs/erofs/dir_rs.rs new file mode 100644 index 000000000000..d965e6076242 --- /dev/null +++ b/fs/erofs/dir_rs.rs @@ -0,0 +1,57 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +//! EROFS Rust Kernel Module Helpers Implementation +//! This is only for experimental purpose. Feedback is always welcome. + +#[allow(dead_code)] +#[allow(missing_docs)] +pub(crate) mod rust; +use core::ffi::*; +use core::ptr::NonNull; + +use kernel::bindings::{dir_context, file}; +use kernel::container_of; + +use rust::{ + erofs_sys::{inode::*, *}, + kinode::*, + ksuperblock::*, +}; + +/// Exported as a replacement of erofs_readdir. +#[no_mangle] +pub unsafe extern "C" fn erofs_readdir_rust( + f: NonNull<file>, + mut ctx: NonNull<dir_context>, +) -> c_int { + // SAFETY: inode is always initialized in file. + let k_inode = unsafe { f.as_ref().f_inode }; + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode, KernelInode, k_inode) }; + // SAFETY: The super_block is always initialized when calling iget5_locked. + let sb = unsafe { (*k_inode).i_sb }; + let sbi = erofs_sbi(NonNull::new(sb).unwrap()); + // SAFETY: ctx is nonnull. + let offset = unsafe { ctx.as_ref().pos }; + match sbi + .filesystem + .fill_dentries(erofs_inode, offset as Off, &mut |dir, pos| unsafe { + // inline expansion from dir_emit + ctx.as_ref().actor.unwrap()( + ctx.as_ptr(), + dir.name.as_ptr().cast(), + dir.name.len() as i32, + pos as i64, + dir.desc.nid as u64, + dir.desc.file_type as u32, + ); + ctx.as_mut().pos = pos as i64; + }) { + Ok(_) => { + unsafe { ctx.as_mut().pos = erofs_inode.info().file_size() as i64 } + 0 + } + Err(e) => (i32::from(e)) as c_int, + } +} diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 1d9dfae285d5..6f57bb866637 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -444,6 +444,7 @@ int erofs_iget5_set(struct inode *inode, void *opaque); #define erofs_iget erofs_iget_rust #define erofs_get_parent erofs_get_parent_rust #define erofs_lookup erofs_lookup_rust +#define erofs_readdir erofs_readdir_rust #else struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid); #endif diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index b35014aa5cae..8b71d65e2c0b 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -23,4 +23,5 @@ extern struct inode *erofs_iget_rust(struct super_block *sb, erofs_nid_t nid); extern struct dentry *erofs_lookup_rust(struct inode *inode, struct dentry *dentry, unsigned int flags); extern struct dentry *erofs_get_parent_rust(struct dentry *dentry); +extern int erofs_readdir_rust(struct file *file, struct dir_context *ctx); #endif -- 2.46.0