FROMLIST: rust: miscdevice: add mmap support

Add the ability to write a file_operations->mmap hook in Rust when using
the miscdevice abstraction. The `vma` argument to the `mmap` hook uses
the `VmAreaNew` type from the previous commit; this type provides the
correct set of operations for a file_operations->mmap hook.

Acked-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> (for mm bits)
Change-Id: I00a0769625bd9e6cbb2dc9613cda8ae371a3ac3b
Signed-off-by: Alice Ryhl <aliceryhl@google.com>

Bug: 370906207
Link: https://lore.kernel.org/all/20250115-vma-v12-7-375099ae017a@google.com/
Change-Id: I5f4441b60673fdc08190eaf566099dcb88905bb9
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2024-10-10 14:40:47 +02:00
parent 7d1983ce89
commit 88a4dfa30b
+44
View File
@@ -13,6 +13,7 @@ use crate::{
device::Device,
error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
fs::File,
mm::virt::VmAreaNew,
prelude::*,
seq_file::SeqFile,
str::CStr,
@@ -123,6 +124,22 @@ pub trait MiscDevice: Sized {
drop(device);
}
/// Handle for mmap.
///
/// This function is invoked when a user space process invokes the `mmap` system call on
/// `file`. The function is a callback that is part of the VMA initializer. The kernel will do
/// initial setup of the VMA before calling this function. The function can then interact with
/// the VMA initialization by calling methods of `vma`. If the function does not return an
/// error, the kernel will complete initialization of the VMA according to the properties of
/// `vma`.
fn mmap(
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_vma: &VmAreaNew,
) -> Result {
kernel::build_error!(VTABLE_DEFAULT_ERROR)
}
/// Handler for ioctls.
///
/// The `cmd` argument is usually manipulated using the utilties in [`kernel::ioctl`].
@@ -180,6 +197,7 @@ const fn create_vtable<T: MiscDevice>() -> &'static bindings::file_operations {
const VTABLE: bindings::file_operations = bindings::file_operations {
open: Some(fops_open::<T>),
release: Some(fops_release::<T>),
mmap: maybe_fn(T::HAS_MMAP, fops_mmap::<T>),
unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::<T>),
#[cfg(CONFIG_COMPAT)]
compat_ioctl: if T::HAS_COMPAT_IOCTL {
@@ -261,6 +279,32 @@ unsafe extern "C" fn fops_release<T: MiscDevice>(
0
}
/// # Safety
///
/// `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 fops_mmap<T: MiscDevice>(
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 };
// 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) };
// SAFETY: The caller provides a vma that is undergoing initial VMA setup.
let area = unsafe { VmAreaNew::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) };
match T::mmap(device, file, area) {
Ok(()) => 0,
Err(err) => err.to_errno() as c_int,
}
}
/// # Safety
///
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.