diff options
Diffstat (limited to 'drivers/android')
| -rw-r--r-- | drivers/android/binder.c | 2 | ||||
| -rw-r--r-- | drivers/android/binder/node.rs | 6 | ||||
| -rw-r--r-- | drivers/android/binder/process.rs | 81 | ||||
| -rw-r--r-- | drivers/android/binder/rust_binder_main.rs | 22 | ||||
| -rw-r--r-- | drivers/android/binder/thread.rs | 4 | ||||
| -rw-r--r-- | drivers/android/binderfs.c | 3 | ||||
| -rw-r--r-- | drivers/android/tests/binder_alloc_kunit.c | 2 |
7 files changed, 67 insertions, 53 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a3a1b5c33ba3..535fc881c8da 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4669,6 +4669,8 @@ static int binder_wait_for_work(struct binder_thread *thread, * * If we fail to allocate an fd, skip the install and release * any fds that have already been allocated. + * + * Return: 0 on success, a negative errno code on failure. */ static int binder_apply_fd_fixups(struct binder_proc *proc, struct binder_transaction *t) diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index 08d362deaf61..c26d113ede96 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -541,10 +541,10 @@ impl Node { guard = self.owner.inner.lock(); } - let death_list = core::mem::take(&mut self.inner.access_mut(&mut guard).death_list); - drop(guard); - for death in death_list { + while let Some(death) = self.inner.access_mut(&mut guard).death_list.pop_front() { + drop(guard); death.into_arc().set_dead(); + guard = self.owner.inner.lock(); } } diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index e5237e9ec552..132055b4790f 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -19,6 +19,7 @@ use kernel::{ cred::Credential, error::Error, fs::file::{self, File}, + id_pool::IdPool, list::{List, ListArc, ListArcField, ListLinks}, mm, prelude::*, @@ -394,6 +395,8 @@ kernel::list::impl_list_item! { struct ProcessNodeRefs { /// Used to look up nodes using the 32-bit id that this process knows it by. by_handle: RBTree<u32, ListArc<NodeRefInfo, { NodeRefInfo::LIST_PROC }>>, + /// Used to quickly find unused ids in `by_handle`. + handle_is_present: IdPool, /// Used to look up nodes without knowing their local 32-bit id. The usize is the address of /// the underlying `Node` struct as returned by `Node::global_id`. by_node: RBTree<usize, u32>, @@ -408,6 +411,7 @@ impl ProcessNodeRefs { fn new() -> Self { Self { by_handle: RBTree::new(), + handle_is_present: IdPool::new(), by_node: RBTree::new(), freeze_listeners: RBTree::new(), } @@ -802,7 +806,7 @@ impl Process { pub(crate) fn insert_or_update_handle( self: ArcBorrow<'_, Process>, node_ref: NodeRef, - is_mananger: bool, + is_manager: bool, ) -> Result<u32> { { let mut refs = self.node_refs.lock(); @@ -821,7 +825,33 @@ impl Process { let reserve2 = RBTreeNodeReservation::new(GFP_KERNEL)?; let info = UniqueArc::new_uninit(GFP_KERNEL)?; - let mut refs = self.node_refs.lock(); + let mut refs_lock = self.node_refs.lock(); + let mut refs = &mut *refs_lock; + + let (unused_id, by_handle_slot) = loop { + // ID 0 may only be used by the manager. + let start = if is_manager { 0 } else { 1 }; + + if let Some(res) = refs.handle_is_present.find_unused_id(start) { + match refs.by_handle.entry(res.as_u32()) { + rbtree::Entry::Vacant(entry) => break (res, entry), + rbtree::Entry::Occupied(_) => { + pr_err!("Detected mismatch between handle_is_present and by_handle"); + res.acquire(); + kernel::warn_on!(true); + return Err(EINVAL); + } + } + } + + let grow_request = refs.handle_is_present.grow_request().ok_or(ENOMEM)?; + drop(refs_lock); + let resizer = grow_request.realloc(GFP_KERNEL)?; + refs_lock = self.node_refs.lock(); + refs = &mut *refs_lock; + refs.handle_is_present.grow(resizer); + }; + let handle = unused_id.as_u32(); // Do a lookup again as node may have been inserted before the lock was reacquired. if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) { @@ -831,20 +861,9 @@ impl Process { return Ok(handle); } - // Find id. - let mut target: u32 = if is_mananger { 0 } else { 1 }; - for handle in refs.by_handle.keys() { - if *handle > target { - break; - } - if *handle == target { - target = target.checked_add(1).ok_or(ENOMEM)?; - } - } - let gid = node_ref.node.global_id(); let (info_proc, info_node) = { - let info_init = NodeRefInfo::new(node_ref, target, self.into()); + let info_init = NodeRefInfo::new(node_ref, handle, self.into()); match info.pin_init_with(info_init) { Ok(info) => ListArc::pair_from_pin_unique(info), // error is infallible @@ -865,9 +884,10 @@ impl Process { // `info_node` into the right node's `refs` list. unsafe { info_proc.node_ref2().node.insert_node_info(info_node) }; - refs.by_node.insert(reserve1.into_node(gid, target)); - refs.by_handle.insert(reserve2.into_node(target, info_proc)); - Ok(target) + refs.by_node.insert(reserve1.into_node(gid, handle)); + by_handle_slot.insert(info_proc, reserve2); + unused_id.acquire(); + Ok(handle) } pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult<NodeRef> { @@ -932,6 +952,16 @@ impl Process { let id = info.node_ref().node.global_id(); refs.by_handle.remove(&handle); refs.by_node.remove(&id); + refs.handle_is_present.release_id(handle as usize); + + if let Some(shrink) = refs.handle_is_present.shrink_request() { + drop(refs); + // This intentionally ignores allocation failures. + if let Ok(new_bitmap) = shrink.realloc(GFP_KERNEL) { + refs = self.node_refs.lock(); + refs.handle_is_present.shrink(new_bitmap); + } + } } } else { // All refs are cleared in process exit, so this warning is expected in that case. @@ -1362,8 +1392,12 @@ impl Process { work.into_arc().cancel(); } - let delivered_deaths = take(&mut self.inner.lock().delivered_deaths); - drop(delivered_deaths); + // Clear delivered_deaths list. + // + // Scope ensures that MutexGuard is dropped while executing the body. + while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } { + drop(delivered_death); + } // Free any resources kept alive by allocated buffers. let omapping = self.inner.lock().mapping.take(); @@ -1623,15 +1657,6 @@ impl Process { } } - pub(crate) fn compat_ioctl( - this: ArcBorrow<'_, Process>, - file: &File, - cmd: u32, - arg: usize, - ) -> Result { - Self::ioctl(this, file, cmd, arg) - } - pub(crate) fn mmap( this: ArcBorrow<'_, Process>, _file: &File, diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs index 6773b7c273ec..c79a9e742240 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -313,8 +313,8 @@ pub static rust_binder_fops: AssertSync<kernel::bindings::file_operations> = { let ops = kernel::bindings::file_operations { owner: THIS_MODULE.as_ptr(), poll: Some(rust_binder_poll), - unlocked_ioctl: Some(rust_binder_unlocked_ioctl), - compat_ioctl: Some(rust_binder_compat_ioctl), + unlocked_ioctl: Some(rust_binder_ioctl), + compat_ioctl: Some(bindings::compat_ptr_ioctl), mmap: Some(rust_binder_mmap), open: Some(rust_binder_open), release: Some(rust_binder_release), @@ -402,23 +402,7 @@ unsafe extern "C" fn rust_binder_release( /// # Safety /// Only called by binderfs. -unsafe extern "C" fn rust_binder_compat_ioctl( - file: *mut bindings::file, - cmd: kernel::ffi::c_uint, - arg: kernel::ffi::c_ulong, -) -> kernel::ffi::c_long { - // SAFETY: We previously set `private_data` in `rust_binder_open`. - let f = unsafe { Arc::<Process>::borrow((*file).private_data) }; - // SAFETY: The caller ensures that the file is valid. - match Process::compat_ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) { - Ok(()) => 0, - Err(err) => err.to_errno() as isize, - } -} - -/// # Safety -/// Only called by binderfs. -unsafe extern "C" fn rust_binder_unlocked_ioctl( +unsafe extern "C" fn rust_binder_ioctl( file: *mut bindings::file, cmd: kernel::ffi::c_uint, arg: kernel::ffi::c_ulong, diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 7e34ccd394f8..1a8e6fdc0dc4 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -1323,12 +1323,12 @@ impl Thread { } BC_FREE_BUFFER => { let buffer = self.process.buffer_get(reader.read()?); - if let Some(buffer) = &buffer { + if let Some(buffer) = buffer { if buffer.looper_need_return_on_free() { self.inner.lock().looper_need_return = true; } + drop(buffer); } - drop(buffer); } BC_INCREFS => { self.process diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index a28d0511960e..b46bcb91072d 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -211,6 +211,9 @@ err: /** * binder_ctl_ioctl - handle binder device node allocation requests + * @file: The file pointer for the binder-control device node. + * @cmd: The ioctl command. + * @arg: The ioctl argument. * * The request handler for the binder-control device. All requests operate on * the binderfs mount the binder-control device resides in: diff --git a/drivers/android/tests/binder_alloc_kunit.c b/drivers/android/tests/binder_alloc_kunit.c index 9b884d977f76..7f9cc003bbe3 100644 --- a/drivers/android/tests/binder_alloc_kunit.c +++ b/drivers/android/tests/binder_alloc_kunit.c @@ -554,7 +554,7 @@ static void binder_alloc_test_exit(struct kunit *test) static struct kunit_case binder_alloc_test_cases[] = { KUNIT_CASE(binder_alloc_test_init_freelist), KUNIT_CASE(binder_alloc_test_mmap), - KUNIT_CASE(binder_alloc_exhaustive_test), + KUNIT_CASE_SLOW(binder_alloc_exhaustive_test), {} }; |
