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

selftests/bpf: Add tests for RCU lock transfer between subprogs

Add selftests covering the following cases:
- A static or global subprog called from within a RCU read section works
- A static subprog taking an RCU read lock which is released in caller works
- A static subprog releasing the caller's RCU read lock works

Global subprogs that leave the lock in an imbalanced state will not
work, as they are verified separately, so ensure those cases fail as
well.

Acked-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: David Vernet <void@manifault.com>
Link: https://lore.kernel.org/r/20240205055646.1112186-3-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kumar Kartikeya Dwivedi and committed by
Alexei Starovoitov
8be6a014 6fceea0f

+126
+6
tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
··· 29 29 bpf_program__set_autoload(skel->progs.non_sleepable_1, true); 30 30 bpf_program__set_autoload(skel->progs.non_sleepable_2, true); 31 31 bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true); 32 + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog, true); 33 + bpf_program__set_autoload(skel->progs.rcu_read_lock_global_subprog, true); 34 + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_lock, true); 35 + bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_unlock, true); 32 36 err = rcu_read_lock__load(skel); 33 37 if (!ASSERT_OK(err, "skel_load")) 34 38 goto out; ··· 79 75 "inproper_sleepable_helper", 80 76 "inproper_sleepable_kfunc", 81 77 "nested_rcu_region", 78 + "rcu_read_lock_global_subprog_lock", 79 + "rcu_read_lock_global_subprog_unlock", 82 80 }; 83 81 84 82 static void test_inproper_region(void)
+120
tools/testing/selftests/bpf/progs/rcu_read_lock.c
··· 319 319 bpf_rcu_read_unlock(); 320 320 return 0; 321 321 } 322 + 323 + __noinline 324 + static int static_subprog(void *ctx) 325 + { 326 + volatile int ret = 0; 327 + 328 + if (bpf_get_prandom_u32()) 329 + return ret + 42; 330 + return ret + bpf_get_prandom_u32(); 331 + } 332 + 333 + __noinline 334 + int global_subprog(u64 a) 335 + { 336 + volatile int ret = a; 337 + 338 + return ret + static_subprog(NULL); 339 + } 340 + 341 + __noinline 342 + static int static_subprog_lock(void *ctx) 343 + { 344 + volatile int ret = 0; 345 + 346 + bpf_rcu_read_lock(); 347 + if (bpf_get_prandom_u32()) 348 + return ret + 42; 349 + return ret + bpf_get_prandom_u32(); 350 + } 351 + 352 + __noinline 353 + int global_subprog_lock(u64 a) 354 + { 355 + volatile int ret = a; 356 + 357 + return ret + static_subprog_lock(NULL); 358 + } 359 + 360 + __noinline 361 + static int static_subprog_unlock(void *ctx) 362 + { 363 + volatile int ret = 0; 364 + 365 + bpf_rcu_read_unlock(); 366 + if (bpf_get_prandom_u32()) 367 + return ret + 42; 368 + return ret + bpf_get_prandom_u32(); 369 + } 370 + 371 + __noinline 372 + int global_subprog_unlock(u64 a) 373 + { 374 + volatile int ret = a; 375 + 376 + return ret + static_subprog_unlock(NULL); 377 + } 378 + 379 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 380 + int rcu_read_lock_subprog(void *ctx) 381 + { 382 + volatile int ret = 0; 383 + 384 + bpf_rcu_read_lock(); 385 + if (bpf_get_prandom_u32()) 386 + ret += static_subprog(ctx); 387 + bpf_rcu_read_unlock(); 388 + return 0; 389 + } 390 + 391 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 392 + int rcu_read_lock_global_subprog(void *ctx) 393 + { 394 + volatile int ret = 0; 395 + 396 + bpf_rcu_read_lock(); 397 + if (bpf_get_prandom_u32()) 398 + ret += global_subprog(ret); 399 + bpf_rcu_read_unlock(); 400 + return 0; 401 + } 402 + 403 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 404 + int rcu_read_lock_subprog_lock(void *ctx) 405 + { 406 + volatile int ret = 0; 407 + 408 + ret += static_subprog_lock(ctx); 409 + bpf_rcu_read_unlock(); 410 + return 0; 411 + } 412 + 413 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 414 + int rcu_read_lock_global_subprog_lock(void *ctx) 415 + { 416 + volatile int ret = 0; 417 + 418 + ret += global_subprog_lock(ret); 419 + bpf_rcu_read_unlock(); 420 + return 0; 421 + } 422 + 423 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 424 + int rcu_read_lock_subprog_unlock(void *ctx) 425 + { 426 + volatile int ret = 0; 427 + 428 + bpf_rcu_read_lock(); 429 + ret += static_subprog_unlock(ctx); 430 + return 0; 431 + } 432 + 433 + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 434 + int rcu_read_lock_global_subprog_unlock(void *ctx) 435 + { 436 + volatile int ret = 0; 437 + 438 + bpf_rcu_read_lock(); 439 + ret += global_subprog_unlock(ret); 440 + return 0; 441 + }