Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Tiffany Y. Yang and committed by
Greg Kroah-Hartman
91f1bbaa 8c0a5598

+68 -51
+68 -51
drivers/android/binder.c
··· 6374 6374 } 6375 6375 6376 6376 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) 6381 6381 { 6382 6382 struct binder_node *node; 6383 6383 struct binder_transaction *t; ··· 6427 6427 6428 6428 static void print_binder_thread_ilocked(struct seq_file *m, 6429 6429 struct binder_thread *thread, 6430 - int print_always) 6430 + bool print_always) 6431 6431 { 6432 6432 struct binder_transaction *t; 6433 6433 struct binder_work *w; ··· 6502 6502 binder_node_unlock(ref->node); 6503 6503 } 6504 6504 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) 6507 6552 { 6508 6553 struct binder_work *w; 6509 6554 struct rb_node *n; ··· 6561 6516 header_pos = m->count; 6562 6517 6563 6518 binder_inner_proc_lock(proc); 6564 - for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) 6519 + for (n = rb_first(&proc->threads); n; n = rb_next(n)) 6565 6520 print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, 6566 6521 rb_node), print_all); 6567 6522 6568 - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { 6523 + for (n = rb_first(&proc->nodes); n; n = rb_next(n)) { 6569 6524 struct binder_node *node = rb_entry(n, struct binder_node, 6570 6525 rb_node); 6571 6526 if (!print_all && !node->has_async_transaction) 6572 6527 continue; 6573 6528 6574 - /* 6575 - * take a temporary reference on the node so it 6576 - * survives and isn't removed from the tree 6577 - * while we print it. 6578 - */ 6579 - binder_inc_node_tmpref_ilocked(node); 6580 - /* Need to drop inner lock to take node lock */ 6581 - binder_inner_proc_unlock(proc); 6582 - if (last_node) 6583 - binder_put_node(last_node); 6584 - binder_node_inner_lock(node); 6585 - print_binder_node_nilocked(m, node); 6586 - binder_node_inner_unlock(node); 6587 - last_node = node; 6588 - binder_inner_proc_lock(proc); 6529 + last_node = print_next_binder_node_ilocked(m, proc, node, 6530 + last_node); 6589 6531 } 6590 6532 binder_inner_proc_unlock(proc); 6591 6533 if (last_node) ··· 6580 6548 6581 6549 if (print_all) { 6582 6550 binder_proc_lock(proc); 6583 - for (n = rb_first(&proc->refs_by_desc); 6584 - n != NULL; 6585 - n = rb_next(n)) 6551 + for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) 6586 6552 print_binder_ref_olocked(m, rb_entry(n, 6587 - struct binder_ref, 6588 - rb_node_desc)); 6553 + struct binder_ref, 6554 + rb_node_desc)); 6589 6555 binder_proc_unlock(proc); 6590 6556 } 6591 6557 binder_alloc_print_allocated(m, &proc->alloc); ··· 6723 6693 count = 0; 6724 6694 ready_threads = 0; 6725 6695 binder_inner_proc_lock(proc); 6726 - for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) 6696 + for (n = rb_first(&proc->threads); n; n = rb_next(n)) 6727 6697 count++; 6728 6698 6729 6699 list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) ··· 6737 6707 ready_threads, 6738 6708 free_async_space); 6739 6709 count = 0; 6740 - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) 6710 + for (n = rb_first(&proc->nodes); n; n = rb_next(n)) 6741 6711 count++; 6742 6712 binder_inner_proc_unlock(proc); 6743 6713 seq_printf(m, " nodes: %d\n", count); ··· 6745 6715 strong = 0; 6746 6716 weak = 0; 6747 6717 binder_proc_lock(proc); 6748 - for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { 6718 + for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) { 6749 6719 struct binder_ref *ref = rb_entry(n, struct binder_ref, 6750 6720 rb_node_desc); 6751 6721 count++; ··· 6783 6753 spin_lock(&binder_dead_nodes_lock); 6784 6754 if (!hlist_empty(&binder_dead_nodes)) 6785 6755 seq_puts(m, "dead nodes:\n"); 6786 - hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { 6787 - /* 6788 - * take a temporary reference on the node so it 6789 - * survives and isn't removed from the list 6790 - * while we print it. 6791 - */ 6792 - node->tmp_refs++; 6793 - spin_unlock(&binder_dead_nodes_lock); 6794 - if (last_node) 6795 - binder_put_node(last_node); 6796 - binder_node_lock(node); 6797 - print_binder_node_nilocked(m, node); 6798 - binder_node_unlock(node); 6799 - last_node = node; 6800 - spin_lock(&binder_dead_nodes_lock); 6801 - } 6756 + hlist_for_each_entry(node, &binder_dead_nodes, dead_node) 6757 + last_node = print_next_binder_node_ilocked(m, NULL, node, 6758 + last_node); 6802 6759 spin_unlock(&binder_dead_nodes_lock); 6803 6760 if (last_node) 6804 6761 binder_put_node(last_node); 6805 6762 6806 6763 mutex_lock(&binder_procs_lock); 6807 6764 hlist_for_each_entry(proc, &binder_procs, proc_node) 6808 - print_binder_proc(m, proc, 1); 6765 + print_binder_proc(m, proc, true); 6809 6766 mutex_unlock(&binder_procs_lock); 6810 6767 6811 6768 return 0; ··· 6821 6804 seq_puts(m, "binder transactions:\n"); 6822 6805 mutex_lock(&binder_procs_lock); 6823 6806 hlist_for_each_entry(proc, &binder_procs, proc_node) 6824 - print_binder_proc(m, proc, 0); 6807 + print_binder_proc(m, proc, false); 6825 6808 mutex_unlock(&binder_procs_lock); 6826 6809 6827 6810 return 0; ··· 6836 6819 hlist_for_each_entry(itr, &binder_procs, proc_node) { 6837 6820 if (itr->pid == pid) { 6838 6821 seq_puts(m, "binder proc state:\n"); 6839 - print_binder_proc(m, itr, 1); 6822 + print_binder_proc(m, itr, true); 6840 6823 } 6841 6824 } 6842 6825 mutex_unlock(&binder_procs_lock);