Skip to content

Commit

Permalink
libbpf-tools/klockstat: Fallback to kprobe if fentry is not available
Browse files Browse the repository at this point in the history
If fentry is not available, let's fallback to kprobe instead. This would
allows the tool to run on old kernels or architectures without BPF trampoline.

Signed-off-by: Hengqi Chen <[email protected]>
  • Loading branch information
chenhengqi authored and yonghong-song committed Sep 11, 2022
1 parent bfc8252 commit dfb0d98
Show file tree
Hide file tree
Showing 4 changed files with 442 additions and 44 deletions.
338 changes: 336 additions & 2 deletions libbpf-tools/klockstat.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ struct {
__type(value, struct lock_stat);
} stat_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, u32);
__type(value, void *);
} locks SEC(".maps");

static bool tracing_task(u64 task_id)
{
u32 tgid = task_id >> 32;
Expand Down Expand Up @@ -98,8 +105,8 @@ static void lock_contended(void *ctx, void *lock)
* Note: if you make major changes to this bpf program, double check
* that you aren't skipping too many frames.
*/
li->stack_id = bpf_get_stackid(ctx, &stack_map,
4 | BPF_F_FAST_STACK_CMP);
li->stack_id = bpf_get_stackid(ctx, &stack_map, 4 | BPF_F_FAST_STACK_CMP);

/* Legit failures include EEXIST */
if (li->stack_id < 0)
return;
Expand Down Expand Up @@ -405,4 +412,331 @@ int BPF_PROG(up_write, struct rw_semaphore *lock)
return 0;
}

SEC("kprobe/mutex_lock")
int BPF_KPROBE(kprobe_mutex_lock, struct mutex *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/mutex_lock")
int BPF_KRETPROBE(kprobe_mutex_lock_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);
lock_acquired(*lock);
return 0;
}

SEC("kprobe/mutex_trylock")
int BPF_KPROBE(kprobe_mutex_trylock, struct mutex *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
return 0;
}

SEC("kretprobe/mutex_trylock")
int BPF_KRETPROBE(kprobe_mutex_trylock_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret) {
lock_contended(ctx, *lock);
lock_acquired(*lock);
}
return 0;
}

SEC("kprobe/mutex_lock_interruptible")
int BPF_KPROBE(kprobe_mutex_lock_interruptible, struct mutex *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/mutex_lock_interruptible")
int BPF_KRETPROBE(kprobe_mutex_lock_interruptible_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret)
lock_aborted(*lock);
else
lock_acquired(*lock);
return 0;
}

SEC("kprobe/mutex_lock_killable")
int BPF_KPROBE(kprobe_mutex_lock_killable, struct mutex *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/mutex_lock_killable")
int BPF_KRETPROBE(kprobe_mutex_lock_killable_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret)
lock_aborted(*lock);
else
lock_acquired(*lock);
return 0;
}

SEC("kprobe/mutex_unlock")
int BPF_KPROBE(kprobe_mutex_unlock, struct mutex *lock)
{
lock_released(lock);
return 0;
}

SEC("kprobe/down_read")
int BPF_KPROBE(kprobe_down_read, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/down_read")
int BPF_KRETPROBE(kprobe_down_read_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

lock_acquired(*lock);
return 0;
}

SEC("kprobe/down_read_trylock")
int BPF_KPROBE(kprobe_down_read_trylock, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
return 0;
}

SEC("kretprobe/down_read_trylock")
int BPF_KRETPROBE(kprobe_down_read_trylock_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret == 1) {
lock_contended(ctx, *lock);
lock_acquired(*lock);
}
return 0;
}

SEC("kprobe/down_read_interruptible")
int BPF_KPROBE(kprobe_down_read_interruptible, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/down_read_interruptible")
int BPF_KRETPROBE(kprobe_down_read_interruptible_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret)
lock_aborted(*lock);
else
lock_acquired(*lock);
return 0;
}

SEC("kprobe/down_read_killable")
int BPF_KPROBE(kprobe_down_read_killable, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/down_read_killable")
int BPF_KRETPROBE(kprobe_down_read_killable_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret)
lock_aborted(*lock);
else
lock_acquired(*lock);
return 0;
}

SEC("kprobe/up_read")
int BPF_KPROBE(kprobe_up_read, struct rw_semaphore *lock)
{
lock_released(lock);
return 0;
}

SEC("kprobe/down_write")
int BPF_KPROBE(kprobe_down_write, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/down_write")
int BPF_KRETPROBE(kprobe_down_write_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

lock_acquired(*lock);
return 0;
}

SEC("kprobe/down_write_trylock")
int BPF_KPROBE(kprobe_down_write_trylock, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
return 0;
}

SEC("kretprobe/down_write_trylock")
int BPF_KRETPROBE(kprobe_down_write_trylock_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret == 1) {
lock_contended(ctx, *lock);
lock_acquired(*lock);
}
return 0;
}

SEC("kprobe/down_write_killable")
int BPF_KPROBE(kprobe_down_write_killable, struct rw_semaphore *lock)
{
u32 tid = (u32)bpf_get_current_pid_tgid();

bpf_map_update_elem(&locks, &tid, &lock, BPF_ANY);
lock_contended(ctx, lock);
return 0;
}

SEC("kretprobe/down_write_killable")
int BPF_KRETPROBE(kprobe_down_write_killable_exit, long ret)
{
u32 tid = (u32)bpf_get_current_pid_tgid();
void **lock;

lock = bpf_map_lookup_elem(&locks, &tid);
if (!lock)
return 0;

bpf_map_delete_elem(&locks, &tid);

if (ret)
lock_aborted(*lock);
else
lock_acquired(*lock);
return 0;
}

SEC("kprobe/up_write")
int BPF_KPROBE(kprobe_up_write, struct rw_semaphore *lock)
{
lock_released(lock);
return 0;
}

char LICENSE[] SEC("license") = "GPL";
Loading

0 comments on commit dfb0d98

Please sign in to comment.