mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 15:32:04 +02:00
The .log2 key modifier files a value under its base-2 order:
# echo 'hist:keys=bytes_req.log2' > events/kmem/kmalloc/trigger
hist_field_log2() computes that as ilog2(roundup_pow_of_two(val)). The
out-of-line form of roundup_pow_of_two() is
return 1UL << fls_long(n - 1);
which shifts by 64 on a 64-bit kernel both when n is 0, where n - 1
wraps to ULONG_MAX, and when n is above 2^63. Both are ordinary keys,
because the field fetch hands every value over as a u64: a syscall
argument of 0 reaches the first, and one above 2^63 reaches the second.
Keying sys_enter_lseek on offset.log2 and passing 0, 1, 2, 3, 1000,
2^63+1 and U64_MAX gives
{ offset: ~ 2^1 } hitcount: 1
{ offset: ~ 2^10 } hitcount: 1
{ offset: ~ 2^2 } hitcount: 1
{ offset: ~ 2^0 } hitcount: 4
Keys above 2^63 land in the lowest bucket. With CONFIG_UBSAN_SHIFT=y
the shift is also reported:
UBSAN: shift-out-of-bounds in include/linux/log2.h:57:13
shift exponent 64 is too large for 64-bit type 'long unsigned int'
__ubsan_handle_shift_out_of_bounds.cold+0xdd/0x1cb
hist_fn_call.cold+0x8b/0xd9
event_hist_trigger+0x1cc/0x790
ftrace_syscall_enter+0x197/0x360
do_syscall_64+0x402/0x4b0
Use order_base_2(), which is ilog2(n - 1) + 1 for n > 1 and 0 below
that. It returns what the old expression returned on every input the
old one was defined for. Where it was not, 0 stays in bucket 0, which
is where x86_64 had been putting it, and the keys above 2^63 move into
bucket 64.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260916002735.808520-1-donggeunyoo.kernel@gmail.com
Fixes:
|
||
|---|---|---|
| .. | ||
| rv | ||
| blktrace.c | ||
| bpf_trace.c | ||
| bpf_trace.h | ||
| error_report-traces.c | ||
| fgraph.c | ||
| fprobe.c | ||
| ftrace_internal.h | ||
| ftrace.c | ||
| Kconfig | ||
| kprobe_event_gen_test.c | ||
| Makefile | ||
| pid_list.c | ||
| pid_list.h | ||
| power-traces.c | ||
| preemptirq_delay_test.c | ||
| remote_test_events.h | ||
| remote_test.c | ||
| rethook.c | ||
| ring_buffer_benchmark.c | ||
| ring_buffer.c | ||
| rpm-traces.c | ||
| simple_ring_buffer.c | ||
| synth_event_gen_test.c | ||
| trace_benchmark.c | ||
| trace_benchmark.h | ||
| trace_boot.c | ||
| trace_branch.c | ||
| trace_btf.c | ||
| trace_btf.h | ||
| trace_clock.c | ||
| trace_dynevent.c | ||
| trace_dynevent.h | ||
| trace_entries.h | ||
| trace_eprobe.c | ||
| trace_event_perf.c | ||
| trace_events_filter_test.h | ||
| trace_events_filter.c | ||
| trace_events_hist.c | ||
| trace_events_inject.c | ||
| trace_events_synth.c | ||
| trace_events_trigger.c | ||
| trace_events_user.c | ||
| trace_events.c | ||
| trace_export.c | ||
| trace_fprobe.c | ||
| trace_functions_graph.c | ||
| trace_functions.c | ||
| trace_hwlat.c | ||
| trace_irqsoff.c | ||
| trace_kdb.c | ||
| trace_kprobe_selftest.c | ||
| trace_kprobe_selftest.h | ||
| trace_kprobe.c | ||
| trace_mmiotrace.c | ||
| trace_nop.c | ||
| trace_osnoise.c | ||
| trace_output.c | ||
| trace_output.h | ||
| trace_pid.c | ||
| trace_preemptirq.c | ||
| trace_printk.c | ||
| trace_probe_kernel.h | ||
| trace_probe_tmpl.h | ||
| trace_probe.c | ||
| trace_probe.h | ||
| trace_recursion_record.c | ||
| trace_remote.c | ||
| trace_sched_switch.c | ||
| trace_sched_wakeup.c | ||
| trace_selftest_dynamic.c | ||
| trace_selftest.c | ||
| trace_seq.c | ||
| trace_snapshot.c | ||
| trace_stack.c | ||
| trace_stat.c | ||
| trace_stat.h | ||
| trace_synth.h | ||
| trace_syscalls.c | ||
| trace_uprobe.c | ||
| trace.c | ||
| trace.h | ||
| tracing_map.c | ||
| tracing_map.h | ||
| undefsyms_base.c | ||