mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

Toolchain and infrastructure: - KUnit '#[test]'s: - Support KUnit-mapped 'assert!' macros. The support that landed last cycle was very basic, and the 'assert!' macros panicked since they were the standard library ones. Now, they are mapped to the KUnit ones in a similar way to how is done for doctests, reusing the infrastructure there. With this, a failing test like: #[test] fn my_first_test() { assert_eq!(42, 43); } will report: # my_first_test: ASSERTION FAILED at rust/kernel/lib.rs:251 Expected 42 == 43 to be true, but is false # my_first_test.speed: normal not ok 1 my_first_test - Support tests with checked 'Result' return types. The return value of test functions that return a 'Result' will be checked, thus one can now easily catch errors when e.g. using the '?' operator in tests. With this, a failing test like: #[test] fn my_test() -> Result { f()?; Ok(()) } will report: # my_test: ASSERTION FAILED at rust/kernel/lib.rs:321 Expected is_test_result_ok(my_test()) to be true, but is false # my_test.speed: normal not ok 1 my_test - Add 'kunit_tests' to the prelude. - Clarify the remaining language unstable features in use. - Compile 'core' with edition 2024 for Rust >= 1.87. - Workaround 'bindgen' issue with forward references to 'enum' types. - objtool: relax slice condition to cover more 'noreturn' functions. - Use absolute paths in macros referencing 'core' and 'kernel' crates. - Skip '-mno-fdpic' flag for bindgen in GCC 32-bit arm builds. - Clean some 'doc_markdown' lint hits -- we may enable it later on. 'kernel' crate: - 'alloc' module: - 'Box': support for type coercion, e.g. 'Box<T>' to 'Box<dyn U>' if 'T' implements 'U'. - 'Vec': implement new methods (prerequisites for nova-core and binder): 'truncate', 'resize', 'clear', 'pop', 'push_within_capacity' (with new error type 'PushError'), 'drain_all', 'retain', 'remove' (with new error type 'RemoveError'), insert_within_capacity' (with new error type 'InsertError'). In addition, simplify 'push' using 'spare_capacity_mut', split 'set_len' into 'inc_len' and 'dec_len', add type invariant 'len <= capacity' and simplify 'truncate' using 'dec_len'. - 'time' module: - Morph the Rust hrtimer subsystem into the Rust timekeeping subsystem, covering delay, sleep, timekeeping, timers. This new subsystem has all the relevant timekeeping C maintainers listed in the entry. - Replace 'Ktime' with 'Delta' and 'Instant' types to represent a duration of time and a point in time. - Temporarily add 'Ktime' to 'hrtimer' module to allow 'hrtimer' to delay converting to 'Instant' and 'Delta'. - 'xarray' module: - Add a Rust abstraction for the 'xarray' data structure. This abstraction allows Rust code to leverage the 'xarray' to store types that implement 'ForeignOwnable'. This support is a dependency for memory backing feature of the Rust null block driver, which is waiting to be merged. - Set up an entry in 'MAINTAINERS' for the XArray Rust support. Patches will go to the new Rust XArray tree and then via the Rust subsystem tree for now. - Allow 'ForeignOwnable' to carry information about the pointed-to type. This helps asserting alignment requirements for the pointer passed to the foreign language. - 'container_of!': retain pointer mut-ness and add a compile-time check of the type of the first parameter ('$field_ptr'). - Support optional message in 'static_assert!'. - Add C FFI types (e.g. 'c_int') to the prelude. - 'str' module: simplify KUnit tests 'format!' macro, convert 'rusttest' tests into KUnit, take advantage of the '-> Result' support in KUnit '#[test]'s. - 'list' module: add examples for 'List', fix path of 'assert_pinned!' (so far unused macro rule). - 'workqueue' module: remove 'HasWork::OFFSET'. - 'page' module: add 'inline' attribute. 'macros' crate: - 'module' macro: place 'cleanup_module()' in '.exit.text' section. 'pin-init' crate: - Add 'Wrapper<T>' trait for creating pin-initializers for wrapper structs with a structurally pinned value such as 'UnsafeCell<T>' or 'MaybeUninit<T>'. - Add 'MaybeZeroable' derive macro to try to derive 'Zeroable', but not error if not all fields implement it. This is needed to derive 'Zeroable' for all bindgen-generated structs. - Add 'unsafe fn cast_[pin_]init()' functions to unsafely change the initialized type of an initializer. These are utilized by the 'Wrapper<T>' implementations. - Add support for visibility in 'Zeroable' derive macro. - Add support for 'union's in 'Zeroable' derive macro. - Upstream dev news: streamline CI, fix some bugs. Add new workflows to check if the user-space version and the one in the kernel tree have diverged. Use the issues tab [1] to track them, which should help folks report and diagnose issues w.r.t. 'pin-init' better. [1] https://github.com/rust-for-linux/pin-init/issues Documentation: - Testing: add docs on the new KUnit '#[test]' tests. - Coding guidelines: explain that '///' vs. '//' applies to private items too. Add section on C FFI types. - Quick Start guide: update Ubuntu instructions and split them into "25.04" and "24.04 LTS and older". And a few other cleanups and improvements. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmhBAvYACgkQGXyLc2ht IW3qvA/+KRTCYKcI6JyUT9TdhRmaaMsQ0/5j6Kx4CfRQPZTSWsXyBEU75yEIZUQD SUGQFwmMAYeAKQD1SumFCRy973VzUO45DyKM+7vuVhKN1ZjnAtv63+31C3UFATlA 8Tm3GCqQEGKl4IER7xI3D/vpZA5FOv+GotjNieF3O9FpHDCvV/JQScq9I2oXQPCt 17kRLww/DTfpf4qiLmxmxHn6nCsbecdfEce1kfjk3nNuE6B2tPf+ddYOwunLEvkB LA4Cr6T1Cy1ovRQgxg9Pdkl/0Rta0tFcsKt1LqPgjR+n95stsHgAzbyMGuUKoeZx u2R2pwlrJt6Xe4CEZgTIRfYWgF81qUzdcPuflcSMDCpH0nTep74A2lIiWUHWZSh4 LbPh7r90Q8YwGKVJiWqLfHUmQBnmTEm3D2gydSExPKJXSzB4Rbv4w4fPF3dhzMtC 4+KvmHKIojFkAdTLt+5rkKipJGo/rghvQvaQr9JOu+QO4vfhkesB4pUWC4sZd9A9 GJBP97ynWAsXGGaeaaSli0b851X+VE/WIDOmPMselbA3rVADChE6HsJnY/wVVeWK jupvAhUExSczDPCluGv8T9EVXvv6+fg3bB5pD6R01NNJe6iE/LIDQ5Gj5rg4qahM EFzMgPj6hMt5McvWI8q1/ym0bzdeC2/cmaV6E14hvphAZoORUKI= =JRqL -----END PGP SIGNATURE----- Merge tag 'rust-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - KUnit '#[test]'s: - Support KUnit-mapped 'assert!' macros. The support that landed last cycle was very basic, and the 'assert!' macros panicked since they were the standard library ones. Now, they are mapped to the KUnit ones in a similar way to how is done for doctests, reusing the infrastructure there. With this, a failing test like: #[test] fn my_first_test() { assert_eq!(42, 43); } will report: # my_first_test: ASSERTION FAILED at rust/kernel/lib.rs:251 Expected 42 == 43 to be true, but is false # my_first_test.speed: normal not ok 1 my_first_test - Support tests with checked 'Result' return types. The return value of test functions that return a 'Result' will be checked, thus one can now easily catch errors when e.g. using the '?' operator in tests. With this, a failing test like: #[test] fn my_test() -> Result { f()?; Ok(()) } will report: # my_test: ASSERTION FAILED at rust/kernel/lib.rs:321 Expected is_test_result_ok(my_test()) to be true, but is false # my_test.speed: normal not ok 1 my_test - Add 'kunit_tests' to the prelude. - Clarify the remaining language unstable features in use. - Compile 'core' with edition 2024 for Rust >= 1.87. - Workaround 'bindgen' issue with forward references to 'enum' types. - objtool: relax slice condition to cover more 'noreturn' functions. - Use absolute paths in macros referencing 'core' and 'kernel' crates. - Skip '-mno-fdpic' flag for bindgen in GCC 32-bit arm builds. - Clean some 'doc_markdown' lint hits -- we may enable it later on. 'kernel' crate: - 'alloc' module: - 'Box': support for type coercion, e.g. 'Box<T>' to 'Box<dyn U>' if 'T' implements 'U'. - 'Vec': implement new methods (prerequisites for nova-core and binder): 'truncate', 'resize', 'clear', 'pop', 'push_within_capacity' (with new error type 'PushError'), 'drain_all', 'retain', 'remove' (with new error type 'RemoveError'), insert_within_capacity' (with new error type 'InsertError'). In addition, simplify 'push' using 'spare_capacity_mut', split 'set_len' into 'inc_len' and 'dec_len', add type invariant 'len <= capacity' and simplify 'truncate' using 'dec_len'. - 'time' module: - Morph the Rust hrtimer subsystem into the Rust timekeeping subsystem, covering delay, sleep, timekeeping, timers. This new subsystem has all the relevant timekeeping C maintainers listed in the entry. - Replace 'Ktime' with 'Delta' and 'Instant' types to represent a duration of time and a point in time. - Temporarily add 'Ktime' to 'hrtimer' module to allow 'hrtimer' to delay converting to 'Instant' and 'Delta'. - 'xarray' module: - Add a Rust abstraction for the 'xarray' data structure. This abstraction allows Rust code to leverage the 'xarray' to store types that implement 'ForeignOwnable'. This support is a dependency for memory backing feature of the Rust null block driver, which is waiting to be merged. - Set up an entry in 'MAINTAINERS' for the XArray Rust support. Patches will go to the new Rust XArray tree and then via the Rust subsystem tree for now. - Allow 'ForeignOwnable' to carry information about the pointed-to type. This helps asserting alignment requirements for the pointer passed to the foreign language. - 'container_of!': retain pointer mut-ness and add a compile-time check of the type of the first parameter ('$field_ptr'). - Support optional message in 'static_assert!'. - Add C FFI types (e.g. 'c_int') to the prelude. - 'str' module: simplify KUnit tests 'format!' macro, convert 'rusttest' tests into KUnit, take advantage of the '-> Result' support in KUnit '#[test]'s. - 'list' module: add examples for 'List', fix path of 'assert_pinned!' (so far unused macro rule). - 'workqueue' module: remove 'HasWork::OFFSET'. - 'page' module: add 'inline' attribute. 'macros' crate: - 'module' macro: place 'cleanup_module()' in '.exit.text' section. 'pin-init' crate: - Add 'Wrapper<T>' trait for creating pin-initializers for wrapper structs with a structurally pinned value such as 'UnsafeCell<T>' or 'MaybeUninit<T>'. - Add 'MaybeZeroable' derive macro to try to derive 'Zeroable', but not error if not all fields implement it. This is needed to derive 'Zeroable' for all bindgen-generated structs. - Add 'unsafe fn cast_[pin_]init()' functions to unsafely change the initialized type of an initializer. These are utilized by the 'Wrapper<T>' implementations. - Add support for visibility in 'Zeroable' derive macro. - Add support for 'union's in 'Zeroable' derive macro. - Upstream dev news: streamline CI, fix some bugs. Add new workflows to check if the user-space version and the one in the kernel tree have diverged. Use the issues tab [1] to track them, which should help folks report and diagnose issues w.r.t. 'pin-init' better. [1] https://github.com/rust-for-linux/pin-init/issues Documentation: - Testing: add docs on the new KUnit '#[test]' tests. - Coding guidelines: explain that '///' vs. '//' applies to private items too. Add section on C FFI types. - Quick Start guide: update Ubuntu instructions and split them into "25.04" and "24.04 LTS and older". And a few other cleanups and improvements" * tag 'rust-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (78 commits) rust: list: Fix typo `much` in arc.rs rust: check type of `$ptr` in `container_of!` rust: workqueue: remove HasWork::OFFSET rust: retain pointer mut-ness in `container_of!` Documentation: rust: testing: add docs on the new KUnit `#[test]` tests Documentation: rust: rename `#[test]`s to "`rusttest` host tests" rust: str: take advantage of the `-> Result` support in KUnit `#[test]`'s rust: str: simplify KUnit tests `format!` macro rust: str: convert `rusttest` tests into KUnit rust: add `kunit_tests` to the prelude rust: kunit: support checked `-> Result`s in KUnit `#[test]`s rust: kunit: support KUnit-mapped `assert!` macros in `#[test]`s rust: make section names plural rust: list: fix path of `assert_pinned!` rust: compile libcore with edition 2024 for 1.87+ rust: dma: add missing Markdown code span rust: task: add missing Markdown code spans and intra-doc links rust: pci: fix docs related to missing Markdown code spans rust: alloc: add missing Markdown code span rust: alloc: add missing Markdown code spans ...
365 lines
14 KiB
Rust
365 lines
14 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
// Copyright (C) 2024 Google LLC.
|
|
|
|
//! Miscdevice support.
|
|
//!
|
|
//! C headers: [`include/linux/miscdevice.h`](srctree/include/linux/miscdevice.h).
|
|
//!
|
|
//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
|
|
|
|
use crate::{
|
|
bindings,
|
|
device::Device,
|
|
error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
|
|
ffi::{c_int, c_long, c_uint, c_ulong},
|
|
fs::File,
|
|
mm::virt::VmaNew,
|
|
prelude::*,
|
|
seq_file::SeqFile,
|
|
str::CStr,
|
|
types::{ForeignOwnable, Opaque},
|
|
};
|
|
use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin};
|
|
|
|
/// Options for creating a misc device.
|
|
#[derive(Copy, Clone)]
|
|
pub struct MiscDeviceOptions {
|
|
/// The name of the miscdevice.
|
|
pub name: &'static CStr,
|
|
}
|
|
|
|
impl MiscDeviceOptions {
|
|
/// Create a raw `struct miscdev` ready for registration.
|
|
pub const fn into_raw<T: MiscDevice>(self) -> bindings::miscdevice {
|
|
// SAFETY: All zeros is valid for this C type.
|
|
let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };
|
|
result.minor = bindings::MISC_DYNAMIC_MINOR as _;
|
|
result.name = self.name.as_char_ptr();
|
|
result.fops = MiscdeviceVTable::<T>::build();
|
|
result
|
|
}
|
|
}
|
|
|
|
/// A registration of a miscdevice.
|
|
///
|
|
/// # Invariants
|
|
///
|
|
/// `inner` is a registered misc device.
|
|
#[repr(transparent)]
|
|
#[pin_data(PinnedDrop)]
|
|
pub struct MiscDeviceRegistration<T> {
|
|
#[pin]
|
|
inner: Opaque<bindings::miscdevice>,
|
|
_t: PhantomData<T>,
|
|
}
|
|
|
|
// SAFETY: It is allowed to call `misc_deregister` on a different thread from where you called
|
|
// `misc_register`.
|
|
unsafe impl<T> Send for MiscDeviceRegistration<T> {}
|
|
// SAFETY: All `&self` methods on this type are written to ensure that it is safe to call them in
|
|
// parallel.
|
|
unsafe impl<T> Sync for MiscDeviceRegistration<T> {}
|
|
|
|
impl<T: MiscDevice> MiscDeviceRegistration<T> {
|
|
/// Register a misc device.
|
|
pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
|
|
try_pin_init!(Self {
|
|
inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscdevice| {
|
|
// SAFETY: The initializer can write to the provided `slot`.
|
|
unsafe { slot.write(opts.into_raw::<T>()) };
|
|
|
|
// SAFETY: We just wrote the misc device options to the slot. The miscdevice will
|
|
// get unregistered before `slot` is deallocated because the memory is pinned and
|
|
// the destructor of this type deallocates the memory.
|
|
// INVARIANT: If this returns `Ok(())`, then the `slot` will contain a registered
|
|
// misc device.
|
|
to_result(unsafe { bindings::misc_register(slot) })
|
|
}),
|
|
_t: PhantomData,
|
|
})
|
|
}
|
|
|
|
/// Returns a raw pointer to the misc device.
|
|
pub fn as_raw(&self) -> *mut bindings::miscdevice {
|
|
self.inner.get()
|
|
}
|
|
|
|
/// Access the `this_device` field.
|
|
pub fn device(&self) -> &Device {
|
|
// SAFETY: This can only be called after a successful register(), which always
|
|
// initialises `this_device` with a valid device. Furthermore, the signature of this
|
|
// function tells the borrow-checker that the `&Device` reference must not outlive the
|
|
// `&MiscDeviceRegistration<T>` used to obtain it, so the last use of the reference must be
|
|
// before the underlying `struct miscdevice` is destroyed.
|
|
unsafe { Device::as_ref((*self.as_raw()).this_device) }
|
|
}
|
|
}
|
|
|
|
#[pinned_drop]
|
|
impl<T> PinnedDrop for MiscDeviceRegistration<T> {
|
|
fn drop(self: Pin<&mut Self>) {
|
|
// SAFETY: We know that the device is registered by the type invariants.
|
|
unsafe { bindings::misc_deregister(self.inner.get()) };
|
|
}
|
|
}
|
|
|
|
/// Trait implemented by the private data of an open misc device.
|
|
#[vtable]
|
|
pub trait MiscDevice: Sized {
|
|
/// What kind of pointer should `Self` be wrapped in.
|
|
type Ptr: ForeignOwnable + Send + Sync;
|
|
|
|
/// Called when the misc device is opened.
|
|
///
|
|
/// The returned pointer will be stored as the private data for the file.
|
|
fn open(_file: &File, _misc: &MiscDeviceRegistration<Self>) -> Result<Self::Ptr>;
|
|
|
|
/// Called when the misc device is released.
|
|
fn release(device: Self::Ptr, _file: &File) {
|
|
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: &VmaNew,
|
|
) -> Result {
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
|
}
|
|
|
|
/// Handler for ioctls.
|
|
///
|
|
/// The `cmd` argument is usually manipulated using the utilties in [`kernel::ioctl`].
|
|
///
|
|
/// [`kernel::ioctl`]: mod@crate::ioctl
|
|
fn ioctl(
|
|
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
|
|
_file: &File,
|
|
_cmd: u32,
|
|
_arg: usize,
|
|
) -> Result<isize> {
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
|
}
|
|
|
|
/// Handler for ioctls.
|
|
///
|
|
/// Used for 32-bit userspace on 64-bit platforms.
|
|
///
|
|
/// This method is optional and only needs to be provided if the ioctl relies on structures
|
|
/// that have different layout on 32-bit and 64-bit userspace. If no implementation is
|
|
/// provided, then `compat_ptr_ioctl` will be used instead.
|
|
#[cfg(CONFIG_COMPAT)]
|
|
fn compat_ioctl(
|
|
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
|
|
_file: &File,
|
|
_cmd: u32,
|
|
_arg: usize,
|
|
) -> Result<isize> {
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
|
}
|
|
|
|
/// Show info for this fd.
|
|
fn show_fdinfo(
|
|
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
|
|
_m: &SeqFile,
|
|
_file: &File,
|
|
) {
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
|
}
|
|
}
|
|
|
|
/// A vtable for the file operations of a Rust miscdevice.
|
|
struct MiscdeviceVTable<T: MiscDevice>(PhantomData<T>);
|
|
|
|
impl<T: MiscDevice> MiscdeviceVTable<T> {
|
|
/// # Safety
|
|
///
|
|
/// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
|
|
/// The file must be associated with a `MiscDeviceRegistration<T>`.
|
|
unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut bindings::file) -> c_int {
|
|
// SAFETY: The pointers are valid and for a file being opened.
|
|
let ret = unsafe { bindings::generic_file_open(inode, raw_file) };
|
|
if ret != 0 {
|
|
return ret;
|
|
}
|
|
|
|
// SAFETY: The open call of a file can access the private data.
|
|
let misc_ptr = 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>>() };
|
|
|
|
// SAFETY:
|
|
// * This underlying file is valid for (much longer than) the duration of `T::open`.
|
|
// * There is no active fdget_pos region on the file on this thread.
|
|
let file = unsafe { File::from_raw_file(raw_file) };
|
|
|
|
let ptr = match T::open(file, misc) {
|
|
Ok(ptr) => ptr,
|
|
Err(err) => return err.to_errno(),
|
|
};
|
|
|
|
// This overwrites the private data with the value specified by the user, changing the type
|
|
// of this file's private data. All future accesses to the private data is performed by
|
|
// other fops_* methods in this file, which all correctly cast the private data to the new
|
|
// type.
|
|
//
|
|
// SAFETY: The open call of a file can access the private data.
|
|
unsafe { (*raw_file).private_data = ptr.into_foreign().cast() };
|
|
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `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 {
|
|
// SAFETY: The release call of a file owns the private data.
|
|
let private = unsafe { (*file).private_data }.cast();
|
|
// SAFETY: The release call of a file owns the private data.
|
|
let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
|
|
|
|
// 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) });
|
|
|
|
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 mmap(
|
|
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.cast()) };
|
|
// 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) };
|
|
|
|
match T::mmap(device, file, area) {
|
|
Ok(()) => 0,
|
|
Err(err) => err.to_errno(),
|
|
}
|
|
}
|
|
|
|
/// # 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 {
|
|
// SAFETY: The ioctl call of a file can access the private data.
|
|
let private = unsafe { (*file).private_data }.cast();
|
|
// SAFETY: Ioctl calls can borrow the private data of the file.
|
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
|
|
|
// 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::ioctl(device, file, cmd, arg) {
|
|
Ok(ret) => ret as c_long,
|
|
Err(err) => err.to_errno() as c_long,
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// `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,
|
|
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 }.cast();
|
|
// SAFETY: Ioctl calls can borrow the private data of the file.
|
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
|
|
|
// 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::compat_ioctl(device, file, cmd, arg) {
|
|
Ok(ret) => ret as c_long,
|
|
Err(err) => err.to_errno() as c_long,
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// - `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) {
|
|
// SAFETY: The release call of a file owns the private data.
|
|
let private = unsafe { (*file).private_data }.cast();
|
|
// SAFETY: Ioctl calls can borrow the private data of the file.
|
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
|
// 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) };
|
|
// 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) };
|
|
|
|
T::show_fdinfo(device, m, file);
|
|
}
|
|
|
|
const VTABLE: bindings::file_operations = bindings::file_operations {
|
|
open: Some(Self::open),
|
|
release: Some(Self::release),
|
|
mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None },
|
|
unlocked_ioctl: if T::HAS_IOCTL {
|
|
Some(Self::ioctl)
|
|
} else {
|
|
None
|
|
},
|
|
#[cfg(CONFIG_COMPAT)]
|
|
compat_ioctl: if T::HAS_COMPAT_IOCTL {
|
|
Some(Self::compat_ioctl)
|
|
} else if T::HAS_IOCTL {
|
|
Some(bindings::compat_ptr_ioctl)
|
|
} else {
|
|
None
|
|
},
|
|
show_fdinfo: if T::HAS_SHOW_FDINFO {
|
|
Some(Self::show_fdinfo)
|
|
} else {
|
|
None
|
|
},
|
|
// SAFETY: All zeros is a valid value for `bindings::file_operations`.
|
|
..unsafe { MaybeUninit::zeroed().assume_init() }
|
|
};
|
|
|
|
const fn build() -> &'static bindings::file_operations {
|
|
&Self::VTABLE
|
|
}
|
|
}
|