summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-24 15:44:26 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-24 15:44:26 -1000
commit330517c63aa9b48227b6ab45f01003effac77ae4 (patch)
tree51b6e38214a50c0253eba6dc05eeed6ae0f5b995 /rust
parent168151cdb0f93d26557f9f3c7aae659b8d6b1863 (diff)
parent985955d8e6b2b15cfd65b7ac6893e3a5a90c5870 (diff)
Merge tag 'char-misc-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull Char/Misc/IIO/others driver updates from Greg KH: "Here is the big set of char/misc/android/iio and other small driver subsystem patches for 7.4-rc1. Loads of stuff in here, larger than normal. Highlights include: - removal of the C binder code, the rust version is stable and will be used going forward in a few billion devices. Great job by those developers - loads and loads of IIO driver updates and feature additions - speakup driver fixes and updates - mhi driver updates - mei driver updates - xillybus driver fixes - comedi driver fixes - lots of coresight driver updates - Interconnect driver updates - nvmem driver updates and fixes - slimbus driver updates and fixes - spmi driver updates and fixes - lots of tiny misc and char driver fixes based on people scanning for things All of these have been in linux-next for a while with no reported issues, other than a merge conflict with one of the rust tree files, which should be simple to resolve" * tag 'char-misc-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (446 commits) rust_binder: wake epoll on self-work queued to poll thread rust_binder: avoid overflow in get_node_debug_info() MAINTAINERS: Add Abel as SPMI co-maintainer spmi: mtk-pmif: Fix clock reference leak in mtk_spmi_bus_probe() iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions iio: adc: qcom-spmi-iadc: Migrate to devm_spmi_subdevice_alloc_and_add() misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add() phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add() power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add() nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() spmi: Add helper to get a parent SPMI device spmi: Implement spmi_subdevice_alloc_and_add() and devm variant spmi: Remove unneeded goto in spmi_device_add() error path spmi: Print error status with %pe format spmi: Remove redundant dev_name() print in spmi_device_add() spmi: Fix potential use-after-free by grabbing of_node reference spmi: mtk-pmif: Add workaround for FSM lockup/error in read operation MAINTAINERS: Add Qualcomm SPMI controller entry spmi: pmic-arb: return 0 in spmi_pmic_arb_register_buses() on success comedi: addi_apci_3xxx: fix subdevice count underallocation ...
Diffstat (limited to 'rust')
-rw-r--r--rust/kernel/error.rs5
-rw-r--r--rust/kernel/miscdevice.rs100
2 files changed, 73 insertions, 32 deletions
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index e52793f77196..9003a1b86da8 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -199,8 +199,13 @@ pub mod code {
///
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
pub struct Error(NonZeroI32);
+// SAFETY: `Error` is `repr(transparent)` over `NonZeroI32`, which is part of the option layout
+// optimization guarantee, so all zeroes is a valid representation for `None`.
+unsafe impl pin_init::ZeroableOption for Error {}
+
impl Error {
/// Creates an [`Error`] from a kernel error code.
///
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index eacea29e3fb0..900676ea6bbc 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -10,6 +10,7 @@
use crate::{
bindings,
+ container_of,
device::Device,
error::to_result,
fs::{
@@ -29,7 +30,10 @@ use crate::{
Opaque, //
}, //
};
-use core::marker::PhantomData;
+use core::{
+ marker::PhantomData,
+ ops::Deref, //
+};
/// Options for creating a misc device.
#[derive(Copy, Clone)]
@@ -60,37 +64,56 @@ impl MiscDeviceOptions {
/// - Deregistration occurs exactly once in [`Drop`] via `misc_deregister()`.
/// - `inner` wraps a valid, pinned `miscdevice` created using
/// [`MiscDeviceOptions::into_raw`].
-#[repr(transparent)]
+#[repr(C)]
#[pin_data(PinnedDrop)]
pub struct MiscDeviceRegistration<T> {
#[pin]
inner: Opaque<bindings::miscdevice>,
- _t: PhantomData<T>,
+ #[pin]
+ data: 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> {}
+// `misc_register`, and `T` is `Send`.
+unsafe impl<T: Send> 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> {}
+// parallel, and `T` is `Sync`.
+unsafe impl<T: Sync> Sync for MiscDeviceRegistration<T> {}
impl<T: MiscDevice> MiscDeviceRegistration<T> {
/// Register a misc device.
- pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
+ ///
+ /// # Safety
+ ///
+ /// The caller must not `mem::forget()` the returned [`MiscDeviceRegistration`] or otherwise
+ /// prevent its [`Drop`] implementation from running.
+ pub unsafe fn register<'a>(
+ opts: MiscDeviceOptions,
+ data: impl PinInit<T, Error> + 'a,
+ ) -> impl PinInit<Self, Error> + 'a
+ where
+ T: 'a,
+ {
try_pin_init!(Self {
+ data <- data,
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.
+ // the caller guarantees that the destructor of this type will run.
+ //
+ // The `data` field is already initialized and is only dropped after
+ // `misc_deregister` in `PinnedDrop::drop`. Since `T: Sync` and the caller
+ // guarantees that `Drop` will run before `T` becomes invalid, it is sound for the
+ // `open` callback to access `&MiscDeviceRegistration<T>` until `misc_deregister`
+ // returns.
+ //
// INVARIANT: If this returns `Ok(())`, then the `slot` will contain a registered
// misc device.
to_result(unsafe { bindings::misc_register(slot) })
}),
- _t: PhantomData,
})
}
@@ -110,6 +133,14 @@ impl<T: MiscDevice> MiscDeviceRegistration<T> {
}
}
+impl<T> Deref for MiscDeviceRegistration<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &T {
+ &self.data
+ }
+}
+
#[pinned_drop]
impl<T> PinnedDrop for MiscDeviceRegistration<T> {
fn drop(self: Pin<&mut Self>) {
@@ -118,19 +149,23 @@ impl<T> PinnedDrop for MiscDeviceRegistration<T> {
}
}
-/// Trait implemented by the private data of an open misc device.
+/// Trait implemented by the data stored in a [`MiscDeviceRegistration`].
#[vtable]
-pub trait MiscDevice: Sized {
- /// What kind of pointer should `Self` be wrapped in.
- type Ptr: ForeignOwnable + Send + Sync;
+pub trait MiscDevice: Sized + Sync {
+ /// The type of the data stored in each file for this miscdevice.
+ ///
+ /// This type must be pointer-sized, so it will usually be a [`KBox`] or [`Arc`].
+ ///
+ /// [`Arc`]: crate::sync::Arc
+ type File: ForeignOwnable + Send + Sync + 'static;
/// 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>;
+ fn open(_file: &File, _misc: &MiscDeviceRegistration<Self>) -> Result<Self::File>;
/// Called when the misc device is released.
- fn release(device: Self::Ptr, _file: &File) {
+ fn release(device: Self::File, _file: &File) {
drop(device);
}
@@ -144,18 +179,18 @@ pub trait MiscDevice: Sized {
/// `vma`.
#[optional]
fn mmap(
- _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ _device: <Self::File as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_vma: &VmaNew,
) -> Result;
/// Read from this miscdevice.
#[optional]
- fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterDest<'_>) -> Result<usize>;
+ fn read_iter(_kiocb: Kiocb<'_, Self::File>, _iov: &mut IovIterDest<'_>) -> Result<usize>;
/// Write to this miscdevice.
#[optional]
- fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterSource<'_>) -> Result<usize>;
+ fn write_iter(_kiocb: Kiocb<'_, Self::File>, _iov: &mut IovIterSource<'_>) -> Result<usize>;
/// Handler for ioctls.
///
@@ -164,7 +199,7 @@ pub trait MiscDevice: Sized {
/// [`kernel::ioctl`]: mod@crate::ioctl
#[optional]
fn ioctl(
- _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ _device: <Self::File as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_cmd: u32,
_arg: usize,
@@ -180,7 +215,7 @@ pub trait MiscDevice: Sized {
#[cfg(CONFIG_COMPAT)]
#[optional]
fn compat_ioctl(
- _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ _device: <Self::File as ForeignOwnable>::Borrowed<'_>,
_file: &File,
_cmd: u32,
_arg: usize,
@@ -189,7 +224,7 @@ pub trait MiscDevice: Sized {
/// Show info for this fd.
#[optional]
fn show_fdinfo(
- _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+ _device: <Self::File as ForeignOwnable>::Borrowed<'_>,
_m: &SeqFile,
_file: &File,
);
@@ -211,13 +246,14 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
}
// SAFETY: The open call of a file can access the private data.
- let misc_ptr = unsafe { (*raw_file).private_data };
+ let misc_ptr = Opaque::cast_from(unsafe { (*raw_file).private_data }.cast());
// 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>>() };
+ // associated `struct miscdevice` (which is the `inner` field of a valid
+ // `MiscDeviceRegistration<T>`) before calling into this method. Furthermore, `misc_open()`
+ // ensures that the miscdevice can't be unregistered and freed during this call to
+ // `fops_open`, and `T: Sync` allows sharing `&MiscDeviceRegistration<T>` across threads.
+ let misc = unsafe { &*container_of!(misc_ptr, MiscDeviceRegistration<T>, inner) };
// SAFETY:
// * This underlying file is valid for (much longer than) the duration of `T::open`.
@@ -248,7 +284,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// SAFETY: The release call of a file owns the private data.
let private = unsafe { (*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 ptr = unsafe { <T::File as ForeignOwnable>::from_foreign(private) };
// SAFETY:
// * The file is valid for the duration of this call.
@@ -311,7 +347,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// 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::File as ForeignOwnable>::borrow(private) };
// SAFETY: The caller provides a vma that is undergoing initial VMA setup.
let area = unsafe { VmaNew::from_raw(vma) };
// SAFETY:
@@ -332,7 +368,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// SAFETY: The ioctl call of a file can access the private data.
let private = unsafe { (*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::File as ForeignOwnable>::borrow(private) };
// SAFETY:
// * The file is valid for the duration of this call.
@@ -357,7 +393,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// SAFETY: The compat ioctl call of a file can access the private data.
let private = unsafe { (*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::File as ForeignOwnable>::borrow(private) };
// SAFETY:
// * The file is valid for the duration of this call.
@@ -378,7 +414,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// SAFETY: The release call of a file owns the private data.
let private = unsafe { (*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::File 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.