linux/rust/kernel/sync/poll.rs
Linus Torvalds 93e4b3076b Char/Misc/IIO/etc driver update for 7.3-rc1
Here is the big set of char, misc, iio, counter, fpga, and other small
 driver subsystems for 7.3-rc1.
 
 Overall, due to some driver removals we only added a bit more code than
 removed, which was a nice change.  Highlights in this merge request are:
   - Loads of IIO driver updates and additions
   - binder driver updates (more on that below...)
   - Removal of the SGI XP and GRU drivers as they are not used anymore
     and turn out to be pretty insecure overall
   - Removal of the obsolete ibmasm driver as it's not being used anymore
   - Coresight driver updates and additions
   - Mei driver udpates
   - Counter driver updates
   - FPGA driver updates
   - ICC driver updates
   - lots and lots of other tiny driver updates to resolve reported
     issues
 
 All of these have been in linux-next for a while, with the only reported
 issues being some major merge conflicts.  Miguel pointed out some of
 these with the Rust tree merge, which is the majority of them.  I'll
 follow up with a diffstat of the merge resolution I made against your
 most recent tree, which works for me.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCao143A8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymtUgCeKB62gT1JfA86cg3NDB1opp+10N0An3oBBegQ
 IJLqJgK45dTNtMGBwGFV
 =68af
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc/IIO/etc driver updates from Greg KH:
 "Here is the big set of char, misc, iio, counter, fpga, and other small
  driver subsystems for 7.3-rc1.

  Overall, due to some driver removals we only added a bit more code
  than removed, which was a nice change. Highlights in this merge
  request are:

   - Loads of IIO driver updates and additions

   - binder driver updates (more on that below...)

   - Removal of the SGI XP and GRU drivers as they are not used anymore
     and turn out to be pretty insecure overall

   - Removal of the obsolete ibmasm driver as it's not being used
     anymore

   - Coresight driver updates and additions

   - Mei driver udpates

   - Counter driver updates

   - FPGA driver updates

   - ICC driver updates

   - lots and lots of other tiny driver updates to resolve reported
     issues

  All of these have been in linux-next for a while"

* tag 'char-misc-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (513 commits)
  iio: chemical: atlas-sensor: use iio_trigger_poll_nested() to fix remove UAF
  iio: adc: pac1921: fix wrong channel used in trigger handler read
  iio: light: gp2ap002: re-enable irq if runtime suspend fails
  iio: light: gp2ap002: Fix unbalanced runtime PM on repeated event writes
  iio: light: apds9306: fix PM reference leak in apds9306_read_data()
  iio: gyro: mpu3050: fix sign of raw angular velocity readings
  iio: srf04: fix pm_runtime handling on probe error path
  iio: adc: ad4080: configure backend data size
  iio: adc: adi-axi-adc: add data size support for AD408X backend
  iio: chemical: atlas-sensor: fix PM reference leak in buffer postenable
  iio: dac: ad5446: fix OF module device table
  iio: light: opt4001: Fix reversed GENMASK() arguments in fault count mask
  iio: light: opt4001: Reject integration times with a non-zero seconds part
  iio: light: opt4001: Fix incompatible pointer type passed to div_u64_rem()
  iio: light: opt4001: Fix power down clearing bits of the wrong register
  iio: light: opt4060: Fix incorrect register name in threshold read error message
  iio: light: opt4060: Fix pointer type passed to div_u64_rem()
  iio: light: opt4060: Reject integration times with a non-zero seconds part
  iio: light: ltrf216a: fix runtime PM reference leak in error path
  iio: pressure: dps310: fix NULL pointer dereference on ACPI probe
  ...
2026-08-25 09:38:50 -07:00

