Files
bpf-developer-tutorial/src/features/bpf_iters/task_stack.bpf.c
yunwei37 b88ab2ae0e Add BPF Workqueues support and example
- Introduced BPF workqueues to enable asynchronous work from BPF programs, allowing deferred processing, non-blocking operations, and sleepable contexts for long-running tasks.
- Added README.md to document the BPF workqueues, including use cases, technical architecture, and code examples.
- Created bpf_experimental.h header file to define necessary BPF workqueue functions and structures.
- Implemented a simple BPF workqueue example (wq_simple) demonstrating the initialization, scheduling, and execution of work in a separate context.
- Developed a userspace test (wq_simple.c) to verify the functionality of the BPF workqueue by triggering a syscall and checking the execution results.
2025-10-04 22:49:09 -07:00

119 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Kernel task stack and file descriptor iterator */
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
char _license[] SEC("license") = "GPL";
#define MAX_STACK_TRACE_DEPTH 64
unsigned long entries[MAX_STACK_TRACE_DEPTH] = {};
#define SIZE_OF_ULONG (sizeof(unsigned long))
/* Filter: only show stacks for tasks with this name (empty = show all) */
char target_comm[16] = "";
__u32 stacks_shown = 0;
__u32 files_shown = 0;
/* Task stack iterator */
SEC("iter/task")
int dump_task_stack(struct bpf_iter__task *ctx)
{
struct seq_file *seq = ctx->meta->seq;
struct task_struct *task = ctx->task;
long i, retlen;
int match = 1;
if (task == (void *)0) {
/* End of iteration - print summary */
if (stacks_shown > 0) {
BPF_SEQ_PRINTF(seq, "\n=== Summary: %u task stacks shown ===\n",
stacks_shown);
}
return 0;
}
/* Filter by task name if specified */
if (target_comm[0] != '\0') {
match = 0;
for (i = 0; i < 16; i++) {
if (task->comm[i] != target_comm[i])
break;
if (task->comm[i] == '\0') {
match = 1;
break;
}
}
if (!match)
return 0;
}
/* Get kernel stack trace for this task */
retlen = bpf_get_task_stack(task, entries,
MAX_STACK_TRACE_DEPTH * SIZE_OF_ULONG, 0);
if (retlen < 0)
return 0;
stacks_shown++;
/* Print task info and stack trace */
BPF_SEQ_PRINTF(seq, "=== Task: %s (pid=%u, tgid=%u) ===\n",
task->comm, task->pid, task->tgid);
BPF_SEQ_PRINTF(seq, "Stack depth: %u frames\n", retlen / SIZE_OF_ULONG);
for (i = 0; i < MAX_STACK_TRACE_DEPTH; i++) {
if (retlen > i * SIZE_OF_ULONG)
BPF_SEQ_PRINTF(seq, " [%2ld] %pB\n", i, (void *)entries[i]);
}
BPF_SEQ_PRINTF(seq, "\n");
return 0;
}
/* Task file descriptor iterator */
SEC("iter/task_file")
int dump_task_file(struct bpf_iter__task_file *ctx)
{
struct seq_file *seq = ctx->meta->seq;
struct task_struct *task = ctx->task;
struct file *file = ctx->file;
__u32 fd = ctx->fd;
long i;
int match = 1;
if (task == (void *)0 || file == (void *)0) {
if (files_shown > 0 && ctx->meta->seq_num > 0) {
BPF_SEQ_PRINTF(seq, "\n=== Summary: %u file descriptors shown ===\n",
files_shown);
}
return 0;
}
/* Filter by task name if specified */
if (target_comm[0] != '\0') {
match = 0;
for (i = 0; i < 16; i++) {
if (task->comm[i] != target_comm[i])
break;
if (task->comm[i] == '\0') {
match = 1;
break;
}
}
if (!match)
return 0;
}
if (ctx->meta->seq_num == 0) {
BPF_SEQ_PRINTF(seq, "%-16s %8s %8s %6s %s\n",
"COMM", "TGID", "PID", "FD", "FILE_OPS");
}
files_shown++;
BPF_SEQ_PRINTF(seq, "%-16s %8d %8d %6d 0x%lx\n",
task->comm, task->tgid, task->pid, fd,
(long)file->f_op);
return 0;
}