Merge android11-5.4 into android11-5.4-lts

This merges the android11-5.4 branch into the -lts branch, catching
it up with the latest changes in there.

It contains the following commits:

* 3d01868604 Merge tag 'android11-5.4.294_r00' into android11-5.4
* 45cc71553d BACKPORT: binder: Create safe versions of binder log files
* e85fa50159 UPSTREAM: binder: Refactor binder_node print synchronization

Change-Id: I1407c91e71752fcd23d93aff6b5f68a45dc11a25
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2025-06-25 09:37:48 +00:00
commit b3fbf76488
3 changed files with 153 additions and 69 deletions

View file

@ -6337,10 +6337,10 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
}
static void print_binder_work_ilocked(struct seq_file *m,
struct binder_proc *proc,
const char *prefix,
const char *transaction_prefix,
struct binder_work *w)
struct binder_proc *proc,
const char *prefix,
const char *transaction_prefix,
struct binder_work *w, bool hash_ptrs)
{
struct binder_node *node;
struct binder_transaction *t;
@ -6363,9 +6363,15 @@ static void print_binder_work_ilocked(struct seq_file *m,
break;
case BINDER_WORK_NODE:
node = container_of(w, struct binder_node, work);
seq_printf(m, "%snode work %d: u%016llx c%016llx\n",
prefix, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
if (hash_ptrs)
seq_printf(m, "%snode work %d: u%p c%p\n",
prefix, node->debug_id,
(void *)(long)node->ptr,
(void *)(long)node->cookie);
else
seq_printf(m, "%snode work %d: u%016llx c%016llx\n",
prefix, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
break;
case BINDER_WORK_DEAD_BINDER:
seq_printf(m, "%shas dead binder\n", prefix);
@ -6390,7 +6396,7 @@ static void print_binder_work_ilocked(struct seq_file *m,
static void print_binder_thread_ilocked(struct seq_file *m,
struct binder_thread *thread,
int print_always)
bool print_always, bool hash_ptrs)
{
struct binder_transaction *t;
struct binder_work *w;
@ -6420,14 +6426,16 @@ static void print_binder_thread_ilocked(struct seq_file *m,
}
list_for_each_entry(w, &thread->todo, entry) {
print_binder_work_ilocked(m, thread->proc, " ",
" pending transaction", w);
" pending transaction",
w, hash_ptrs);
}
if (!print_always && m->count == header_pos)
m->count = start_pos;
}
static void print_binder_node_nilocked(struct seq_file *m,
struct binder_node *node)
struct binder_node *node,
bool hash_ptrs)
{
struct binder_ref *ref;
struct binder_work *w;
@ -6437,8 +6445,13 @@ static void print_binder_node_nilocked(struct seq_file *m,
hlist_for_each_entry(ref, &node->refs, node_entry)
count++;
seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d",
node->debug_id, (u64)node->ptr, (u64)node->cookie,
if (hash_ptrs)
seq_printf(m, " node %d: u%p c%p", node->debug_id,
(void *)(long)node->ptr, (void *)(long)node->cookie);
else
seq_printf(m, " node %d: u%016llx c%016llx", node->debug_id,
(u64)node->ptr, (u64)node->cookie);
seq_printf(m, " pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d",
node->sched_policy, node->min_priority,
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
@ -6452,7 +6465,8 @@ static void print_binder_node_nilocked(struct seq_file *m,
if (node->proc) {
list_for_each_entry(w, &node->async_todo, entry)
print_binder_work_ilocked(m, node->proc, " ",
" pending async transaction", w);
" pending async transaction",
w, hash_ptrs);
}
}
@ -6468,8 +6482,54 @@ static void print_binder_ref_olocked(struct seq_file *m,
binder_node_unlock(ref->node);
}
static void print_binder_proc(struct seq_file *m,
struct binder_proc *proc, int print_all)
/**
* print_next_binder_node_ilocked() - Print binder_node from a locked list
* @m: struct seq_file for output via seq_printf()
* @proc: struct binder_proc we hold the inner_proc_lock to (if any)
* @node: struct binder_node to print fields of
* @prev_node: struct binder_node we hold a temporary reference to (if any)
* @hash_ptrs: whether to hash @node's binder_uintptr_t fields
*
* Helper function to handle synchronization around printing a struct
* binder_node while iterating through @proc->nodes or the dead nodes list.
* Caller must hold either @proc->inner_lock (for live nodes) or
* binder_dead_nodes_lock. This lock will be released during the body of this
* function, but it will be reacquired before returning to the caller.
*
* Return: pointer to the struct binder_node we hold a tmpref on
*/
static struct binder_node *
print_next_binder_node_ilocked(struct seq_file *m, struct binder_proc *proc,
struct binder_node *node,
struct binder_node *prev_node, bool hash_ptrs)
{
/*
* Take a temporary reference on the node so that isn't freed while
* we print it.
*/
binder_inc_node_tmpref_ilocked(node);
/*
* Live nodes need to drop the inner proc lock and dead nodes need to
* drop the binder_dead_nodes_lock before trying to take the node lock.
*/
if (proc)
binder_inner_proc_unlock(proc);
else
spin_unlock(&binder_dead_nodes_lock);
if (prev_node)
binder_put_node(prev_node);
binder_node_inner_lock(node);
print_binder_node_nilocked(m, node, hash_ptrs);
binder_node_inner_unlock(node);
if (proc)
binder_inner_proc_lock(proc);
else
spin_lock(&binder_dead_nodes_lock);
return node;
}
static void print_binder_proc(struct seq_file *m, struct binder_proc *proc,
bool print_all, bool hash_ptrs)
{
struct binder_work *w;
struct rb_node *n;
@ -6482,31 +6542,19 @@ static void print_binder_proc(struct seq_file *m,
header_pos = m->count;
binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
for (n = rb_first(&proc->threads); n; n = rb_next(n))
print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread,
rb_node), print_all);
rb_node), print_all, hash_ptrs);
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
for (n = rb_first(&proc->nodes); n; n = rb_next(n)) {
struct binder_node *node = rb_entry(n, struct binder_node,
rb_node);
if (!print_all && !node->has_async_transaction)
continue;
/*
* take a temporary reference on the node so it
* survives and isn't removed from the tree
* while we print it.
*/
binder_inc_node_tmpref_ilocked(node);
/* Need to drop inner lock to take node lock */
binder_inner_proc_unlock(proc);
if (last_node)
binder_put_node(last_node);
binder_node_inner_lock(node);
print_binder_node_nilocked(m, node);
binder_node_inner_unlock(node);
last_node = node;
binder_inner_proc_lock(proc);
last_node = print_next_binder_node_ilocked(m, proc, node,
last_node,
hash_ptrs);
}
binder_inner_proc_unlock(proc);
if (last_node)
@ -6514,19 +6562,18 @@ static void print_binder_proc(struct seq_file *m,
if (print_all) {
binder_proc_lock(proc);
for (n = rb_first(&proc->refs_by_desc);
n != NULL;
n = rb_next(n))
for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n))
print_binder_ref_olocked(m, rb_entry(n,
struct binder_ref,
rb_node_desc));
struct binder_ref,
rb_node_desc));
binder_proc_unlock(proc);
}
binder_alloc_print_allocated(m, &proc->alloc);
binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry)
print_binder_work_ilocked(m, proc, " ",
" pending transaction", w);
" pending transaction", w,
hash_ptrs);
list_for_each_entry(w, &proc->delivered_death, entry) {
seq_puts(m, " has delivered dead binder\n");
break;
@ -6652,7 +6699,7 @@ static void print_binder_proc_stats(struct seq_file *m,
count = 0;
ready_threads = 0;
binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
for (n = rb_first(&proc->threads); n; n = rb_next(n))
count++;
list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node)
@ -6666,7 +6713,7 @@ static void print_binder_proc_stats(struct seq_file *m,
ready_threads,
free_async_space);
count = 0;
for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
for (n = rb_first(&proc->nodes); n; n = rb_next(n))
count++;
binder_inner_proc_unlock(proc);
seq_printf(m, " nodes: %d\n", count);
@ -6674,7 +6721,7 @@ static void print_binder_proc_stats(struct seq_file *m,
strong = 0;
weak = 0;
binder_proc_lock(proc);
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) {
struct binder_ref *ref = rb_entry(n, struct binder_ref,
rb_node_desc);
count++;
@ -6701,8 +6748,7 @@ static void print_binder_proc_stats(struct seq_file *m,
print_binder_stats(m, " ", &proc->stats);
}
int binder_state_show(struct seq_file *m, void *unused)
static void print_binder_state(struct seq_file *m, bool hash_ptrs)
{
struct binder_proc *proc;
struct binder_node *node;
@ -6713,31 +6759,40 @@ int binder_state_show(struct seq_file *m, void *unused)
spin_lock(&binder_dead_nodes_lock);
if (!hlist_empty(&binder_dead_nodes))
seq_puts(m, "dead nodes:\n");
hlist_for_each_entry(node, &binder_dead_nodes, dead_node) {
/*
* take a temporary reference on the node so it
* survives and isn't removed from the list
* while we print it.
*/
node->tmp_refs++;
spin_unlock(&binder_dead_nodes_lock);
if (last_node)
binder_put_node(last_node);
binder_node_lock(node);
print_binder_node_nilocked(m, node);
binder_node_unlock(node);
last_node = node;
spin_lock(&binder_dead_nodes_lock);
}
hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
last_node = print_next_binder_node_ilocked(m, NULL, node,
last_node,
hash_ptrs);
spin_unlock(&binder_dead_nodes_lock);
if (last_node)
binder_put_node(last_node);
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc(m, proc, 1);
print_binder_proc(m, proc, true, hash_ptrs);
mutex_unlock(&binder_procs_lock);
}
static void print_binder_transactions(struct seq_file *m, bool hash_ptrs)
{
struct binder_proc *proc;
seq_puts(m, "binder transactions:\n");
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc(m, proc, false, hash_ptrs);
mutex_unlock(&binder_procs_lock);
}
int binder_state_show(struct seq_file *m, void *unused)
{
print_binder_state(m, false);
return 0;
}
int binder_state_hashed_show(struct seq_file *m, void *unused)
{
print_binder_state(m, true);
return 0;
}
@ -6759,14 +6814,13 @@ int binder_stats_show(struct seq_file *m, void *unused)
int binder_transactions_show(struct seq_file *m, void *unused)
{
struct binder_proc *proc;
seq_puts(m, "binder transactions:\n");
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
print_binder_proc(m, proc, 0);
mutex_unlock(&binder_procs_lock);
print_binder_transactions(m, false);
return 0;
}
int binder_transactions_hashed_show(struct seq_file *m, void *unused)
{
print_binder_transactions(m, true);
return 0;
}
@ -6779,7 +6833,7 @@ static int proc_show(struct seq_file *m, void *unused)
hlist_for_each_entry(itr, &binder_procs, proc_node) {
if (itr->pid == pid) {
seq_puts(m, "binder proc state:\n");
print_binder_proc(m, itr, 1);
print_binder_proc(m, itr, true, false);
}
}
mutex_unlock(&binder_procs_lock);
@ -6900,6 +6954,11 @@ static int __init binder_init(void)
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("state_hashed",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_hashed_fops);
debugfs_create_file("stats",
0444,
binder_debugfs_dir_entry_root,
@ -6910,6 +6969,11 @@ static int __init binder_init(void)
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transactions_hashed",
0444,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_hashed_fops);
debugfs_create_file("transaction_log",
0444,
binder_debugfs_dir_entry_root,

View file

@ -113,9 +113,15 @@ DEFINE_SHOW_ATTRIBUTE(binder_stats);
int binder_state_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_state);
int binder_state_hashed_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_state_hashed);
int binder_transactions_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transactions);
int binder_transactions_hashed_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transactions_hashed);
int binder_transaction_log_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transaction_log);

View file

@ -659,6 +659,13 @@ static int init_binder_logs(struct super_block *sb)
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, "state_hashed",
&binder_state_hashed_fops, NULL);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, "transactions",
&binder_transactions_fops, NULL);
if (IS_ERR(dentry)) {
@ -666,6 +673,13 @@ static int init_binder_logs(struct super_block *sb)
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir, "transactions_hashed",
&binder_transactions_hashed_fops, NULL);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto out;
}
dentry = binderfs_create_file(binder_logs_root_dir,
"transaction_log",
&binder_transaction_log_fops,