rust_binder: refactor context management to use KVVec

Replace the linked list management in context.rs with KVVec.
This simplifies the ownership model by using standard
Arc-based tracking and moves away from manual unsafe list removals.

The refactor improves memory safety by leveraging Rust's contiguous
collection types while maintaining proper error propagation for
allocation failures during process registration.

Suggested-by: Alice Ryhl <aliceryhl@google.com>
Link: https://github.com/rust-for-linux/linux/issues/1215
Signed-off-by: Jason Hall <jason.kei.hall@gmail.com>
Link: https://patch.msgid.link/20260120134119.98048-1-jason.kei.hall@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jason Hall
2026-01-20 06:41:19 -07:00
committed by Greg Kroah-Hartman
parent a8a6d9b4da
commit b7f42b0cfb
2 changed files with 36 additions and 53 deletions

View File

@@ -3,8 +3,8 @@
// Copyright (C) 2025 Google LLC.
use kernel::{
error::Error,
list::{List, ListArc, ListLinks},
alloc::kvec::KVVec,
error::code::*,
prelude::*,
security,
str::{CStr, CString},
@@ -17,22 +17,19 @@
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 {
list: List::new(),
contexts: KVVec::new(),
};
}
pub(crate) struct ContextList {
list: List<Context>,
contexts: KVVec<Arc<Context>>,
}
pub(crate) fn get_all_contexts() -> Result<KVec<Arc<Context>>> {
pub(crate) fn get_all_contexts() -> Result<KVVec<Arc<Context>>> {
let lock = CONTEXTS.lock();
let count = lock.list.iter().count();
let mut ctxs = KVec::with_capacity(count, GFP_KERNEL)?;
for ctx in &lock.list {
ctxs.push(Arc::from(ctx), GFP_KERNEL)?;
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)
}
@@ -42,7 +39,7 @@ pub(crate) fn get_all_contexts() -> Result<KVec<Arc<Context>>> {
struct Manager {
node: Option<NodeRef>,
uid: Option<Kuid>,
all_procs: List<Process>,
all_procs: KVVec<Arc<Process>>,
}
/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc)
@@ -51,28 +48,16 @@ pub(crate) struct Context {
#[pin]
manager: Mutex<Manager>,
pub(crate) name: CString,
#[pin]
links: ListLinks,
}
kernel::list::impl_list_arc_safe! {
impl ListArcSafe<0> for Context { untracked; }
}
kernel::list::impl_list_item! {
impl ListItem<0> for Context {
using ListLinks { self.links };
}
}
impl Context {
pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
let name = CString::try_from(name)?;
let list_ctx = ListArc::pin_init::<Error>(
let ctx = Arc::pin_init(
try_pin_init!(Context {
name,
links <- ListLinks::new(),
manager <- kernel::new_mutex!(Manager {
all_procs: List::new(),
all_procs: KVVec::new(),
node: None,
uid: None,
}, "Context::manager"),
@@ -80,8 +65,7 @@ pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
GFP_KERNEL,
)?;
let ctx = list_ctx.clone_arc();
CONTEXTS.lock().list.push_back(list_ctx);
CONTEXTS.lock().contexts.push(ctx.clone(), GFP_KERNEL)?;
Ok(ctx)
}
@@ -89,27 +73,27 @@ pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
/// Called when the file for this context is unlinked.
///
/// No-op if called twice.
pub(crate) fn deregister(&self) {
// SAFETY: We never add the context to any other linked list than this one, so it is either
// in this list, or not in any list.
unsafe { CONTEXTS.lock().list.remove(self) };
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: ListArc<Process>) {
pub(crate) fn register_process(self: &Arc<Self>, proc: Arc<Process>) -> Result {
if !Arc::ptr_eq(self, &proc.ctx) {
pr_err!("Context::register_process called on the wrong context.");
return;
return Err(EINVAL);
}
self.manager.lock().all_procs.push_back(proc);
self.manager.lock().all_procs.push(proc, GFP_KERNEL)?;
Ok(())
}
pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Process) {
pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Arc<Process>) {
if !Arc::ptr_eq(self, &proc.ctx) {
pr_err!("Context::deregister_process called on the wrong context.");
return;
}
// SAFETY: We just checked that this is the right list.
unsafe { self.manager.lock().all_procs.remove(proc) };
let mut manager = self.manager.lock();
manager.all_procs.retain(|p| !Arc::ptr_eq(p, proc));
}
pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
@@ -158,23 +142,23 @@ pub(crate) fn for_each_proc<F>(&self, mut func: F)
}
}
pub(crate) fn get_all_procs(&self) -> Result<KVec<Arc<Process>>> {
pub(crate) fn get_all_procs(&self) -> Result<KVVec<Arc<Process>>> {
let lock = self.manager.lock();
let count = lock.all_procs.iter().count();
let mut procs = KVec::with_capacity(count, GFP_KERNEL)?;
for proc in &lock.all_procs {
procs.push(Arc::from(proc), GFP_KERNEL)?;
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<KVec<Arc<Process>>> {
let orig = self.get_all_procs()?;
let mut backing = KVec::with_capacity(orig.len(), GFP_KERNEL)?;
for proc in orig.into_iter().filter(|proc| proc.task.pid() == pid) {
backing.push(proc, GFP_KERNEL)?;
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(backing)
Ok(matching_procs)
}
}

View File

@@ -503,7 +503,7 @@ fn run(me: Arc<Self>) {
impl Process {
fn new(ctx: Arc<Context>, cred: ARef<Credential>) -> Result<Arc<Self>> {
let current = kernel::current!();
let list_process = ListArc::pin_init::<Error>(
let process = Arc::pin_init::<Error>(
try_pin_init!(Process {
ctx,
cred,
@@ -519,8 +519,7 @@ fn new(ctx: Arc<Context>, cred: ARef<Credential>) -> Result<Arc<Self>> {
GFP_KERNEL,
)?;
let process = list_process.clone_arc();
process.ctx.register_process(list_process);
process.ctx.register_process(process.clone())?;
Ok(process)
}