1c540957aSSong Liu // SPDX-License-Identifier: GPL-2.0
2c540957aSSong Liu /* Copyright (c) 2021 Facebook */
3c540957aSSong Liu 
4c540957aSSong Liu #include "vmlinux.h"
5c540957aSSong Liu #include <bpf/bpf_helpers.h>
6c540957aSSong Liu #include <bpf/bpf_tracing.h>
7c540957aSSong Liu 
8*387b5321SMartin KaFai Lau #ifndef EBUSY
9*387b5321SMartin KaFai Lau #define EBUSY 16
10*387b5321SMartin KaFai Lau #endif
11*387b5321SMartin KaFai Lau 
12c540957aSSong Liu char _license[] SEC("license") = "GPL";
13*387b5321SMartin KaFai Lau int nr_del_errs = 0;
14*387b5321SMartin KaFai Lau int test_pid = 0;
15c540957aSSong Liu 
16c540957aSSong Liu struct {
17c540957aSSong Liu 	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
18c540957aSSong Liu 	__uint(map_flags, BPF_F_NO_PREALLOC);
19c540957aSSong Liu 	__type(key, int);
20c540957aSSong Liu 	__type(value, long);
21c540957aSSong Liu } map_a SEC(".maps");
22c540957aSSong Liu 
23c540957aSSong Liu struct {
24c540957aSSong Liu 	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
25c540957aSSong Liu 	__uint(map_flags, BPF_F_NO_PREALLOC);
26c540957aSSong Liu 	__type(key, int);
27c540957aSSong Liu 	__type(value, long);
28c540957aSSong Liu } map_b SEC(".maps");
29c540957aSSong Liu 
30c540957aSSong Liu SEC("fentry/bpf_local_storage_lookup")
BPF_PROG(on_lookup)31c540957aSSong Liu int BPF_PROG(on_lookup)
32c540957aSSong Liu {
33c540957aSSong Liu 	struct task_struct *task = bpf_get_current_task_btf();
34c540957aSSong Liu 
35*387b5321SMartin KaFai Lau 	if (!test_pid || task->pid != test_pid)
36*387b5321SMartin KaFai Lau 		return 0;
37*387b5321SMartin KaFai Lau 
38*387b5321SMartin KaFai Lau 	/* The bpf_task_storage_delete will call
39*387b5321SMartin KaFai Lau 	 * bpf_local_storage_lookup.  The prog->active will
40*387b5321SMartin KaFai Lau 	 * stop the recursion.
41*387b5321SMartin KaFai Lau 	 */
42c540957aSSong Liu 	bpf_task_storage_delete(&map_a, task);
43c540957aSSong Liu 	bpf_task_storage_delete(&map_b, task);
44c540957aSSong Liu 	return 0;
45c540957aSSong Liu }
46c540957aSSong Liu 
47c540957aSSong Liu SEC("fentry/bpf_local_storage_update")
BPF_PROG(on_update)48c540957aSSong Liu int BPF_PROG(on_update)
49c540957aSSong Liu {
50c540957aSSong Liu 	struct task_struct *task = bpf_get_current_task_btf();
51c540957aSSong Liu 	long *ptr;
52c540957aSSong Liu 
53*387b5321SMartin KaFai Lau 	if (!test_pid || task->pid != test_pid)
54*387b5321SMartin KaFai Lau 		return 0;
55*387b5321SMartin KaFai Lau 
56c540957aSSong Liu 	ptr = bpf_task_storage_get(&map_a, task, 0,
57c540957aSSong Liu 				   BPF_LOCAL_STORAGE_GET_F_CREATE);
58*387b5321SMartin KaFai Lau 	/* ptr will not be NULL when it is called from
59*387b5321SMartin KaFai Lau 	 * the bpf_task_storage_get(&map_b,...F_CREATE) in
60*387b5321SMartin KaFai Lau 	 * the BPF_PROG(on_enter) below.  It is because
61*387b5321SMartin KaFai Lau 	 * the value can be found in map_a and the kernel
62*387b5321SMartin KaFai Lau 	 * does not need to acquire any spin_lock.
63*387b5321SMartin KaFai Lau 	 */
64*387b5321SMartin KaFai Lau 	if (ptr) {
65*387b5321SMartin KaFai Lau 		int err;
66c540957aSSong Liu 
67*387b5321SMartin KaFai Lau 		*ptr += 1;
68*387b5321SMartin KaFai Lau 		err = bpf_task_storage_delete(&map_a, task);
69*387b5321SMartin KaFai Lau 		if (err == -EBUSY)
70*387b5321SMartin KaFai Lau 			nr_del_errs++;
71*387b5321SMartin KaFai Lau 	}
72*387b5321SMartin KaFai Lau 
73*387b5321SMartin KaFai Lau 	/* This will still fail because map_b is empty and
74*387b5321SMartin KaFai Lau 	 * this BPF_PROG(on_update) has failed to acquire
75*387b5321SMartin KaFai Lau 	 * the percpu busy lock => meaning potential
76*387b5321SMartin KaFai Lau 	 * deadlock is detected and it will fail to create
77*387b5321SMartin KaFai Lau 	 * new storage.
78*387b5321SMartin KaFai Lau 	 */
79c540957aSSong Liu 	ptr = bpf_task_storage_get(&map_b, task, 0,
80c540957aSSong Liu 				   BPF_LOCAL_STORAGE_GET_F_CREATE);
81c540957aSSong Liu 	if (ptr)
82c540957aSSong Liu 		*ptr += 1;
83c540957aSSong Liu 
84c540957aSSong Liu 	return 0;
85c540957aSSong Liu }
86c540957aSSong Liu 
87c540957aSSong Liu SEC("tp_btf/sys_enter")
BPF_PROG(on_enter,struct pt_regs * regs,long id)88c540957aSSong Liu int BPF_PROG(on_enter, struct pt_regs *regs, long id)
89c540957aSSong Liu {
90c540957aSSong Liu 	struct task_struct *task;
91c540957aSSong Liu 	long *ptr;
92c540957aSSong Liu 
93c540957aSSong Liu 	task = bpf_get_current_task_btf();
94*387b5321SMartin KaFai Lau 	if (!test_pid || task->pid != test_pid)
95*387b5321SMartin KaFai Lau 		return 0;
96*387b5321SMartin KaFai Lau 
97c540957aSSong Liu 	ptr = bpf_task_storage_get(&map_a, task, 0,
98c540957aSSong Liu 				   BPF_LOCAL_STORAGE_GET_F_CREATE);
99*387b5321SMartin KaFai Lau 	if (ptr && !*ptr)
100c540957aSSong Liu 		*ptr = 200;
101c540957aSSong Liu 
102c540957aSSong Liu 	ptr = bpf_task_storage_get(&map_b, task, 0,
103c540957aSSong Liu 				   BPF_LOCAL_STORAGE_GET_F_CREATE);
104*387b5321SMartin KaFai Lau 	if (ptr && !*ptr)
105c540957aSSong Liu 		*ptr = 100;
106c540957aSSong Liu 	return 0;
107c540957aSSong Liu }
108