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

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 <rmoar@google.com>
Signed-off-by: Tiffany Yang <ynaffit@google.com>
Acked-by: Carlos Llamas <cmllamas@google.com>
Link: https://lore.kernel.org/r/20250714185321.2417234-5-ynaffit@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tiffany Yang and committed by
Greg Kroah-Hartman
5e024582 bdfa89c4

+208 -6
+11
drivers/android/Kconfig
··· 47 47 exhaustively with combinations of various buffer sizes and 48 48 alignments. 49 49 50 + config ANDROID_BINDER_ALLOC_KUNIT_TEST 51 + tristate "KUnit Tests for Android Binder Alloc" if !KUNIT_ALL_TESTS 52 + depends on ANDROID_BINDER_IPC && KUNIT 53 + default KUNIT_ALL_TESTS 54 + help 55 + This feature builds the binder alloc KUnit tests. 56 + 57 + Each test case runs using a pared-down binder_alloc struct and 58 + test-specific freelist, which allows this KUnit module to be loaded 59 + for testing without interfering with a running system. 60 + 50 61 endmenu
+1
drivers/android/Makefile
··· 4 4 obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o 5 5 obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o 6 6 obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o 7 + obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
+4 -1
drivers/android/binder.c
··· 68 68 #include <linux/sizes.h> 69 69 #include <linux/ktime.h> 70 70 71 + #include <kunit/visibility.h> 72 + 71 73 #include <uapi/linux/android/binder.h> 72 74 73 75 #include <linux/cacheflush.h> ··· 5949 5947 binder_alloc_vma_close(&proc->alloc); 5950 5948 } 5951 5949 5952 - static vm_fault_t binder_vm_fault(struct vm_fault *vmf) 5950 + VISIBLE_IF_KUNIT vm_fault_t binder_vm_fault(struct vm_fault *vmf) 5953 5951 { 5954 5952 return VM_FAULT_SIGBUS; 5955 5953 } 5954 + EXPORT_SYMBOL_IF_KUNIT(binder_vm_fault); 5956 5955 5957 5956 static const struct vm_operations_struct binder_vm_ops = { 5958 5957 .open = binder_vma_open,
+10 -5
drivers/android/binder_alloc.c
··· 23 23 #include <linux/uaccess.h> 24 24 #include <linux/highmem.h> 25 25 #include <linux/sizes.h> 26 + #include <kunit/visibility.h> 26 27 #include "binder_alloc.h" 27 28 #include "binder_trace.h" 28 29 ··· 58 57 return list_entry(buffer->entry.prev, struct binder_buffer, entry); 59 58 } 60 59 61 - static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, 62 - struct binder_buffer *buffer) 60 + VISIBLE_IF_KUNIT size_t binder_alloc_buffer_size(struct binder_alloc *alloc, 61 + struct binder_buffer *buffer) 63 62 { 64 63 if (list_is_last(&buffer->entry, &alloc->buffers)) 65 64 return alloc->vm_start + alloc->buffer_size - buffer->user_data; 66 65 return binder_buffer_next(buffer)->user_data - buffer->user_data; 67 66 } 67 + EXPORT_SYMBOL_IF_KUNIT(binder_alloc_buffer_size); 68 68 69 69 static void binder_insert_free_buffer(struct binder_alloc *alloc, 70 70 struct binder_buffer *new_buffer) ··· 957 955 failure_string, ret); 958 956 return ret; 959 957 } 960 - 958 + EXPORT_SYMBOL_IF_KUNIT(binder_alloc_mmap_handler); 961 959 962 960 void binder_alloc_deferred_release(struct binder_alloc *alloc) 963 961 { ··· 1026 1024 "%s: %d buffers %d, pages %d\n", 1027 1025 __func__, alloc->pid, buffers, page_count); 1028 1026 } 1027 + EXPORT_SYMBOL_IF_KUNIT(binder_alloc_deferred_release); 1029 1028 1030 1029 /** 1031 1030 * binder_alloc_print_allocated() - print buffer info ··· 1119 1116 { 1120 1117 binder_alloc_set_mapped(alloc, false); 1121 1118 } 1119 + EXPORT_SYMBOL_IF_KUNIT(binder_alloc_vma_close); 1122 1120 1123 1121 /** 1124 1122 * binder_alloc_free_page() - shrinker callback to free pages ··· 1227 1223 1228 1224 static struct shrinker *binder_shrinker; 1229 1225 1230 - static void __binder_alloc_init(struct binder_alloc *alloc, 1231 - struct list_lru *freelist) 1226 + VISIBLE_IF_KUNIT void __binder_alloc_init(struct binder_alloc *alloc, 1227 + struct list_lru *freelist) 1232 1228 { 1233 1229 alloc->pid = current->group_leader->pid; 1234 1230 alloc->mm = current->mm; ··· 1237 1233 INIT_LIST_HEAD(&alloc->buffers); 1238 1234 alloc->freelist = freelist; 1239 1235 } 1236 + EXPORT_SYMBOL_IF_KUNIT(__binder_alloc_init); 1240 1237 1241 1238 /** 1242 1239 * binder_alloc_init() - called by binder_open() for per-proc initialization
+6
drivers/android/binder_alloc.h
··· 184 184 binder_size_t buffer_offset, 185 185 size_t bytes); 186 186 187 + #if IS_ENABLED(CONFIG_KUNIT) 188 + void __binder_alloc_init(struct binder_alloc *alloc, struct list_lru *freelist); 189 + size_t binder_alloc_buffer_size(struct binder_alloc *alloc, 190 + struct binder_buffer *buffer); 191 + #endif 192 + 187 193 #endif /* _LINUX_BINDER_ALLOC_H */ 188 194
+4
drivers/android/binder_internal.h
··· 592 592 */ 593 593 void binder_remove_device(struct binder_device *device); 594 594 595 + #if IS_ENABLED(CONFIG_KUNIT) 596 + vm_fault_t binder_vm_fault(struct vm_fault *vmf); 597 + #endif 598 + 595 599 #endif /* _LINUX_BINDER_INTERNAL_H */
+3
drivers/android/tests/.kunitconfig
··· 1 + CONFIG_KUNIT=y 2 + CONFIG_ANDROID_BINDER_IPC=y 3 + CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST=y
+3
drivers/android/tests/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += binder_alloc_kunit.o
+166
drivers/android/tests/binder_alloc_kunit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Test cases for binder allocator code 4 + */ 5 + 6 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 + 8 + #include <kunit/test.h> 9 + #include <linux/anon_inodes.h> 10 + #include <linux/err.h> 11 + #include <linux/file.h> 12 + #include <linux/fs.h> 13 + #include <linux/mm.h> 14 + #include <linux/mman.h> 15 + #include <linux/sizes.h> 16 + 17 + #include "../binder_alloc.h" 18 + #include "../binder_internal.h" 19 + 20 + MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 21 + 22 + #define BINDER_MMAP_SIZE SZ_128K 23 + 24 + struct binder_alloc_test { 25 + struct binder_alloc alloc; 26 + struct list_lru binder_test_freelist; 27 + struct file *filp; 28 + unsigned long mmap_uaddr; 29 + }; 30 + 31 + static void binder_alloc_test_init_freelist(struct kunit *test) 32 + { 33 + struct binder_alloc_test *priv = test->priv; 34 + 35 + KUNIT_EXPECT_PTR_EQ(test, priv->alloc.freelist, 36 + &priv->binder_test_freelist); 37 + } 38 + 39 + static void binder_alloc_test_mmap(struct kunit *test) 40 + { 41 + struct binder_alloc_test *priv = test->priv; 42 + struct binder_alloc *alloc = &priv->alloc; 43 + struct binder_buffer *buf; 44 + struct rb_node *n; 45 + 46 + KUNIT_EXPECT_EQ(test, alloc->mapped, true); 47 + KUNIT_EXPECT_EQ(test, alloc->buffer_size, BINDER_MMAP_SIZE); 48 + 49 + n = rb_first(&alloc->allocated_buffers); 50 + KUNIT_EXPECT_PTR_EQ(test, n, NULL); 51 + 52 + n = rb_first(&alloc->free_buffers); 53 + buf = rb_entry(n, struct binder_buffer, rb_node); 54 + KUNIT_EXPECT_EQ(test, binder_alloc_buffer_size(alloc, buf), 55 + BINDER_MMAP_SIZE); 56 + KUNIT_EXPECT_TRUE(test, list_is_last(&buf->entry, &alloc->buffers)); 57 + } 58 + 59 + /* ===== End test cases ===== */ 60 + 61 + static void binder_alloc_test_vma_close(struct vm_area_struct *vma) 62 + { 63 + struct binder_alloc *alloc = vma->vm_private_data; 64 + 65 + binder_alloc_vma_close(alloc); 66 + } 67 + 68 + static const struct vm_operations_struct binder_alloc_test_vm_ops = { 69 + .close = binder_alloc_test_vma_close, 70 + .fault = binder_vm_fault, 71 + }; 72 + 73 + static int binder_alloc_test_mmap_handler(struct file *filp, 74 + struct vm_area_struct *vma) 75 + { 76 + struct binder_alloc *alloc = filp->private_data; 77 + 78 + vm_flags_mod(vma, VM_DONTCOPY | VM_MIXEDMAP, VM_MAYWRITE); 79 + 80 + vma->vm_ops = &binder_alloc_test_vm_ops; 81 + vma->vm_private_data = alloc; 82 + 83 + return binder_alloc_mmap_handler(alloc, vma); 84 + } 85 + 86 + static const struct file_operations binder_alloc_test_fops = { 87 + .mmap = binder_alloc_test_mmap_handler, 88 + }; 89 + 90 + static int binder_alloc_test_init(struct kunit *test) 91 + { 92 + struct binder_alloc_test *priv; 93 + int ret; 94 + 95 + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 96 + if (!priv) 97 + return -ENOMEM; 98 + test->priv = priv; 99 + 100 + ret = list_lru_init(&priv->binder_test_freelist); 101 + if (ret) { 102 + kunit_err(test, "Failed to initialize test freelist\n"); 103 + return ret; 104 + } 105 + 106 + /* __binder_alloc_init requires mm to be attached */ 107 + ret = kunit_attach_mm(); 108 + if (ret) { 109 + kunit_err(test, "Failed to attach mm\n"); 110 + return ret; 111 + } 112 + __binder_alloc_init(&priv->alloc, &priv->binder_test_freelist); 113 + 114 + priv->filp = anon_inode_getfile("binder_alloc_kunit", 115 + &binder_alloc_test_fops, &priv->alloc, 116 + O_RDWR | O_CLOEXEC); 117 + if (IS_ERR_OR_NULL(priv->filp)) { 118 + kunit_err(test, "Failed to open binder alloc test driver file\n"); 119 + return priv->filp ? PTR_ERR(priv->filp) : -ENOMEM; 120 + } 121 + 122 + priv->mmap_uaddr = kunit_vm_mmap(test, priv->filp, 0, BINDER_MMAP_SIZE, 123 + PROT_READ, MAP_PRIVATE | MAP_NORESERVE, 124 + 0); 125 + if (!priv->mmap_uaddr) { 126 + kunit_err(test, "Could not map the test's transaction memory\n"); 127 + return -ENOMEM; 128 + } 129 + 130 + return 0; 131 + } 132 + 133 + static void binder_alloc_test_exit(struct kunit *test) 134 + { 135 + struct binder_alloc_test *priv = test->priv; 136 + 137 + /* Close the backing file to make sure binder_alloc_vma_close runs */ 138 + if (!IS_ERR_OR_NULL(priv->filp)) 139 + fput(priv->filp); 140 + 141 + if (priv->alloc.mm) 142 + binder_alloc_deferred_release(&priv->alloc); 143 + 144 + /* Make sure freelist is empty */ 145 + KUNIT_EXPECT_EQ(test, list_lru_count(&priv->binder_test_freelist), 0); 146 + list_lru_destroy(&priv->binder_test_freelist); 147 + } 148 + 149 + static struct kunit_case binder_alloc_test_cases[] = { 150 + KUNIT_CASE(binder_alloc_test_init_freelist), 151 + KUNIT_CASE(binder_alloc_test_mmap), 152 + {} 153 + }; 154 + 155 + static struct kunit_suite binder_alloc_test_suite = { 156 + .name = "binder_alloc", 157 + .test_cases = binder_alloc_test_cases, 158 + .init = binder_alloc_test_init, 159 + .exit = binder_alloc_test_exit, 160 + }; 161 + 162 + kunit_test_suite(binder_alloc_test_suite); 163 + 164 + MODULE_AUTHOR("Tiffany Yang <ynaffit@google.com>"); 165 + MODULE_DESCRIPTION("Binder Alloc KUnit tests"); 166 + MODULE_LICENSE("GPL");