mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 15:22:21 -04:00
rust_binder: avoid destructors in insert_or_update_handle()
The insert_or_update_handle() function currently has two places where it drops objects under the node_refs lock. In preparation for changing node_refs into a spinlock, update the code to either entirely remove the codepath or drop the node_refs lock first before running the destructor. This also has the side-benefit that we avoid traversing the by_node rbtree twice. Currently it's first traversed to see if the new node is present, and then traversed again to insert it. By saving the VacantEntry from the first lookup, we can perform the insertion without traversing the tree again. Reviewed-by: Matthew Maurer <mmaurer@google.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://patch.msgid.link/20260615-binder-noderefs-spin-v3-5-3235f5a3e0a0@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2812b20e16
commit
63b4af40e2
@@ -861,14 +861,17 @@ pub(crate) fn insert_or_update_handle(
|
||||
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()) {
|
||||
let handle = *handle_ref;
|
||||
let info = refs.by_handle.get_mut(&handle).unwrap();
|
||||
info.node_ref().absorb(node_ref);
|
||||
return Ok(handle);
|
||||
}
|
||||
let by_node_slot = match refs.by_node.entry(node_ref.node.global_id()) {
|
||||
rbtree::Entry::Vacant(by_node_slot) => by_node_slot,
|
||||
rbtree::Entry::Occupied(handle_ref) => {
|
||||
// The node was inserted by another thread while we didn't hold the lock.
|
||||
let handle = handle_ref.get();
|
||||
let info = refs.by_handle.get_mut(handle).unwrap();
|
||||
info.node_ref().absorb(node_ref);
|
||||
return Ok(*handle);
|
||||
}
|
||||
};
|
||||
|
||||
let gid = node_ref.node.global_id();
|
||||
let (info_proc, info_node) = {
|
||||
let info_init = NodeRefInfo::new(node_ref, handle, self.into());
|
||||
match info.pin_init_with(info_init) {
|
||||
@@ -884,6 +887,9 @@ pub(crate) fn insert_or_update_handle(
|
||||
// first thing in `deferred_release`, process cleanup will not miss the items inserted into
|
||||
// `refs` below.
|
||||
if self.inner.lock().is_dead {
|
||||
// Explicitly drop the lock so that `info_proc` and `info_node` are dropped outside of
|
||||
// the lock.
|
||||
drop(refs_lock);
|
||||
return Err(ESRCH);
|
||||
}
|
||||
|
||||
@@ -891,7 +897,7 @@ pub(crate) fn insert_or_update_handle(
|
||||
// `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, handle));
|
||||
by_node_slot.insert(handle, reserve1);
|
||||
by_handle_slot.insert(info_proc, reserve2);
|
||||
unused_id.acquire();
|
||||
Ok(handle)
|
||||
|
||||
Reference in New Issue
Block a user