From: Wedson Almeida Filho <walmeida@xxxxxxxxxxxxx> This allows file systems to customise their behaviour when callers want to read from a file. Signed-off-by: Wedson Almeida Filho <walmeida@xxxxxxxxxxxxx> --- rust/kernel/fs/file.rs | 35 ++++++++++++++++++++++++++++++++++- rust/kernel/user.rs | 1 - samples/rust/rust_rofs.rs | 6 +++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 77eb6d230568..2ba456a1eee1 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -12,6 +12,7 @@ bindings, error::{code::*, from_result, Error, Result}, types::{ARef, AlwaysRefCounted, Locked, Opaque}, + user, }; use core::{marker::PhantomData, mem::ManuallyDrop, ptr}; use macros::vtable; @@ -324,6 +325,15 @@ pub trait Operations { /// File system that these operations are compatible with. type FileSystem: FileSystem + ?Sized; + /// Reads data from this file into the caller's buffer. + fn read( + _file: &File<Self::FileSystem>, + _buffer: &mut user::Writer, + _offset: &mut Offset, + ) -> Result<usize> { + Err(EINVAL) + } + /// Seeks the file to the given offset. fn seek(_file: &File<Self::FileSystem>, _offset: Offset, _whence: Whence) -> Result<Offset> { Err(EINVAL) @@ -356,7 +366,11 @@ impl<T: Operations + ?Sized> Table<T> { } else { None }, - read: None, + read: if T::HAS_READ { + Some(Self::read_callback) + } else { + None + }, write: None, read_iter: None, write_iter: None, @@ -407,6 +421,25 @@ impl<T: Operations + ?Sized> Table<T> { }) } + unsafe extern "C" fn read_callback( + file_ptr: *mut bindings::file, + ptr: *mut core::ffi::c_char, + len: usize, + offset: *mut bindings::loff_t, + ) -> isize { + from_result(|| { + // SAFETY: The C API guarantees that `file` is valid for the duration of the + // callback. Since this callback is specifically for filesystem T, we know `T` + // is the right filesystem. + let file = unsafe { File::from_raw(file_ptr) }; + let mut writer = user::Writer::new(ptr, len); + + // SAFETY: The C API guarantees that `offset` is valid for read and write. + let read = T::read(file, &mut writer, unsafe { &mut *offset })?; + Ok(isize::try_from(read)?) + }) + } + unsafe extern "C" fn read_dir_callback( file_ptr: *mut bindings::file, ctx_ptr: *mut bindings::dir_context, diff --git a/rust/kernel/user.rs b/rust/kernel/user.rs index 35a673ebcd58..20fb887f4640 100644 --- a/rust/kernel/user.rs +++ b/rust/kernel/user.rs @@ -11,7 +11,6 @@ pub struct Writer { } impl Writer { - #[allow(dead_code)] pub(crate) fn new(ptr: *mut i8, len: usize) -> Self { Self { ptr: ptr.cast::<u8>(), diff --git a/samples/rust/rust_rofs.rs b/samples/rust/rust_rofs.rs index abec084360da..f4be5908369c 100644 --- a/samples/rust/rust_rofs.rs +++ b/samples/rust/rust_rofs.rs @@ -4,7 +4,7 @@ use kernel::fs::{dentry, file, file::File, inode, inode::INode, sb::SuperBlock, Offset}; use kernel::prelude::*; -use kernel::{c_str, fs, time::UNIX_EPOCH, types::Either, types::Locked}; +use kernel::{c_str, fs, time::UNIX_EPOCH, types::Either, types::Locked, user}; kernel::module_fs! { type: RoFs, @@ -80,6 +80,10 @@ fn seek(file: &File<Self>, offset: Offset, whence: file::Whence) -> Result<Offse file::generic_seek(file, offset, whence) } + fn read(_: &File<Self>, _: &mut user::Writer, _: &mut Offset) -> Result<usize> { + Err(EISDIR) + } + fn read_dir( _file: &File<Self>, inode: &Locked<&INode<Self>, inode::ReadSem>, -- 2.34.1