This patch introduces erofs_map_blocks alternative written in Rust, which will be hooked inside the erofs_iomap_begin. Signed-off-by: Yiyang Wu <toolmanp@xxxxxxx> --- fs/erofs/Makefile | 2 +- fs/erofs/data.c | 5 ++++ fs/erofs/data_rs.rs | 63 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/rust_bindings.h | 4 +++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 fs/erofs/data_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index e086487971b6..219ddca0642e 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 dir_rs.o rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o dir_rs.o data_rs.o rust_helpers.o diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 61debd799cf9..c9694661136b 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -293,7 +293,12 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, map.m_la = offset; map.m_llen = length; +#ifdef CONFIG_EROFS_FS_RUST + ret = erofs_map_blocks_rust(inode, &map); +#else ret = erofs_map_blocks(inode, &map); +#endif + if (ret < 0) return ret; diff --git a/fs/erofs/data_rs.rs b/fs/erofs/data_rs.rs new file mode 100644 index 000000000000..ac34a9dd2079 --- /dev/null +++ b/fs/erofs/data_rs.rs @@ -0,0 +1,63 @@ +// 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::inode; +use kernel::container_of; + +use rust::{erofs_sys::*, kinode::*, ksuperblock::*}; + +#[repr(C)] +struct ErofsBuf { + mapping: NonNull<c_void>, + page: NonNull<c_void>, + base: NonNull<c_void>, + kmap_type: c_int, +} + +/// A helper sturct to map blocks for iomap_begin because iomap is not generated by bindgen +#[repr(C)] +pub struct ErofsMapBlocks { + buf: ErofsBuf, + pub(crate) m_pa: u64, + pub(crate) m_la: u64, + pub(crate) m_plen: u64, + pub(crate) m_llen: u64, + pub(crate) m_deviceid: u16, + pub(crate) m_flags: u32, +} +/// Exported as a replacement for erofs_map_blocks. +#[no_mangle] +pub unsafe extern "C" fn erofs_map_blocks_rust( + k_inode: NonNull<inode>, + mut map: NonNull<ErofsMapBlocks>, +) -> c_int { + // SAFETY: super_block and superblockinfo is always initialized in k_inode. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) }; + // SAFETY: The map is always initialized in the caller. + match sbi + .filesystem + .map(erofs_inode, unsafe { map.as_ref().m_la } as Off) + { + Ok(m) => unsafe { + map.as_mut().m_pa = m.physical.start; + map.as_mut().m_la = map.as_ref().m_la; + map.as_mut().m_plen = m.physical.len; + map.as_mut().m_llen = m.physical.len; + map.as_mut().m_deviceid = m.device_id; + map.as_mut().m_flags = m.map_type.into(); + 0 + }, + Err(e) => i32::from(e) as c_int, + } +} diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index 8b71d65e2c0b..ad9aa75a7a2c 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -24,4 +24,8 @@ extern struct dentry *erofs_lookup_rust(struct inode *inode, struct dentry *dent 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); + +struct erofs_map_blocks; +extern int erofs_map_blocks_rust(struct inode *inode, + struct erofs_map_blocks *map); #endif -- 2.46.0