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.

Revert "revocable: Add Kunit test cases"

This reverts commit cd7693419bb5abd91ad2f407dab69c480e417a61.

The new revocable functionality is fundamentally broken and at a minimum
needs to be redesigned.

Drop the revocable Kunit tests to allow the implementation to be reverted.

Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260204142849.22055-3-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Johan Hovold and committed by
Greg Kroah-Hartman
7149ce34 379a5aad

-296
-1
MAINTAINERS
··· 22390 22390 L: linux-kernel@vger.kernel.org 22391 22391 S: Maintained 22392 22392 F: drivers/base/revocable.c 22393 - F: drivers/base/revocable_test.c 22394 22393 F: include/linux/revocable.h 22395 22394 22396 22395 RFKILL
-8
drivers/base/Kconfig
··· 250 250 work on. 251 251 252 252 endmenu 253 - 254 - # Kunit test cases 255 - config REVOCABLE_KUNIT_TEST 256 - tristate "Kunit tests for revocable" if !KUNIT_ALL_TESTS 257 - depends on KUNIT && BROKEN 258 - default KUNIT_ALL_TESTS 259 - help 260 - Kunit tests for the revocable API.
-3
drivers/base/Makefile
··· 35 35 # define_trace.h needs to know how to find our header 36 36 CFLAGS_trace.o := -I$(src) 37 37 obj-$(CONFIG_TRACING) += trace.o 38 - 39 - # Kunit test cases 40 - obj-$(CONFIG_REVOCABLE_KUNIT_TEST) += revocable_test.o
-284
drivers/base/revocable_test.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright 2026 Google LLC 4 - * 5 - * Kunit tests for the revocable API. 6 - * 7 - * The test cases cover the following scenarios: 8 - * 9 - * - Basic: Verifies that a consumer can successfully access the resource 10 - * provided via the provider. 11 - * 12 - * - Revocation: Verifies that after the provider revokes the resource, 13 - * the consumer correctly receives a NULL pointer on a subsequent access. 14 - * 15 - * - Try Access Macro: Same as "Revocation" but uses the 16 - * REVOCABLE_TRY_ACCESS_WITH() and REVOCABLE_TRY_ACCESS_SCOPED(). 17 - * 18 - * - Provider Use-after-free: Verifies revocable_init() correctly handles 19 - * race conditions where the provider is being released. 20 - * 21 - * - Concurrent Access: Verifies multiple threads can access the resource. 22 - */ 23 - 24 - #include <kunit/test.h> 25 - #include <linux/completion.h> 26 - #include <linux/delay.h> 27 - #include <linux/kthread.h> 28 - #include <linux/refcount.h> 29 - #include <linux/revocable.h> 30 - 31 - static void revocable_test_basic(struct kunit *test) 32 - { 33 - struct revocable_provider __rcu *rp; 34 - struct revocable rev; 35 - void *real_res = (void *)0x12345678, *res; 36 - int ret; 37 - 38 - rp = revocable_provider_alloc(real_res); 39 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 40 - 41 - ret = revocable_init(rp, &rev); 42 - KUNIT_ASSERT_EQ(test, ret, 0); 43 - 44 - res = revocable_try_access(&rev); 45 - KUNIT_EXPECT_PTR_EQ(test, res, real_res); 46 - revocable_withdraw_access(&rev); 47 - 48 - revocable_deinit(&rev); 49 - revocable_provider_revoke(&rp); 50 - KUNIT_EXPECT_PTR_EQ(test, unrcu_pointer(rp), NULL); 51 - } 52 - 53 - static void revocable_test_revocation(struct kunit *test) 54 - { 55 - struct revocable_provider __rcu *rp; 56 - struct revocable rev; 57 - void *real_res = (void *)0x12345678, *res; 58 - int ret; 59 - 60 - rp = revocable_provider_alloc(real_res); 61 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 62 - 63 - ret = revocable_init(rp, &rev); 64 - KUNIT_ASSERT_EQ(test, ret, 0); 65 - 66 - res = revocable_try_access(&rev); 67 - KUNIT_EXPECT_PTR_EQ(test, res, real_res); 68 - revocable_withdraw_access(&rev); 69 - 70 - revocable_provider_revoke(&rp); 71 - KUNIT_EXPECT_PTR_EQ(test, unrcu_pointer(rp), NULL); 72 - 73 - res = revocable_try_access(&rev); 74 - KUNIT_EXPECT_PTR_EQ(test, res, NULL); 75 - revocable_withdraw_access(&rev); 76 - 77 - revocable_deinit(&rev); 78 - } 79 - 80 - static void revocable_test_try_access_macro(struct kunit *test) 81 - { 82 - struct revocable_provider __rcu *rp; 83 - void *real_res = (void *)0x12345678, *res; 84 - 85 - rp = revocable_provider_alloc(real_res); 86 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 87 - 88 - { 89 - REVOCABLE_TRY_ACCESS_WITH(rp, res); 90 - KUNIT_EXPECT_PTR_EQ(test, res, real_res); 91 - } 92 - 93 - revocable_provider_revoke(&rp); 94 - KUNIT_EXPECT_PTR_EQ(test, unrcu_pointer(rp), NULL); 95 - 96 - { 97 - REVOCABLE_TRY_ACCESS_WITH(rp, res); 98 - KUNIT_EXPECT_PTR_EQ(test, res, NULL); 99 - } 100 - } 101 - 102 - static void revocable_test_try_access_macro2(struct kunit *test) 103 - { 104 - struct revocable_provider __rcu *rp; 105 - void *real_res = (void *)0x12345678, *res; 106 - bool accessed; 107 - 108 - rp = revocable_provider_alloc(real_res); 109 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 110 - 111 - accessed = false; 112 - REVOCABLE_TRY_ACCESS_SCOPED(rp, res) { 113 - KUNIT_EXPECT_PTR_EQ(test, res, real_res); 114 - accessed = true; 115 - } 116 - KUNIT_EXPECT_TRUE(test, accessed); 117 - 118 - revocable_provider_revoke(&rp); 119 - KUNIT_EXPECT_PTR_EQ(test, unrcu_pointer(rp), NULL); 120 - 121 - accessed = false; 122 - REVOCABLE_TRY_ACCESS_SCOPED(rp, res) { 123 - KUNIT_EXPECT_PTR_EQ(test, res, NULL); 124 - accessed = true; 125 - } 126 - KUNIT_EXPECT_TRUE(test, accessed); 127 - } 128 - 129 - static void revocable_test_provider_use_after_free(struct kunit *test) 130 - { 131 - struct revocable_provider __rcu *rp; 132 - struct revocable_provider *old_rp; 133 - struct revocable rev; 134 - void *real_res = (void *)0x12345678; 135 - int ret; 136 - 137 - rp = revocable_provider_alloc(real_res); 138 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 139 - 140 - ret = revocable_init(NULL, &rev); 141 - KUNIT_EXPECT_NE(test, ret, 0); 142 - 143 - /* Simulate the provider has been freed. */ 144 - old_rp = rcu_replace_pointer(rp, NULL, 1); 145 - ret = revocable_init(rp, &rev); 146 - KUNIT_EXPECT_NE(test, ret, 0); 147 - rcu_replace_pointer(rp, old_rp, 1); 148 - 149 - struct { 150 - struct srcu_struct srcu; 151 - void __rcu *res; 152 - struct kref kref; 153 - struct rcu_head rcu; 154 - } *rp_internal = (void *)rp; 155 - 156 - /* Simulate the provider is releasing. */ 157 - refcount_set(&rp_internal->kref.refcount, 0); 158 - ret = revocable_init(rp, &rev); 159 - KUNIT_EXPECT_NE(test, ret, 0); 160 - refcount_set(&rp_internal->kref.refcount, 1); 161 - 162 - revocable_provider_revoke(&rp); 163 - KUNIT_EXPECT_PTR_EQ(test, unrcu_pointer(rp), NULL); 164 - ret = revocable_init(rp, &rev); 165 - KUNIT_EXPECT_NE(test, ret, 0); 166 - } 167 - 168 - struct test_concurrent_access_context { 169 - struct kunit *test; 170 - struct revocable_provider __rcu *rp; 171 - struct revocable rev; 172 - struct completion started, enter, exit; 173 - struct task_struct *thread; 174 - void *expected_res; 175 - }; 176 - 177 - static int test_concurrent_access_provider(void *data) 178 - { 179 - struct test_concurrent_access_context *ctx = data; 180 - 181 - complete(&ctx->started); 182 - 183 - wait_for_completion(&ctx->enter); 184 - revocable_provider_revoke(&ctx->rp); 185 - KUNIT_EXPECT_PTR_EQ(ctx->test, unrcu_pointer(ctx->rp), NULL); 186 - 187 - return 0; 188 - } 189 - 190 - static int test_concurrent_access_consumer(void *data) 191 - { 192 - struct test_concurrent_access_context *ctx = data; 193 - void *res; 194 - 195 - complete(&ctx->started); 196 - 197 - wait_for_completion(&ctx->enter); 198 - res = revocable_try_access(&ctx->rev); 199 - KUNIT_EXPECT_PTR_EQ(ctx->test, res, ctx->expected_res); 200 - 201 - wait_for_completion(&ctx->exit); 202 - revocable_withdraw_access(&ctx->rev); 203 - 204 - return 0; 205 - } 206 - 207 - static void revocable_test_concurrent_access(struct kunit *test) 208 - { 209 - struct revocable_provider __rcu *rp; 210 - void *real_res = (void *)0x12345678; 211 - struct test_concurrent_access_context *ctx; 212 - int ret, i; 213 - 214 - rp = revocable_provider_alloc(real_res); 215 - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rp); 216 - 217 - ctx = kunit_kmalloc_array(test, 3, sizeof(*ctx), GFP_KERNEL); 218 - KUNIT_ASSERT_NOT_NULL(test, ctx); 219 - 220 - for (i = 0; i < 3; ++i) { 221 - ctx[i].test = test; 222 - init_completion(&ctx[i].started); 223 - init_completion(&ctx[i].enter); 224 - init_completion(&ctx[i].exit); 225 - 226 - if (i == 0) { 227 - ctx[i].rp = rp; 228 - ctx[i].thread = kthread_run( 229 - test_concurrent_access_provider, ctx + i, 230 - "revocable_provider_%d", i); 231 - } else { 232 - ret = revocable_init(rp, &ctx[i].rev); 233 - KUNIT_ASSERT_EQ(test, ret, 0); 234 - 235 - ctx[i].thread = kthread_run( 236 - test_concurrent_access_consumer, ctx + i, 237 - "revocable_consumer_%d", i); 238 - } 239 - KUNIT_ASSERT_FALSE(test, IS_ERR(ctx[i].thread)); 240 - 241 - wait_for_completion(&ctx[i].started); 242 - } 243 - ctx[1].expected_res = real_res; 244 - ctx[2].expected_res = NULL; 245 - 246 - /* consumer1 enters read-side critical section */ 247 - complete(&ctx[1].enter); 248 - msleep(100); 249 - /* provider0 revokes the resource */ 250 - complete(&ctx[0].enter); 251 - msleep(100); 252 - /* consumer2 enters read-side critical section */ 253 - complete(&ctx[2].enter); 254 - msleep(100); 255 - 256 - /* consumer{1,2} exit read-side critical section */ 257 - complete(&ctx[1].exit); 258 - complete(&ctx[2].exit); 259 - 260 - for (i = 0; i < 3; ++i) 261 - kthread_stop(ctx[i].thread); 262 - for (i = 1; i < 3; ++i) 263 - revocable_deinit(&ctx[i].rev); 264 - } 265 - 266 - static struct kunit_case revocable_test_cases[] = { 267 - KUNIT_CASE(revocable_test_basic), 268 - KUNIT_CASE(revocable_test_revocation), 269 - KUNIT_CASE(revocable_test_try_access_macro), 270 - KUNIT_CASE(revocable_test_try_access_macro2), 271 - KUNIT_CASE(revocable_test_provider_use_after_free), 272 - KUNIT_CASE(revocable_test_concurrent_access), 273 - {} 274 - }; 275 - 276 - static struct kunit_suite revocable_test_suite = { 277 - .name = "revocable_test", 278 - .test_cases = revocable_test_cases, 279 - }; 280 - 281 - kunit_test_suite(revocable_test_suite); 282 - 283 - MODULE_DESCRIPTION("KUnit tests for the revocable API"); 284 - MODULE_LICENSE("GPL");