From 0d6526f82c3cdefcca47f73f5fc08dc6f335eac6 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Mon, 21 Sep 2026 17:37:22 -0700 Subject: sched/cache: Keep nr_pref_llc_running in the runnable domain, to fix LLC mis-scheduling bug alb_break_llc() decides whether to break LLC preference during active load balance. It does so by testing that every runnable fair task on the source rq prefers its LLC: env->src_rq->nr_pref_llc_running == env->src_rq->cfs.h_nr_runnable But the two counters cover different sets. nr_pref_llc_running is updated in account_llc_enqueue()/account_llc_dequeue(), next to cfs_rq->nr_queued, so it follows queued tasks. h_nr_runnable is updated in set_delayed()/ clear_delayed() and drops delay-dequeued tasks. So under DELAY_DEQUEUE, a preferring task that goes to sleep stays counted in nr_pref_llc_running while h_nr_runnable falls. The equality then breaks, alb_break_llc() returns false, and active balance is free to pull a task off its preferred LLC. Active balance only moves runnable tasks, and this is the only LLC check it consults: once the stopper runs, LBF_ACTIVE_LB skips the per-task test in can_migrate_task(). The runnable set is the one we want. Fix it on the counter side. A task should be counted in nr_pref_llc_running exactly while it is both queued on its preferred LLC (pref_llc_queued) and runnable (!sched_delayed). Define that membership once in task_pref_llc_runnable(), and adjust the counter only through pref_llc_running_inc()/pref_llc_running_dec() from the four sites that change either input: account_llc_enqueue(), account_llc_dequeue(), set_delayed() and clear_delayed(). Gating every update on the same predicate keeps the delay, wake and dequeue paths from double-counting or underflowing; see the comments at those sites for the ordering. nr_llc_running and sd->llc_counts are not touched and stay on queued semantics. Fixes: 714059f79ff0 ("sched/cache: Handle moving single tasks to/from their preferred LLC") Closes: https://lore.kernel.org/lkml/20260827135000.735138-1-zhanxusheng@xiaomi.com/ Reported-by: Zhan Xusheng Suggested-by: Chen Yu Signed-off-by: Tim Chen Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Reviewed-by: Kayra Cizmeci Cc: # v7.2.x Link: https://patch.msgid.link/06af61afedac32e6477f57feb4d658f6c411c3af.1790035273.git.tim.c.chen@linux.intel.com --- net/rxrpc/tests/Makefile | 3 + net/rxrpc/tests/rxrpc_kunit.c | 140 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 net/rxrpc/tests/Makefile create mode 100644 net/rxrpc/tests/rxrpc_kunit.c (limited to 'net/rxrpc/tests') diff --git a/net/rxrpc/tests/Makefile b/net/rxrpc/tests/Makefile new file mode 100644 index 000000000..4f5100880 --- /dev/null +++ b/net/rxrpc/tests/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_AF_RXRPC_KUNIT_TEST) += rxrpc_kunit.o diff --git a/net/rxrpc/tests/rxrpc_kunit.c b/net/rxrpc/tests/rxrpc_kunit.c new file mode 100644 index 000000000..95fd05a07 --- /dev/null +++ b/net/rxrpc/tests/rxrpc_kunit.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Unit tests for RxRPC crypto functions + * + * Copyright 2026 Google LLC + */ +#include "../ar-internal.h" +#include +#include + +struct fcrypt_pcbc_testvec { + u8 key[FCRYPT_BSIZE]; + u8 iv[FCRYPT_BSIZE]; + const u8 *ptext; /* plaintext */ + const u8 *ctext; /* ciphertext */ + size_t nblocks; /* length of ptext and ctext in blocks */ +}; + +/* FCrypt-PCBC test vectors */ +static const struct fcrypt_pcbc_testvec fcrypt_pcbc_testvecs[] = { + { + /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00", + .ctext = "\x0E\x09\x00\xC7\x3E\xF7\xED\x41", + .nblocks = 1, + }, + { + .key = "\x11\x44\x77\xAA\xDD\x00\x33\x66", + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00", + .ptext = "\x12\x34\x56\x78\x9A\xBC\xDE\xF0", + .ctext = "\xD8\xED\x78\x74\x77\xEC\x06\x80", + .nblocks = 1, + }, + { + /* From Arla */ + .key = "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87", + .iv = "\xfe\xdc\xba\x98\x76\x54\x32\x10", + .ptext = "The quick brown fox jumps over the lazy dogs.\0\0", + .ctext = "\x00\xf0\x0e\x11\x75\xe6\x23\x82" + "\xee\xac\x98\x62\x44\x51\xe4\x84" + "\xc3\x59\xd8\xaa\x64\x60\xae\xf7" + "\xd2\xd9\x13\x79\x72\xa3\x45\x03" + "\x23\xb5\x62\xd7\x0c\xf5\x27\xd1" + "\xf8\x91\x3c\xac\x44\x22\x92\xef", + .nblocks = 6, + }, + { + .key = "\xfe\xdc\xba\x98\x76\x54\x32\x10", + .iv = "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87", + .ptext = "The quick brown fox jumps over the lazy dogs.\0\0", + .ctext = "\xca\x90\xf5\x9d\xcb\xd4\xd2\x3c" + "\x01\x88\x7f\x3e\x31\x6e\x62\x9d" + "\xd8\xe0\x57\xa3\x06\x3a\x42\x58" + "\x2a\x28\xfe\x72\x52\x2f\xdd\xe0" + "\x19\x89\x09\x1c\x2a\x8e\x8c\x94" + "\xfc\xc7\x68\xe4\x88\xaa\xde\x0f", + .nblocks = 6, + } +}; + +static void test_fcrypt_pcbc(struct kunit *test) +{ + u8 data[48]; + + for (size_t i = 0; i < ARRAY_SIZE(fcrypt_pcbc_testvecs); i++) { + const struct fcrypt_pcbc_testvec *tv = &fcrypt_pcbc_testvecs[i]; + const size_t nblocks = tv->nblocks; + const size_t len = nblocks * FCRYPT_BSIZE; + struct fcrypt_key key; + + KUNIT_ASSERT_GE(test, sizeof(data), len); + + fcrypt_preparekey(&key, tv->key); + + /* out-of-place encryption */ + fcrypt_pcbc_encrypt(&key, tv->iv, tv->ptext, data, nblocks); + KUNIT_ASSERT_MEMEQ(test, tv->ctext, data, len); + + /* in-place encryption */ + memcpy(data, tv->ptext, len); + fcrypt_pcbc_encrypt(&key, tv->iv, data, data, nblocks); + KUNIT_ASSERT_MEMEQ(test, tv->ctext, data, len); + + /* out-of-place decryption */ + fcrypt_pcbc_decrypt(&key, tv->iv, tv->ctext, data, nblocks); + KUNIT_ASSERT_MEMEQ(test, tv->ptext, data, len); + + /* in-place decryption */ + memcpy(data, tv->ctext, len); + fcrypt_pcbc_decrypt(&key, tv->iv, data, data, nblocks); + KUNIT_ASSERT_MEMEQ(test, tv->ptext, data, len); + } +} + +static void test_des_pcbc(struct kunit *test) +{ + /* This was generated from the original pcbc(des) crypto API code. */ + static const u8 expected_ptext[24] = + "\xc8\xe2\x3c\xdf\x80\x61\x8a\xad\xa5\x52\xb4\x20" + "\x74\x32\x1f\xe4\x2c\x15\x7d\x21\x57\xda\x3f\x31"; + u8 key[8]; + union { + __le64 w; + u8 b[8]; + } iv; + u8 data[24]; + struct des_ctx ctx; + int err; + + for (int i = 0; i < 8; i++) { + key[i] = i; + iv.b[i] = 255 - i; + } + for (int i = 0; i < sizeof(data); i++) + data[i] = i; + + err = des_expand_key(&ctx, key, sizeof(key)); + KUNIT_ASSERT_EQ(test, 0, err); + + des_pcbc_decrypt_inplace(&ctx, iv.w, data, sizeof(data)); + KUNIT_ASSERT_MEMEQ(test, expected_ptext, data, sizeof(data)); +} + +static struct kunit_case rxrpc_test_cases[] = { + KUNIT_CASE(test_fcrypt_pcbc), + KUNIT_CASE(test_des_pcbc), + {}, +}; + +static struct kunit_suite rxrpc_test_suite = { + .name = "rxrpc", + .test_cases = rxrpc_test_cases, +}; +kunit_test_suite(rxrpc_test_suite); + +MODULE_DESCRIPTION("Unit tests for RxRPC crypto functions"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); +MODULE_LICENSE("GPL"); -- cgit v1.3.1