1407b36f6SNamhyung Kim // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2407b36f6SNamhyung Kim // Copyright (c) 2022 Google
3407b36f6SNamhyung Kim #include "vmlinux.h"
4407b36f6SNamhyung Kim #include <bpf/bpf_helpers.h>
5407b36f6SNamhyung Kim #include <bpf/bpf_tracing.h>
6407b36f6SNamhyung Kim #include <bpf/bpf_core_read.h>
7222de5e5SNamhyung Kim #include <asm-generic/errno-base.h>
8407b36f6SNamhyung Kim
9fd507d3eSNamhyung Kim #include "lock_data.h"
10407b36f6SNamhyung Kim
11d24c0144SNamhyung Kim /* for collect_lock_syms(). 4096 was rejected by the verifier */
12d24c0144SNamhyung Kim #define MAX_CPUS 1024
13d24c0144SNamhyung Kim
143477f079SNamhyung Kim /* lock contention flags from include/trace/events/lock.h */
153477f079SNamhyung Kim #define LCB_F_SPIN (1U << 0)
163477f079SNamhyung Kim #define LCB_F_READ (1U << 1)
173477f079SNamhyung Kim #define LCB_F_WRITE (1U << 2)
183477f079SNamhyung Kim #define LCB_F_RT (1U << 3)
193477f079SNamhyung Kim #define LCB_F_PERCPU (1U << 4)
203477f079SNamhyung Kim #define LCB_F_MUTEX (1U << 5)
213477f079SNamhyung Kim
22407b36f6SNamhyung Kim struct tstamp_data {
23407b36f6SNamhyung Kim __u64 timestamp;
24407b36f6SNamhyung Kim __u64 lock;
25407b36f6SNamhyung Kim __u32 flags;
266d499a6bSNamhyung Kim __s32 stack_id;
27407b36f6SNamhyung Kim };
28407b36f6SNamhyung Kim
29407b36f6SNamhyung Kim /* callstack storage */
30407b36f6SNamhyung Kim struct {
31407b36f6SNamhyung Kim __uint(type, BPF_MAP_TYPE_STACK_TRACE);
32407b36f6SNamhyung Kim __uint(key_size, sizeof(__u32));
33fd507d3eSNamhyung Kim __uint(value_size, sizeof(__u64));
34407b36f6SNamhyung Kim __uint(max_entries, MAX_ENTRIES);
35407b36f6SNamhyung Kim } stacks SEC(".maps");
36407b36f6SNamhyung Kim
37407b36f6SNamhyung Kim /* maintain timestamp at the beginning of contention */
38407b36f6SNamhyung Kim struct {
39c66a36afSNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
40407b36f6SNamhyung Kim __type(key, int);
41407b36f6SNamhyung Kim __type(value, struct tstamp_data);
42c66a36afSNamhyung Kim __uint(max_entries, MAX_ENTRIES);
43407b36f6SNamhyung Kim } tstamp SEC(".maps");
44407b36f6SNamhyung Kim
45407b36f6SNamhyung Kim /* actual lock contention statistics */
46407b36f6SNamhyung Kim struct {
47407b36f6SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
48407b36f6SNamhyung Kim __uint(key_size, sizeof(struct contention_key));
49407b36f6SNamhyung Kim __uint(value_size, sizeof(struct contention_data));
50407b36f6SNamhyung Kim __uint(max_entries, MAX_ENTRIES);
51407b36f6SNamhyung Kim } lock_stat SEC(".maps");
52407b36f6SNamhyung Kim
536fda2405SNamhyung Kim struct {
546fda2405SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
556fda2405SNamhyung Kim __uint(key_size, sizeof(__u32));
56eca949b2SNamhyung Kim __uint(value_size, sizeof(struct contention_task_data));
57eca949b2SNamhyung Kim __uint(max_entries, MAX_ENTRIES);
58eca949b2SNamhyung Kim } task_data SEC(".maps");
59eca949b2SNamhyung Kim
60eca949b2SNamhyung Kim struct {
61eca949b2SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
62d24c0144SNamhyung Kim __uint(key_size, sizeof(__u64));
63d24c0144SNamhyung Kim __uint(value_size, sizeof(__u32));
642d8d0165SNamhyung Kim __uint(max_entries, MAX_ENTRIES);
65d24c0144SNamhyung Kim } lock_syms SEC(".maps");
66d24c0144SNamhyung Kim
67d24c0144SNamhyung Kim struct {
68d24c0144SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
69eca949b2SNamhyung Kim __uint(key_size, sizeof(__u32));
706fda2405SNamhyung Kim __uint(value_size, sizeof(__u8));
716fda2405SNamhyung Kim __uint(max_entries, 1);
726fda2405SNamhyung Kim } cpu_filter SEC(".maps");
736fda2405SNamhyung Kim
746fda2405SNamhyung Kim struct {
756fda2405SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
766fda2405SNamhyung Kim __uint(key_size, sizeof(__u32));
776fda2405SNamhyung Kim __uint(value_size, sizeof(__u8));
786fda2405SNamhyung Kim __uint(max_entries, 1);
796fda2405SNamhyung Kim } task_filter SEC(".maps");
806fda2405SNamhyung Kim
81529772c4SNamhyung Kim struct {
82529772c4SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
83529772c4SNamhyung Kim __uint(key_size, sizeof(__u32));
84529772c4SNamhyung Kim __uint(value_size, sizeof(__u8));
85529772c4SNamhyung Kim __uint(max_entries, 1);
86529772c4SNamhyung Kim } type_filter SEC(".maps");
87529772c4SNamhyung Kim
885e3febe7SNamhyung Kim struct {
895e3febe7SNamhyung Kim __uint(type, BPF_MAP_TYPE_HASH);
905e3febe7SNamhyung Kim __uint(key_size, sizeof(__u64));
915e3febe7SNamhyung Kim __uint(value_size, sizeof(__u8));
925e3febe7SNamhyung Kim __uint(max_entries, 1);
935e3febe7SNamhyung Kim } addr_filter SEC(".maps");
945e3febe7SNamhyung Kim
951bece135SNamhyung Kim struct rw_semaphore___old {
961bece135SNamhyung Kim struct task_struct *owner;
971bece135SNamhyung Kim } __attribute__((preserve_access_index));
981bece135SNamhyung Kim
991bece135SNamhyung Kim struct rw_semaphore___new {
1001bece135SNamhyung Kim atomic_long_t owner;
1011bece135SNamhyung Kim } __attribute__((preserve_access_index));
1021bece135SNamhyung Kim
1033ace2435SNamhyung Kim struct mm_struct___old {
1043ace2435SNamhyung Kim struct rw_semaphore mmap_sem;
1053ace2435SNamhyung Kim } __attribute__((preserve_access_index));
1063ace2435SNamhyung Kim
1073ace2435SNamhyung Kim struct mm_struct___new {
1083ace2435SNamhyung Kim struct rw_semaphore mmap_lock;
1093ace2435SNamhyung Kim } __attribute__((preserve_access_index));
1103ace2435SNamhyung Kim
111407b36f6SNamhyung Kim /* control flags */
112407b36f6SNamhyung Kim int enabled;
1136fda2405SNamhyung Kim int has_cpu;
1146fda2405SNamhyung Kim int has_task;
115529772c4SNamhyung Kim int has_type;
1165e3febe7SNamhyung Kim int has_addr;
117ebab2916SNamhyung Kim int needs_callstack;
118c1da8dd5SNamhyung Kim int stack_skip;
1193477f079SNamhyung Kim int lock_owner;
1206fda2405SNamhyung Kim
121eca949b2SNamhyung Kim /* determine the key of lock stat */
122eca949b2SNamhyung Kim int aggr_mode;
123eca949b2SNamhyung Kim
1246d499a6bSNamhyung Kim /* error stat */
12584c3a2bbSNamhyung Kim int task_fail;
12684c3a2bbSNamhyung Kim int stack_fail;
12784c3a2bbSNamhyung Kim int time_fail;
128954cdac7SNamhyung Kim int data_fail;
1296d499a6bSNamhyung Kim
130222de5e5SNamhyung Kim int task_map_full;
131222de5e5SNamhyung Kim int data_map_full;
132222de5e5SNamhyung Kim
can_record(u64 * ctx)133529772c4SNamhyung Kim static inline int can_record(u64 *ctx)
1346fda2405SNamhyung Kim {
1356fda2405SNamhyung Kim if (has_cpu) {
1366fda2405SNamhyung Kim __u32 cpu = bpf_get_smp_processor_id();
1376fda2405SNamhyung Kim __u8 *ok;
1386fda2405SNamhyung Kim
1396fda2405SNamhyung Kim ok = bpf_map_lookup_elem(&cpu_filter, &cpu);
1406fda2405SNamhyung Kim if (!ok)
1416fda2405SNamhyung Kim return 0;
1426fda2405SNamhyung Kim }
1436fda2405SNamhyung Kim
1446fda2405SNamhyung Kim if (has_task) {
1456fda2405SNamhyung Kim __u8 *ok;
1466fda2405SNamhyung Kim __u32 pid = bpf_get_current_pid_tgid();
1476fda2405SNamhyung Kim
1486fda2405SNamhyung Kim ok = bpf_map_lookup_elem(&task_filter, &pid);
1496fda2405SNamhyung Kim if (!ok)
1506fda2405SNamhyung Kim return 0;
1516fda2405SNamhyung Kim }
1526fda2405SNamhyung Kim
153529772c4SNamhyung Kim if (has_type) {
154529772c4SNamhyung Kim __u8 *ok;
155529772c4SNamhyung Kim __u32 flags = (__u32)ctx[1];
156529772c4SNamhyung Kim
157529772c4SNamhyung Kim ok = bpf_map_lookup_elem(&type_filter, &flags);
158529772c4SNamhyung Kim if (!ok)
159529772c4SNamhyung Kim return 0;
160529772c4SNamhyung Kim }
161529772c4SNamhyung Kim
1625e3febe7SNamhyung Kim if (has_addr) {
1635e3febe7SNamhyung Kim __u8 *ok;
1645e3febe7SNamhyung Kim __u64 addr = ctx[0];
1655e3febe7SNamhyung Kim
1665e3febe7SNamhyung Kim ok = bpf_map_lookup_elem(&addr_filter, &addr);
1675e3febe7SNamhyung Kim if (!ok)
1685e3febe7SNamhyung Kim return 0;
1695e3febe7SNamhyung Kim }
1705e3febe7SNamhyung Kim
1716fda2405SNamhyung Kim return 1;
1726fda2405SNamhyung Kim }
173407b36f6SNamhyung Kim
update_task_data(struct task_struct * task)1743477f079SNamhyung Kim static inline int update_task_data(struct task_struct *task)
175eca949b2SNamhyung Kim {
176eca949b2SNamhyung Kim struct contention_task_data *p;
1773477f079SNamhyung Kim int pid, err;
1783477f079SNamhyung Kim
1793477f079SNamhyung Kim err = bpf_core_read(&pid, sizeof(pid), &task->pid);
1803477f079SNamhyung Kim if (err)
1813477f079SNamhyung Kim return -1;
182eca949b2SNamhyung Kim
183eca949b2SNamhyung Kim p = bpf_map_lookup_elem(&task_data, &pid);
184222de5e5SNamhyung Kim if (p == NULL && !task_map_full) {
1853477f079SNamhyung Kim struct contention_task_data data = {};
186eca949b2SNamhyung Kim
1873477f079SNamhyung Kim BPF_CORE_READ_STR_INTO(&data.comm, task, comm);
188222de5e5SNamhyung Kim if (bpf_map_update_elem(&task_data, &pid, &data, BPF_NOEXIST) == -E2BIG)
189222de5e5SNamhyung Kim task_map_full = 1;
190eca949b2SNamhyung Kim }
1913477f079SNamhyung Kim
1923477f079SNamhyung Kim return 0;
193eca949b2SNamhyung Kim }
194eca949b2SNamhyung Kim
1951bece135SNamhyung Kim #ifndef __has_builtin
1961bece135SNamhyung Kim # define __has_builtin(x) 0
1971bece135SNamhyung Kim #endif
1981bece135SNamhyung Kim
get_lock_owner(__u64 lock,__u32 flags)1991bece135SNamhyung Kim static inline struct task_struct *get_lock_owner(__u64 lock, __u32 flags)
2001bece135SNamhyung Kim {
2011bece135SNamhyung Kim struct task_struct *task;
2021bece135SNamhyung Kim __u64 owner = 0;
2031bece135SNamhyung Kim
2041bece135SNamhyung Kim if (flags & LCB_F_MUTEX) {
2051bece135SNamhyung Kim struct mutex *mutex = (void *)lock;
2061bece135SNamhyung Kim owner = BPF_CORE_READ(mutex, owner.counter);
2071bece135SNamhyung Kim } else if (flags == LCB_F_READ || flags == LCB_F_WRITE) {
20817535a33SIan Rogers /*
20917535a33SIan Rogers * Support for the BPF_TYPE_MATCHES argument to the
21017535a33SIan Rogers * __builtin_preserve_type_info builtin was added at some point during
21117535a33SIan Rogers * development of clang 15 and it's what is needed for
21217535a33SIan Rogers * bpf_core_type_matches.
21317535a33SIan Rogers */
21417535a33SIan Rogers #if __has_builtin(__builtin_preserve_type_info) && __clang_major__ >= 15
2151bece135SNamhyung Kim if (bpf_core_type_matches(struct rw_semaphore___old)) {
2161bece135SNamhyung Kim struct rw_semaphore___old *rwsem = (void *)lock;
2171bece135SNamhyung Kim owner = (unsigned long)BPF_CORE_READ(rwsem, owner);
2181bece135SNamhyung Kim } else if (bpf_core_type_matches(struct rw_semaphore___new)) {
2191bece135SNamhyung Kim struct rw_semaphore___new *rwsem = (void *)lock;
2201bece135SNamhyung Kim owner = BPF_CORE_READ(rwsem, owner.counter);
2211bece135SNamhyung Kim }
2221bece135SNamhyung Kim #else
2231bece135SNamhyung Kim /* assume new struct */
2241bece135SNamhyung Kim struct rw_semaphore *rwsem = (void *)lock;
2251bece135SNamhyung Kim owner = BPF_CORE_READ(rwsem, owner.counter);
2261bece135SNamhyung Kim #endif
2271bece135SNamhyung Kim }
2281bece135SNamhyung Kim
2291bece135SNamhyung Kim if (!owner)
2301bece135SNamhyung Kim return NULL;
2311bece135SNamhyung Kim
2321bece135SNamhyung Kim task = (void *)(owner & ~7UL);
2331bece135SNamhyung Kim return task;
2341bece135SNamhyung Kim }
2351bece135SNamhyung Kim
check_lock_type(__u64 lock,__u32 flags)2363ace2435SNamhyung Kim static inline __u32 check_lock_type(__u64 lock, __u32 flags)
2373ace2435SNamhyung Kim {
2383ace2435SNamhyung Kim struct task_struct *curr;
2393ace2435SNamhyung Kim struct mm_struct___old *mm_old;
2403ace2435SNamhyung Kim struct mm_struct___new *mm_new;
241*c418d7a6SNamhyung Kim struct sighand_struct *sighand;
2423ace2435SNamhyung Kim
2433ace2435SNamhyung Kim switch (flags) {
2443ace2435SNamhyung Kim case LCB_F_READ: /* rwsem */
2453ace2435SNamhyung Kim case LCB_F_WRITE:
2463ace2435SNamhyung Kim curr = bpf_get_current_task_btf();
2473ace2435SNamhyung Kim if (curr->mm == NULL)
2483ace2435SNamhyung Kim break;
2493ace2435SNamhyung Kim mm_new = (void *)curr->mm;
2503ace2435SNamhyung Kim if (bpf_core_field_exists(mm_new->mmap_lock)) {
2513ace2435SNamhyung Kim if (&mm_new->mmap_lock == (void *)lock)
2523ace2435SNamhyung Kim return LCD_F_MMAP_LOCK;
2533ace2435SNamhyung Kim break;
2543ace2435SNamhyung Kim }
2553ace2435SNamhyung Kim mm_old = (void *)curr->mm;
2563ace2435SNamhyung Kim if (bpf_core_field_exists(mm_old->mmap_sem)) {
2573ace2435SNamhyung Kim if (&mm_old->mmap_sem == (void *)lock)
2583ace2435SNamhyung Kim return LCD_F_MMAP_LOCK;
2593ace2435SNamhyung Kim }
2603ace2435SNamhyung Kim break;
2611811e827SNamhyung Kim case LCB_F_SPIN: /* spinlock */
2621811e827SNamhyung Kim curr = bpf_get_current_task_btf();
263*c418d7a6SNamhyung Kim sighand = curr->sighand;
264*c418d7a6SNamhyung Kim
265*c418d7a6SNamhyung Kim if (sighand && &sighand->siglock == (void *)lock)
2661811e827SNamhyung Kim return LCD_F_SIGHAND_LOCK;
2671811e827SNamhyung Kim break;
2683ace2435SNamhyung Kim default:
2693ace2435SNamhyung Kim break;
2703ace2435SNamhyung Kim }
2713ace2435SNamhyung Kim return 0;
2723ace2435SNamhyung Kim }
2733ace2435SNamhyung Kim
274407b36f6SNamhyung Kim SEC("tp_btf/contention_begin")
contention_begin(u64 * ctx)275407b36f6SNamhyung Kim int contention_begin(u64 *ctx)
276407b36f6SNamhyung Kim {
277c66a36afSNamhyung Kim __u32 pid;
278407b36f6SNamhyung Kim struct tstamp_data *pelem;
279407b36f6SNamhyung Kim
280529772c4SNamhyung Kim if (!enabled || !can_record(ctx))
281407b36f6SNamhyung Kim return 0;
282407b36f6SNamhyung Kim
283c66a36afSNamhyung Kim pid = bpf_get_current_pid_tgid();
284c66a36afSNamhyung Kim pelem = bpf_map_lookup_elem(&tstamp, &pid);
285c66a36afSNamhyung Kim if (pelem && pelem->lock)
286407b36f6SNamhyung Kim return 0;
287407b36f6SNamhyung Kim
288c66a36afSNamhyung Kim if (pelem == NULL) {
289c66a36afSNamhyung Kim struct tstamp_data zero = {};
290c66a36afSNamhyung Kim
291c66a36afSNamhyung Kim bpf_map_update_elem(&tstamp, &pid, &zero, BPF_ANY);
292c66a36afSNamhyung Kim pelem = bpf_map_lookup_elem(&tstamp, &pid);
293c66a36afSNamhyung Kim if (pelem == NULL) {
29484c3a2bbSNamhyung Kim __sync_fetch_and_add(&task_fail, 1);
295c66a36afSNamhyung Kim return 0;
296c66a36afSNamhyung Kim }
297c66a36afSNamhyung Kim }
298c66a36afSNamhyung Kim
299407b36f6SNamhyung Kim pelem->timestamp = bpf_ktime_get_ns();
300407b36f6SNamhyung Kim pelem->lock = (__u64)ctx[0];
301407b36f6SNamhyung Kim pelem->flags = (__u32)ctx[1];
302407b36f6SNamhyung Kim
303ebab2916SNamhyung Kim if (needs_callstack) {
304eca949b2SNamhyung Kim pelem->stack_id = bpf_get_stackid(ctx, &stacks,
305eca949b2SNamhyung Kim BPF_F_FAST_STACK_CMP | stack_skip);
3066d499a6bSNamhyung Kim if (pelem->stack_id < 0)
30784c3a2bbSNamhyung Kim __sync_fetch_and_add(&stack_fail, 1);
3083477f079SNamhyung Kim } else if (aggr_mode == LOCK_AGGR_TASK) {
3093477f079SNamhyung Kim struct task_struct *task;
3103477f079SNamhyung Kim
3113477f079SNamhyung Kim if (lock_owner) {
3121bece135SNamhyung Kim task = get_lock_owner(pelem->lock, pelem->flags);
3133477f079SNamhyung Kim
3143477f079SNamhyung Kim /* The flags is not used anymore. Pass the owner pid. */
3153477f079SNamhyung Kim if (task)
3163477f079SNamhyung Kim pelem->flags = BPF_CORE_READ(task, pid);
3173477f079SNamhyung Kim else
3183477f079SNamhyung Kim pelem->flags = -1U;
3193477f079SNamhyung Kim
3203477f079SNamhyung Kim } else {
3213477f079SNamhyung Kim task = bpf_get_current_task_btf();
3223477f079SNamhyung Kim }
3233477f079SNamhyung Kim
3243477f079SNamhyung Kim if (task) {
3253477f079SNamhyung Kim if (update_task_data(task) < 0 && lock_owner)
3263477f079SNamhyung Kim pelem->flags = -1U;
3273477f079SNamhyung Kim }
328eca949b2SNamhyung Kim }
329eca949b2SNamhyung Kim
330407b36f6SNamhyung Kim return 0;
331407b36f6SNamhyung Kim }
332407b36f6SNamhyung Kim
333407b36f6SNamhyung Kim SEC("tp_btf/contention_end")
contention_end(u64 * ctx)334407b36f6SNamhyung Kim int contention_end(u64 *ctx)
335407b36f6SNamhyung Kim {
336c66a36afSNamhyung Kim __u32 pid;
337407b36f6SNamhyung Kim struct tstamp_data *pelem;
338ebab2916SNamhyung Kim struct contention_key key = {};
339407b36f6SNamhyung Kim struct contention_data *data;
340407b36f6SNamhyung Kim __u64 duration;
341407b36f6SNamhyung Kim
342407b36f6SNamhyung Kim if (!enabled)
343407b36f6SNamhyung Kim return 0;
344407b36f6SNamhyung Kim
345c66a36afSNamhyung Kim pid = bpf_get_current_pid_tgid();
346c66a36afSNamhyung Kim pelem = bpf_map_lookup_elem(&tstamp, &pid);
347407b36f6SNamhyung Kim if (!pelem || pelem->lock != ctx[0])
348407b36f6SNamhyung Kim return 0;
349407b36f6SNamhyung Kim
350407b36f6SNamhyung Kim duration = bpf_ktime_get_ns() - pelem->timestamp;
35184c3a2bbSNamhyung Kim if ((__s64)duration < 0) {
35284c3a2bbSNamhyung Kim bpf_map_delete_elem(&tstamp, &pid);
35384c3a2bbSNamhyung Kim __sync_fetch_and_add(&time_fail, 1);
35484c3a2bbSNamhyung Kim return 0;
35584c3a2bbSNamhyung Kim }
356407b36f6SNamhyung Kim
357688d2e8dSNamhyung Kim switch (aggr_mode) {
358688d2e8dSNamhyung Kim case LOCK_AGGR_CALLER:
359ebab2916SNamhyung Kim key.stack_id = pelem->stack_id;
360688d2e8dSNamhyung Kim break;
361688d2e8dSNamhyung Kim case LOCK_AGGR_TASK:
3623477f079SNamhyung Kim if (lock_owner)
3633477f079SNamhyung Kim key.pid = pelem->flags;
3643477f079SNamhyung Kim else
365ebab2916SNamhyung Kim key.pid = pid;
366ebab2916SNamhyung Kim if (needs_callstack)
367ebab2916SNamhyung Kim key.stack_id = pelem->stack_id;
368688d2e8dSNamhyung Kim break;
369688d2e8dSNamhyung Kim case LOCK_AGGR_ADDR:
370ebab2916SNamhyung Kim key.lock_addr = pelem->lock;
371ebab2916SNamhyung Kim if (needs_callstack)
372ebab2916SNamhyung Kim key.stack_id = pelem->stack_id;
373688d2e8dSNamhyung Kim break;
374688d2e8dSNamhyung Kim default:
375688d2e8dSNamhyung Kim /* should not happen */
376688d2e8dSNamhyung Kim return 0;
377eca949b2SNamhyung Kim }
378eca949b2SNamhyung Kim
379407b36f6SNamhyung Kim data = bpf_map_lookup_elem(&lock_stat, &key);
380407b36f6SNamhyung Kim if (!data) {
381222de5e5SNamhyung Kim if (data_map_full) {
382222de5e5SNamhyung Kim bpf_map_delete_elem(&tstamp, &pid);
383222de5e5SNamhyung Kim __sync_fetch_and_add(&data_fail, 1);
384222de5e5SNamhyung Kim return 0;
385222de5e5SNamhyung Kim }
386222de5e5SNamhyung Kim
387407b36f6SNamhyung Kim struct contention_data first = {
388407b36f6SNamhyung Kim .total_time = duration,
389407b36f6SNamhyung Kim .max_time = duration,
390407b36f6SNamhyung Kim .min_time = duration,
391407b36f6SNamhyung Kim .count = 1,
392407b36f6SNamhyung Kim .flags = pelem->flags,
393407b36f6SNamhyung Kim };
394222de5e5SNamhyung Kim int err;
395407b36f6SNamhyung Kim
3963ace2435SNamhyung Kim if (aggr_mode == LOCK_AGGR_ADDR)
3973ace2435SNamhyung Kim first.flags |= check_lock_type(pelem->lock, pelem->flags);
3983ace2435SNamhyung Kim
399222de5e5SNamhyung Kim err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
400222de5e5SNamhyung Kim if (err < 0) {
401222de5e5SNamhyung Kim if (err == -E2BIG)
402222de5e5SNamhyung Kim data_map_full = 1;
403954cdac7SNamhyung Kim __sync_fetch_and_add(&data_fail, 1);
404222de5e5SNamhyung Kim }
405c66a36afSNamhyung Kim bpf_map_delete_elem(&tstamp, &pid);
406407b36f6SNamhyung Kim return 0;
407407b36f6SNamhyung Kim }
408407b36f6SNamhyung Kim
409407b36f6SNamhyung Kim __sync_fetch_and_add(&data->total_time, duration);
410407b36f6SNamhyung Kim __sync_fetch_and_add(&data->count, 1);
411407b36f6SNamhyung Kim
412407b36f6SNamhyung Kim /* FIXME: need atomic operations */
413407b36f6SNamhyung Kim if (data->max_time < duration)
414407b36f6SNamhyung Kim data->max_time = duration;
415407b36f6SNamhyung Kim if (data->min_time > duration)
416407b36f6SNamhyung Kim data->min_time = duration;
417407b36f6SNamhyung Kim
418c66a36afSNamhyung Kim bpf_map_delete_elem(&tstamp, &pid);
419407b36f6SNamhyung Kim return 0;
420407b36f6SNamhyung Kim }
421407b36f6SNamhyung Kim
422d24c0144SNamhyung Kim extern struct rq runqueues __ksym;
423d24c0144SNamhyung Kim
424e53de7b6SNamhyung Kim struct rq___old {
4250c122848SIan Rogers raw_spinlock_t lock;
4260c122848SIan Rogers } __attribute__((preserve_access_index));
4270c122848SIan Rogers
428e53de7b6SNamhyung Kim struct rq___new {
4290c122848SIan Rogers raw_spinlock_t __lock;
4300c122848SIan Rogers } __attribute__((preserve_access_index));
4310c122848SIan Rogers
432d24c0144SNamhyung Kim SEC("raw_tp/bpf_test_finish")
BPF_PROG(collect_lock_syms)433d24c0144SNamhyung Kim int BPF_PROG(collect_lock_syms)
434d24c0144SNamhyung Kim {
435b9f82b5cSNamhyung Kim __u64 lock_addr, lock_off;
436d24c0144SNamhyung Kim __u32 lock_flag;
437d24c0144SNamhyung Kim
438b9f82b5cSNamhyung Kim if (bpf_core_field_exists(struct rq___new, __lock))
439b9f82b5cSNamhyung Kim lock_off = offsetof(struct rq___new, __lock);
440b9f82b5cSNamhyung Kim else
441b9f82b5cSNamhyung Kim lock_off = offsetof(struct rq___old, lock);
442b9f82b5cSNamhyung Kim
443d24c0144SNamhyung Kim for (int i = 0; i < MAX_CPUS; i++) {
444d24c0144SNamhyung Kim struct rq *rq = bpf_per_cpu_ptr(&runqueues, i);
445d24c0144SNamhyung Kim
446d24c0144SNamhyung Kim if (rq == NULL)
447d24c0144SNamhyung Kim break;
448d24c0144SNamhyung Kim
449b9f82b5cSNamhyung Kim lock_addr = (__u64)(void *)rq + lock_off;
450d24c0144SNamhyung Kim lock_flag = LOCK_CLASS_RQLOCK;
451d24c0144SNamhyung Kim bpf_map_update_elem(&lock_syms, &lock_addr, &lock_flag, BPF_ANY);
452d24c0144SNamhyung Kim }
453d24c0144SNamhyung Kim return 0;
454d24c0144SNamhyung Kim }
455d24c0144SNamhyung Kim
456407b36f6SNamhyung Kim char LICENSE[] SEC("license") = "Dual BSD/GPL";
457