180 lines
5.3 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 Google LLC.
//! Utilities for working with `struct poll_table`.
use crate::{
alloc::AllocError,
bindings,
fs::File,
prelude::*,
sync::{
rcu::synchronize_rcu,
CondVar,
LockClassKey, //
}, //
types::Opaque, //
};
use core::{
marker::PhantomData,
mem::ManuallyDrop,
ops::Deref, //
};
/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
#[macro_export]
macro_rules! new_poll_condvar {
($($name:literal)?) => {
$crate::sync::poll::PollCondVar::new(
$crate::optional_name!($($name)?), $crate::static_lock_class!()
)
};
}
/// Wraps the kernel's `poll_table`.
///
/// # Invariants
///
/// The pointer must be null or reference a valid `poll_table`.
#[repr(transparent)]
pub struct PollTable<'a> {
table: *mut bindings::poll_table,
_lifetime: PhantomData<&'a bindings::poll_table>,
}
impl<'a> PollTable<'a> {
/// Creates a [`PollTable`] from a valid pointer.
///
/// # Safety
///
/// The pointer must be null or reference a valid `poll_table` for the duration of `'a`.
pub unsafe fn from_raw(table: *mut bindings::poll_table) -> Self {
// INVARIANTS: The safety requirements are the same as the struct invariants.
PollTable {
table,
_lifetime: PhantomData,
}
}
/// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
/// using the condition variable.
pub fn register_wait(&self, file: &File, cv: &PollCondVar) {
// SAFETY:
// * `file.as_ptr()` references a valid file for the duration of this call.
// * `self.table` is null or references a valid poll_table for the duration of this call.
// * Since `PollCondVar` is pinned, its destructor is guaranteed to run before the memory
// containing `cv.wait_queue_head` is invalidated. Since the destructor clears all
// waiters and then waits for an rcu grace period, it's guaranteed that
// `cv.wait_queue_head` remains valid for at least an rcu grace period after the removal
// of the last waiter.
unsafe { bindings::poll_wait(file.as_ptr(), cv.wait_queue_head.get(), self.table) }
}
}
/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`].
///
/// [`CondVar`]: crate::sync::CondVar
#[pin_data(PinnedDrop)]
#[repr(transparent)]
pub struct PollCondVar {
#[pin]
inner: CondVar,
}
impl PollCondVar {
/// Constructs a new condvar initialiser.
pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
pin_init!(Self {
inner <- CondVar::new(name, key),
})
}
}
// Make the `CondVar` methods callable on `PollCondVar`.
impl Deref for PollCondVar {
type Target = CondVar;
fn deref(&self) -> &CondVar {
&self.inner
}
}
#[pinned_drop]
impl PinnedDrop for PollCondVar {
#[inline]
fn drop(self: Pin<&mut Self>) {
// Clear anything registered using `register_wait`.
//
// SAFETY: The pointer points at a valid `wait_queue_head`.
unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) };
// Wait for epoll items to be properly removed.
synchronize_rcu();
}
}
/// A [`KBox<PollCondVar>`] that uses `kfree_rcu`.
///
/// [`KBox<PollCondVar>`]: PollCondVar
pub struct PollCondVarBox {
inner: ManuallyDrop<Pin<KBox<PollCondVarBoxInner>>>,
}
#[pin_data]
#[repr(C)]
struct PollCondVarBoxInner {
#[pin]
inner: PollCondVar,
rcu: Opaque<bindings::kvfree_rcu_head>,
}
// SAFETY: PollCondVar is Send
unsafe impl Send for PollCondVarBoxInner {}
// SAFETY: PollCondVar is Sync
unsafe impl Sync for PollCondVarBoxInner {}
impl PollCondVarBox {
/// Constructs a new boxed [`PollCondVar`].
pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> Result<Self, AllocError> {
let b = KBox::pin_init(
pin_init!(PollCondVarBoxInner {
inner <- PollCondVar::new(name, key),
rcu: Opaque::uninit(),
}),
GFP_KERNEL,
)
.map_err(|_| AllocError)?;
Ok(PollCondVarBox {
inner: ManuallyDrop::new(b),
})
}
}
impl Deref for PollCondVarBox {
type Target = PollCondVar;
fn deref(&self) -> &PollCondVar {
&self.inner.inner
}
}
impl Drop for PollCondVarBox {
#[inline]
fn drop(&mut self) {
// SAFETY: ManuallyDrop::take ok because not already taken.
let boxed = unsafe { ManuallyDrop::take(&mut self.inner) };
// SAFETY: The code below frees the box without calling the actual destructor of the type,
// but it's okay because it re-implements the destructor using `kfree_rcu()` in place of
// `synchronize_rcu()`.
let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(boxed) });
// SAFETY: The pointer points at a valid `wait_queue_head`.
unsafe { bindings::__wake_up_pollfree((*ptr).inner.inner.wait_queue_head.get()) };
// SAFETY: This was allocated using `KBox::pin_init`, so it can be freed with `kvfree`.
unsafe { bindings::kvfree_call_rcu((*ptr).rcu.get(), ptr.cast::<ffi::c_void>()) };
}
}