Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Resolve symbols with ftrace_lookup_symbols for kprobe multi link

Using kallsyms_lookup_names function to speed up symbols lookup in
kprobe multi link attachment and replacing with it the current
kprobe_multi_resolve_syms function.

This speeds up bpftrace kprobe attachment:

# perf stat -r 5 -e cycles ./src/bpftrace -e 'kprobe:x* { } i:ms:1 { exit(); }'
...
6.5681 +- 0.0225 seconds time elapsed ( +- 0.34% )

After:

# perf stat -r 5 -e cycles ./src/bpftrace -e 'kprobe:x* { } i:ms:1 { exit(); }'
...
0.5661 +- 0.0275 seconds time elapsed ( +- 4.85% )

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20220510122616.2652285-5-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Jiri Olsa and committed by
Alexei Starovoitov
0236fec5 8be92533

+66 -46
+66 -46
kernel/trace/bpf_trace.c
··· 2229 2229 unsigned long entry_ip; 2230 2230 }; 2231 2231 2232 + struct user_syms { 2233 + const char **syms; 2234 + char *buf; 2235 + }; 2236 + 2237 + static int copy_user_syms(struct user_syms *us, unsigned long __user *usyms, u32 cnt) 2238 + { 2239 + unsigned long __user usymbol; 2240 + const char **syms = NULL; 2241 + char *buf = NULL, *p; 2242 + int err = -ENOMEM; 2243 + unsigned int i; 2244 + 2245 + syms = kvmalloc(cnt * sizeof(*syms), GFP_KERNEL); 2246 + if (!syms) 2247 + goto error; 2248 + 2249 + buf = kvmalloc(cnt * KSYM_NAME_LEN, GFP_KERNEL); 2250 + if (!buf) 2251 + goto error; 2252 + 2253 + for (p = buf, i = 0; i < cnt; i++) { 2254 + if (__get_user(usymbol, usyms + i)) { 2255 + err = -EFAULT; 2256 + goto error; 2257 + } 2258 + err = strncpy_from_user(p, (const char __user *) usymbol, KSYM_NAME_LEN); 2259 + if (err == KSYM_NAME_LEN) 2260 + err = -E2BIG; 2261 + if (err < 0) 2262 + goto error; 2263 + syms[i] = p; 2264 + p += err + 1; 2265 + } 2266 + 2267 + us->syms = syms; 2268 + us->buf = buf; 2269 + return 0; 2270 + 2271 + error: 2272 + if (err) { 2273 + kvfree(syms); 2274 + kvfree(buf); 2275 + } 2276 + return err; 2277 + } 2278 + 2279 + static void free_user_syms(struct user_syms *us) 2280 + { 2281 + kvfree(us->syms); 2282 + kvfree(us->buf); 2283 + } 2284 + 2232 2285 static void bpf_kprobe_multi_link_release(struct bpf_link *link) 2233 2286 { 2234 2287 struct bpf_kprobe_multi_link *kmulti_link; ··· 2402 2349 kprobe_multi_link_prog_run(link, entry_ip, regs); 2403 2350 } 2404 2351 2405 - static int 2406 - kprobe_multi_resolve_syms(const void __user *usyms, u32 cnt, 2407 - unsigned long *addrs) 2352 + static int symbols_cmp(const void *a, const void *b) 2408 2353 { 2409 - unsigned long addr, size; 2410 - const char __user **syms; 2411 - int err = -ENOMEM; 2412 - unsigned int i; 2413 - char *func; 2354 + const char **str_a = (const char **) a; 2355 + const char **str_b = (const char **) b; 2414 2356 2415 - size = cnt * sizeof(*syms); 2416 - syms = kvzalloc(size, GFP_KERNEL); 2417 - if (!syms) 2418 - return -ENOMEM; 2419 - 2420 - func = kmalloc(KSYM_NAME_LEN, GFP_KERNEL); 2421 - if (!func) 2422 - goto error; 2423 - 2424 - if (copy_from_user(syms, usyms, size)) { 2425 - err = -EFAULT; 2426 - goto error; 2427 - } 2428 - 2429 - for (i = 0; i < cnt; i++) { 2430 - err = strncpy_from_user(func, syms[i], KSYM_NAME_LEN); 2431 - if (err == KSYM_NAME_LEN) 2432 - err = -E2BIG; 2433 - if (err < 0) 2434 - goto error; 2435 - err = -EINVAL; 2436 - addr = kallsyms_lookup_name(func); 2437 - if (!addr) 2438 - goto error; 2439 - if (!kallsyms_lookup_size_offset(addr, &size, NULL)) 2440 - goto error; 2441 - addr = ftrace_location_range(addr, addr + size - 1); 2442 - if (!addr) 2443 - goto error; 2444 - addrs[i] = addr; 2445 - } 2446 - 2447 - err = 0; 2448 - error: 2449 - kvfree(syms); 2450 - kfree(func); 2451 - return err; 2357 + return strcmp(*str_a, *str_b); 2452 2358 } 2453 2359 2454 2360 int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) ··· 2453 2441 goto error; 2454 2442 } 2455 2443 } else { 2456 - err = kprobe_multi_resolve_syms(usyms, cnt, addrs); 2444 + struct user_syms us; 2445 + 2446 + err = copy_user_syms(&us, usyms, cnt); 2447 + if (err) 2448 + goto error; 2449 + 2450 + sort(us.syms, cnt, sizeof(*us.syms), symbols_cmp, NULL); 2451 + err = ftrace_lookup_symbols(us.syms, cnt, addrs); 2452 + free_user_syms(&us); 2457 2453 if (err) 2458 2454 goto error; 2459 2455 }