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_tracing.h>
6 #include "readahead.h"
7 #include "bits.bpf.h"
8
9 #define MAX_ENTRIES 10240
10
11 struct {
12 __uint(type, BPF_MAP_TYPE_HASH);
13 __uint(max_entries, MAX_ENTRIES);
14 __type(key, u32);
15 __type(value, u64);
16 __uint(map_flags, BPF_F_NO_PREALLOC);
17 } in_readahead SEC(".maps");
18
19 struct {
20 __uint(type, BPF_MAP_TYPE_HASH);
21 __uint(max_entries, MAX_ENTRIES);
22 __type(key, struct page *);
23 __type(value, u64);
24 __uint(map_flags, BPF_F_NO_PREALLOC);
25 } birth SEC(".maps");
26
27 struct hist hist = {};
28
29 SEC("fentry/do_page_cache_ra")
BPF_PROG(do_page_cache_ra)30 int BPF_PROG(do_page_cache_ra)
31 {
32 u32 pid = bpf_get_current_pid_tgid();
33 u64 one = 1;
34
35 bpf_map_update_elem(&in_readahead, &pid, &one, 0);
36 return 0;
37 }
38
39 SEC("fexit/__page_cache_alloc")
BPF_PROG(page_cache_alloc_ret,gfp_t gfp,struct page * ret)40 int BPF_PROG(page_cache_alloc_ret, gfp_t gfp, struct page *ret)
41 {
42 u32 pid = bpf_get_current_pid_tgid();
43 u64 ts;
44
45 if (!bpf_map_lookup_elem(&in_readahead, &pid))
46 return 0;
47
48 ts = bpf_ktime_get_ns();
49 bpf_map_update_elem(&birth, &ret, &ts, 0);
50 __sync_fetch_and_add(&hist.unused, 1);
51 __sync_fetch_and_add(&hist.total, 1);
52
53 return 0;
54 }
55
56 SEC("fexit/do_page_cache_ra")
BPF_PROG(do_page_cache_ra_ret)57 int BPF_PROG(do_page_cache_ra_ret)
58 {
59 u32 pid = bpf_get_current_pid_tgid();
60
61 bpf_map_delete_elem(&in_readahead, &pid);
62 return 0;
63 }
64
65 SEC("fentry/mark_page_accessed")
BPF_PROG(mark_page_accessed,struct page * page)66 int BPF_PROG(mark_page_accessed, struct page *page)
67 {
68 u64 *tsp, slot, ts = bpf_ktime_get_ns();
69 s64 delta;
70
71 tsp = bpf_map_lookup_elem(&birth, &page);
72 if (!tsp)
73 return 0;
74 delta = (s64)(ts - *tsp);
75 if (delta < 0)
76 goto update_and_cleanup;
77 slot = log2l(delta / 1000000U);
78 if (slot >= MAX_SLOTS)
79 slot = MAX_SLOTS - 1;
80 __sync_fetch_and_add(&hist.slots[slot], 1);
81
82 update_and_cleanup:
83 __sync_fetch_and_add(&hist.unused, -1);
84 bpf_map_delete_elem(&birth, &page);
85
86 return 0;
87 }
88
89 char LICENSE[] SEC("license") = "GPL";
90