Files
Linus Torvalds 330517c63a 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
  ...
2026-10-24 15:44:26 -10:00

176 lines
5.4 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
use kernel::{
alloc::kvec::KVVec,
error::code::*,
prelude::*,
security,
str::{CStr, CString},
sync::{Arc, Mutex},
task::Kuid,
};
use crate::{error::BinderError, node::NodeRef, process::Process};
kernel::sync::global_lock! {
// SAFETY: We call `init` in the module initializer, so it's initialized before first use.
pub(crate) unsafe(uninit) static CONTEXTS: Mutex<ContextList> = ContextList {
contexts: KVVec::new(),
};
}
pub(crate) struct ContextList {
contexts: KVVec<Arc<Context>>,
}
pub(crate) fn get_all_contexts() -> Result<KVVec<Arc<Context>>> {
let lock = CONTEXTS.lock();
let mut ctxs = KVVec::with_capacity(lock.contexts.len(), GFP_KERNEL)?;
for ctx in lock.contexts.iter() {
ctxs.push(ctx.clone(), GFP_KERNEL)?;
}
Ok(ctxs)
}
/// This struct keeps track of the processes using this context, and which process is the context
/// manager.
struct Manager {
node: Option<NodeRef>,
uid: Option<Kuid>,
all_procs: KVVec<Arc<Process>>,
}
/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc)
#[pin_data]
pub(crate) struct Context {
#[pin]
manager: Mutex<Manager>,
pub(crate) name: CString,
}
impl Context {
pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
let name = CString::try_from(name)?;
let ctx = Arc::pin_init(
try_pin_init!(Context {
name,
manager <- kernel::new_mutex!(Manager {
all_procs: KVVec::new(),
node: None,
uid: None,
}, "Context::manager"),
}),
GFP_KERNEL,
)?;
CONTEXTS.lock().contexts.push(ctx.clone(), GFP_KERNEL)?;
Ok(ctx)
}
/// Called when the file for this context is unlinked.
///
/// No-op if called twice.
pub(crate) fn deregister(self: &Arc<Self>) {
// Safe removal using retain
CONTEXTS.lock().contexts.retain(|c| !Arc::ptr_eq(c, self));
}
pub(crate) fn register_process(self: &Arc<Self>, proc: Arc<Process>) -> Result {
if !Arc::ptr_eq(self, &proc.ctx) {
pr_err_ratelimited!("Context::register_process called on the wrong context.\n");
return Err(EINVAL);
}
self.manager.lock().all_procs.push(proc, GFP_KERNEL)?;
Ok(())
}
pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Arc<Process>) {
if !Arc::ptr_eq(self, &proc.ctx) {
pr_err_ratelimited!("Context::deregister_process called on the wrong context.\n");
return;
}
let mut manager = self.manager.lock();
manager.all_procs.retain(|p| !Arc::ptr_eq(p, proc));
// Shrink the vector if it has significant unused capacity to avoid memory waste,
// but use a conservative strategy to prevent shrink-then-regrow oscillation.
// Only shrink when length drops below 1/4 of capacity, and shrink to twice the length.
let len = manager.all_procs.len();
let cap = manager.all_procs.capacity();
if len < cap / 4 {
// Shrink to twice the current length. Ignore allocation failures since this
// is just an optimization; the vector remains valid even if shrinking fails.
let _ = manager.all_procs.shrink_to(len * 2, GFP_KERNEL);
}
}
pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
let mut manager = self.manager.lock();
if manager.node.is_some() {
pr_warn_ratelimited!("BINDER_SET_CONTEXT_MGR already set\n");
return Err(EBUSY);
}
security::binder_set_context_mgr(&node_ref.node.owner.cred)?;
// If the context manager has been set before, ensure that we use the same euid.
let caller_uid = Kuid::current_euid();
if let Some(ref uid) = manager.uid {
if *uid != caller_uid {
return Err(EPERM);
}
}
manager.node = Some(node_ref);
manager.uid = Some(caller_uid);
Ok(())
}
pub(crate) fn unset_manager_node(&self) {
let node_ref = self.manager.lock().node.take();
drop(node_ref);
}
pub(crate) fn get_manager_node(&self, strong: bool) -> Result<NodeRef, BinderError> {
Ok(self
.manager
.lock()
.node
.as_ref()
.ok_or_else(|| BinderError::new_dead())?
.clone(strong)?)
}
pub(crate) fn for_each_proc<F>(&self, mut func: F)
where
F: FnMut(&Process),
{
let lock = self.manager.lock();
for proc in &lock.all_procs {
func(proc);
}
}
pub(crate) fn get_all_procs(&self) -> Result<KVVec<Arc<Process>>> {
let lock = self.manager.lock();
let mut procs = KVVec::with_capacity(lock.all_procs.len(), GFP_KERNEL)?;
for proc in lock.all_procs.iter() {
procs.push(Arc::clone(proc), GFP_KERNEL)?;
}
Ok(procs)
}
pub(crate) fn get_procs_with_pid(&self, pid: i32) -> Result<KVVec<Arc<Process>>> {
let lock = self.manager.lock();
let mut matching_procs = KVVec::new();
for proc in lock.all_procs.iter() {
if proc.task.pid() == pid {
matching_procs.push(Arc::clone(proc), GFP_KERNEL)?;
}
}
Ok(matching_procs)
}
}