[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250918144356.28585-3-manerakai@protonmail.com>
Date: Thu, 18 Sep 2025 14:45:36 +0000
From: ManeraKai <manerakai@...tonmail.com>
To: "aliceryhl@...gle.com" <aliceryhl@...gle.com>, "gregkh@...uxfoundation.org" <gregkh@...uxfoundation.org>, "arnd@...db.de" <arnd@...db.de>
Cc: "rust-for-linux@...r.kernel.org" <rust-for-linux@...r.kernel.org>, "linux-fsdevel@...r.kernel.org" <linux-fsdevel@...r.kernel.org>, "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>, "manerakai@...tonmail.com" <manerakai@...tonmail.com>
Subject: [PATCH 2/3] rust: miscdevice: Implemented `read` and `write`
Added the general declaration in `FileOperations`. And implemented the
safe wrapping for misc.
Note: Renamed some raw pointer variables to `raw_<name>`. I'm not sure
this way of naming is good or not. I would like your opinion.
Signed-off-by: ManeraKai <manerakai@...tonmail.com>
---
rust/kernel/fs/file_operations.rs | 20 +++++-
rust/kernel/miscdevice.rs | 108 +++++++++++++++++++++++-------
2 files changed, 104 insertions(+), 24 deletions(-)
diff --git a/rust/kernel/fs/file_operations.rs b/rust/kernel/fs/file_operations.rs
index aa60cd46a012..b21a2bae4803 100644
--- a/rust/kernel/fs/file_operations.rs
+++ b/rust/kernel/fs/file_operations.rs
@@ -14,7 +14,7 @@
miscdevice::MiscDeviceRegistration,
mm::virt::VmaNew,
seq_file::SeqFile,
- types::ForeignOwnable,
+ types::ForeignOwnable, uaccess::{UserSliceReader, UserSliceWriter},
};
/// Trait implemented by the private data of an open misc device.
@@ -23,6 +23,24 @@ pub trait FileOperations: Sized {
/// What kind of pointer should `Self` be wrapped in.
type Ptr: ForeignOwnable + Send + Sync;
+ /// Handler for read.
+ fn read(
+ _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ _buf: UserSliceWriter,
+ _offset: &mut i64,
+ ) -> Result<i64> {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
+ /// Handler for write.
+ fn write(
+ _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ mut _buf: UserSliceReader,
+ _offset: &mut i64,
+ ) -> Result<i64> {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
/// Called when the misc device is opened.
///
/// The returned pointer will be stored as the private data for the file.
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index 578f33383ce6..f4b6388a3742 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -8,6 +8,8 @@
//!
//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+use bindings::loff_t;
+
use crate::{
bindings,
device::Device,
@@ -17,7 +19,7 @@
mm::virt::VmaNew,
prelude::*,
seq_file::SeqFile,
- types::{ForeignOwnable, Opaque},
+ types::{ForeignOwnable, Opaque}, uaccess::UserSlice,
};
use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin};
@@ -112,6 +114,54 @@ fn drop(self: Pin<&mut Self>) {
struct MiscdeviceVTable<T: FileOperations>(PhantomData<T>);
impl<T: FileOperations> MiscdeviceVTable<T> {
+ unsafe extern "C" fn read(
+ raw_file: *mut bindings::file,
+ raw_buf: *mut ffi::c_char,
+ size: usize,
+ raw_offset: *mut loff_t,
+ ) -> c_long {
+ // SAFETY: The read call of a file can access file and its private_data.
+ let raw_device = unsafe { (*raw_file).private_data };
+
+ // SAFETY: The read call of a file can borrow the private_data of the file.
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
+
+ let user_slice = UserSlice::new(UserPtr::from_ptr(raw_buf as *mut c_void), size);
+ let user_slice_writer = user_slice.writer();
+
+ // SAFETY: The read call of a file can access and modify the offset pointer value.
+ let offset = unsafe { &mut *raw_offset };
+
+ match T::read(device, user_slice_writer, offset) {
+ Ok(ret) => ret as c_long,
+ Err(err) => err.to_errno() as c_long,
+ }
+ }
+
+ unsafe extern "C" fn write(
+ raw_file: *mut bindings::file,
+ raw_buf: *const ffi::c_char,
+ size: usize,
+ raw_offset: *mut loff_t,
+ ) -> c_long {
+ // SAFETY: The read call of a file can access file and its private_data.
+ let raw_device = unsafe { (*raw_file).private_data };
+
+ // SAFETY: The read call of a file can borrow the private_data of the file.
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
+
+ let user_slice = UserSlice::new(UserPtr::from_ptr(raw_buf as *mut c_void), size);
+ let user_slice_reader = user_slice.reader();
+
+ // SAFETY: The read call of a file can access and modify the offset pointer value.
+ let offset = unsafe { &mut *raw_offset };
+
+ match T::write(device, user_slice_reader, offset) {
+ Ok(ret) => ret as c_long,
+ Err(err) => err.to_errno() as c_long,
+ }
+ }
+
/// # Safety
///
/// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
@@ -124,13 +174,13 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
}
// SAFETY: The open call of a file can access the private data.
- let misc_ptr = unsafe { (*raw_file).private_data };
+ let raw_misc = unsafe { (*raw_file).private_data };
// SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
// associated `struct miscdevice` before calling into this method. Furthermore,
// `misc_open()` ensures that the miscdevice can't be unregistered and freed during this
// call to `fops_open`.
- let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() };
+ let misc = unsafe { &*raw_misc.cast::<MiscDeviceRegistration<T>>() };
// SAFETY:
// * This underlying file is valid for (much longer than) the duration of `T::open`.
@@ -157,16 +207,19 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
///
/// `file` and `inode` must be the file and inode for a file that is being released. The file
/// must be associated with a `MiscDeviceRegistration<T>`.
- unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
+ unsafe extern "C" fn release(
+ _inode: *mut bindings::inode,
+ raw_file: *mut bindings::file,
+ ) -> c_int {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
+ let raw_device = unsafe { (*raw_file).private_data };
// SAFETY: The release call of a file owns the private data.
- let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
+ let device = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(raw_device) };
// SAFETY:
// * The file is valid for the duration of this call.
// * There is no active fdget_pos region on the file on this thread.
- T::release(ptr, unsafe { File::from_raw_file(file) });
+ T::release(device, unsafe { File::from_raw_file(raw_file) });
0
}
@@ -176,21 +229,21 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
/// `vma` must be a vma that is currently being mmap'ed with this file.
unsafe extern "C" fn mmap(
- file: *mut bindings::file,
+ raw_file: *mut bindings::file,
vma: *mut bindings::vm_area_struct,
) -> c_int {
// SAFETY: The mmap call of a file can access the private data.
- let private = unsafe { (*file).private_data };
+ let raw_device = unsafe { (*raw_file).private_data };
// SAFETY: This is a Rust Miscdevice, so we call `into_foreign` in `open` and
// `from_foreign` in `release`, and `fops_mmap` is guaranteed to be called between those
// two operations.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private.cast()) };
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
// SAFETY: The caller provides a vma that is undergoing initial VMA setup.
let area = unsafe { VmaNew::from_raw(vma) };
// SAFETY:
// * The file is valid for the duration of this call.
// * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
+ let file = unsafe { File::from_raw_file(raw_file) };
match T::mmap(device, file, area) {
Ok(()) => 0,
@@ -201,16 +254,16 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
/// # Safety
///
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
- unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
+ unsafe extern "C" fn ioctl(raw_file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
// SAFETY: The ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
+ let raw_device = unsafe { (*raw_file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
// SAFETY:
// * The file is valid for the duration of this call.
// * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
+ let file = unsafe { File::from_raw_file(raw_file) };
match T::ioctl(device, file, cmd, arg) {
Ok(ret) => ret as c_long,
@@ -223,19 +276,19 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
#[cfg(CONFIG_COMPAT)]
unsafe extern "C" fn compat_ioctl(
- file: *mut bindings::file,
+ raw_file: *mut bindings::file,
cmd: c_uint,
arg: c_ulong,
) -> c_long {
// SAFETY: The compat ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
+ let raw_device = unsafe { (*raw_file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
// SAFETY:
// * The file is valid for the duration of this call.
// * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
+ let file = unsafe { File::from_raw_file(raw_file) };
match T::compat_ioctl(device, file, cmd, arg) {
Ok(ret) => ret as c_long,
@@ -247,15 +300,18 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
///
/// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
/// - `seq_file` must be a valid `struct seq_file` that we can write to.
- unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
+ unsafe extern "C" fn show_fdinfo(
+ seq_file: *mut bindings::seq_file,
+ raw_file: *mut bindings::file,
+ ) {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
+ let raw_device = unsafe { (*raw_file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
// SAFETY:
// * The file is valid for the duration of this call.
// * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
+ let file = unsafe { File::from_raw_file(raw_file) };
// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in
// which this method is called.
let m = unsafe { SeqFile::from_raw(seq_file) };
@@ -264,6 +320,12 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
}
const VTABLE: bindings::file_operations = bindings::file_operations {
+ read: if T::HAS_READ { Some(Self::read) } else { None },
+ write: if T::HAS_WRITE {
+ Some(Self::write)
+ } else {
+ None
+ },
open: Some(Self::open),
release: Some(Self::release),
mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None },
--
2.43.0
Powered by blists - more mailing lists