diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-24 15:44:26 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-24 15:44:26 -1000 |
| commit | 330517c63aa9b48227b6ab45f01003effac77ae4 (patch) | |
| tree | 51b6e38214a50c0253eba6dc05eeed6ae0f5b995 /rust | |
| parent | 168151cdb0f93d26557f9f3c7aae659b8d6b1863 (diff) | |
| parent | 985955d8e6b2b15cfd65b7ac6893e3a5a90c5870 (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.rs | 5 | ||||
| -rw-r--r-- | rust/kernel/miscdevice.rs | 100 |
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. |
