12a52ca7cSTejun Heo /* SPDX-License-Identifier: GPL-2.0 */ 22a52ca7cSTejun Heo /* 32a52ca7cSTejun Heo * Define struct user_exit_info which is shared between BPF and userspace parts 42a52ca7cSTejun Heo * to communicate exit status and other information. 52a52ca7cSTejun Heo * 62a52ca7cSTejun Heo * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 72a52ca7cSTejun Heo * Copyright (c) 2022 Tejun Heo <tj@kernel.org> 82a52ca7cSTejun Heo * Copyright (c) 2022 David Vernet <dvernet@meta.com> 92a52ca7cSTejun Heo */ 102a52ca7cSTejun Heo #ifndef __USER_EXIT_INFO_H 112a52ca7cSTejun Heo #define __USER_EXIT_INFO_H 122a52ca7cSTejun Heo 132a52ca7cSTejun Heo enum uei_sizes { 142a52ca7cSTejun Heo UEI_REASON_LEN = 128, 152a52ca7cSTejun Heo UEI_MSG_LEN = 1024, 1607814a94STejun Heo UEI_DUMP_DFL_LEN = 32768, 172a52ca7cSTejun Heo }; 182a52ca7cSTejun Heo 192a52ca7cSTejun Heo struct user_exit_info { 202a52ca7cSTejun Heo int kind; 212a52ca7cSTejun Heo s64 exit_code; 222a52ca7cSTejun Heo char reason[UEI_REASON_LEN]; 232a52ca7cSTejun Heo char msg[UEI_MSG_LEN]; 242a52ca7cSTejun Heo }; 252a52ca7cSTejun Heo 262a52ca7cSTejun Heo #ifdef __bpf__ 272a52ca7cSTejun Heo 28*a748db0cSTejun Heo #ifdef LSP 29*a748db0cSTejun Heo #include "../vmlinux/vmlinux.h" 30*a748db0cSTejun Heo #else 312a52ca7cSTejun Heo #include "vmlinux.h" 32*a748db0cSTejun Heo #endif 332a52ca7cSTejun Heo #include <bpf/bpf_core_read.h> 342a52ca7cSTejun Heo 352a52ca7cSTejun Heo #define UEI_DEFINE(__name) \ 3607814a94STejun Heo char RESIZABLE_ARRAY(data, __name##_dump); \ 3707814a94STejun Heo const volatile u32 __name##_dump_len; \ 382a52ca7cSTejun Heo struct user_exit_info __name SEC(".data") 392a52ca7cSTejun Heo 402a52ca7cSTejun Heo #define UEI_RECORD(__uei_name, __ei) ({ \ 412a52ca7cSTejun Heo bpf_probe_read_kernel_str(__uei_name.reason, \ 422a52ca7cSTejun Heo sizeof(__uei_name.reason), (__ei)->reason); \ 432a52ca7cSTejun Heo bpf_probe_read_kernel_str(__uei_name.msg, \ 442a52ca7cSTejun Heo sizeof(__uei_name.msg), (__ei)->msg); \ 4507814a94STejun Heo bpf_probe_read_kernel_str(__uei_name##_dump, \ 4607814a94STejun Heo __uei_name##_dump_len, (__ei)->dump); \ 472a52ca7cSTejun Heo if (bpf_core_field_exists((__ei)->exit_code)) \ 482a52ca7cSTejun Heo __uei_name.exit_code = (__ei)->exit_code; \ 492a52ca7cSTejun Heo /* use __sync to force memory barrier */ \ 502a52ca7cSTejun Heo __sync_val_compare_and_swap(&__uei_name.kind, __uei_name.kind, \ 512a52ca7cSTejun Heo (__ei)->kind); \ 522a52ca7cSTejun Heo }) 532a52ca7cSTejun Heo 542a52ca7cSTejun Heo #else /* !__bpf__ */ 552a52ca7cSTejun Heo 562a52ca7cSTejun Heo #include <stdio.h> 572a52ca7cSTejun Heo #include <stdbool.h> 582a52ca7cSTejun Heo 5907814a94STejun Heo /* no need to call the following explicitly if SCX_OPS_LOAD() is used */ 6007814a94STejun Heo #define UEI_SET_SIZE(__skel, __ops_name, __uei_name) ({ \ 6107814a94STejun Heo u32 __len = (__skel)->struct_ops.__ops_name->exit_dump_len ?: UEI_DUMP_DFL_LEN; \ 6207814a94STejun Heo (__skel)->rodata->__uei_name##_dump_len = __len; \ 6307814a94STejun Heo RESIZE_ARRAY((__skel), data, __uei_name##_dump, __len); \ 6407814a94STejun Heo }) 6507814a94STejun Heo 662a52ca7cSTejun Heo #define UEI_EXITED(__skel, __uei_name) ({ \ 672a52ca7cSTejun Heo /* use __sync to force memory barrier */ \ 682a52ca7cSTejun Heo __sync_val_compare_and_swap(&(__skel)->data->__uei_name.kind, -1, -1); \ 692a52ca7cSTejun Heo }) 702a52ca7cSTejun Heo 712a52ca7cSTejun Heo #define UEI_REPORT(__skel, __uei_name) ({ \ 722a52ca7cSTejun Heo struct user_exit_info *__uei = &(__skel)->data->__uei_name; \ 7307814a94STejun Heo char *__uei_dump = (__skel)->data_##__uei_name##_dump->__uei_name##_dump; \ 7407814a94STejun Heo if (__uei_dump[0] != '\0') { \ 7507814a94STejun Heo fputs("\nDEBUG DUMP\n", stderr); \ 7607814a94STejun Heo fputs("================================================================================\n\n", stderr); \ 7707814a94STejun Heo fputs(__uei_dump, stderr); \ 7807814a94STejun Heo fputs("\n================================================================================\n\n", stderr); \ 7907814a94STejun Heo } \ 802a52ca7cSTejun Heo fprintf(stderr, "EXIT: %s", __uei->reason); \ 812a52ca7cSTejun Heo if (__uei->msg[0] != '\0') \ 822a52ca7cSTejun Heo fprintf(stderr, " (%s)", __uei->msg); \ 832a52ca7cSTejun Heo fputs("\n", stderr); \ 8460c27fb5STejun Heo __uei->exit_code; \ 852a52ca7cSTejun Heo }) 862a52ca7cSTejun Heo 8760c27fb5STejun Heo /* 8860c27fb5STejun Heo * We can't import vmlinux.h while compiling user C code. Let's duplicate 8960c27fb5STejun Heo * scx_exit_code definition. 9060c27fb5STejun Heo */ 9160c27fb5STejun Heo enum scx_exit_code { 9260c27fb5STejun Heo /* Reasons */ 9360c27fb5STejun Heo SCX_ECODE_RSN_HOTPLUG = 1LLU << 32, 9460c27fb5STejun Heo 9560c27fb5STejun Heo /* Actions */ 9660c27fb5STejun Heo SCX_ECODE_ACT_RESTART = 1LLU << 48, 9760c27fb5STejun Heo }; 9860c27fb5STejun Heo 9960c27fb5STejun Heo enum uei_ecode_mask { 10060c27fb5STejun Heo UEI_ECODE_USER_MASK = ((1LLU << 32) - 1), 10160c27fb5STejun Heo UEI_ECODE_SYS_RSN_MASK = ((1LLU << 16) - 1) << 32, 10260c27fb5STejun Heo UEI_ECODE_SYS_ACT_MASK = ((1LLU << 16) - 1) << 48, 10360c27fb5STejun Heo }; 10460c27fb5STejun Heo 10560c27fb5STejun Heo /* 10660c27fb5STejun Heo * These macro interpret the ecode returned from UEI_REPORT(). 10760c27fb5STejun Heo */ 10860c27fb5STejun Heo #define UEI_ECODE_USER(__ecode) ((__ecode) & UEI_ECODE_USER_MASK) 10960c27fb5STejun Heo #define UEI_ECODE_SYS_RSN(__ecode) ((__ecode) & UEI_ECODE_SYS_RSN_MASK) 11060c27fb5STejun Heo #define UEI_ECODE_SYS_ACT(__ecode) ((__ecode) & UEI_ECODE_SYS_ACT_MASK) 11160c27fb5STejun Heo 11260c27fb5STejun Heo #define UEI_ECODE_RESTART(__ecode) (UEI_ECODE_SYS_ACT((__ecode)) == SCX_ECODE_ACT_RESTART) 11360c27fb5STejun Heo 1142a52ca7cSTejun Heo #endif /* __bpf__ */ 1152a52ca7cSTejun Heo #endif /* __USER_EXIT_INFO_H */ 116