162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci// Copyright (c) 2022 Google
362306a36Sopenharmony_ci#include "vmlinux.h"
462306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
562306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
662306a36Sopenharmony_ci#include <bpf/bpf_core_read.h>
762306a36Sopenharmony_ci#include <asm-generic/errno-base.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "lock_data.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* for collect_lock_syms().  4096 was rejected by the verifier */
1262306a36Sopenharmony_ci#define MAX_CPUS  1024
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* lock contention flags from include/trace/events/lock.h */
1562306a36Sopenharmony_ci#define LCB_F_SPIN	(1U << 0)
1662306a36Sopenharmony_ci#define LCB_F_READ	(1U << 1)
1762306a36Sopenharmony_ci#define LCB_F_WRITE	(1U << 2)
1862306a36Sopenharmony_ci#define LCB_F_RT	(1U << 3)
1962306a36Sopenharmony_ci#define LCB_F_PERCPU	(1U << 4)
2062306a36Sopenharmony_ci#define LCB_F_MUTEX	(1U << 5)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct tstamp_data {
2362306a36Sopenharmony_ci	__u64 timestamp;
2462306a36Sopenharmony_ci	__u64 lock;
2562306a36Sopenharmony_ci	__u32 flags;
2662306a36Sopenharmony_ci	__s32 stack_id;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* callstack storage  */
3062306a36Sopenharmony_cistruct {
3162306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_STACK_TRACE);
3262306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
3362306a36Sopenharmony_ci	__uint(value_size, sizeof(__u64));
3462306a36Sopenharmony_ci	__uint(max_entries, MAX_ENTRIES);
3562306a36Sopenharmony_ci} stacks SEC(".maps");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* maintain timestamp at the beginning of contention */
3862306a36Sopenharmony_cistruct {
3962306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
4062306a36Sopenharmony_ci	__type(key, int);
4162306a36Sopenharmony_ci	__type(value, struct tstamp_data);
4262306a36Sopenharmony_ci	__uint(max_entries, MAX_ENTRIES);
4362306a36Sopenharmony_ci} tstamp SEC(".maps");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* actual lock contention statistics */
4662306a36Sopenharmony_cistruct {
4762306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
4862306a36Sopenharmony_ci	__uint(key_size, sizeof(struct contention_key));
4962306a36Sopenharmony_ci	__uint(value_size, sizeof(struct contention_data));
5062306a36Sopenharmony_ci	__uint(max_entries, MAX_ENTRIES);
5162306a36Sopenharmony_ci} lock_stat SEC(".maps");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct {
5462306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
5562306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
5662306a36Sopenharmony_ci	__uint(value_size, sizeof(struct contention_task_data));
5762306a36Sopenharmony_ci	__uint(max_entries, MAX_ENTRIES);
5862306a36Sopenharmony_ci} task_data SEC(".maps");
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct {
6162306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
6262306a36Sopenharmony_ci	__uint(key_size, sizeof(__u64));
6362306a36Sopenharmony_ci	__uint(value_size, sizeof(__u32));
6462306a36Sopenharmony_ci	__uint(max_entries, MAX_ENTRIES);
6562306a36Sopenharmony_ci} lock_syms SEC(".maps");
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct {
6862306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
6962306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
7062306a36Sopenharmony_ci	__uint(value_size, sizeof(__u8));
7162306a36Sopenharmony_ci	__uint(max_entries, 1);
7262306a36Sopenharmony_ci} cpu_filter SEC(".maps");
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct {
7562306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
7662306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
7762306a36Sopenharmony_ci	__uint(value_size, sizeof(__u8));
7862306a36Sopenharmony_ci	__uint(max_entries, 1);
7962306a36Sopenharmony_ci} task_filter SEC(".maps");
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct {
8262306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
8362306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
8462306a36Sopenharmony_ci	__uint(value_size, sizeof(__u8));
8562306a36Sopenharmony_ci	__uint(max_entries, 1);
8662306a36Sopenharmony_ci} type_filter SEC(".maps");
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct {
8962306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
9062306a36Sopenharmony_ci	__uint(key_size, sizeof(__u64));
9162306a36Sopenharmony_ci	__uint(value_size, sizeof(__u8));
9262306a36Sopenharmony_ci	__uint(max_entries, 1);
9362306a36Sopenharmony_ci} addr_filter SEC(".maps");
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct rw_semaphore___old {
9662306a36Sopenharmony_ci	struct task_struct *owner;
9762306a36Sopenharmony_ci} __attribute__((preserve_access_index));
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistruct rw_semaphore___new {
10062306a36Sopenharmony_ci	atomic_long_t owner;
10162306a36Sopenharmony_ci} __attribute__((preserve_access_index));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistruct mm_struct___old {
10462306a36Sopenharmony_ci	struct rw_semaphore mmap_sem;
10562306a36Sopenharmony_ci} __attribute__((preserve_access_index));
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistruct mm_struct___new {
10862306a36Sopenharmony_ci	struct rw_semaphore mmap_lock;
10962306a36Sopenharmony_ci} __attribute__((preserve_access_index));
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* control flags */
11262306a36Sopenharmony_ciint enabled;
11362306a36Sopenharmony_ciint has_cpu;
11462306a36Sopenharmony_ciint has_task;
11562306a36Sopenharmony_ciint has_type;
11662306a36Sopenharmony_ciint has_addr;
11762306a36Sopenharmony_ciint needs_callstack;
11862306a36Sopenharmony_ciint stack_skip;
11962306a36Sopenharmony_ciint lock_owner;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* determine the key of lock stat */
12262306a36Sopenharmony_ciint aggr_mode;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* error stat */
12562306a36Sopenharmony_ciint task_fail;
12662306a36Sopenharmony_ciint stack_fail;
12762306a36Sopenharmony_ciint time_fail;
12862306a36Sopenharmony_ciint data_fail;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciint task_map_full;
13162306a36Sopenharmony_ciint data_map_full;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline int can_record(u64 *ctx)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	if (has_cpu) {
13662306a36Sopenharmony_ci		__u32 cpu = bpf_get_smp_processor_id();
13762306a36Sopenharmony_ci		__u8 *ok;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		ok = bpf_map_lookup_elem(&cpu_filter, &cpu);
14062306a36Sopenharmony_ci		if (!ok)
14162306a36Sopenharmony_ci			return 0;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (has_task) {
14562306a36Sopenharmony_ci		__u8 *ok;
14662306a36Sopenharmony_ci		__u32 pid = bpf_get_current_pid_tgid();
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		ok = bpf_map_lookup_elem(&task_filter, &pid);
14962306a36Sopenharmony_ci		if (!ok)
15062306a36Sopenharmony_ci			return 0;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (has_type) {
15462306a36Sopenharmony_ci		__u8 *ok;
15562306a36Sopenharmony_ci		__u32 flags = (__u32)ctx[1];
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		ok = bpf_map_lookup_elem(&type_filter, &flags);
15862306a36Sopenharmony_ci		if (!ok)
15962306a36Sopenharmony_ci			return 0;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (has_addr) {
16362306a36Sopenharmony_ci		__u8 *ok;
16462306a36Sopenharmony_ci		__u64 addr = ctx[0];
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		ok = bpf_map_lookup_elem(&addr_filter, &addr);
16762306a36Sopenharmony_ci		if (!ok)
16862306a36Sopenharmony_ci			return 0;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return 1;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic inline int update_task_data(struct task_struct *task)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct contention_task_data *p;
17762306a36Sopenharmony_ci	int pid, err;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	err = bpf_core_read(&pid, sizeof(pid), &task->pid);
18062306a36Sopenharmony_ci	if (err)
18162306a36Sopenharmony_ci		return -1;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	p = bpf_map_lookup_elem(&task_data, &pid);
18462306a36Sopenharmony_ci	if (p == NULL && !task_map_full) {
18562306a36Sopenharmony_ci		struct contention_task_data data = {};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		BPF_CORE_READ_STR_INTO(&data.comm, task, comm);
18862306a36Sopenharmony_ci		if (bpf_map_update_elem(&task_data, &pid, &data, BPF_NOEXIST) == -E2BIG)
18962306a36Sopenharmony_ci			task_map_full = 1;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#ifndef __has_builtin
19662306a36Sopenharmony_ci# define __has_builtin(x) 0
19762306a36Sopenharmony_ci#endif
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic inline struct task_struct *get_lock_owner(__u64 lock, __u32 flags)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct task_struct *task;
20262306a36Sopenharmony_ci	__u64 owner = 0;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (flags & LCB_F_MUTEX) {
20562306a36Sopenharmony_ci		struct mutex *mutex = (void *)lock;
20662306a36Sopenharmony_ci		owner = BPF_CORE_READ(mutex, owner.counter);
20762306a36Sopenharmony_ci	} else if (flags == LCB_F_READ || flags == LCB_F_WRITE) {
20862306a36Sopenharmony_ci	/*
20962306a36Sopenharmony_ci	 * Support for the BPF_TYPE_MATCHES argument to the
21062306a36Sopenharmony_ci	 * __builtin_preserve_type_info builtin was added at some point during
21162306a36Sopenharmony_ci	 * development of clang 15 and it's what is needed for
21262306a36Sopenharmony_ci	 * bpf_core_type_matches.
21362306a36Sopenharmony_ci	 */
21462306a36Sopenharmony_ci#if __has_builtin(__builtin_preserve_type_info) && __clang_major__ >= 15
21562306a36Sopenharmony_ci		if (bpf_core_type_matches(struct rw_semaphore___old)) {
21662306a36Sopenharmony_ci			struct rw_semaphore___old *rwsem = (void *)lock;
21762306a36Sopenharmony_ci			owner = (unsigned long)BPF_CORE_READ(rwsem, owner);
21862306a36Sopenharmony_ci		} else if (bpf_core_type_matches(struct rw_semaphore___new)) {
21962306a36Sopenharmony_ci			struct rw_semaphore___new *rwsem = (void *)lock;
22062306a36Sopenharmony_ci			owner = BPF_CORE_READ(rwsem, owner.counter);
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci#else
22362306a36Sopenharmony_ci		/* assume new struct */
22462306a36Sopenharmony_ci		struct rw_semaphore *rwsem = (void *)lock;
22562306a36Sopenharmony_ci		owner = BPF_CORE_READ(rwsem, owner.counter);
22662306a36Sopenharmony_ci#endif
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (!owner)
23062306a36Sopenharmony_ci		return NULL;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	task = (void *)(owner & ~7UL);
23362306a36Sopenharmony_ci	return task;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic inline __u32 check_lock_type(__u64 lock, __u32 flags)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct task_struct *curr;
23962306a36Sopenharmony_ci	struct mm_struct___old *mm_old;
24062306a36Sopenharmony_ci	struct mm_struct___new *mm_new;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	switch (flags) {
24362306a36Sopenharmony_ci	case LCB_F_READ:  /* rwsem */
24462306a36Sopenharmony_ci	case LCB_F_WRITE:
24562306a36Sopenharmony_ci		curr = bpf_get_current_task_btf();
24662306a36Sopenharmony_ci		if (curr->mm == NULL)
24762306a36Sopenharmony_ci			break;
24862306a36Sopenharmony_ci		mm_new = (void *)curr->mm;
24962306a36Sopenharmony_ci		if (bpf_core_field_exists(mm_new->mmap_lock)) {
25062306a36Sopenharmony_ci			if (&mm_new->mmap_lock == (void *)lock)
25162306a36Sopenharmony_ci				return LCD_F_MMAP_LOCK;
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		mm_old = (void *)curr->mm;
25562306a36Sopenharmony_ci		if (bpf_core_field_exists(mm_old->mmap_sem)) {
25662306a36Sopenharmony_ci			if (&mm_old->mmap_sem == (void *)lock)
25762306a36Sopenharmony_ci				return LCD_F_MMAP_LOCK;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci		break;
26062306a36Sopenharmony_ci	case LCB_F_SPIN:  /* spinlock */
26162306a36Sopenharmony_ci		curr = bpf_get_current_task_btf();
26262306a36Sopenharmony_ci		if (&curr->sighand->siglock == (void *)lock)
26362306a36Sopenharmony_ci			return LCD_F_SIGHAND_LOCK;
26462306a36Sopenharmony_ci		break;
26562306a36Sopenharmony_ci	default:
26662306a36Sopenharmony_ci		break;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	return 0;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ciSEC("tp_btf/contention_begin")
27262306a36Sopenharmony_ciint contention_begin(u64 *ctx)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	__u32 pid;
27562306a36Sopenharmony_ci	struct tstamp_data *pelem;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (!enabled || !can_record(ctx))
27862306a36Sopenharmony_ci		return 0;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	pid = bpf_get_current_pid_tgid();
28162306a36Sopenharmony_ci	pelem = bpf_map_lookup_elem(&tstamp, &pid);
28262306a36Sopenharmony_ci	if (pelem && pelem->lock)
28362306a36Sopenharmony_ci		return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (pelem == NULL) {
28662306a36Sopenharmony_ci		struct tstamp_data zero = {};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		bpf_map_update_elem(&tstamp, &pid, &zero, BPF_ANY);
28962306a36Sopenharmony_ci		pelem = bpf_map_lookup_elem(&tstamp, &pid);
29062306a36Sopenharmony_ci		if (pelem == NULL) {
29162306a36Sopenharmony_ci			__sync_fetch_and_add(&task_fail, 1);
29262306a36Sopenharmony_ci			return 0;
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	pelem->timestamp = bpf_ktime_get_ns();
29762306a36Sopenharmony_ci	pelem->lock = (__u64)ctx[0];
29862306a36Sopenharmony_ci	pelem->flags = (__u32)ctx[1];
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (needs_callstack) {
30162306a36Sopenharmony_ci		pelem->stack_id = bpf_get_stackid(ctx, &stacks,
30262306a36Sopenharmony_ci						  BPF_F_FAST_STACK_CMP | stack_skip);
30362306a36Sopenharmony_ci		if (pelem->stack_id < 0)
30462306a36Sopenharmony_ci			__sync_fetch_and_add(&stack_fail, 1);
30562306a36Sopenharmony_ci	} else if (aggr_mode == LOCK_AGGR_TASK) {
30662306a36Sopenharmony_ci		struct task_struct *task;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		if (lock_owner) {
30962306a36Sopenharmony_ci			task = get_lock_owner(pelem->lock, pelem->flags);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci			/* The flags is not used anymore.  Pass the owner pid. */
31262306a36Sopenharmony_ci			if (task)
31362306a36Sopenharmony_ci				pelem->flags = BPF_CORE_READ(task, pid);
31462306a36Sopenharmony_ci			else
31562306a36Sopenharmony_ci				pelem->flags = -1U;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		} else {
31862306a36Sopenharmony_ci			task = bpf_get_current_task_btf();
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		if (task) {
32262306a36Sopenharmony_ci			if (update_task_data(task) < 0 && lock_owner)
32362306a36Sopenharmony_ci				pelem->flags = -1U;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return 0;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciSEC("tp_btf/contention_end")
33162306a36Sopenharmony_ciint contention_end(u64 *ctx)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	__u32 pid;
33462306a36Sopenharmony_ci	struct tstamp_data *pelem;
33562306a36Sopenharmony_ci	struct contention_key key = {};
33662306a36Sopenharmony_ci	struct contention_data *data;
33762306a36Sopenharmony_ci	__u64 duration;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!enabled)
34062306a36Sopenharmony_ci		return 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	pid = bpf_get_current_pid_tgid();
34362306a36Sopenharmony_ci	pelem = bpf_map_lookup_elem(&tstamp, &pid);
34462306a36Sopenharmony_ci	if (!pelem || pelem->lock != ctx[0])
34562306a36Sopenharmony_ci		return 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	duration = bpf_ktime_get_ns() - pelem->timestamp;
34862306a36Sopenharmony_ci	if ((__s64)duration < 0) {
34962306a36Sopenharmony_ci		bpf_map_delete_elem(&tstamp, &pid);
35062306a36Sopenharmony_ci		__sync_fetch_and_add(&time_fail, 1);
35162306a36Sopenharmony_ci		return 0;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	switch (aggr_mode) {
35562306a36Sopenharmony_ci	case LOCK_AGGR_CALLER:
35662306a36Sopenharmony_ci		key.stack_id = pelem->stack_id;
35762306a36Sopenharmony_ci		break;
35862306a36Sopenharmony_ci	case LOCK_AGGR_TASK:
35962306a36Sopenharmony_ci		if (lock_owner)
36062306a36Sopenharmony_ci			key.pid = pelem->flags;
36162306a36Sopenharmony_ci		else
36262306a36Sopenharmony_ci			key.pid = pid;
36362306a36Sopenharmony_ci		if (needs_callstack)
36462306a36Sopenharmony_ci			key.stack_id = pelem->stack_id;
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	case LOCK_AGGR_ADDR:
36762306a36Sopenharmony_ci		key.lock_addr = pelem->lock;
36862306a36Sopenharmony_ci		if (needs_callstack)
36962306a36Sopenharmony_ci			key.stack_id = pelem->stack_id;
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	default:
37262306a36Sopenharmony_ci		/* should not happen */
37362306a36Sopenharmony_ci		return 0;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	data = bpf_map_lookup_elem(&lock_stat, &key);
37762306a36Sopenharmony_ci	if (!data) {
37862306a36Sopenharmony_ci		if (data_map_full) {
37962306a36Sopenharmony_ci			bpf_map_delete_elem(&tstamp, &pid);
38062306a36Sopenharmony_ci			__sync_fetch_and_add(&data_fail, 1);
38162306a36Sopenharmony_ci			return 0;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		struct contention_data first = {
38562306a36Sopenharmony_ci			.total_time = duration,
38662306a36Sopenharmony_ci			.max_time = duration,
38762306a36Sopenharmony_ci			.min_time = duration,
38862306a36Sopenharmony_ci			.count = 1,
38962306a36Sopenharmony_ci			.flags = pelem->flags,
39062306a36Sopenharmony_ci		};
39162306a36Sopenharmony_ci		int err;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		if (aggr_mode == LOCK_AGGR_ADDR)
39462306a36Sopenharmony_ci			first.flags |= check_lock_type(pelem->lock, pelem->flags);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
39762306a36Sopenharmony_ci		if (err < 0) {
39862306a36Sopenharmony_ci			if (err == -E2BIG)
39962306a36Sopenharmony_ci				data_map_full = 1;
40062306a36Sopenharmony_ci			__sync_fetch_and_add(&data_fail, 1);
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		bpf_map_delete_elem(&tstamp, &pid);
40362306a36Sopenharmony_ci		return 0;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	__sync_fetch_and_add(&data->total_time, duration);
40762306a36Sopenharmony_ci	__sync_fetch_and_add(&data->count, 1);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* FIXME: need atomic operations */
41062306a36Sopenharmony_ci	if (data->max_time < duration)
41162306a36Sopenharmony_ci		data->max_time = duration;
41262306a36Sopenharmony_ci	if (data->min_time > duration)
41362306a36Sopenharmony_ci		data->min_time = duration;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	bpf_map_delete_elem(&tstamp, &pid);
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciextern struct rq runqueues __ksym;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistruct rq___old {
42262306a36Sopenharmony_ci	raw_spinlock_t lock;
42362306a36Sopenharmony_ci} __attribute__((preserve_access_index));
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistruct rq___new {
42662306a36Sopenharmony_ci	raw_spinlock_t __lock;
42762306a36Sopenharmony_ci} __attribute__((preserve_access_index));
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ciSEC("raw_tp/bpf_test_finish")
43062306a36Sopenharmony_ciint BPF_PROG(collect_lock_syms)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	__u64 lock_addr, lock_off;
43362306a36Sopenharmony_ci	__u32 lock_flag;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (bpf_core_field_exists(struct rq___new, __lock))
43662306a36Sopenharmony_ci		lock_off = offsetof(struct rq___new, __lock);
43762306a36Sopenharmony_ci	else
43862306a36Sopenharmony_ci		lock_off = offsetof(struct rq___old, lock);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (int i = 0; i < MAX_CPUS; i++) {
44162306a36Sopenharmony_ci		struct rq *rq = bpf_per_cpu_ptr(&runqueues, i);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		if (rq == NULL)
44462306a36Sopenharmony_ci			break;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		lock_addr = (__u64)(void *)rq + lock_off;
44762306a36Sopenharmony_ci		lock_flag = LOCK_CLASS_RQLOCK;
44862306a36Sopenharmony_ci		bpf_map_update_elem(&lock_syms, &lock_addr, &lock_flag, BPF_ANY);
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL";
454