From b7f42b0cfb94d4cc96371ef77c4ecffbc1c02ac2 Mon Sep 17 00:00:00 2001 From: Jason Hall Date: Tue, 20 Jan 2026 06:41:19 -0700 Subject: [PATCH] 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 Link: https://github.com/rust-for-linux/linux/issues/1215 Signed-off-by: Jason Hall Link: https://patch.msgid.link/20260120134119.98048-1-jason.kei.hall@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/context.rs | 84 +++++++++++++------------------ drivers/android/binder/process.rs | 5 +- 2 files changed, 36 insertions(+), 53 deletions(-) diff --git a/drivers/android/binder/context.rs b/drivers/android/binder/context.rs index 3d135ec03ca74..c7b75efef217f 100644 --- a/drivers/android/binder/context.rs +++ b/drivers/android/binder/context.rs @@ -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 @@ 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 { - list: List::new(), + contexts: KVVec::new(), }; } pub(crate) struct ContextList { - list: List, + contexts: KVVec>, } -pub(crate) fn get_all_contexts() -> Result>> { +pub(crate) fn get_all_contexts() -> Result>> { 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>> { struct Manager { node: Option, uid: Option, - all_procs: List, + all_procs: KVVec>, } /// There is one context per binder file (/dev/binder, /dev/hwbinder, etc) @@ -51,28 +48,16 @@ pub(crate) struct Context { #[pin] manager: Mutex, 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> { let name = CString::try_from(name)?; - let list_ctx = ListArc::pin_init::( + 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 @@ impl Context { 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 @@ impl Context { /// 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) { + // Safe removal using retain + CONTEXTS.lock().contexts.retain(|c| !Arc::ptr_eq(c, self)); } - pub(crate) fn register_process(self: &Arc, proc: ListArc) { + pub(crate) fn register_process(self: &Arc, proc: Arc) -> 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, proc: &Process) { + pub(crate) fn deregister_process(self: &Arc, proc: &Arc) { 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 @@ impl Context { } } - pub(crate) fn get_all_procs(&self) -> Result>> { + pub(crate) fn get_all_procs(&self) -> Result>> { 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>> { - 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>> { + 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) } } diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 62b8279b711fe..ba98ef9f35453 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -503,7 +503,7 @@ impl workqueue::WorkItem for Process { impl Process { fn new(ctx: Arc, cred: ARef) -> Result> { let current = kernel::current!(); - let list_process = ListArc::pin_init::( + let process = Arc::pin_init::( try_pin_init!(Process { ctx, cred, @@ -519,8 +519,7 @@ impl Process { GFP_KERNEL, )?; - let process = list_process.clone_arc(); - process.ctx.register_process(list_process); + process.ctx.register_process(process.clone())?; Ok(process) } -- 2.47.3