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