Skip to content

Commit e5d31ac

Browse files
authored
tools/readahead: Fix incorrect page accessed count since v5.16 (#5266)
Since Linux v5.16 commit 76580b65("mm/swap: Add folio_mark_accessed()") [1], filemap_read() no longer calls mark_page_accessed() but instead uses folio_mark_accessed(). This change caused the readahead tool to miss tracking accessed pages, resulting in incorrect statistics. This patch fixes the issue by detecting whether folio_mark_accessed() or mark_page_accessed() is available in the kernel and probing the appropriate function to correctly count page accesses. The implementation maintains compatibility with both pre-v5.16 and post-v5.16 kernels. Verified with v5.15.60 (Arch Linux) and v6.8.0 (Ubuntu 2404). [1]: torvalds/linux@76580b65 Signed-off-by: Ism Hong <[email protected]>
1 parent 1706b2a commit e5d31ac

File tree

1 file changed

+41
-9
lines changed

1 file changed

+41
-9
lines changed

tools/readahead.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
8282
int entry_mark_page_accessed(struct pt_regs *ctx) {
8383
u64 ts, delta;
84-
struct page *arg0 = (struct page *) PT_REGS_PARM1(ctx);
84+
struct page *arg0 = GET_ARG1_PAGE;
8585
u32 zero = 0; // static key for accessing pages[0]
8686
u64 *bts = birth.lookup(&arg0);
8787
if (bts != NULL) {
@@ -94,7 +94,7 @@
9494
}
9595
"""
9696

97-
bpf_text_kfunc = """
97+
bpf_text_kfunc_cache_readahead = """
9898
KFUNC_PROBE(RA_FUNC)
9999
{
100100
u32 pid = bpf_get_current_pid_tgid();
@@ -112,18 +112,21 @@
112112
flag.update(&pid, &zero);
113113
return 0;
114114
}
115+
"""
115116

116-
KFUNC_PROBE(mark_page_accessed, struct page *arg0)
117+
bpf_text_kfunc_mark_accessed_template = """
118+
KFUNC_PROBE(MA_FUNC_NAME, MA_ARG_TYPE arg0)
117119
{
118120
u64 ts, delta;
119121
u32 zero = 0; // static key for accessing pages[0]
120-
u64 *bts = birth.lookup(&arg0);
122+
struct page *page = GET_PAGE_PTR_FROM_ARG0;
123+
u64 *bts = birth.lookup(&page);
121124
122125
if (bts != NULL) {
123126
delta = bpf_ktime_get_ns() - *bts;
124127
dist.atomic_increment(bpf_log2l(delta/1000000));
125128
pages.atomic_increment(zero, -1);
126-
birth.delete(&arg0); // remove the entry from hashmap
129+
birth.delete(&page); // remove the entry from hashmap
127130
}
128131
return 0;
129132
}
@@ -181,9 +184,9 @@
181184
elif BPF.get_kprobe_functions(b"page_cache_ra_order"):
182185
ra_func = "page_cache_ra_order"
183186
else:
184-
print("Not found any kfunc.")
187+
print("Not found any kfunc for page cache readahead.")
185188
exit()
186-
bpf_text += bpf_text_kfunc.replace("RA_FUNC", ra_func)
189+
bpf_text += bpf_text_kfunc_cache_readahead.replace("RA_FUNC", ra_func)
187190
if BPF.get_kprobe_functions(b"__page_cache_alloc"):
188191
bpf_text += bpf_text_kfunc_cache_alloc_ret_page
189192
else:
@@ -195,6 +198,26 @@
195198
print("ERROR: No cache alloc function found. Exiting.")
196199
exit()
197200
bpf_text += bpf_text_kfunc_cache_alloc_ret_folio_func_body
201+
if BPF.get_kprobe_functions(b"folio_mark_accessed"):
202+
ma_func_name = "folio_mark_accessed"
203+
ma_arg_type = "struct folio *"
204+
get_page_ptr_code = "folio_page(arg0, 0)"
205+
bpf_text_kfunc_mark_accessed = bpf_text_kfunc_mark_accessed_template \
206+
.replace("MA_FUNC_NAME", ma_func_name) \
207+
.replace("MA_ARG_TYPE", ma_arg_type) \
208+
.replace("GET_PAGE_PTR_FROM_ARG0", get_page_ptr_code)
209+
elif BPF.get_kprobe_functions(b"mark_page_accessed"):
210+
ma_func_name = "mark_page_accessed"
211+
ma_arg_type = "struct page *"
212+
get_page_ptr_code = "arg0"
213+
bpf_text_kfunc_mark_accessed = bpf_text_kfunc_mark_accessed_template \
214+
.replace("MA_FUNC_NAME", ma_func_name) \
215+
.replace("MA_ARG_TYPE", ma_arg_type) \
216+
.replace("GET_PAGE_PTR_FROM_ARG0", get_page_ptr_code)
217+
else:
218+
print("Not found any kfunc for page cache mark accessed.")
219+
exit()
220+
bpf_text += bpf_text_kfunc_mark_accessed
198221
b = BPF(text=bpf_text)
199222
else:
200223
bpf_text += bpf_text_kprobe
@@ -205,7 +228,7 @@
205228
elif BPF.get_kprobe_functions(b"page_cache_ra_order"):
206229
ra_event = "page_cache_ra_order"
207230
else:
208-
print("Not found any kprobe.")
231+
print("Not found any kprobe for page cache readahead.")
209232
exit()
210233
if BPF.get_kprobe_functions(b"__page_cache_alloc"):
211234
cache_func = "__page_cache_alloc"
@@ -219,12 +242,21 @@
219242
print("ERROR: No cache alloc function found. Exiting.")
220243
exit()
221244
bpf_text = bpf_text.replace('GET_RETVAL_PAGE', 'folio_page((struct folio *)PT_REGS_RC(ctx), 0)')
245+
if BPF.get_kprobe_functions(b"folio_mark_accessed"):
246+
ma_event = "folio_mark_accessed"
247+
bpf_text = bpf_text.replace('GET_ARG1_PAGE', 'folio_page((struct folio *)PT_REGS_PARM1(ctx), 0)')
248+
elif BPF.get_kprobe_functions(b"mark_page_accessed"):
249+
ma_event = "mark_page_accessed"
250+
bpf_text = bpf_text.replace('GET_ARG1_PAGE', '(struct page *)PT_REGS_PARM1(ctx)')
251+
else:
252+
print("Not found any kprobe for page cache mark accessed.")
253+
exit()
222254

223255
b = BPF(text=bpf_text)
224256
b.attach_kprobe(event=ra_event, fn_name="entry__do_page_cache_readahead")
225257
b.attach_kretprobe(event=ra_event, fn_name="exit__do_page_cache_readahead")
226258
b.attach_kretprobe(event=cache_func, fn_name="exit__page_cache_alloc")
227-
b.attach_kprobe(event="mark_page_accessed", fn_name="entry_mark_page_accessed")
259+
b.attach_kprobe(event=ma_event, fn_name="entry_mark_page_accessed")
228260

229261
# header
230262
print("Tracing... Hit Ctrl-C to end.")

0 commit comments

Comments
 (0)