Skip to content

Commit 91f1bba

Browse files
ynaffitgnaygregkh
authored andcommitted
binder: Refactor binder_node print synchronization
The binder driver outputs information about each dead binder node by iterating over the dead nodes list, and it prints the state of each live node in the system by traversing each binder_proc's proc->nodes tree. Both cases require similar logic to maintain the global lock ordering while accessing each node. Create a helper function to synchronize around printing binder nodes in a list. Opportunistically make minor cosmetic changes to binder print functions. Acked-by: Carlos Llamas <cmllamas@google.com> Signed-off-by: "Tiffany Y. Yang" <ynaffit@google.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20250510013435.1520671-5-ynaffit@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8c0a559 commit 91f1bba

1 file changed

Lines changed: 68 additions & 51 deletions

File tree

drivers/android/binder.c

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6374,10 +6374,10 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
63746374
}
63756375

63766376
static void print_binder_work_ilocked(struct seq_file *m,
6377-
struct binder_proc *proc,
6378-
const char *prefix,
6379-
const char *transaction_prefix,
6380-
struct binder_work *w)
6377+
struct binder_proc *proc,
6378+
const char *prefix,
6379+
const char *transaction_prefix,
6380+
struct binder_work *w)
63816381
{
63826382
struct binder_node *node;
63836383
struct binder_transaction *t;
@@ -6427,7 +6427,7 @@ static void print_binder_work_ilocked(struct seq_file *m,
64276427

64286428
static void print_binder_thread_ilocked(struct seq_file *m,
64296429
struct binder_thread *thread,
6430-
int print_always)
6430+
bool print_always)
64316431
{
64326432
struct binder_transaction *t;
64336433
struct binder_work *w;
@@ -6502,8 +6502,53 @@ static void print_binder_ref_olocked(struct seq_file *m,
65026502
binder_node_unlock(ref->node);
65036503
}
65046504

6505-
static void print_binder_proc(struct seq_file *m,
6506-
struct binder_proc *proc, int print_all)
6505+
/**
6506+
* print_next_binder_node_ilocked() - Print binder_node from a locked list
6507+
* @m: struct seq_file for output via seq_printf()
6508+
* @proc: struct binder_proc we hold the inner_proc_lock to (if any)
6509+
* @node: struct binder_node to print fields of
6510+
* @prev_node: struct binder_node we hold a temporary reference to (if any)
6511+
*
6512+
* Helper function to handle synchronization around printing a struct
6513+
* binder_node while iterating through @proc->nodes or the dead nodes list.
6514+
* Caller must hold either @proc->inner_lock (for live nodes) or
6515+
* binder_dead_nodes_lock. This lock will be released during the body of this
6516+
* function, but it will be reacquired before returning to the caller.
6517+
*
6518+
* Return: pointer to the struct binder_node we hold a tmpref on
6519+
*/
6520+
static struct binder_node *
6521+
print_next_binder_node_ilocked(struct seq_file *m, struct binder_proc *proc,
6522+
struct binder_node *node,
6523+
struct binder_node *prev_node)
6524+
{
6525+
/*
6526+
* Take a temporary reference on the node so that isn't freed while
6527+
* we print it.
6528+
*/
6529+
binder_inc_node_tmpref_ilocked(node);
6530+
/*
6531+
* Live nodes need to drop the inner proc lock and dead nodes need to
6532+
* drop the binder_dead_nodes_lock before trying to take the node lock.
6533+
*/
6534+
if (proc)
6535+
binder_inner_proc_unlock(proc);
6536+
else
6537+
spin_unlock(&binder_dead_nodes_lock);
6538+
if (prev_node)
6539+
binder_put_node(prev_node);
6540+
binder_node_inner_lock(node);
6541+
print_binder_node_nilocked(m, node);
6542+
binder_node_inner_unlock(node);
6543+
if (proc)
6544+
binder_inner_proc_lock(proc);
6545+
else
6546+
spin_lock(&binder_dead_nodes_lock);
6547+
return node;
6548+
}
6549+
6550+
static void print_binder_proc(struct seq_file *m, struct binder_proc *proc,
6551+
bool print_all)
65076552
{
65086553
struct binder_work *w;
65096554
struct rb_node *n;
@@ -6516,44 +6561,29 @@ static void print_binder_proc(struct seq_file *m,
65166561
header_pos = m->count;
65176562

65186563
binder_inner_proc_lock(proc);
6519-
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
6564+
for (n = rb_first(&proc->threads); n; n = rb_next(n))
65206565
print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread,
65216566
rb_node), print_all);
65226567

6523-
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
6568+
for (n = rb_first(&proc->nodes); n; n = rb_next(n)) {
65246569
struct binder_node *node = rb_entry(n, struct binder_node,
65256570
rb_node);
65266571
if (!print_all && !node->has_async_transaction)
65276572
continue;
65286573

6529-
/*
6530-
* take a temporary reference on the node so it
6531-
* survives and isn't removed from the tree
6532-
* while we print it.
6533-
*/
6534-
binder_inc_node_tmpref_ilocked(node);
6535-
/* Need to drop inner lock to take node lock */
6536-
binder_inner_proc_unlock(proc);
6537-
if (last_node)
6538-
binder_put_node(last_node);
6539-
binder_node_inner_lock(node);
6540-
print_binder_node_nilocked(m, node);
6541-
binder_node_inner_unlock(node);
6542-
last_node = node;
6543-
binder_inner_proc_lock(proc);
6574+
last_node = print_next_binder_node_ilocked(m, proc, node,
6575+
last_node);
65446576
}
65456577
binder_inner_proc_unlock(proc);
65466578
if (last_node)
65476579
binder_put_node(last_node);
65486580

65496581
if (print_all) {
65506582
binder_proc_lock(proc);
6551-
for (n = rb_first(&proc->refs_by_desc);
6552-
n != NULL;
6553-
n = rb_next(n))
6583+
for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n))
65546584
print_binder_ref_olocked(m, rb_entry(n,
6555-
struct binder_ref,
6556-
rb_node_desc));
6585+
struct binder_ref,
6586+
rb_node_desc));
65576587
binder_proc_unlock(proc);
65586588
}
65596589
binder_alloc_print_allocated(m, &proc->alloc);
@@ -6693,7 +6723,7 @@ static void print_binder_proc_stats(struct seq_file *m,
66936723
count = 0;
66946724
ready_threads = 0;
66956725
binder_inner_proc_lock(proc);
6696-
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
6726+
for (n = rb_first(&proc->threads); n; n = rb_next(n))
66976727
count++;
66986728

66996729
list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node)
@@ -6707,15 +6737,15 @@ static void print_binder_proc_stats(struct seq_file *m,
67076737
ready_threads,
67086738
free_async_space);
67096739
count = 0;
6710-
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
6740+
for (n = rb_first(&proc->nodes); n; n = rb_next(n))
67116741
count++;
67126742
binder_inner_proc_unlock(proc);
67136743
seq_printf(m, " nodes: %d\n", count);
67146744
count = 0;
67156745
strong = 0;
67166746
weak = 0;
67176747
binder_proc_lock(proc);
6718-
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
6748+
for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) {
67196749
struct binder_ref *ref = rb_entry(n, struct binder_ref,
67206750
rb_node_desc);
67216751
count++;
@@ -6753,29 +6783,16 @@ static int state_show(struct seq_file *m, void *unused)
67536783
spin_lock(&binder_dead_nodes_lock);
67546784
if (!hlist_empty(&binder_dead_nodes))
67556785
seq_puts(m, "dead nodes:\n");
6756-
hlist_for_each_entry(node, &binder_dead_nodes, dead_node) {
6757-
/*
6758-
* take a temporary reference on the node so it
6759-
* survives and isn't removed from the list
6760-
* while we print it.
6761-
*/
6762-
node->tmp_refs++;
6763-
spin_unlock(&binder_dead_nodes_lock);
6764-
if (last_node)
6765-
binder_put_node(last_node);
6766-
binder_node_lock(node);
6767-
print_binder_node_nilocked(m, node);
6768-
binder_node_unlock(node);
6769-
last_node = node;
6770-
spin_lock(&binder_dead_nodes_lock);
6771-
}
6786+
hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
6787+
last_node = print_next_binder_node_ilocked(m, NULL, node,
6788+
last_node);
67726789
spin_unlock(&binder_dead_nodes_lock);
67736790
if (last_node)
67746791
binder_put_node(last_node);
67756792

67766793
mutex_lock(&binder_procs_lock);
67776794
hlist_for_each_entry(proc, &binder_procs, proc_node)
6778-
print_binder_proc(m, proc, 1);
6795+
print_binder_proc(m, proc, true);
67796796
mutex_unlock(&binder_procs_lock);
67806797

67816798
return 0;
@@ -6804,7 +6821,7 @@ static int transactions_show(struct seq_file *m, void *unused)
68046821
seq_puts(m, "binder transactions:\n");
68056822
mutex_lock(&binder_procs_lock);
68066823
hlist_for_each_entry(proc, &binder_procs, proc_node)
6807-
print_binder_proc(m, proc, 0);
6824+
print_binder_proc(m, proc, false);
68086825
mutex_unlock(&binder_procs_lock);
68096826

68106827
return 0;
@@ -6819,7 +6836,7 @@ static int proc_show(struct seq_file *m, void *unused)
68196836
hlist_for_each_entry(itr, &binder_procs, proc_node) {
68206837
if (itr->pid == pid) {
68216838
seq_puts(m, "binder proc state:\n");
6822-
print_binder_proc(m, itr, 1);
6839+
print_binder_proc(m, itr, true);
68236840
}
68246841
}
68256842
mutex_unlock(&binder_procs_lock);

0 commit comments

Comments
 (0)