From 01afddcac630b8c6a5f44ac5d0e508ca440e44a2 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 26 Jun 2025 10:30:54 +0300 Subject: binder: use guards for plain mutex- and spinlock-protected sections Use 'guard(mutex)' and 'guard(spinlock)' for plain (i.e. non-scoped) mutex- and spinlock-protected sections, respectively, thus making locking a bit simpler. Briefly tested with 'stress-ng --binderfs'. Signed-off-by: Dmitry Antipov Reviewed-by: Alice Ryhl Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20250626073054.7706-2-dmantipov@yandex.ru Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/android/binder_alloc.c') diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index fcfaf1b899c8..a0a7cb58fc05 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -167,12 +167,8 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked( struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, unsigned long user_ptr) { - struct binder_buffer *buffer; - - mutex_lock(&alloc->mutex); - buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); - mutex_unlock(&alloc->mutex); - return buffer; + guard(mutex)(&alloc->mutex); + return binder_alloc_prepare_to_free_locked(alloc, user_ptr); } static inline void @@ -1043,7 +1039,7 @@ void binder_alloc_print_allocated(struct seq_file *m, struct binder_buffer *buffer; struct rb_node *n; - mutex_lock(&alloc->mutex); + guard(mutex)(&alloc->mutex); for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) { buffer = rb_entry(n, struct binder_buffer, rb_node); seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n", @@ -1053,7 +1049,6 @@ void binder_alloc_print_allocated(struct seq_file *m, buffer->extra_buffers_size, buffer->transaction ? "active" : "delivered"); } - mutex_unlock(&alloc->mutex); } /** @@ -1102,10 +1097,9 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) struct rb_node *n; int count = 0; - mutex_lock(&alloc->mutex); + guard(mutex)(&alloc->mutex); for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) count++; - mutex_unlock(&alloc->mutex); return count; } -- cgit From 4328a52642993a0f64c6f9f39b93d2abea0b1a72 Mon Sep 17 00:00:00 2001 From: Tiffany Yang Date: Mon, 14 Jul 2025 11:53:15 -0700 Subject: binder: Store lru freelist in binder_alloc Store a pointer to the free pages list that the binder allocator should use for a process inside of struct binder_alloc. This change allows binder allocator code to be tested and debugged deterministically while a system is using binder; i.e., without interfering with other binder processes and independently of the shrinker. This is necessary to convert the current binder_alloc_selftest into a kunit test that does not rely on hijacking an existing binder_proc to run. A binder process's binder_alloc->freelist should not be changed after it is initialized. A sole exception is the process that runs the existing binder_alloc selftest. Its freelist can be temporarily replaced for the duration of the test because it runs as a single thread before any pages can be added to the global binder freelist, and the test frees every page it allocates before dropping the binder_selftest_lock. This exception allows the existing selftest to be used to check for regressions, but it will be dropped when the binder_alloc tests are converted to kunit in a subsequent patch in this series. Signed-off-by: Tiffany Yang Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20250714185321.2417234-3-ynaffit@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/android/binder_alloc.c') diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index a0a7cb58fc05..0476e8c2b0fb 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -26,7 +26,7 @@ #include "binder_alloc.h" #include "binder_trace.h" -struct list_lru binder_freelist; +static struct list_lru binder_freelist; static DEFINE_MUTEX(binder_alloc_mmap_lock); @@ -206,7 +206,7 @@ static void binder_lru_freelist_add(struct binder_alloc *alloc, trace_binder_free_lru_start(alloc, index); - ret = list_lru_add(&binder_freelist, + ret = list_lru_add(alloc->freelist, page_to_lru(page), page_to_nid(page), NULL); @@ -405,7 +405,7 @@ static void binder_lru_freelist_del(struct binder_alloc *alloc, if (page) { trace_binder_alloc_lru_start(alloc, index); - on_lru = list_lru_del(&binder_freelist, + on_lru = list_lru_del(alloc->freelist, page_to_lru(page), page_to_nid(page), NULL); @@ -1003,7 +1003,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) if (!page) continue; - on_lru = list_lru_del(&binder_freelist, + on_lru = list_lru_del(alloc->freelist, page_to_lru(page), page_to_nid(page), NULL); @@ -1223,6 +1223,17 @@ binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) static struct shrinker *binder_shrinker; +static void __binder_alloc_init(struct binder_alloc *alloc, + struct list_lru *freelist) +{ + alloc->pid = current->group_leader->pid; + alloc->mm = current->mm; + mmgrab(alloc->mm); + mutex_init(&alloc->mutex); + INIT_LIST_HEAD(&alloc->buffers); + alloc->freelist = freelist; +} + /** * binder_alloc_init() - called by binder_open() for per-proc initialization * @alloc: binder_alloc for this proc @@ -1232,11 +1243,7 @@ static struct shrinker *binder_shrinker; */ void binder_alloc_init(struct binder_alloc *alloc) { - alloc->pid = current->group_leader->pid; - alloc->mm = current->mm; - mmgrab(alloc->mm); - mutex_init(&alloc->mutex); - INIT_LIST_HEAD(&alloc->buffers); + __binder_alloc_init(alloc, &binder_freelist); } int binder_alloc_shrinker_init(void) -- cgit From 5e024582f494c6ff5eb2bec5183fd1eb35462500 Mon Sep 17 00:00:00 2001 From: Tiffany Yang Date: Mon, 14 Jul 2025 11:53:17 -0700 Subject: binder: Scaffolding for binder_alloc KUnit tests Add setup and teardown for testing binder allocator code with KUnit. Include minimal test cases to verify that tests are initialized correctly. Tested-by: Rae Moar Signed-off-by: Tiffany Yang Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20250714185321.2417234-5-ynaffit@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/android/binder_alloc.c') diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 0476e8c2b0fb..6351b80457c2 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "binder_alloc.h" #include "binder_trace.h" @@ -57,13 +58,14 @@ static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) return list_entry(buffer->entry.prev, struct binder_buffer, entry); } -static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, - struct binder_buffer *buffer) +VISIBLE_IF_KUNIT size_t binder_alloc_buffer_size(struct binder_alloc *alloc, + struct binder_buffer *buffer) { if (list_is_last(&buffer->entry, &alloc->buffers)) return alloc->vm_start + alloc->buffer_size - buffer->user_data; return binder_buffer_next(buffer)->user_data - buffer->user_data; } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_buffer_size); static void binder_insert_free_buffer(struct binder_alloc *alloc, struct binder_buffer *new_buffer) @@ -955,7 +957,7 @@ err_invalid_mm: failure_string, ret); return ret; } - +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_mmap_handler); void binder_alloc_deferred_release(struct binder_alloc *alloc) { @@ -1024,6 +1026,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) "%s: %d buffers %d, pages %d\n", __func__, alloc->pid, buffers, page_count); } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_deferred_release); /** * binder_alloc_print_allocated() - print buffer info @@ -1116,6 +1119,7 @@ void binder_alloc_vma_close(struct binder_alloc *alloc) { binder_alloc_set_mapped(alloc, false); } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_vma_close); /** * binder_alloc_free_page() - shrinker callback to free pages @@ -1223,8 +1227,8 @@ binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) static struct shrinker *binder_shrinker; -static void __binder_alloc_init(struct binder_alloc *alloc, - struct list_lru *freelist) +VISIBLE_IF_KUNIT void __binder_alloc_init(struct binder_alloc *alloc, + struct list_lru *freelist) { alloc->pid = current->group_leader->pid; alloc->mm = current->mm; @@ -1233,6 +1237,7 @@ static void __binder_alloc_init(struct binder_alloc *alloc, INIT_LIST_HEAD(&alloc->buffers); alloc->freelist = freelist; } +EXPORT_SYMBOL_IF_KUNIT(__binder_alloc_init); /** * binder_alloc_init() - called by binder_open() for per-proc initialization -- cgit From f6544dcdd0d2feb74f395072d8df52e3bea4be51 Mon Sep 17 00:00:00 2001 From: Tiffany Yang Date: Mon, 14 Jul 2025 11:53:18 -0700 Subject: binder: Convert binder_alloc selftests to KUnit Convert the existing binder_alloc_selftest tests into KUnit tests. These tests allocate and free an exhaustive combination of buffers with various sizes and alignments. This change allows them to be run without blocking or otherwise interfering with other processes in binder. This test is refactored into more meaningful cases in the subsequent patch. Signed-off-by: Tiffany Yang Acked-by: Carlos Llamas Link: https://lore.kernel.org/r/20250714185321.2417234-6-ynaffit@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/android/binder_alloc.c') diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 6351b80457c2..979c96b74cad 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -697,6 +697,7 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, out: return buffer; } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_new_buf); static unsigned long buffer_start_page(struct binder_buffer *buffer) { @@ -875,6 +876,7 @@ void binder_alloc_free_buf(struct binder_alloc *alloc, binder_free_buf_locked(alloc, buffer); mutex_unlock(&alloc->mutex); } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_free_buf); /** * binder_alloc_mmap_handler() - map virtual address space for proc @@ -1211,6 +1213,7 @@ err_mmap_read_lock_failed: err_mmget: return LRU_SKIP; } +EXPORT_SYMBOL_IF_KUNIT(binder_alloc_free_page); static unsigned long binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc) -- cgit