github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/fsslower/tracer/bpf/fsslower.bpf.c (about)

     1  /* SPDX-License-Identifier: GPL-2.0 */
     2  /* Copyright (c) 2020 Wenbo Zhang */
     3  #include <vmlinux.h>
     4  #include <bpf/bpf_helpers.h>
     5  #include <bpf/bpf_core_read.h>
     6  #include <bpf/bpf_tracing.h>
     7  #include "fsslower.h"
     8  #include <gadget/mntns_filter.h>
     9  
    10  #define MAX_ENTRIES 8192
    11  
    12  const volatile pid_t target_pid = 0;
    13  const volatile __u64 min_lat_ns = 0;
    14  
    15  // we need this to make sure the compiler doesn't remove our struct
    16  const struct event *unusedevent __attribute__((unused));
    17  
    18  struct data_key {
    19  	__u32 tid;
    20  	/*
    21  	 * We need to take into account the operation to avoid losing some of
    22  	 * them.
    23  	 * Indeed, it is possible to enter statfs syscall while already being in
    24  	 * an open one.
    25  	 */
    26  	enum fs_file_op op;
    27  };
    28  
    29  struct data {
    30  	__u64 ts;
    31  	loff_t start;
    32  	loff_t end;
    33  	struct dentry *dentry;
    34  };
    35  
    36  struct {
    37  	__uint(type, BPF_MAP_TYPE_HASH);
    38  	__uint(max_entries, MAX_ENTRIES);
    39  	__type(key, struct data_key);
    40  	__type(value, struct data);
    41  } starts SEC(".maps");
    42  
    43  struct {
    44  	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
    45  	__uint(key_size, sizeof(__u32));
    46  	__uint(value_size, sizeof(__u32));
    47  } events SEC(".maps");
    48  
    49  static int probe_entry(struct dentry *dentry, enum fs_file_op op, loff_t start,
    50  		       loff_t end)
    51  {
    52  	__u64 pid_tgid = bpf_get_current_pid_tgid();
    53  	__u32 pid = pid_tgid >> 32;
    54  	__u32 tid = (__u32)pid_tgid;
    55  	struct data data;
    56  	struct data_key key = { .tid = tid, .op = op };
    57  	u64 mntns_id;
    58  
    59  	if (!dentry)
    60  		return 0;
    61  
    62  	// TODO: Enabling this conditional causes an error while loading the program
    63  	// invalid argument: number of funcs in func_info doesn't match number of subprogs
    64  	//if (target_pid && target_pid != pid)
    65  	//	return 0;
    66  
    67  	mntns_id = gadget_get_mntns_id();
    68  
    69  	if (gadget_should_discard_mntns_id(mntns_id))
    70  		return 0;
    71  
    72  	data.ts = bpf_ktime_get_ns();
    73  	data.start = start;
    74  	data.end = end;
    75  	data.dentry = dentry;
    76  	bpf_map_update_elem(&starts, &key, &data, BPF_ANY);
    77  	return 0;
    78  }
    79  
    80  static int probe_exit(void *ctx, enum fs_file_op op, ssize_t size)
    81  {
    82  	__u64 pid_tgid = bpf_get_current_pid_tgid();
    83  	__u32 pid = pid_tgid >> 32;
    84  	__u32 tid = (__u32)pid_tgid;
    85  	__u64 end_ns, delta_ns;
    86  	const __u8 *file_name;
    87  	struct data *datap;
    88  	struct event event = {};
    89  	struct data_key key = { .tid = tid, .op = op };
    90  	struct dentry *dentry;
    91  	u64 mntns_id;
    92  
    93  	//if (target_pid && target_pid != pid)
    94  	//	return 0;
    95  
    96  	datap = bpf_map_lookup_elem(&starts, &key);
    97  	if (!datap)
    98  		return 0;
    99  
   100  	bpf_map_delete_elem(&starts, &key);
   101  
   102  	end_ns = bpf_ktime_get_ns();
   103  	delta_ns = end_ns - datap->ts;
   104  	if (delta_ns <= min_lat_ns)
   105  		return 0;
   106  
   107  	event.delta_us = delta_ns / 1000;
   108  	event.end_ns = end_ns;
   109  	event.offset = datap->start;
   110  	if (op != F_FSYNC)
   111  		event.size = size;
   112  	else
   113  		event.size = datap->end - datap->start;
   114  	event.pid = pid;
   115  	event.op = op;
   116  	event.mntns_id = gadget_get_mntns_id();
   117  	event.timestamp = bpf_ktime_get_boot_ns();
   118  	dentry = datap->dentry;
   119  	file_name = BPF_CORE_READ(dentry, d_name.name);
   120  	bpf_probe_read_kernel_str(&event.file, sizeof(event.file), file_name);
   121  	bpf_get_current_comm(&event.task, sizeof(event.task));
   122  	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event,
   123  			      sizeof(event));
   124  	return 0;
   125  }
   126  
   127  SEC("kprobe/dummy_file_read")
   128  int BPF_KPROBE(ig_fssl_read_e, struct kiocb *iocb)
   129  {
   130  	struct dentry *dentry = BPF_CORE_READ(iocb, ki_filp, f_path.dentry);
   131  	loff_t start = BPF_CORE_READ(iocb, ki_pos);
   132  
   133  	return probe_entry(dentry, F_READ, start, 0);
   134  }
   135  
   136  SEC("kretprobe/dummy_file_read")
   137  int BPF_KRETPROBE(ig_fssl_read_x, ssize_t ret)
   138  {
   139  	return probe_exit(ctx, F_READ, ret);
   140  }
   141  
   142  SEC("kprobe/dummy_file_write")
   143  int BPF_KPROBE(ig_fssl_wr_e, struct kiocb *iocb)
   144  {
   145  	struct dentry *dentry = BPF_CORE_READ(iocb, ki_filp, f_path.dentry);
   146  	loff_t start = BPF_CORE_READ(iocb, ki_pos);
   147  
   148  	return probe_entry(dentry, F_WRITE, start, 0);
   149  }
   150  
   151  SEC("kretprobe/dummy_file_write")
   152  int BPF_KRETPROBE(ig_fssl_wr_x, ssize_t ret)
   153  {
   154  	return probe_exit(ctx, F_WRITE, ret);
   155  }
   156  
   157  SEC("kprobe/dummy_file_open")
   158  int BPF_KPROBE(ig_fssl_open_e, struct inode *inode, struct file *file)
   159  {
   160  	struct dentry *dentry = BPF_CORE_READ(file, f_path.dentry);
   161  	return probe_entry(dentry, F_OPEN, 0, 0);
   162  }
   163  
   164  SEC("kretprobe/dummy_file_open")
   165  int BPF_KRETPROBE(ig_fssl_open_x)
   166  {
   167  	return probe_exit(ctx, F_OPEN, 0);
   168  }
   169  
   170  SEC("kprobe/dummy_file_sync")
   171  int BPF_KPROBE(ig_fssl_sync_e, struct file *file, loff_t start, loff_t end)
   172  {
   173  	struct dentry *dentry = BPF_CORE_READ(file, f_path.dentry);
   174  	return probe_entry(dentry, F_FSYNC, start, end);
   175  }
   176  
   177  SEC("kretprobe/dummy_file_sync")
   178  int BPF_KRETPROBE(ig_fssl_sync_x)
   179  {
   180  	return probe_exit(ctx, F_FSYNC, 0);
   181  }
   182  
   183  SEC("kprobe/dummy_file_statfs")
   184  int BPF_KPROBE(ig_fssl_statfs_e, struct dentry *dentry, struct kstatfs *buf)
   185  {
   186  	return probe_entry(dentry, F_STATFS, 0, 0);
   187  }
   188  
   189  SEC("kretprobe/dummy_file_statfs")
   190  int BPF_KRETPROBE(ig_fssl_statfs_x)
   191  {
   192  	return probe_exit(ctx, F_STATFS, 0);
   193  }
   194  
   195  // Comment out the fentry/fexit functions as we don't support them yet.
   196  //SEC("fentry/dummy_file_read")
   197  //int BPF_PROG(file_read_fentry, struct kiocb *iocb)
   198  //{
   199  //	struct file *fp = iocb->ki_filp;
   200  //	loff_t start = iocb->ki_pos;
   201  //
   202  //	return probe_entry(fp, start, 0);
   203  //}
   204  //
   205  //SEC("fexit/dummy_file_read")
   206  //int BPF_PROG(file_read_fexit, struct kiocb *iocb, struct iov_iter *to, ssize_t ret)
   207  //{
   208  //	return probe_exit(ctx, READ, ret);
   209  //}
   210  //
   211  //SEC("fentry/dummy_file_write")
   212  //int BPF_PROG(file_write_fentry, struct kiocb *iocb)
   213  //{
   214  //	struct file *fp = iocb->ki_filp;
   215  //	loff_t start = iocb->ki_pos;
   216  //
   217  //	return probe_entry(fp, start, 0);
   218  //}
   219  //
   220  //SEC("fexit/dummy_file_write")
   221  //int BPF_PROG(file_write_fexit, struct kiocb *iocb, struct iov_iter *from, ssize_t ret)
   222  //{
   223  //	return probe_exit(ctx, WRITE, ret);
   224  //}
   225  //
   226  //SEC("fentry/dummy_file_open")
   227  //int BPF_PROG(file_open_fentry, struct inode *inode, struct file *file)
   228  //{
   229  //	return probe_entry(file, 0, 0);
   230  //}
   231  //
   232  //SEC("fexit/dummy_file_open")
   233  //int BPF_PROG(file_open_fexit)
   234  //{
   235  //	return probe_exit(ctx, OPEN, 0);
   236  //}
   237  //
   238  //SEC("fentry/dummy_file_sync")
   239  //int BPF_PROG(file_sync_fentry, struct file *file, loff_t start, loff_t end)
   240  //{
   241  //	return probe_entry(file, start, end);
   242  //}
   243  //
   244  //SEC("fexit/dummy_file_sync")
   245  //int BPF_PROG(file_sync_fexit)
   246  //{
   247  //	return probe_exit(ctx, FSYNC, 0);
   248  //}
   249  
   250  char LICENSE[] SEC("license") = "GPL";