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