2024-10-01 08:22:22 +00:00
|
|
|
// 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,
|
2024-12-10 09:39:02 +00:00
|
|
|
device::Device,
|
2024-10-01 08:22:22 +00:00
|
|
|
error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
|
2024-12-15 22:43:53 +01:00
|
|
|
ffi::{c_int, c_long, c_uint, c_ulong},
|
2024-12-10 09:39:00 +00:00
|
|
|
fs::File,
|
2025-04-08 09:22:44 +00:00
|
|
|
mm::virt::VmaNew,
|
2024-10-01 08:22:22 +00:00
|
|
|
prelude::*,
|
2024-12-03 12:34:38 +00:00
|
|
|
seq_file::SeqFile,
|
2024-10-01 08:22:22 +00:00
|
|
|
types::{ForeignOwnable, Opaque},
|
|
|
|
};
|
2024-12-15 22:43:53 +01:00
|
|
|
use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin};
|
2024-10-01 08:22:22 +00:00
|
|
|
|
|
|
|
/// 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() };
|
2025-06-15 16:55:08 -04:00
|
|
|
result.minor = bindings::MISC_DYNAMIC_MINOR as ffi::c_int;
|
2024-10-01 08:22:22 +00:00
|
|
|
result.name = self.name.as_char_ptr();
|
2025-02-27 13:22:31 +00:00
|
|
|
result.fops = MiscdeviceVTable::<T>::build();
|
2024-10-01 08:22:22 +00:00
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A registration of a miscdevice.
|
|
|
|
///
|
|
|
|
/// # Invariants
|
|
|
|
///
|
2025-06-26 16:15:20 +05:30
|
|
|
/// - `inner` contains a `struct miscdevice` that is registered using
|
|
|
|
/// `misc_register()`.
|
|
|
|
/// - This registration remains valid for the entire lifetime of the
|
|
|
|
/// [`MiscDeviceRegistration`] instance.
|
|
|
|
/// - Deregistration occurs exactly once in [`Drop`] via `misc_deregister()`.
|
|
|
|
/// - `inner` wraps a valid, pinned `miscdevice` created using
|
|
|
|
/// [`MiscDeviceOptions::into_raw`].
|
2024-10-01 08:22:22 +00:00
|
|
|
#[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()
|
|
|
|
}
|
2024-12-10 09:39:02 +00:00
|
|
|
|
|
|
|
/// 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.
|
device: rust: rename Device::as_ref() to Device::from_raw()
The prefix as_* should not be used for a constructor. Constructors
usually use the prefix from_* instead.
Some prior art in the stdlib: Box::from_raw, CString::from_raw,
Rc::from_raw, Arc::from_raw, Waker::from_raw, File::from_raw_fd.
There is also prior art in the kernel crate: cpufreq::Policy::from_raw,
fs::File::from_raw_file, Kuid::from_raw, ARef::from_raw,
SeqFile::from_raw, VmaNew::from_raw, Io::from_raw.
Link: https://lore.kernel.org/r/aCd8D5IA0RXZvtcv@pollux
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20250711-device-as-ref-v2-1-1b16ab6402d7@google.com
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
2025-07-11 08:04:37 +00:00
|
|
|
unsafe { Device::from_raw((*self.as_raw()).this_device) }
|
2024-12-10 09:39:02 +00:00
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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]
|
2024-12-10 09:39:01 +00:00
|
|
|
pub trait MiscDevice: Sized {
|
2024-10-01 08:22:22 +00:00
|
|
|
/// 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.
|
2024-12-10 09:39:01 +00:00
|
|
|
fn open(_file: &File, _misc: &MiscDeviceRegistration<Self>) -> Result<Self::Ptr>;
|
2024-10-01 08:22:22 +00:00
|
|
|
|
|
|
|
/// Called when the misc device is released.
|
2024-12-10 09:39:00 +00:00
|
|
|
fn release(device: Self::Ptr, _file: &File) {
|
2024-10-01 08:22:22 +00:00
|
|
|
drop(device);
|
|
|
|
}
|
|
|
|
|
2025-04-08 09:22:44 +00:00
|
|
|
/// 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)
|
|
|
|
}
|
|
|
|
|
2024-10-01 08:22:22 +00:00
|
|
|
/// Handler for ioctls.
|
|
|
|
///
|
2025-05-17 13:06:15 +02:00
|
|
|
/// The `cmd` argument is usually manipulated using the utilities in [`kernel::ioctl`].
|
2024-10-01 08:22:22 +00:00
|
|
|
///
|
|
|
|
/// [`kernel::ioctl`]: mod@crate::ioctl
|
|
|
|
fn ioctl(
|
|
|
|
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
|
2024-12-10 09:39:00 +00:00
|
|
|
_file: &File,
|
2024-10-01 08:22:22 +00:00
|
|
|
_cmd: u32,
|
|
|
|
_arg: usize,
|
|
|
|
) -> Result<isize> {
|
2024-11-23 23:28:49 +01:00
|
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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<'_>,
|
2024-12-10 09:39:00 +00:00
|
|
|
_file: &File,
|
2024-10-01 08:22:22 +00:00
|
|
|
_cmd: u32,
|
|
|
|
_arg: usize,
|
|
|
|
) -> Result<isize> {
|
2024-11-23 23:28:49 +01:00
|
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
2024-12-03 12:34:38 +00:00
|
|
|
|
|
|
|
/// Show info for this fd.
|
|
|
|
fn show_fdinfo(
|
|
|
|
_device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
|
|
|
|
_m: &SeqFile,
|
|
|
|
_file: &File,
|
|
|
|
) {
|
Driver core and debugfs updates
Here is the big set of driver core and debugfs updates for 6.14-rc1.
It's coming late in the merge cycle as there are a number of merge
conflicts with your tree now, and I wanted to make sure they were
working properly. To resolve them, look in linux-next, and I will send
the "fixup" patch as a response to the pull request.
Included in here is a bunch of driver core, PCI, OF, and platform rust
bindings (all acked by the different subsystem maintainers), hence the
merge conflict with the rust tree, and some driver core api updates to
mark things as const, which will also require some fixups due to new
stuff coming in through other trees in this merge window.
There are also a bunch of debugfs updates from Al, and there is at least
one user that does have a regression with these, but Al is working on
tracking down the fix for it. In my use (and everyone else's linux-next
use), it does not seem like a big issue at the moment.
Here's a short list of the things in here:
- driver core bindings for PCI, platform, OF, and some i/o functions.
We are almost at the "write a real driver in rust" stage now,
depending on what you want to do.
- misc device rust bindings and a sample driver to show how to use
them
- debugfs cleanups in the fs as well as the users of the fs api for
places where drivers got it wrong or were unnecessarily doing things
in complex ways.
- driver core const work, making more of the api take const * for
different parameters to make the rust bindings easier overall.
- other small fixes and updates
All of these have been in linux-next with all of the aforementioned
merge conflicts, and the one debugfs issue, which looks to be resolved
"soon".
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-----BEGIN PGP SIGNATURE-----
iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZ5koPA8cZ3JlZ0Brcm9h
aC5jb20ACgkQMUfUDdst+ymFHACfT5acDKf2Bov2Lc/5u3vBW/R6ChsAnj+LmgVI
hcDSPodj4szR40RRnzBd
=u5Ey
-----END PGP SIGNATURE-----
Merge tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core and debugfs updates from Greg KH:
"Here is the big set of driver core and debugfs updates for 6.14-rc1.
Included in here is a bunch of driver core, PCI, OF, and platform rust
bindings (all acked by the different subsystem maintainers), hence the
merge conflict with the rust tree, and some driver core api updates to
mark things as const, which will also require some fixups due to new
stuff coming in through other trees in this merge window.
There are also a bunch of debugfs updates from Al, and there is at
least one user that does have a regression with these, but Al is
working on tracking down the fix for it. In my use (and everyone
else's linux-next use), it does not seem like a big issue at the
moment.
Here's a short list of the things in here:
- driver core rust bindings for PCI, platform, OF, and some i/o
functions.
We are almost at the "write a real driver in rust" stage now,
depending on what you want to do.
- misc device rust bindings and a sample driver to show how to use
them
- debugfs cleanups in the fs as well as the users of the fs api for
places where drivers got it wrong or were unnecessarily doing
things in complex ways.
- driver core const work, making more of the api take const * for
different parameters to make the rust bindings easier overall.
- other small fixes and updates
All of these have been in linux-next with all of the aforementioned
merge conflicts, and the one debugfs issue, which looks to be resolved
"soon""
* tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (95 commits)
rust: device: Use as_char_ptr() to avoid explicit cast
rust: device: Replace CString with CStr in property_present()
devcoredump: Constify 'struct bin_attribute'
devcoredump: Define 'struct bin_attribute' through macro
rust: device: Add property_present()
saner replacement for debugfs_rename()
orangefs-debugfs: don't mess with ->d_name
octeontx2: don't mess with ->d_parent or ->d_parent->d_name
arm_scmi: don't mess with ->d_parent->d_name
slub: don't mess with ->d_name
sof-client-ipc-flood-test: don't mess with ->d_name
qat: don't mess with ->d_name
xhci: don't mess with ->d_iname
mtu3: don't mess wiht ->d_iname
greybus/camera - stop messing with ->d_iname
mediatek: stop messing with ->d_iname
netdevsim: don't embed file_operations into your structs
b43legacy: make use of debugfs_get_aux()
b43: stop embedding struct file_operations into their objects
carl9170: stop embedding file_operations into their objects
...
2025-01-28 12:25:12 -08:00
|
|
|
build_error!(VTABLE_DEFAULT_ERROR)
|
2024-12-03 12:34:38 +00:00
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
/// 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;
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
// SAFETY: The open call of a file can access the private data.
|
|
|
|
let misc_ptr = unsafe { (*raw_file).private_data };
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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>>() };
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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) };
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
let ptr = match T::open(file, misc) {
|
|
|
|
Ok(ptr) => ptr,
|
|
|
|
Err(err) => return err.to_errno(),
|
|
|
|
};
|
2024-12-10 09:39:01 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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.
|
2025-06-12 15:09:43 +02:00
|
|
|
unsafe { (*raw_file).private_data = ptr.into_foreign() };
|
2024-12-10 09:39:01 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
0
|
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
/// # 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.
|
2025-06-12 15:09:43 +02:00
|
|
|
let private = unsafe { (*file).private_data };
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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
|
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-04-08 09:22:44 +00:00
|
|
|
/// # 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.
|
Rust changes for v6.16
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
...
2025-06-04 21:18:37 -07:00
|
|
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private.cast()) };
|
2025-04-08 09:22:44 +00:00
|
|
|
// 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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
/// # 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.
|
2025-06-12 15:09:43 +02:00
|
|
|
let private = unsafe { (*file).private_data };
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
/// # 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.
|
2025-06-12 15:09:43 +02:00
|
|
|
let private = unsafe { (*file).private_data };
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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,
|
|
|
|
}
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
/// # 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.
|
2025-06-12 15:09:43 +02:00
|
|
|
let private = unsafe { (*file).private_data };
|
2025-02-27 13:22:31 +00:00
|
|
|
// 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);
|
2024-10-01 08:22:22 +00:00
|
|
|
}
|
2024-12-03 12:34:38 +00:00
|
|
|
|
2025-02-27 13:22:31 +00:00
|
|
|
const VTABLE: bindings::file_operations = bindings::file_operations {
|
|
|
|
open: Some(Self::open),
|
|
|
|
release: Some(Self::release),
|
2025-04-08 09:22:44 +00:00
|
|
|
mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None },
|
2025-02-27 13:22:31 +00:00
|
|
|
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
|
|
|
|
}
|
2024-12-03 12:34:38 +00:00
|
|
|
}
|