Skip to content

Commit b135040

Browse files
ameryhungKernel Patches Daemon
authored andcommitted
selftests/bpf: Test concurrent task local data key creation
Test thread-safety of tld_create_key(). Since tld_create_key() does not rely on locks but memory barriers and atomic operations to protect the shared metadata, the thread-safety of the function is non-trivial. Make sure concurrent tld_key_create(), both valid and invalid, can not race and corrupt metatada, which may leads to TLDs not being thread- specific or duplicate TLDs with the same name. Signed-off-by: Amery Hung <[email protected]>
1 parent ac49c0d commit b135040

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

tools/testing/selftests/bpf/prog_tests/test_task_local_data.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,113 @@ static void test_task_local_data_basic(void)
185185
test_task_local_data__destroy(skel);
186186
}
187187

188+
#define TEST_RACE_THREAD_NUM (TLD_MAX_DATA_CNT - 3)
189+
190+
void *test_task_local_data_race_thread(void *arg)
191+
{
192+
int err = 0, id = (intptr_t)arg;
193+
char key_name[32];
194+
tld_key_t key;
195+
196+
key = tld_create_key("value_not_exist", TLD_PAGE_SIZE + 1);
197+
if (tld_key_err_or_zero(key) != -E2BIG) {
198+
err = 1;
199+
goto out;
200+
}
201+
202+
/* Only one thread will succeed in creating value1 */
203+
key = tld_create_key("value1", sizeof(int));
204+
if (!tld_key_is_err(key))
205+
tld_keys[1] = key;
206+
207+
/* Only one thread will succeed in creating value2 */
208+
key = tld_create_key("value2", sizeof(struct test_tld_struct));
209+
if (!tld_key_is_err(key))
210+
tld_keys[2] = key;
211+
212+
snprintf(key_name, 32, "thread_%d", id);
213+
tld_keys[id] = tld_create_key(key_name, sizeof(int));
214+
if (tld_key_is_err(tld_keys[id]))
215+
err = 2;
216+
out:
217+
return (void *)(intptr_t)err;
218+
}
219+
220+
static void test_task_local_data_race(void)
221+
{
222+
LIBBPF_OPTS(bpf_test_run_opts, opts);
223+
pthread_t thread[TEST_RACE_THREAD_NUM];
224+
struct test_task_local_data *skel;
225+
int fd, i, j, err, *data;
226+
void *ret = NULL;
227+
228+
skel = test_task_local_data__open_and_load();
229+
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
230+
return;
231+
232+
tld_keys = calloc(TLD_MAX_DATA_CNT, sizeof(tld_key_t));
233+
if (!ASSERT_OK_PTR(tld_keys, "calloc tld_keys"))
234+
goto out;
235+
236+
fd = bpf_map__fd(skel->maps.tld_data_map);
237+
238+
ASSERT_FALSE(tld_key_is_err(value0_key), "TLD_DEFINE_KEY");
239+
tld_keys[0] = value0_key;
240+
241+
for (j = 0; j < 100; j++) {
242+
reset_tld();
243+
244+
for (i = 0; i < TEST_RACE_THREAD_NUM; i++) {
245+
/*
246+
* Try to make tld_create_key() race with each other. Call
247+
* tld_create_key(), both valid and invalid, from different threads.
248+
*/
249+
err = pthread_create(&thread[i], NULL, test_task_local_data_race_thread,
250+
(void *)(intptr_t)(i + 3));
251+
if (CHECK_FAIL(err))
252+
break;
253+
}
254+
255+
/* Wait for all tld_create_key() to return */
256+
for (i = 0; i < TEST_RACE_THREAD_NUM; i++) {
257+
pthread_join(thread[i], &ret);
258+
if (CHECK_FAIL(ret))
259+
break;
260+
}
261+
262+
/* Write a unique number to each TLD */
263+
for (i = 0; i < TLD_MAX_DATA_CNT; i++) {
264+
data = tld_get_data(fd, tld_keys[i]);
265+
if (CHECK_FAIL(!data))
266+
break;
267+
*data = i;
268+
}
269+
270+
/* Read TLDs and check the value to see if any address collides with another */
271+
for (i = 0; i < TLD_MAX_DATA_CNT; i++) {
272+
data = tld_get_data(fd, tld_keys[i]);
273+
if (CHECK_FAIL(*data != i))
274+
break;
275+
}
276+
277+
/* Run task_main to make sure no invalid TLDs are added */
278+
err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.task_main), &opts);
279+
ASSERT_OK(err, "run task_main");
280+
ASSERT_OK(opts.retval, "task_main retval");
281+
}
282+
out:
283+
if (tld_keys) {
284+
free(tld_keys);
285+
tld_keys = NULL;
286+
}
287+
tld_free();
288+
test_task_local_data__destroy(skel);
289+
}
290+
188291
void test_task_local_data(void)
189292
{
190293
if (test__start_subtest("task_local_data_basic"))
191294
test_task_local_data_basic();
295+
if (test__start_subtest("task_local_data_race"))
296+
test_task_local_data_race();
192297
}

0 commit comments

Comments
 (0)