LKDTM 소개
 
LKDTM은 Linux Kernel Dump Test Module (LKDTM)의 약자로 kdump를 활용해 덤프(vmcore)가 제대로 추출되는지 테스트하는 용도로 작성된 드라이버입니다.
 
관련 자료는 아래 링크에서 확인할 수 있습니다.
 
 
LKDTM 소스는 커널 버전이 업그레이드되면서 (불필요하게) 복잡해 졌는데요. 
전체 구조는 예전 v3.18 소스를 보면 더 빨리 파악할 수 있습니다.
 
 
LKDTM 컨피그를 키는 방법
 
LKDTM는 드라이버 모듈 형식으로 빌드하거나 아예 빌트인으로 커널 이미지에 포함되도록 빌드할 수 있습니다. 이번에는 커널 이미지에 LKDTM을 포함시키는 방법을 소개합니다.
 
아래는 LKDTM 컨피그를 키는 예제 코드입니다. 라즈비안 커널 소스 기준입니다.
 
diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig
index 16d756c..191fb28 100644
--- a/arch/arm64/configs/bcm2711_defconfig
+++ b/arch/arm64/configs/bcm2711_defconfig
@@ -16,6 +16,11 @@ CONFIG_IKCONFIG=m
 CONFIG_IKCONFIG_PROC=y
 CONFIG_MEMCG=y
 CONFIG_BLK_CGROUP=y
 CONFIG_DEBUG_INFO=y
+CONFIG_LKDTM=y
 CONFIG_CFS_BANDWIDTH=y
 CONFIG_CGROUP_PIDS=y
 CONFIG_CGROUP_FREEZER=y
 
bcm2711_defconfig 파일에 'CONFIG_LKDTM=y' 코드 한 줄이 추가됐음을 확인할 수 있습니다.
위와 같은 커널 컨피그를 적용한 후 빌드를 하면, .config(빌드하면 생성되는)에서 'CONFIG_LKDTM=y'가 확인됩니다.
 
$ vi out/.config
...
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
CONFIG_RUNTIME_TESTING_MENU=y
CONFIG_LKDTM=y
# CONFIG_TEST_MIN_HEAP is not set
 
'CONFIG_LKDTM=y'을 반영하고 커널을 빌드합니다. 빌드한 다음에 생성되는 커널 이미지를 타겟에 다운로드(플래시)합니다.
 
LKDTM 실행 하기 전 체크 포인트
 
LKDTM 컨피그가 플레시된 타겟 디바이스에서, LKDTM 실행 하기 전에 먼저 아래 파일이 제대로 보이는지 확인해야 합니다.
 
/sys/kernel/debug/provoke-crash
 
만약 위 파일이 보이지 않으면 'CONFIG_LKDTM=y' 컨피그에 제대로 적용되지 않고 빌드됐으니 다시 빌드를 해야 합니다.
 
LKDTM 간략한 코드 리뷰
 
LKDTM을 실행하는 방법을 설명드리기 전에 간단히 LKDTM에 대한 코드를 리뷰합니다.
 
LKDTM은 강제로 크래시를 유발할 수 있는 코드로 구성돼 있으며 각각 종류는 아래 코드에서 확인할 수 있습니다. (v5.4 기준)
 
/* Define the possible types of crashes that can be triggered. */
static const struct crashtype crashtypes[] = {
CRASHTYPE(PANIC),
CRASHTYPE(BUG),
CRASHTYPE(WARNING),
CRASHTYPE(WARNING_MESSAGE),
CRASHTYPE(EXCEPTION),
CRASHTYPE(LOOP),
CRASHTYPE(EXHAUST_STACK),
CRASHTYPE(CORRUPT_STACK),
CRASHTYPE(CORRUPT_STACK_STRONG),
CRASHTYPE(CORRUPT_LIST_ADD),
CRASHTYPE(CORRUPT_LIST_DEL),
CRASHTYPE(CORRUPT_USER_DS),
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
CRASHTYPE(UNSET_SMEP),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
CRASHTYPE(WRITE_AFTER_FREE),
CRASHTYPE(READ_AFTER_FREE),
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
CRASHTYPE(READ_BUDDY_AFTER_FREE),
CRASHTYPE(SLAB_FREE_DOUBLE),
CRASHTYPE(SLAB_FREE_CROSS),
CRASHTYPE(SLAB_FREE_PAGE),
CRASHTYPE(SOFTLOCKUP),
CRASHTYPE(HARDLOCKUP),
CRASHTYPE(SPINLOCKUP),
CRASHTYPE(HUNG_TASK),
CRASHTYPE(EXEC_DATA),
CRASHTYPE(EXEC_STACK),
CRASHTYPE(EXEC_KMALLOC),
CRASHTYPE(EXEC_VMALLOC),
CRASHTYPE(EXEC_RODATA),
CRASHTYPE(EXEC_USERSPACE),
CRASHTYPE(EXEC_NULL),
CRASHTYPE(ACCESS_USERSPACE),
CRASHTYPE(ACCESS_NULL),
CRASHTYPE(WRITE_RO),
CRASHTYPE(WRITE_RO_AFTER_INIT),
CRASHTYPE(WRITE_KERN),
CRASHTYPE(REFCOUNT_INC_OVERFLOW),
CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW),
CRASHTYPE(REFCOUNT_DEC_ZERO),
CRASHTYPE(REFCOUNT_DEC_NEGATIVE),
CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE),
CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE),
CRASHTYPE(REFCOUNT_INC_ZERO),
CRASHTYPE(REFCOUNT_ADD_ZERO),
CRASHTYPE(REFCOUNT_INC_SATURATED),
CRASHTYPE(REFCOUNT_DEC_SATURATED),
CRASHTYPE(REFCOUNT_ADD_SATURATED),
CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED),
CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED),
CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED),
CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED),
CRASHTYPE(REFCOUNT_TIMING),
CRASHTYPE(ATOMIC_TIMING),
CRASHTYPE(USERCOPY_HEAP_SIZE_TO),
CRASHTYPE(USERCOPY_HEAP_SIZE_FROM),
CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO),
CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM),
CRASHTYPE(USERCOPY_STACK_FRAME_TO),
CRASHTYPE(USERCOPY_STACK_FRAME_FROM),
CRASHTYPE(USERCOPY_STACK_BEYOND),
CRASHTYPE(USERCOPY_KERNEL),
CRASHTYPE(USERCOPY_KERNEL_DS),
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
}; 
 
크래시 타입 별로 크래시를 유발하는 코드를 확인하는게 중요한데요.
CRASHTYPE(BUG)은 다음 코드에 매핑됩니다.
 
void lkdtm_BUG(void)
{
BUG();
}
 
CRASHTYPE(EXCEPTION)에 매핑되는 루틴은 다음과 같습니다.
 
void lkdtm_EXCEPTION(void)
{
*((volatile int *) 0) = 0;
}
 
제가 위에서 정의된 크래시 타입을 전부 실행했는데, 대부분 크래시가 유발되나 크래시가 유발되지 
않는 경우도 확인했습니다.
 
LKDTM 실행하기
 
(LKDTM 실행하기 전에 먼저 ftrace 이벤트를 활성화하면 좋습니다. vmcore에서 ftrace를 함께 보면 더 많은 디버깅 정보를 확인할 수 있거든요. e.g: sched_switch, irq_handle_entry, irq_handle_exit)
 
LKDTM을 실행하는 방법은 간단합니다. 셸을 하나 열고 아래 포멧으로 명령어를 입력하면 됩니다.
 
$ echo '크래시 타입' > /sys/kernel/debug/provoke-crash/DIRECT
 
몇 가지 예를 들겠습니다. CRASHTYPE(BUG)을 유발하려면 다음과 같은 명령어를 입력하면 됩니다.
 
$ echo BUG > /sys/kernel/debug/provoke-crash/DIRECT
 
'/sys/kernel/debug/provoke-crash/DIRECT'에 BUG 문자열을 전달하면 아래 코드가 실행됩니다.
 
void lkdtm_BUG(void)
{
BUG();
}
 
만약 스택을 오염(Corrupt) 시켜서 크래시를 유발하고 싶으면 아래 명령어를 입력하면 되겠네요.
 
$ echo CORRUPT_STACK > /sys/kernel/debug/provoke-crash/DIRECT
 
위 명령어를 실행하면 lkdtm_CORRUPT_STACK() 함수가 실행되면서 스택을 깹니다.
 
static noinline void __lkdtm_CORRUPT_STACK(void *stack)
{
memset(stack, '\xff', 64);
}
noinline void lkdtm_CORRUPT_STACK(void)
{
/* Use default char array length that triggers stack protection. */
char data[8] __aligned(sizeof(void *));
 
__lkdtm_CORRUPT_STACK(&data);
 
pr_info("Corrupted stack containing char array ...\n");
}
 
data를 char 타입인 배열(8)로 잡았는데, __lkdtm_CORRUPT_STACK() 함수에서 64바이트 사이즈로 메모리 카피를 하니 스택에 '\xff'를 덮어 씁니다. 
 
권장 크래시 타입
 
사실 LKDTM으로 지원되는 크래시 타입을 모두 테스트하면 좋은데요.
실전 프로젝트에서 잘 발생하는 순서로 테스트를 하면 좋을 것 같아요.
 
주석을 달았으니 참고하시면 좋겠네요.
 
static const struct crashtype crashtypes[] = {
CRASHTYPE(PANIC),  /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(BUG), /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(WARNING), /* 테스트 요망 | 발생 가능 | 크래시 유발안됨 *'/
CRASHTYPE(WARNING_MESSAGE),
CRASHTYPE(EXCEPTION), /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(LOOP),
CRASHTYPE(EXHAUST_STACK), /* 테스트 요망 | 종종 발생 | 100% 유발 *'/
CRASHTYPE(CORRUPT_STACK), /* 테스트 요망 | 종종 발생 | 100% 유발 *'/
CRASHTYPE(CORRUPT_STACK_STRONG),
CRASHTYPE(CORRUPT_LIST_ADD), /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(CORRUPT_LIST_DEL),  /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(CORRUPT_USER_DS),  
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
CRASHTYPE(UNSET_SMEP),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
CRASHTYPE(WRITE_AFTER_FREE), /* 테스트 요망 | 종종 발생(메모리 Corruption) | 100% 유발 *'/
CRASHTYPE(READ_AFTER_FREE),  /* 테스트 요망 | 종종 발생(메모리 Corruption) | 100% 유발 *'/
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
CRASHTYPE(READ_BUDDY_AFTER_FREE),
CRASHTYPE(SLAB_FREE_DOUBLE),
CRASHTYPE(SLAB_FREE_CROSS),
CRASHTYPE(SLAB_FREE_PAGE),
CRASHTYPE(SOFTLOCKUP), /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(HARDLOCKUP), /* 테스트 요망 | 자주 발생 | 100% 유발 *'/
CRASHTYPE(SPINLOCKUP), /* 테스트 요망 | 종종 발생 | 100% 유발 *'/
CRASHTYPE(HUNG_TASK),
CRASHTYPE(EXEC_DATA),
CRASHTYPE(EXEC_STACK),
CRASHTYPE(EXEC_KMALLOC),
CRASHTYPE(EXEC_VMALLOC),
CRASHTYPE(EXEC_RODATA),
CRASHTYPE(EXEC_USERSPACE),
CRASHTYPE(EXEC_NULL),
CRASHTYPE(ACCESS_USERSPACE),
CRASHTYPE(ACCESS_NULL),
CRASHTYPE(WRITE_RO),
CRASHTYPE(WRITE_RO_AFTER_INIT),
CRASHTYPE(WRITE_KERN),
CRASHTYPE(REFCOUNT_INC_OVERFLOW),
CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW),
CRASHTYPE(REFCOUNT_DEC_ZERO),
CRASHTYPE(REFCOUNT_DEC_NEGATIVE),
CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE),
CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE),
CRASHTYPE(REFCOUNT_INC_ZERO),
CRASHTYPE(REFCOUNT_ADD_ZERO),
CRASHTYPE(REFCOUNT_INC_SATURATED),
CRASHTYPE(REFCOUNT_DEC_SATURATED),
CRASHTYPE(REFCOUNT_ADD_SATURATED),
CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED),
CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED),
CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED),
CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED),
CRASHTYPE(REFCOUNT_TIMING),
CRASHTYPE(ATOMIC_TIMING),
CRASHTYPE(USERCOPY_HEAP_SIZE_TO),
CRASHTYPE(USERCOPY_HEAP_SIZE_FROM),
CRASHTYPE(USERCOPY_HEAP_WHITELIST_TO),
CRASHTYPE(USERCOPY_HEAP_WHITELIST_FROM),
CRASHTYPE(USERCOPY_STACK_FRAME_TO),
CRASHTYPE(USERCOPY_STACK_FRAME_FROM),
CRASHTYPE(USERCOPY_STACK_BEYOND),
CRASHTYPE(USERCOPY_KERNEL),
CRASHTYPE(USERCOPY_KERNEL_DS),
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
}; 
 
시그니처
 
LKDTM을 실행한 후 덤프(vmcore)에서 받은 커널 로그를 소개합니다.
 
아래는 'echo EXCEPTION > /sys/kernel/debug/provoke-crash/DIRECT' 명령어를 실행후 받은 덤프에서 확인한 커널 로그입니다.
 
[   57.750675] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[   57.757757] pgd = ffffffc045138000
[   57.761957] [00000000] *pgd=0000000000000000
[   57.765404] Internal error: Oops: 96000045 [#1] PREEMPT SMP
[   57.770949] Modules linked in:
[   57.773996] CPU: 7 PID: 1897 Comm: sh Tainted: G    B   W    3.18.49-g9381d81-00083-gb8bb6a4-dirty #2
[   57.783215] task: ffffffc04e980000 ti: ffffffc0450ec000 task.ti: ffffffc0450ec000
[   57.790665] PC is at lkdtm_do_action+0x44/0x130
[   57.795191] LR is at direct_entry+0x100/0x128
[   57.799511] pc : [<ffffffc0006019e8>] lr : [<ffffffc000601bd4>] pstate: 80000145
[   57.806883] sp : ffffffc0450efdb0
[   57.810213] x29: ffffffc0450efdb0 x28: ffffffc0450ec000 
[   57.815480] x27: ffffffc00163b000 x26: 0000000000000040 
[   57.820774] x25: 0000000000000116 x24: 0000000000000015 
[   57.826068] x23: 0000000000000000 x22: 0000000000000003 
[   57.831370] x21: ffffffc0450efec8 x20: ffffffc02f240000 
[   57.836661] x19: 000000000000000a x18: 00000000ffffffff 
[   57.841956] x17: 0000007fa1e89344 x16: ffffffc0002ffb30 
[   57.847252] x15: 0000007fa1d1c120 x14: 0fffffffffffffff 
[   57.852549] x13: 0000000000000038 x12: 0101010101010101 
[   57.857842] x11: 7f7f7f7f7f7f7f7f x10: ff4d4e48534f4442 
[   57.863146] x9 : 7f7fffffffffffff x8 : 5045435845207972 
[   57.868430] x7 : 746e652074636572 x6 : ffffffc00186ee1f 
[   57.873727] x5 : 000000000000000a x4 : 0000000000000004 
[   57.879023] x3 : 0000000000000000 x2 : ffffffc0450ec000 
[   57.884316] x1 : ffffffc0006019d4 x0 : 0000000000000000 [   57.889316] mdss_mdp_video_wait4comp: vsync wait timeout 0, fallback to poll mode
 
이번에는 'echo WRITE_AFTER_FREE > /sys/kernel/debug/provoke-crash/DIRECT' 명령어를 실행한 다음에 받은 덤프에서 확인한 커널 로그입니다.
 
[   84.609150] lkdtm: Performing direct entry WRITE_AFTER_FREE
[   84.127146] BUG kmalloc-1024 (Tainted: G    B   W   ): Poison overwritten
[   84.133909] -----------------------------------------------------------------------------
[   84.143551] INFO: 0xffffffc00dd31600-0xffffffc00dd319fe. First byte 0x78 instead of 0x6b
[   84.151630] INFO: Allocated in lkdtm_do_action+0xd4/0x130 age=8 cpu=4 pid=4509
[   84.158827] +alloc_debug_processing+0x114/0x16c
[   84.163340] +__slab_alloc.isra.52.constprop.58+0x3f4/0x504
[   84.168805] +kmem_cache_alloc_trace+0x9c/0x1e8
[   84.173234] +lkdtm_do_action+0xd0/0x130
[   84.177053] +direct_entry+0xfc/0x128
[   84.180617] +vfs_write+0xcc/0x178
[   84.183912] +SyS_write+0x44/0x74
[   84.187132] +cpu_switch_to+0x48/0x4c
[   84.190689] INFO: Freed in lkdtm_do_action+0xdc/0x130 age=13 cpu=4 pid=4509
[   84.197629] +free_debug_processing+0x22c/0x2cc
[   84.202054] +__slab_free+0x44/0x2b0
[   84.205525] +kfree+0x1f8/0x218
[   84.208566] +lkdtm_do_action+0xd8/0x130
[   84.212387] +direct_entry+0xfc/0x128
[   84.215943] +vfs_write+0xcc/0x178
[   84.219240] +SyS_write+0x44/0x74
[   84.222454] +cpu_switch_to+0x48/0x4c
[   84.226016] INFO: Slab 0xffffffbc05d12780 objects=23 used=23 fp=0x          (null) flags=0x4080
[   84.243379] Bytes b4 ffffffc00dd315f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a  ZZZZZZZZZZZZZZZZ
[   84.837991] Object ffffffc00dd319f0: 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78  xxxxxxxxxxxxxxxx
[   84.847280] Redzone ffffffc00dd31a00: bb bb bb bb bb bb bb bb                          ........
[   84.855961] Padding ffffffc00dd31b40: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a  ZZZZZZZZZZZZZZZZ
[   84.884090] Padding ffffffc00dd31b70: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a  ZZZZZZZZZZZZZZZZ
[   84.893467] CPU: 7 PID: 2510 Comm: Binder_10 Tainted: G    B   W    3.10.49-g9381d81-00083-gb8bb6a4-dirty #
저번 포스트에서는 아래 실행 흐름으로 IPI Call을 요청하는 함수를 알아봤습니다.
 
 
이어서 Arm 아키텍처에서 제공하는 SGI를 이용해 IPI Call을 처리하는 아키텍처에 의존적인 루틴을 분석하겠습니다.
 
다음은 gic_ipi_send_mask() 함수의 구현부입니다.
 
01 static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
02 {
03 int cpu;
04
05 if (WARN_ON(d->hwirq >= 16))
06 return;
07
08 /*
09  * Ensure that stores to Normal memory are visible to the
10  * other CPUs before issuing the IPI.
11  */
12 wmb();
13
14 for_each_cpu(cpu, mask) {
15 u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu));
16 u16 tlist;
17
18 tlist = gic_compute_target_list(&cpu, mask, cluster_id);
19 gic_send_sgi(cluster_id, tlist, d->hwirq);
20 }
21
22 /* Force the above writes to ICC_SGI1R_EL1 to be executed */
23 isb();
24 }
 
핵심 루틴은 gic_send_sgi() 함수를 호출하는 19번째 줄인데요.
 
중요한 함수이니 라인 별로 코드를 분석하겠습니다.
 
먼저 05~06번째 줄을 보겠습니다.
 
05 if (WARN_ON(d->hwirq >= 16))
06 return;
 
'd->hwirq' 에서 지정된 인터럽트 아이디(Interrupt ID)가 16 이상인 경우 리턴 처리하는 루틴입니다.
GICv3 아키텍처에서 SGI의 인터럽트 아이디의 범위는 0~15이라는 점을 기억합시다.
 
이어서 08~12번째 줄을 보겠습니다.
 
08 /*
09  * Ensure that stores to Normal memory are visible to the
10  * other CPUs before issuing the IPI.
11  */
12 wmb();
 
주석을 보면 아마 Arm 개발자가 추가한 듯 보입니다. 
09번째 줄에 있는 Normal memory는 Armv8 아키텍처에서 정의된 메모리 모델인데요.
 
Armv8 에서는 메모리를 Normal Memory와 Device Memory 타입으로 분류합니다.
Normal Memory는 메인 메모리에 접근해 데이터를 로딩하거나 코드를 실행하는 메모리 타입인데요.
Normal Memory로 지정된 루틴은 캐싱(Caching)을 지원합니다.
 
Arm 프로세서 내부에서 프로세서의 성능을 키우기 위해 명령어의 순서를 재배치해 실행하는데요.
 
19번째 줄에 있는 함수를 실행하면 ICC_SGI1R_EL1 시스템 레지스터의 값을 변경하는데,
이전에 'dsb st' 명령어를 실행해 Arm 프로세서 내부에 있는 파이프라인에서 실행되는 명령어와 데이터를 플러시하기 위한 목적으로 12번째 줄이 실행됩니다.
 
다음은 어셈블리 명령어로 본 gic_ipi_send_mask() 함수의 구현부입니다.
각 명령어 옆에 있는 주석문을 참고합시다.
 
ffffffc01047c698 <gic_ipi_send_mask>:
ffffffc01047c698:   71003c3f    cmp w1, #0xf
...
ffffffc01047c6b8:   a9046bf9    stp x25, x26, [sp,#64]
ffffffc01047c6bc:   d5033e9f    dsb st // Store Data Synchronization Barrier 실행
...
ffffffc01047c784:   d518cbb9    msr s3_0_c12_c11_5, x25 // ICC_SGI1R_EL1 설정
ffffffc01047c788:   2a1303e0    mov w0, w19
ffffffc01047c78c:   aa1403e1    mov x1, x20
...
ffffffc01047c7a4:   d5033fdf    isb // Instruction Synchronization Barrier 실행
 
다음으로 19번째 줄을 봅시다.
 
19 gic_send_sgi(cluster_id, tlist, d->hwirq);
 
gic_send_sgi() 함수를 호출합니다.
 
gic_send_sgi() 함수를 보겠습니다.
 
static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
{
u64 val;
 
val = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3) |
       MPIDR_TO_SGI_AFFINITY(cluster_id, 2) |
       irq << ICC_SGI1R_SGI_ID_SHIFT |
       MPIDR_TO_SGI_AFFINITY(cluster_id, 1) |
       MPIDR_TO_SGI_RS(cluster_id) |
       tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
 
pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
gic_write_sgi1r(val);
}
 
val로 아규먼트를 지정한 다음에 gic_write_sgi1r() 함수를 호출합니다.
 
이어서 gic_write_sgi1r() 함수를 보겠습니다.
 
static inline void gic_write_sgi1r(u64 val)
{
write_sysreg_s(val, SYS_ICC_SGI1R_EL1);
}
 
GIC에서 정의된 CPU Interface에서 제공하는 ICC_SGI1R_EL1 시스템 레지스터에
값을 써주는 루틴입니다. 
 
gic_write_sgi1r() 함수가 호출되면 GIC에서 인터럽트를 유발해 다음과 같은 기준으로
프로그램 카운터를 브랜치합니다.
 
   "VBAR_EL1 + 0x280"
IPI(Inter Processor Interrupt)의 약자로 지정한 CPU 코어를 타겟으로 인터럽트(소프트웨어적)를 유발하는 매커니즘입니다. 이번 포스트에서는 리눅스 커널에서 IPI Call을 요청하는 루틴을 리뷰하겠습니다.
 
IPI Call은 아키텍처에 의존적으로 처리되므로 하이 레벨과 로우 레벨로 코드가 구현돼 있습니다.
 
* High Level 코드 위치
 
   kernel/sched/core.c
   kernel/smp.c
   kernel/irq/ipi.c
 
* Low Level (Arm 아키텍처) 코드 위치
 
   arch/arm64/kernel/smp.c
   drivers/irqchip/irq-gic-v3.c
 
IPI Call 요청 루틴(하이 레벨)
 
아래 함수는 Qualcomm Watchdog 드라이버에 존재하는 함수인데요.
 
static void ping_other_cpus(struct msm_watchdog_data *wdog_dd)
{
int cpu;
 
cpumask_clear(&wdog_dd->alive_mask);
/* Make sure alive mask is cleared and set in order */
smp_mb();
for_each_cpu(cpu, cpu_online_mask) {
if (!cpu_idle_pc_state[cpu] && !cpu_isolated(cpu)) {
wdog_dd->ping_start[cpu] = sched_clock();
smp_call_function_single(cpu, keep_alive_response,
 wdog_dd, 1);
}
}
}
 
온라인 상태에 있는 CPU 코어에게 smp_call_function_single() 함수를 호출해 IPI Call을 요청하는 루틴입니다. 여기서 지정된 CPU 코어가 IPI Call을 받으면 콜백으로 지정된 keep_alive_response() 함수가 호출되는데요. keep_alive_response() 함수에서 "난 지금 정상 동작한다"라는 정보를 써줍니다.
 
smp_call_function_single() 함수의 구현부는 다음과 같습니다.
 
int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
     int wait)
{
call_single_data_t *csd;
call_single_data_t csd_stack = {
.node = { .u_flags = CSD_FLAG_LOCK | CSD_TYPE_SYNC, },
};
int this_cpu;
int err;
 
/*
 * prevent preemption and reschedule on another processor,
 * as well as CPU removal
 */
this_cpu = get_cpu();
 
/*
 * Can deadlock when called with interrupts disabled.
 * We allow cpu's that are not yet online though, as no one else can
 * send smp call function interrupt to this cpu and as such deadlocks
 * can't happen.
 */
WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
     && !oops_in_progress);
 
/*
 * When @wait we can deadlock when we interrupt between llist_add() and
 * arch_send_call_function_ipi*(); when !@wait we can deadlock due to
 * csd_lock() on because the interrupt context uses the same csd
 * storage.
 */
WARN_ON_ONCE(!in_task());
 
csd = &csd_stack;
if (!wait) {
csd = this_cpu_ptr(&csd_data);
csd_lock(csd);
}
 
csd->func = func;
csd->info = info;
#ifdef CONFIG_CSD_LOCK_WAIT_DEBUG
csd->node.src = smp_processor_id();
csd->node.dst = cpu;
#endif
 
err = generic_exec_single(cpu, csd);
 
if (wait)
csd_lock_wait(csd);
 
put_cpu();
 
return err;
}
 
call_single_data_t 자료구조에 IPI Call과 관련된 정보를 써주고 generic_exec_single() 함수를 호출합니다.
 
generic_exec_single() 함수의 구현부는 다음과 같습니다.
 
static int generic_exec_single(int cpu, struct __call_single_data *csd)
{
if (cpu == smp_processor_id()) {
smp_call_func_t func = csd->func;
void *info = csd->info;
unsigned long flags;
 
/*
 * We can unlock early even for the synchronous on-stack case,
 * since we're doing this from the same CPU..
 */
csd_lock_record(csd);
csd_unlock(csd);
local_irq_save(flags);
func(info);
csd_lock_record(NULL);
local_irq_restore(flags);
return 0;
}
 
if ((unsigned)cpu >= nr_cpu_ids || !cpu_online(cpu)) {
csd_unlock(csd);
return -ENXIO;
}
 
__smp_call_single_queue(cpu, &csd->node.llist);
 
return 0;
}
 
코드 앞 부분에 자신(CPU)에게 IPI Call을 전달하는 경우의 예외 처리 루틴이 보입니다.
이 루틴을 제외하면 __smp_call_single_queue() 함수를 호출합니다.
 
__smp_call_single_queue() 함수의 구현부는 다음과 같습니다.
 
void __smp_call_single_queue(int cpu, struct llist_node *node)
{
#ifdef CONFIG_CSD_LOCK_WAIT_DEBUG
if (static_branch_unlikely(&csdlock_debug_extended)) {
unsigned int type;
 
type = CSD_TYPE(container_of(node, call_single_data_t,
     node.llist));
if (type == CSD_TYPE_SYNC || type == CSD_TYPE_ASYNC) {
__smp_call_single_queue_debug(cpu, node);
return;
}
}
#endif
 
/*
 * The list addition should be visible before sending the IPI
 * handler locks the list to pull the entry off it because of
 * normal cache coherency rules implied by spinlocks.
 *
 * If IPIs can go out of order to the cache coherency protocol
 * in an architecture, sufficient synchronisation should be added
 * to arch code to make it appear to obey cache coherency WRT
 * locking and barrier primitives. Generic code isn't really
 * equipped to do the right thing...
 */
if (llist_add(node, &per_cpu(call_single_queue, cpu)))
send_call_function_single_ipi(cpu);
}
 
IPI Call을 관리하는 call_single_queue에 Enqueue을 한 다음에 send_call_function_single_ipi() 함수를 호출합니다.
 
이어서 send_call_function_single_ipi() 함수의 구현부를 보겠습니다.
 
void send_call_function_single_ipi(int cpu)
{
struct rq *rq = cpu_rq(cpu);
 
if (!set_nr_if_polling(rq->idle))
arch_send_call_function_single_ipi(cpu);
else
trace_sched_wake_idle_without_ipi(cpu);
}
 
아이들 프로세스를 처리하는 상황이 아니면 arch_send_call_function_single_ipi() 함수를 호출합니다.
 
arch_send_call_function_single_ipi() 함수의 구현부를 보겠습니다.
 
void arch_send_call_function_single_ipi(int cpu)
{
smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC);
}
 
코드의 위치가 'arch/arm64/kernel/smp.c'이므로 Arm64 아키텍처에 의존적인 루틴이라는
점을 알 수 있습니다.
 
smp_cross_call() 함수를 보겠습니다.
 
01 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
02 {
03 trace_ipi_raise(target, ipi_types[ipinr]);
04 __ipi_send_mask(ipi_desc[ipinr], target);
05 }
 
03번째 줄에서는 ftrace로 ipi_raise 이벤트 메시지를 출력합니다.
이어서 04번째 줄에서 __ipi_send_mask() 함수를 호출합니다.
 
__ipi_send_mask() 함수의 구현부를 보겠습니다.
 
int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
unsigned int cpu;
...
if (chip->ipi_send_mask) {
chip->ipi_send_mask(data, dest);
return 0;
}
 
if (irq_domain_is_ipi_per_cpu(data->domain)) {
unsigned int base = data->irq;
 
for_each_cpu(cpu, dest) {
unsigned irq = base + cpu - data->common->ipi_offset;
 
data = irq_get_irq_data(irq);
chip->ipi_send_single(data, cpu);
}
} else {
for_each_cpu(cpu, dest)
chip->ipi_send_single(data, cpu);
}
return 0;
}
 
'chip->ipi_send_mask' 구문을 실행해 함수 포인터를 실행합니다.
여기서 함수를 분석하다가 포기하는 경우가 많은데요. 
 
조금 더 면밀히 코드를 분석하거나 램덤프를 분석하면 다음과 같은 사실을 알 수 있습니다.
 
    "chip->ipi_send_mask를 통해 gic_ipi_send_mask() 함수가 호출된다"
 
GICv3으로 커널 컨피그를 설정하면 아래와 같이 정의된 gic_chip 전역 변수가 
인터럽트 디스크립터로 등록됩니다.
 
static struct irq_chip gic_chip = {
    .name           = "GICv3",
    .irq_mask       = gic_mask_irq,
    .irq_unmask     = gic_unmask_irq,
    .irq_eoi        = gic_eoi_irq,
    .irq_set_type       = gic_set_type,
    .irq_set_affinity   = gic_set_affinity,
    .irq_retrigger          = gic_retrigger,
    .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
    .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
    .irq_nmi_setup      = gic_irq_nmi_setup,
    .irq_nmi_teardown   = gic_irq_nmi_teardown,
    .ipi_send_mask      = gic_ipi_send_mask,
    .flags          = IRQCHIP_SET_TYPE_MASKED |
                  IRQCHIP_SKIP_SET_WAKE |
                  IRQCHIP_MASK_ON_SUSPEND,
};
<v5.4>
 
By default kernel is configured with CONFIG_SCHED_INFO=y.
Looking into .config we can notice the followings;
 
# Scheduler Debugging
#
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHED_INFO=y
# CONFIG_SCHEDSTATS is not set
# end of Scheduler Debugging
 
With below patch, CONFIG_SCHED_INFO can be disabled
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ee00c6c..dd70401 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1007,7 +1007,6 @@ config SCHED_INFO
 config SCHEDSTATS
        bool "Collect scheduler statistics"
        depends on DEBUG_KERNEL && PROC_FS
-       select SCHED_INFO
        help
          If you say Y here, additional code will be inserted into the
          scheduler and related routines to collect statistics about
diff --git a/init/Kconfig b/init/Kconfig
index fc4c9f4..4f4fe52 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -569,7 +569,6 @@ config TASKSTATS
 config TASK_DELAY_ACCT
        bool "Enable per-task delay accounting"
        depends on TASKSTATS
-       select SCHED_INFO
        help
          Collect information on time spent by a task waiting for system
          resources like cpu, synchronous block I/O completion and swapping
 
As above patch indicates, CONFIG_SCHED_DEBUG depends on CONGIF_SCHEDSTATS. 
__schedule() 함수의 구현부
 
MX:FFFFFFC010AD0898|A9B77BFD  __schedule:     stp     x29,x30,[sp,#-0x90]!   ; x29,x30,[sp,#-144]!
MX:FFFFFFC010AD089C|910003FD                  mov     x29,sp
MX:FFFFFFC010AD08A0|A90153F3                  stp     x19,x20,[sp,#0x10]   ; x19,x20,[sp,#16]
MX:FFFFFFC010AD08A4|A9025BF5                  stp     x21,x22,[sp,#0x20]   ; x21,x22,[sp,#32]
MX:FFFFFFC010AD08A8|12001C16                  and     w22,w0,#0xFF     ; w22,preempt,#255
MX:FFFFFFC010AD08AC|D0002935                  adrp    x21,0xFFFFFFC010FF6000   ; x21,dummy_timer_evt
MX:FFFFFFC010AD08B0|A90363F7                  stp     x23,x24,[sp,#0x30]   ; x23,x24,[sp,#48]
MX:FFFFFFC010AD08B4|D5384117                  mrs     x23,#0x3,#0x0,c4,c1,#0x0   ; x23, SP_EL0
MX:FFFFFFC010AD08B8|D00029D8                  adrp    x24,0xFFFFFFC01100A000
MX:FFFFFFC010AD08BC|A9046BF9                  stp     x25,x26,[sp,#0x40]   ; x25,x26,[sp,#64]
MX:FFFFFFC010AD08C0|91188318                  add     x24,x24,#0x620   ; x24,x24,#1568
MX:FFFFFFC010AD08C4|913502B5                  add     x21,x21,#0xD40   ; x21,x21,#3392
MX:FFFFFFC010AD08C8|A90573FB                  stp     x27,x28,[sp,#0x50]   ; x27,x28,[sp,#80]
MX:FFFFFFC010AD08CC|AA1503F3                  mov     x19,x21
 
0xFFFFFFC010AD0898가 vmlinux에서 본 __schedule() 함수의 가상 주소다. 
 
kimage_voffset인 0xffffffbf90000000을 빼자.
 
0x80AD0898 = 0xFFFFFFC010AD0898 - 0xffffffbf90000000 
 
0x80AD0898 주소에 있는 명령어를 보자. __schedule() 함수의 명령어와 완전히 같다.
 
____addr/line|code_____|label____|mnemonic________________|comment
MX:80AD0898|A9B77BFD            stp     x29,x30,[sp,#-0x90]!   ; x29,x30,[sp,#-144]!
MX:80AD089C|910003FD            mov     x29,sp
MX:80AD08A0|A90153F3            stp     x19,x20,[sp,#0x10]   ; x19,x20,[sp,#16]
MX:80AD08A4|A9025BF5            stp     x21,x22,[sp,#0x20]   ; x21,x22,[sp,#32]
MX:80AD08A8|12001C16            and     w22,w0,#0xFF     ; w22,w0,#255
MX:80AD08AC|D0002935            adrp    x21,0x80FF6000
MX:80AD08B0|A90363F7            stp     x23,x24,[sp,#0x30]   ; x23,x24,[sp,#48]
MX:80AD08B4|D5384117            mrs     x23,#0x3,#0x0,c4,c1,#0x0   ; x23, SP_EL0
MX:80AD08B8|D00029D8            adrp    x24,0x8100A000
MX:80AD08BC|A9046BF9            stp     x25,x26,[sp,#0x40]   ; x25,x26,[sp,#64]
MX:80AD08C0|91188318            add     x24,x24,#0x620   ; x24,x24,#1568
MX:80AD08C4|913502B5            add     x21,x21,#0xD40   ; x21,x21,#3392
MX:80AD08C8|A90573FB            stp     x27,x28,[sp,#0x50]   ; x27,x28,[sp,#80]
MX:80AD08CC|AA1503F3            mov     x19,x21
MX:80AD08D0|F90037BE            str     x30,[x29,#0x68]   ; x30,[x29,#104]
MX:80AD08D4|F9428AE0            ldr     x0,[x23,#0x510]   ; x0,[x23,#1296]
MX:80AD08D8|F90047A0            str     x0,[x29,#0x88]   ; x0,[x29,#136]
MX:80AD08DC|D2800000            mov     x0,#0x0          ; x0,#0
MX:80AD08E0|97E6697A            bl      0x8046AEC8
 
이번에는 vmlinux에서 swapper_pg_dir의 주소를 체크하자
 
  (pgd_t [512] *) &swapper_pg_dir = 0xFFFFFFC010F45000 = swapper_pg_dir -> ([0 = 0x0] = ((pgdval_t)
 
0xFFFFFFC010F45000 가 가상 주소다.
 
kimage_voffset인 0xffffffbf90000000을 빼자.
 
0x80F45000 = 0xFFFFFFC010F45000 - 0xffffffbf90000000  
 
0x80F45000로 확인된다.
 
linux_banner
 
  (const char [110] *) &linux_banner = 0xFFFFFFC010AE0090 = linux_banner -> "Linux version 5.4.61 (o
 
____________address|________0________4________8________C_0123456789ABCDEF
MD:FFFFFFC010AE0090|>756E694C 65762078 6F697372 2E35206E Linux version 5.
MD:FFFFFFC010AE00A0| 31362E34 656F2820 6573752D 656F4072 4.61 (oe-user@oe
MD:FFFFFFC010AE00B0| 736F682D 28202974 20636367 73726576 -host) (gcc vers
MD:FFFFFFC010AE00C0| 206E6F69 2E332E39 47282030 29294343 ion 9.3.0 (GCC))
MD:FFFFFFC010AE00D0| 20312320 20504D53 45455250 2054504D  #1 SMP PREEMPT
MD:FFFFFFC010AE00E0| 20646557 20636544 30203232 37353A33 Wed Dec 22 03:57
MD:FFFFFFC010AE00F0| 2035333A 20435455 31323032 0000000A :35 UTC 2021....
 
 
0x80AE0090 = FFFFFFC010AE0090 - 0xffffffbf90000000
 
____address|________0________4________8________C_0123456789ABCDEF
MD:80AE0090|>756E694C 65762078 6F697372 2E35206E Linux version 5.
MD:80AE00A0| 31362E34 656F2820 6573752D 656F4072 4.61 (oe-user@oe
MD:80AE00B0| 736F682D 28202974 20636367 73726576 -host) (gcc vers
MD:80AE00C0| 206E6F69 2E332E39 47282030 29294343 ion 9.3.0 (GCC))
MD:80AE00D0| 20312320 20504D53 45455250 2054504D  #1 SMP PREEMPT
MD:80AE00E0| 20646557 20636544 30203232 37353A33 Wed Dec 22 03:57
MD:80AE00F0| 2035333A 20435455 31323032 0000000A :35 UTC 2021....
MD:80AE0100| 10D69260 FFFFFFC0 00000000 00000000 `...............
<커널: v5.10>
 
부팅 시간을 측정할 때 어떤 파일이 오픈됐는지 확인할 필요가 있습니다.
이 때 활용되면 좋은 패치입니다.
 
Author: Austin Kim <austindh.kim@gmail.com>
Date:   Mon Sep 20 19:16:16 2021 +0900
 
    open: trace the filename with directory
 
    When measuring booting-time, it is necessary to see how the file is
    opened. With this commit, we can trace how file is opened with ftrace buffer.
 
    <...>-124     [001] ....     2.968597: do_sys_openat2: cached_setup_ke: open("/dev/tty5", 131072, 0)
    fd = 3, inode = 25
   <...>-139     [002] ....     2.970130: do_sys_openat2: modprobe: open("/usr/lib/modules/5.10.46-
   v8+/kernel/crypto/sha256_generic.ko", 655360, 0) fd = 0, inode = 284403
   <...>-142     [000] d..1     2.970491: console: [    2.970468] [exec:kbd_mode-142] exec_file:
    /usr/bin/kbd_mode, arg: [kbd_mode] 
   <...>-142     [000] ....     2.970783: do_sys_openat2: kbd_mode: open("/etc/ld.so.cache", 655360, 0)
    fd = 3, inode = 6059
   <...>-142     [000] ....     2.970880: do_sys_openat2: kbd_mode: open("/usr/lib/aarch64-linux-gnu/libc
   -2.28.so", 655360, 0) fd = 3, inode = 6857
   <...>-142     [000] ....     2.971834: do_sys_openat2: kbd_mode: open("/usr/lib/locale/locale-archive",
   655360, 0) fd = 3, inode = 12847
   <...>-142     [000] ....     2.972191: do_sys_openat2: kbd_mode: open("/dev/tty5", 131074, 0) fd = 3, 
   inode = 25
 
diff --git a/fs/open.c b/fs/open.c
index 4d7537ae5..b7c8260f9
--- a/fs/open.c
+++ b/fs/open.c
@@ -1153,6 +1153,27 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 }
 EXPORT_SYMBOL(file_open_root);
 
+static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd)
+{
+       char *buf;
+       char *fname;
+
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       fname = d_path(&filp->f_path, buf, PAGE_SIZE);
+
+       if (IS_ERR(fname))
+               goto out;
+
+       trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n",
+                      current->comm, fname, flags, mode, fd, filp->f_inode->i_ino);
+
+out:
+       kfree(buf);
+}
+
 static long do_sys_openat2(int dfd, const char __user *filename,
                           struct open_how *how)
 {
@@ -1176,6 +1197,7 @@ static long do_sys_openat2(int dfd, const char __user *filename,
                } else {
                        fsnotify_open(f);
                        fd_install(fd, f);
+                       _trace_do_sys_open(f, how->flags, how->mode, fd);
                }
        }
        putname(tmp);
<커널: v5.10>
 
부팅 과정에서 ftrace 로깅이 될 때 ftrace ring-buffer 사이즈가 충분해야 부팅 과정의 
메시지를 ftrace에 저장할 수 있습니다. ring-buffer 사이즈가 작으면 메시지가 overwritten됩니다. 
 
본 페이지에 소개된 패치를 적용하면 부팅 과정에서 ftracing ring-buffer 사이즈를 키울 수 있습니다.
 
commit 0deada593566918d6ac4a3e8df7bca8584fd83e1 (HEAD -> rpi-5.10.y)
Author: Austin Kim <austindh.kim@gmail.com>
Date:   Mon Sep 20 14:52:54 2021 +0900
 
    tracing: increase ftrace ring-buffer size
 
    In case ftrace ring-buffer size is small,
    ftrace message could be overwritten. As a result of this,
    the useful ftrace message can be lost.
 
    With this commit, we could increase ftrace ring-buffer size.
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
old mode 100644
new mode 100755
index b09c59806..8cb872543
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6541,6 +6541,8 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
        return ret;
 }
 
+#define TRACING_FTRACE_MAX_BUFFER_SIZE (4096 * 2)
+
 static ssize_t
 tracing_entries_write(struct file *filp, const char __user *ubuf,
                      size_t cnt, loff_t *ppos)
@@ -6558,6 +6560,10 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        if (!val)
                return -EINVAL;
 
+       if( val < TRACING_FTRACE_MAX_BUFFER_SIZE ) {
+               val = TRACING_FTRACE_MAX_BUFFER_SIZE;
+       }
+
        /* value is in KB */
        val <<= 10;
        ret = tracing_resize_ring_buffer(tr, val, tracing_get_cpu(inode));
 
<커널: v5.10>
 
부팅 과정에서 ftrace가 초기화되면서 ftrace 로깅이 드라이버 레벨로 활성화가 되면,
구지 다음과 같은 명령어를 입력할 필요성을 못 느낍니다.
 
'echo 1 > /sys/kernel/debug/tracing/tracing_on'
 
본 페이지에 소개된 패치를 적용하면 부팅 과정에서 ftracing 로깅을 실행할 수 있습니다.
 
commit 7f75bdc9ac6a2bae4d6352d15640b331d9becfbb
Author: Austin Kim <austindh.kim@gmail.com>
Date:   Mon Sep 20 14:23:17 2021 +0900
 
    tracing: enable ftrace at boot
 
    Using 'echo 1 > /sys/kernel/debug/tracing/tracing_on',
    the ftrace is enabled. But sometimes we are in the situation where
    boot time should be measured using ftrace.
 
    With CONFIG_ENABLE_FTRACE_AT_BOOT enabled, the ftrace is enabled at boot.
 
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
old mode 100644
new mode 100755
index 29db703f6..9e02f297f
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -243,6 +243,13 @@ config STACK_TRACER
 
          Say N if unsure.
 
+config ENABLE_FTRACE_AT_BOOT
+       bool "Enable ftrace at boot"
+       depends on TRACING
+       default y
+    help
+               Enable ftrace at boot
+
 config TRACE_PREEMPT_TOGGLE
        bool
        help
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
old mode 100644
new mode 100755
index ab3cb67b8..e50fd2a8c
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -3424,6 +3424,47 @@ static __init int event_trace_enable(void)
        return 0;
 }
 
+#ifdef CONFIG_ENABLE_FTRACE_AT_BOOT
+static void ftrace_events_enable(int enable)
+{
+       if (enable) {
+               trace_set_clr_event(NULL, "printk", 1);
+               trace_set_clr_event(NULL, "console", 1);
+               trace_set_clr_event(NULL, "signal_generate", 1);
+               trace_set_clr_event(NULL, "signal_deliver", 1);
+    } else {
+               tracing_off();
+               trace_set_clr_event(NULL, NULL, 0);
+    }
+}
+
+static __init int enable_ftrace_boot(void)
+{
+       struct trace_array *tr;
+       int ret = 0;
+
+       tr = top_trace_array();
+       if (!tr) {
+               pr_err("%s: Invalid tr from top_trace_array n", __func__);
+               return -ENODEV;
+       }
+
+       ret = tracing_update_buffers();
+       if (ret != 0) {
+               pr_err("%s: invalid buffer ret=%dn", __func__, ret);
+               return -ENODEV;
+       }
+
+       ftrace_events_enable(1);
+       set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 0);
+
+       tracing_on();
+
+       return 0;
+}
+late_initcall(enable_ftrace_boot);
+#endif
+
 /*
  * event_trace_enable() is called from trace_event_init() first to
  * initialize events and perhaps start any events that are on the
커널 커멘드 라인을 추가하는 가장 간단한 방법은 config에 커멘드 라인을 추가하는 것이다.
 
예를 들어;
 
CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
 
커널 로그;
 
[    0.000000] Kernel command line: coherent_pool=1M 8250.nr_uarts=0 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1  smsc95xx.macaddr=DC:A6:32:B0:F3:62 vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000  console=ttyS0,115200 console=tty1 root=PARTUUID=981c94c6-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

아래는 v5.10, 라즈비안 커널(Aarch64)에서 확인한 전체 ftrace event의 종류이다.

 
root@raspberrypi:/sys/kernel/debug/tracing/events# tree -L 2
.
├── alarmtimer
│   ├── alarmtimer_cancel
│   ├── alarmtimer_fired
│   ├── alarmtimer_start
│   ├── alarmtimer_suspend
│   ├── enable
│   └── filter
├── asoc
│   ├── enable
│   ├── filter
│   ├── snd_soc_bias_level_done
│   ├── snd_soc_bias_level_start
│   ├── snd_soc_dapm_connected
│   ├── snd_soc_dapm_done
│   ├── snd_soc_dapm_path
│   ├── snd_soc_dapm_start
│   ├── snd_soc_dapm_walk_done
│   ├── snd_soc_dapm_widget_event_done
│   ├── snd_soc_dapm_widget_event_start
│   ├── snd_soc_dapm_widget_power
│   ├── snd_soc_jack_irq
│   ├── snd_soc_jack_notify
│   └── snd_soc_jack_report
├── binder
│   ├── binder_alloc_lru_end
│   ├── binder_alloc_lru_start
│   ├── binder_alloc_page_end
│   ├── binder_alloc_page_start
│   ├── binder_command
│   ├── binder_free_lru_end
│   ├── binder_free_lru_start
│   ├── binder_ioctl
│   ├── binder_ioctl_done
│   ├── binder_lock
│   ├── binder_locked
│   ├── binder_read_done
│   ├── binder_return
│   ├── binder_transaction
│   ├── binder_transaction_alloc_buf
│   ├── binder_transaction_buffer_release
│   ├── binder_transaction_failed_buffer_release
│   ├── binder_transaction_fd_recv
│   ├── binder_transaction_fd_send
│   ├── binder_transaction_node_to_ref
│   ├── binder_transaction_received
│   ├── binder_transaction_ref_to_node
│   ├── binder_transaction_ref_to_ref
│   ├── binder_unlock
│   ├── binder_unmap_kernel_end
│   ├── binder_unmap_kernel_start
│   ├── binder_unmap_user_end
│   ├── binder_unmap_user_start
│   ├── binder_update_page_range
│   ├── binder_wait_for_work
│   ├── binder_write_done
│   ├── enable
│   └── filter
├── block
│   ├── block_bio_backmerge
│   ├── block_bio_bounce
│   ├── block_bio_complete
│   ├── block_bio_frontmerge
│   ├── block_bio_queue
│   ├── block_bio_remap
│   ├── block_dirty_buffer
│   ├── block_getrq
│   ├── block_plug
│   ├── block_rq_complete
│   ├── block_rq_insert
│   ├── block_rq_issue
│   ├── block_rq_merge
│   ├── block_rq_remap
│   ├── block_rq_requeue
│   ├── block_sleeprq
│   ├── block_split
│   ├── block_touch_buffer
│   ├── block_unplug
│   ├── enable
│   └── filter
├── bpf_test_run
│   ├── bpf_test_finish
│   ├── enable
│   └── filter
├── bpf_trace
│   ├── bpf_trace_printk
│   ├── enable
│   └── filter
├── bridge
│   ├── br_fdb_add
│   ├── br_fdb_external_learn_add
│   ├── br_fdb_update
│   ├── enable
│   ├── fdb_delete
│   └── filter
├── cachefiles
│   ├── cachefiles_create
│   ├── cachefiles_lookup
│   ├── cachefiles_mark_active
│   ├── cachefiles_mark_buried
│   ├── cachefiles_mark_inactive
│   ├── cachefiles_mkdir
│   ├── cachefiles_ref
│   ├── cachefiles_rename
│   ├── cachefiles_unlink
│   ├── cachefiles_wait_active
│   ├── enable
│   └── filter
├── cfg80211
│   ├── cfg80211_cac_event
│   ├── cfg80211_chandef_dfs_required
│   ├── cfg80211_ch_switch_notify
│   ├── cfg80211_ch_switch_started_notify
│   ├── cfg80211_control_port_tx_status
│   ├── cfg80211_cqm_pktloss_notify
│   ├── cfg80211_cqm_rssi_notify
│   ├── cfg80211_del_sta
│   ├── cfg80211_ft_event
│   ├── cfg80211_get_bss
│   ├── cfg80211_gtk_rekey_notify
│   ├── cfg80211_ibss_joined
│   ├── cfg80211_inform_bss_frame
│   ├── cfg80211_mgmt_tx_status
│   ├── cfg80211_michael_mic_failure
│   ├── cfg80211_new_sta
│   ├── cfg80211_notify_new_peer_candidate
│   ├── cfg80211_pmksa_candidate_notify
│   ├── cfg80211_pmsr_complete
│   ├── cfg80211_pmsr_report
│   ├── cfg80211_probe_status
│   ├── cfg80211_radar_event
│   ├── cfg80211_ready_on_channel
│   ├── cfg80211_ready_on_channel_expired
│   ├── cfg80211_reg_can_beacon
│   ├── cfg80211_report_obss_beacon
│   ├── cfg80211_report_wowlan_wakeup
│   ├── cfg80211_return_bool
│   ├── cfg80211_return_bss
│   ├── cfg80211_return_u32
│   ├── cfg80211_return_uint
│   ├── cfg80211_rx_control_port
│   ├── cfg80211_rx_mgmt
│   ├── cfg80211_rx_mlme_mgmt
│   ├── cfg80211_rx_spurious_frame
│   ├── cfg80211_rx_unexpected_4addr_frame
│   ├── cfg80211_rx_unprot_mlme_mgmt
│   ├── cfg80211_scan_done
│   ├── cfg80211_sched_scan_results
│   ├── cfg80211_sched_scan_stopped
│   ├── cfg80211_send_assoc_timeout
│   ├── cfg80211_send_auth_timeout
│   ├── cfg80211_send_rx_assoc
│   ├── cfg80211_send_rx_auth
│   ├── cfg80211_stop_iface
│   ├── cfg80211_tdls_oper_request
│   ├── cfg80211_tx_mgmt_expired
│   ├── cfg80211_tx_mlme_mgmt
│   ├── cfg80211_update_owe_info_event
│   ├── enable
│   ├── filter
│   ├── rdev_abort_pmsr
│   ├── rdev_abort_scan
│   ├── rdev_add_key
│   ├── rdev_add_mpath
│   ├── rdev_add_nan_func
│   ├── rdev_add_station
│   ├── rdev_add_tx_ts
│   ├── rdev_add_virtual_intf
│   ├── rdev_assoc
│   ├── rdev_auth
│   ├── rdev_cancel_remain_on_channel
│   ├── rdev_change_beacon
│   ├── rdev_change_bss
│   ├── rdev_change_mpath
│   ├── rdev_change_station
│   ├── rdev_change_virtual_intf
│   ├── rdev_channel_switch
│   ├── rdev_connect
│   ├── rdev_crit_proto_start
│   ├── rdev_crit_proto_stop
│   ├── rdev_deauth
│   ├── rdev_del_key
│   ├── rdev_del_mpath
│   ├── rdev_del_nan_func
│   ├── rdev_del_pmk
│   ├── rdev_del_pmksa
│   ├── rdev_del_station
│   ├── rdev_del_tx_ts
│   ├── rdev_del_virtual_intf
│   ├── rdev_disassoc
│   ├── rdev_disconnect
│   ├── rdev_dump_mpath
│   ├── rdev_dump_mpp
│   ├── rdev_dump_station
│   ├── rdev_dump_survey
│   ├── rdev_end_cac
│   ├── rdev_external_auth
│   ├── rdev_flush_pmksa
│   ├── rdev_get_antenna
│   ├── rdev_get_channel
│   ├── rdev_get_ftm_responder_stats
│   ├── rdev_get_key
│   ├── rdev_get_mesh_config
│   ├── rdev_get_mpath
│   ├── rdev_get_mpp
│   ├── rdev_get_station
│   ├── rdev_get_tx_power
│   ├── rdev_get_txq_stats
│   ├── rdev_join_ibss
│   ├── rdev_join_mesh
│   ├── rdev_join_ocb
│   ├── rdev_leave_ibss
│   ├── rdev_leave_mesh
│   ├── rdev_leave_ocb
│   ├── rdev_libertas_set_mesh_channel
│   ├── rdev_mgmt_tx
│   ├── rdev_mgmt_tx_cancel_wait
│   ├── rdev_nan_change_conf
│   ├── rdev_probe_client
│   ├── rdev_probe_mesh_link
│   ├── rdev_remain_on_channel
│   ├── rdev_reset_tid_config
│   ├── rdev_resume
│   ├── rdev_return_chandef
│   ├── rdev_return_int
│   ├── rdev_return_int_cookie
│   ├── rdev_return_int_int
│   ├── rdev_return_int_mesh_config
│   ├── rdev_return_int_mpath_info
│   ├── rdev_return_int_station_info
│   ├── rdev_return_int_survey_info
│   ├── rdev_return_int_tx_rx
│   ├── rdev_return_void
│   ├── rdev_return_void_tx_rx
│   ├── rdev_return_wdev
│   ├── rdev_rfkill_poll
│   ├── rdev_scan
│   ├── rdev_sched_scan_start
│   ├── rdev_sched_scan_stop
│   ├── rdev_set_antenna
│   ├── rdev_set_ap_chanwidth
│   ├── rdev_set_bitrate_mask
│   ├── rdev_set_coalesce
│   ├── rdev_set_cqm_rssi_config
│   ├── rdev_set_cqm_rssi_range_config
│   ├── rdev_set_cqm_txe_config
│   ├── rdev_set_default_beacon_key
│   ├── rdev_set_default_key
│   ├── rdev_set_default_mgmt_key
│   ├── rdev_set_mac_acl
│   ├── rdev_set_mcast_rate
│   ├── rdev_set_monitor_channel
│   ├── rdev_set_multicast_to_unicast
│   ├── rdev_set_noack_map
│   ├── rdev_set_pmk
│   ├── rdev_set_pmksa
│   ├── rdev_set_power_mgmt
│   ├── rdev_set_qos_map
│   ├── rdev_set_rekey_data
│   ├── rdev_set_tid_config
│   ├── rdev_set_tx_power
│   ├── rdev_set_txq_params
│   ├── rdev_set_wakeup
│   ├── rdev_set_wds_peer
│   ├── rdev_set_wiphy_params
│   ├── rdev_start_ap
│   ├── rdev_start_nan
│   ├── rdev_start_p2p_device
│   ├── rdev_start_pmsr
│   ├── rdev_start_radar_detection
│   ├── rdev_stop_ap
│   ├── rdev_stop_nan
│   ├── rdev_stop_p2p_device
│   ├── rdev_suspend
│   ├── rdev_tdls_cancel_channel_switch
│   ├── rdev_tdls_channel_switch
│   ├── rdev_tdls_mgmt
│   ├── rdev_tdls_oper
│   ├── rdev_tx_control_port
│   ├── rdev_update_connect_params
│   ├── rdev_update_ft_ies
│   ├── rdev_update_mesh_config
│   ├── rdev_update_mgmt_frame_registrations
│   └── rdev_update_owe_info
├── cgroup
│   ├── cgroup_attach_task
│   ├── cgroup_destroy_root
│   ├── cgroup_freeze
│   ├── cgroup_mkdir
│   ├── cgroup_notify_frozen
│   ├── cgroup_notify_populated
│   ├── cgroup_release
│   ├── cgroup_remount
│   ├── cgroup_rename
│   ├── cgroup_rmdir
│   ├── cgroup_setup_root
│   ├── cgroup_transfer_tasks
│   ├── cgroup_unfreeze
│   ├── enable
│   └── filter
├── clk
│   ├── clk_disable
│   ├── clk_disable_complete
│   ├── clk_enable
│   ├── clk_enable_complete
│   ├── clk_prepare
│   ├── clk_prepare_complete
│   ├── clk_set_duty_cycle
│   ├── clk_set_duty_cycle_complete
│   ├── clk_set_parent
│   ├── clk_set_parent_complete
│   ├── clk_set_phase
│   ├── clk_set_phase_complete
│   ├── clk_set_rate
│   ├── clk_set_rate_complete
│   ├── clk_unprepare
│   ├── clk_unprepare_complete
│   ├── enable
│   └── filter
├── cma
│   ├── cma_alloc
│   ├── cma_release
│   ├── enable
│   └── filter
├── compaction
│   ├── enable
│   ├── filter
│   ├── mm_compaction_begin
│   ├── mm_compaction_defer_compaction
│   ├── mm_compaction_deferred
│   ├── mm_compaction_defer_reset
│   ├── mm_compaction_end
│   ├── mm_compaction_finished
│   ├── mm_compaction_isolate_freepages
│   ├── mm_compaction_isolate_migratepages
│   ├── mm_compaction_kcompactd_sleep
│   ├── mm_compaction_kcompactd_wake
│   ├── mm_compaction_migratepages
│   ├── mm_compaction_suitable
│   ├── mm_compaction_try_to_compact_pages
│   └── mm_compaction_wakeup_kcompactd
├── cpuhp
│   ├── cpuhp_enter
│   ├── cpuhp_exit
│   ├── cpuhp_multi_enter
│   ├── enable
│   └── filter
├── dma_fence
│   ├── dma_fence_destroy
│   ├── dma_fence_emit
│   ├── dma_fence_enable_signal
│   ├── dma_fence_init
│   ├── dma_fence_signaled
│   ├── dma_fence_wait_end
│   ├── dma_fence_wait_start
│   ├── enable
│   └── filter
├── drm
│   ├── drm_vblank_event
│   ├── drm_vblank_event_delivered
│   ├── drm_vblank_event_queued
│   ├── enable
│   └── filter
├── emulation
│   ├── enable
│   ├── filter
│   └── instruction_emulation
├── enable
├── ext4
│   ├── enable
│   ├── ext4_allocate_blocks
│   ├── ext4_allocate_inode
│   ├── ext4_alloc_da_blocks
│   ├── ext4_begin_ordered_truncate
│   ├── ext4_collapse_range
│   ├── ext4_da_release_space
│   ├── ext4_da_reserve_space
│   ├── ext4_da_update_reserve_space
│   ├── ext4_da_write_begin
│   ├── ext4_da_write_end
│   ├── ext4_da_write_pages
│   ├── ext4_da_write_pages_extent
│   ├── ext4_direct_IO_enter
│   ├── ext4_direct_IO_exit
│   ├── ext4_discard_blocks
│   ├── ext4_discard_preallocations
│   ├── ext4_drop_inode
│   ├── ext4_error
│   ├── ext4_es_cache_extent
│   ├── ext4_es_find_extent_range_enter
│   ├── ext4_es_find_extent_range_exit
│   ├── ext4_es_insert_delayed_block
│   ├── ext4_es_insert_extent
│   ├── ext4_es_lookup_extent_enter
│   ├── ext4_es_lookup_extent_exit
│   ├── ext4_es_remove_extent
│   ├── ext4_es_shrink
│   ├── ext4_es_shrink_count
│   ├── ext4_es_shrink_scan_enter
│   ├── ext4_es_shrink_scan_exit
│   ├── ext4_evict_inode
│   ├── ext4_ext_convert_to_initialized_enter
│   ├── ext4_ext_convert_to_initialized_fastpath
│   ├── ext4_ext_handle_unwritten_extents
│   ├── ext4_ext_in_cache
│   ├── ext4_ext_load_extent
│   ├── ext4_ext_map_blocks_enter
│   ├── ext4_ext_map_blocks_exit
│   ├── ext4_ext_put_in_cache
│   ├── ext4_ext_remove_space
│   ├── ext4_ext_remove_space_done
│   ├── ext4_ext_rm_idx
│   ├── ext4_ext_rm_leaf
│   ├── ext4_ext_show_extent
│   ├── ext4_fallocate_enter
│   ├── ext4_fallocate_exit
│   ├── ext4_fc_commit_start
│   ├── ext4_fc_commit_stop
│   ├── ext4_fc_replay
│   ├── ext4_fc_replay_scan
│   ├── ext4_fc_stats
│   ├── ext4_fc_track_create
│   ├── ext4_fc_track_inode
│   ├── ext4_fc_track_link
│   ├── ext4_fc_track_range
│   ├── ext4_fc_track_unlink
│   ├── ext4_find_delalloc_range
│   ├── ext4_forget
│   ├── ext4_free_blocks
│   ├── ext4_free_inode
│   ├── ext4_fsmap_high_key
│   ├── ext4_fsmap_low_key
│   ├── ext4_fsmap_mapping
│   ├── ext4_getfsmap_high_key
│   ├── ext4_getfsmap_low_key
│   ├── ext4_getfsmap_mapping
│   ├── ext4_get_implied_cluster_alloc_exit
│   ├── ext4_get_reserved_cluster_alloc
│   ├── ext4_ind_map_blocks_enter
│   ├── ext4_ind_map_blocks_exit
│   ├── ext4_insert_range
│   ├── ext4_invalidatepage
│   ├── ext4_journalled_invalidatepage
│   ├── ext4_journalled_write_end
│   ├── ext4_journal_start
│   ├── ext4_journal_start_reserved
│   ├── ext4_lazy_itable_init
│   ├── ext4_load_inode
│   ├── ext4_load_inode_bitmap
│   ├── ext4_mark_inode_dirty
│   ├── ext4_mballoc_alloc
│   ├── ext4_mballoc_discard
│   ├── ext4_mballoc_free
│   ├── ext4_mballoc_prealloc
│   ├── ext4_mb_bitmap_load
│   ├── ext4_mb_buddy_bitmap_load
│   ├── ext4_mb_discard_preallocations
│   ├── ext4_mb_new_group_pa
│   ├── ext4_mb_new_inode_pa
│   ├── ext4_mb_release_group_pa
│   ├── ext4_mb_release_inode_pa
│   ├── ext4_nfs_commit_metadata
│   ├── ext4_other_inode_update_time
│   ├── ext4_prefetch_bitmaps
│   ├── ext4_punch_hole
│   ├── ext4_read_block_bitmap_load
│   ├── ext4_readpage
│   ├── ext4_releasepage
│   ├── ext4_remove_blocks
│   ├── ext4_request_blocks
│   ├── ext4_request_inode
│   ├── ext4_shutdown
│   ├── ext4_sync_file_enter
│   ├── ext4_sync_file_exit
│   ├── ext4_sync_fs
│   ├── ext4_trim_all_free
│   ├── ext4_trim_extent
│   ├── ext4_truncate_enter
│   ├── ext4_truncate_exit
│   ├── ext4_unlink_enter
│   ├── ext4_unlink_exit
│   ├── ext4_write_begin
│   ├── ext4_write_end
│   ├── ext4_writepage
│   ├── ext4_writepages
│   ├── ext4_writepages_result
│   ├── ext4_zero_range
│   └── filter
├── f2fs
│   ├── enable
│   ├── f2fs_background_gc
│   ├── f2fs_bmap
│   ├── f2fs_commit_inmem_page
│   ├── f2fs_compress_pages_end
│   ├── f2fs_compress_pages_start
│   ├── f2fs_decompress_pages_end
│   ├── f2fs_decompress_pages_start
│   ├── f2fs_destroy_extent_tree
│   ├── f2fs_direct_IO_enter
│   ├── f2fs_direct_IO_exit
│   ├── f2fs_do_write_data_page
│   ├── f2fs_drop_inode
│   ├── f2fs_evict_inode
│   ├── f2fs_fallocate
│   ├── f2fs_fiemap
│   ├── f2fs_filemap_fault
│   ├── f2fs_file_write_iter
│   ├── f2fs_gc_begin
│   ├── f2fs_gc_end
│   ├── f2fs_get_victim
│   ├── f2fs_iget
│   ├── f2fs_iget_exit
│   ├── f2fs_iostat
│   ├── f2fs_issue_discard
│   ├── f2fs_issue_flush
│   ├── f2fs_issue_reset_zone
│   ├── f2fs_lookup_end
│   ├── f2fs_lookup_extent_tree_end
│   ├── f2fs_lookup_extent_tree_start
│   ├── f2fs_lookup_start
│   ├── f2fs_map_blocks
│   ├── f2fs_new_inode
│   ├── f2fs_prepare_read_bio
│   ├── f2fs_prepare_write_bio
│   ├── f2fs_queue_discard
│   ├── f2fs_readdir
│   ├── f2fs_readpage
│   ├── f2fs_readpages
│   ├── f2fs_register_inmem_page
│   ├── f2fs_remove_discard
│   ├── f2fs_reserve_new_blocks
│   ├── f2fs_set_page_dirty
│   ├── f2fs_shrink_extent_tree
│   ├── f2fs_shutdown
│   ├── f2fs_submit_page_bio
│   ├── f2fs_submit_page_write
│   ├── f2fs_submit_read_bio
│   ├── f2fs_submit_write_bio
│   ├── f2fs_sync_dirty_inodes_enter
│   ├── f2fs_sync_dirty_inodes_exit
│   ├── f2fs_sync_file_enter
│   ├── f2fs_sync_file_exit
│   ├── f2fs_sync_fs
│   ├── f2fs_truncate
│   ├── f2fs_truncate_blocks_enter
│   ├── f2fs_truncate_blocks_exit
│   ├── f2fs_truncate_data_blocks_range
│   ├── f2fs_truncate_inode_blocks_enter
│   ├── f2fs_truncate_inode_blocks_exit
│   ├── f2fs_truncate_node
│   ├── f2fs_truncate_nodes_enter
│   ├── f2fs_truncate_nodes_exit
│   ├── f2fs_truncate_partial_nodes
│   ├── f2fs_unlink_enter
│   ├── f2fs_unlink_exit
│   ├── f2fs_update_extent_tree_range
│   ├── f2fs_vm_page_mkwrite
│   ├── f2fs_write_begin
│   ├── f2fs_write_checkpoint
│   ├── f2fs_write_end
│   ├── f2fs_writepage
│   ├── f2fs_writepages
│   └── filter
├── fib
│   ├── enable
│   ├── fib_table_lookup
│   └── filter
├── fib6
│   ├── enable
│   ├── fib6_table_lookup
│   └── filter
├── filelock
│   ├── break_lease_block
│   ├── break_lease_noblock
│   ├── break_lease_unblock
│   ├── enable
│   ├── fcntl_setlk
│   ├── filter
│   ├── flock_lock_inode
│   ├── generic_add_lease
│   ├── generic_delete_lease
│   ├── leases_conflict
│   ├── locks_get_lock_context
│   ├── locks_remove_posix
│   ├── posix_lock_inode
│   └── time_out_leases
├── filemap
│   ├── enable
│   ├── file_check_and_advance_wb_err
│   ├── filemap_set_wb_err
│   ├── filter
│   ├── mm_filemap_add_to_page_cache
│   └── mm_filemap_delete_from_page_cache
├── fscache
│   ├── enable
│   ├── filter
│   ├── fscache_acquire
│   ├── fscache_check_page
│   ├── fscache_cookie
│   ├── fscache_disable
│   ├── fscache_enable
│   ├── fscache_gang_lookup
│   ├── fscache_netfs
│   ├── fscache_op
│   ├── fscache_osm
│   ├── fscache_page
│   ├── fscache_page_op
│   ├── fscache_relinquish
│   ├── fscache_wake_cookie
│   └── fscache_wrote_page
├── ftrace
│   ├── bprint
│   ├── bputs
│   ├── branch
│   ├── context_switch
│   ├── enable
│   ├── filter
│   ├── funcgraph_entry
│   ├── funcgraph_exit
│   ├── function
│   ├── hwlat
│   ├── kernel_stack
│   ├── mmiotrace_map
│   ├── mmiotrace_rw
│   ├── print
│   ├── raw_data
│   ├── user_stack
│   └── wakeup
├── gadget
│   ├── enable
│   ├── filter
│   ├── usb_ep_alloc_request
│   ├── usb_ep_clear_halt
│   ├── usb_ep_dequeue
│   ├── usb_ep_disable
│   ├── usb_ep_enable
│   ├── usb_ep_fifo_flush
│   ├── usb_ep_fifo_status
│   ├── usb_ep_free_request
│   ├── usb_ep_queue
│   ├── usb_ep_set_halt
│   ├── usb_ep_set_maxpacket_limit
│   ├── usb_ep_set_wedge
│   ├── usb_gadget_activate
│   ├── usb_gadget_clear_selfpowered
│   ├── usb_gadget_connect
│   ├── usb_gadget_deactivate
│   ├── usb_gadget_disconnect
│   ├── usb_gadget_frame_number
│   ├── usb_gadget_giveback_request
│   ├── usb_gadget_set_selfpowered
│   ├── usb_gadget_vbus_connect
│   ├── usb_gadget_vbus_disconnect
│   ├── usb_gadget_vbus_draw
│   └── usb_gadget_wakeup
├── gpio
│   ├── enable
│   ├── filter
│   ├── gpio_direction
│   └── gpio_value
├── gpu_scheduler
│   ├── drm_run_job
│   ├── drm_sched_job
│   ├── drm_sched_job_wait_dep
│   ├── drm_sched_process_job
│   ├── enable
│   └── filter
├── header_event
├── header_page
├── hwmon
│   ├── enable
│   ├── filter
│   ├── hwmon_attr_show
│   ├── hwmon_attr_show_string
│   └── hwmon_attr_store
├── i2c
│   ├── enable
│   ├── filter
│   ├── i2c_read
│   ├── i2c_reply
│   ├── i2c_result
│   └── i2c_write
├── initcall
│   ├── enable
│   ├── filter
│   ├── initcall_finish
│   ├── initcall_level
│   └── initcall_start
├── iomap
│   ├── enable
│   ├── filter
│   ├── iomap_apply
│   ├── iomap_apply_dstmap
│   ├── iomap_apply_srcmap
│   ├── iomap_dio_invalidate_fail
│   ├── iomap_invalidatepage
│   ├── iomap_readahead
│   ├── iomap_readpage
│   ├── iomap_releasepage
│   └── iomap_writepage
├── io_uring
│   ├── enable
│   ├── filter
│   ├── io_uring_complete
│   ├── io_uring_cqring_wait
│   ├── io_uring_create
│   ├── io_uring_defer
│   ├── io_uring_fail_link
│   ├── io_uring_file_get
│   ├── io_uring_link
│   ├── io_uring_poll_arm
│   ├── io_uring_poll_wake
│   ├── io_uring_queue_async_work
│   ├── io_uring_register
│   ├── io_uring_submit_sqe
│   ├── io_uring_task_add
│   └── io_uring_task_run
├── ipi
│   ├── enable
│   ├── filter
│   ├── ipi_entry
│   ├── ipi_exit
│   └── ipi_raise
├── irq
│   ├── enable
│   ├── filter
│   ├── irq_handler_entry
│   ├── irq_handler_exit
│   ├── softirq_entry
│   ├── softirq_exit
│   └── softirq_raise
├── iscsi
│   ├── enable
│   ├── filter
│   ├── iscsi_dbg_conn
│   ├── iscsi_dbg_eh
│   ├── iscsi_dbg_session
│   ├── iscsi_dbg_sw_tcp
│   ├── iscsi_dbg_tcp
│   ├── iscsi_dbg_trans_conn
│   └── iscsi_dbg_trans_session
├── jbd2
│   ├── enable
│   ├── filter
│   ├── jbd2_checkpoint
│   ├── jbd2_checkpoint_stats
│   ├── jbd2_commit_flushing
│   ├── jbd2_commit_locking
│   ├── jbd2_commit_logging
│   ├── jbd2_drop_transaction
│   ├── jbd2_end_commit
│   ├── jbd2_handle_extend
│   ├── jbd2_handle_restart
│   ├── jbd2_handle_start
│   ├── jbd2_handle_stats
│   ├── jbd2_lock_buffer_stall
│   ├── jbd2_run_stats
│   ├── jbd2_start_commit
│   ├── jbd2_submit_inode_data
│   ├── jbd2_update_log_tail
│   └── jbd2_write_superblock
├── kmem
│   ├── enable
│   ├── filter
│   ├── kfree
│   ├── kmalloc
│   ├── kmalloc_node
│   ├── kmem_cache_alloc
│   ├── kmem_cache_alloc_node
│   ├── kmem_cache_free
│   ├── mm_page_alloc
│   ├── mm_page_alloc_extfrag
│   ├── mm_page_alloc_zone_locked
│   ├── mm_page_free
│   ├── mm_page_free_batched
│   ├── mm_page_pcpu_drain
│   └── rss_stat
├── kvm
│   ├── enable
│   ├── filter
│   ├── kvm_access_fault
│   ├── kvm_ack_irq
│   ├── kvm_age_hva
│   ├── kvm_age_page
│   ├── kvm_arm_clear_debug
│   ├── kvm_arm_set_dreg32
│   ├── kvm_arm_set_regset
│   ├── kvm_arm_setup_debug
│   ├── kvm_entry
│   ├── kvm_exit
│   ├── kvm_fpu
│   ├── kvm_get_timer_map
│   ├── kvm_guest_fault
│   ├── kvm_halt_poll_ns
│   ├── kvm_handle_sys_reg
│   ├── kvm_hvc_arm64
│   ├── kvm_irq_line
│   ├── kvm_mmio
│   ├── kvm_mmio_emulate
│   ├── kvm_set_guest_debug
│   ├── kvm_set_irq
│   ├── kvm_set_spte_hva
│   ├── kvm_set_way_flush
│   ├── kvm_sys_access
│   ├── kvm_test_age_hva
│   ├── kvm_timer_emulate
│   ├── kvm_timer_hrtimer_expire
│   ├── kvm_timer_restore_state
│   ├── kvm_timer_save_state
│   ├── kvm_timer_update_irq
│   ├── kvm_toggle_cache
│   ├── kvm_unmap_hva_range
│   ├── kvm_userspace_exit
│   ├── kvm_vcpu_wakeup
│   ├── kvm_wfx_arm64
│   ├── trap_reg
│   └── vgic_update_irq_pending
├── kyber
│   ├── enable
│   ├── filter
│   ├── kyber_adjust
│   ├── kyber_latency
│   └── kyber_throttled
├── mdio
│   ├── enable
│   ├── filter
│   └── mdio_access
├── migrate
│   ├── enable
│   ├── filter
│   └── mm_migrate_pages
├── mmap
│   ├── enable
│   ├── filter
│   └── vm_unmapped_area
├── mmc
│   ├── enable
│   ├── filter
│   ├── mmc_request_done
│   └── mmc_request_start
├── module
│   ├── enable
│   ├── filter
│   ├── module_free
│   ├── module_get
│   ├── module_load
│   ├── module_put
│   └── module_request
├── napi
│   ├── enable
│   ├── filter
│   └── napi_poll
├── neigh
│   ├── enable
│   ├── filter
│   ├── neigh_cleanup_and_release
│   ├── neigh_create
│   ├── neigh_event_send_dead
│   ├── neigh_event_send_done
│   ├── neigh_timer_handler
│   ├── neigh_update
│   └── neigh_update_done
├── net
│   ├── enable
│   ├── filter
│   ├── napi_gro_frags_entry
│   ├── napi_gro_frags_exit
│   ├── napi_gro_receive_entry
│   ├── napi_gro_receive_exit
│   ├── net_dev_queue
│   ├── net_dev_start_xmit
│   ├── net_dev_xmit
│   ├── net_dev_xmit_timeout
│   ├── netif_receive_skb
│   ├── netif_receive_skb_entry
│   ├── netif_receive_skb_exit
│   ├── netif_receive_skb_list_entry
│   ├── netif_receive_skb_list_exit
│   ├── netif_rx
│   ├── netif_rx_entry
│   ├── netif_rx_exit
│   ├── netif_rx_ni_entry
│   └── netif_rx_ni_exit
├── nfs
│   ├── enable
│   ├── filter
│   ├── nfs_access_enter
│   ├── nfs_access_exit
│   ├── nfs_atomic_open_enter
│   ├── nfs_atomic_open_exit
│   ├── nfs_commit_done
│   ├── nfs_commit_error
│   ├── nfs_comp_error
│   ├── nfs_create_enter
│   ├── nfs_create_exit
│   ├── nfs_fh_to_dentry
│   ├── nfs_fsync_enter
│   ├── nfs_fsync_exit
│   ├── nfs_getattr_enter
│   ├── nfs_getattr_exit
│   ├── nfs_initiate_commit
│   ├── nfs_initiate_read
│   ├── nfs_initiate_write
│   ├── nfs_invalidate_mapping_enter
│   ├── nfs_invalidate_mapping_exit
│   ├── nfs_link_enter
│   ├── nfs_link_exit
│   ├── nfs_lookup_enter
│   ├── nfs_lookup_exit
│   ├── nfs_lookup_revalidate_enter
│   ├── nfs_lookup_revalidate_exit
│   ├── nfs_mkdir_enter
│   ├── nfs_mkdir_exit
│   ├── nfs_mknod_enter
│   ├── nfs_mknod_exit
│   ├── nfs_pgio_error
│   ├── nfs_readpage_done
│   ├── nfs_readpage_short
│   ├── nfs_refresh_inode_enter
│   ├── nfs_refresh_inode_exit
│   ├── nfs_remove_enter
│   ├── nfs_remove_exit
│   ├── nfs_rename_enter
│   ├── nfs_rename_exit
│   ├── nfs_revalidate_inode_enter
│   ├── nfs_revalidate_inode_exit
│   ├── nfs_rmdir_enter
│   ├── nfs_rmdir_exit
│   ├── nfs_setattr_enter
│   ├── nfs_setattr_exit
│   ├── nfs_set_inode_stale
│   ├── nfs_sillyrename_rename
│   ├── nfs_sillyrename_unlink
│   ├── nfs_symlink_enter
│   ├── nfs_symlink_exit
│   ├── nfs_unlink_enter
│   ├── nfs_unlink_exit
│   ├── nfs_writeback_done
│   ├── nfs_writeback_inode_enter
│   ├── nfs_writeback_inode_exit
│   ├── nfs_writeback_page_enter
│   ├── nfs_writeback_page_exit
│   ├── nfs_write_error
│   └── nfs_xdr_status
├── nfs4
│   ├── enable
│   ├── ff_layout_commit_error
│   ├── ff_layout_read_error
│   ├── ff_layout_write_error
│   ├── filter
│   ├── nfs4_access
│   ├── nfs4_bind_conn_to_session
│   ├── nfs4_cached_open
│   ├── nfs4_cb_getattr
│   ├── nfs4_cb_layoutrecall_file
│   ├── nfs4_cb_recall
│   ├── nfs4_cb_seqid_err
│   ├── nfs4_cb_sequence
│   ├── nfs4_close
│   ├── nfs4_close_stateid_update_wait
│   ├── nfs4_commit
│   ├── nfs4_create_session
│   ├── nfs4_delegreturn
│   ├── nfs4_delegreturn_exit
│   ├── nfs4_destroy_clientid
│   ├── nfs4_destroy_session
│   ├── nfs4_exchange_id
│   ├── nfs4_fsinfo
│   ├── nfs4_get_acl
│   ├── nfs4_getattr
│   ├── nfs4_get_fs_locations
│   ├── nfs4_get_lock
│   ├── nfs4_get_security_label
│   ├── nfs4_layoutcommit
│   ├── nfs4_layouterror
│   ├── nfs4_layoutget
│   ├── nfs4_layoutreturn
│   ├── nfs4_layoutreturn_on_close
│   ├── nfs4_layoutstats
│   ├── nfs4_lookup
│   ├── nfs4_lookupp
│   ├── nfs4_lookup_root
│   ├── nfs4_map_gid_to_group
│   ├── nfs4_map_group_to_gid
│   ├── nfs4_map_name_to_uid
│   ├── nfs4_map_uid_to_name
│   ├── nfs4_mkdir
│   ├── nfs4_mknod
│   ├── nfs4_open_expired
│   ├── nfs4_open_file
│   ├── nfs4_open_reclaim
│   ├── nfs4_open_stateid_update
│   ├── nfs4_open_stateid_update_wait
│   ├── nfs4_pnfs_commit_ds
│   ├── nfs4_pnfs_read
│   ├── nfs4_pnfs_write
│   ├── nfs4_read
│   ├── nfs4_readdir
│   ├── nfs4_readlink
│   ├── nfs4_reclaim_complete
│   ├── nfs4_reclaim_delegation
│   ├── nfs4_remove
│   ├── nfs4_rename
│   ├── nfs4_renew
│   ├── nfs4_renew_async
│   ├── nfs4_secinfo
│   ├── nfs4_sequence
│   ├── nfs4_sequence_done
│   ├── nfs4_set_acl
│   ├── nfs4_setattr
│   ├── nfs4_setclientid
│   ├── nfs4_setclientid_confirm
│   ├── nfs4_set_delegation
│   ├── nfs4_set_lock
│   ├── nfs4_set_security_label
│   ├── nfs4_setup_sequence
│   ├── nfs4_state_lock_reclaim
│   ├── nfs4_state_mgr
│   ├── nfs4_state_mgr_failed
│   ├── nfs4_symlink
│   ├── nfs4_test_delegation_stateid
│   ├── nfs4_test_lock_stateid
│   ├── nfs4_test_open_stateid
│   ├── nfs4_unlock
│   ├── nfs4_write
│   ├── nfs4_xdr_status
│   ├── nfs_cb_badprinc
│   ├── nfs_cb_no_clp
│   ├── pnfs_mds_fallback_pg_get_mirror_count
│   ├── pnfs_mds_fallback_pg_init_read
│   ├── pnfs_mds_fallback_pg_init_write
│   ├── pnfs_mds_fallback_read_done
│   ├── pnfs_mds_fallback_read_pagelist
│   ├── pnfs_mds_fallback_write_done
│   ├── pnfs_mds_fallback_write_pagelist
│   └── pnfs_update_layout
├── nvme
│   ├── enable
│   ├── filter
│   ├── nvme_async_event
│   ├── nvme_complete_rq
│   ├── nvme_setup_cmd
│   └── nvme_sq
├── oom
│   ├── compact_retry
│   ├── enable
│   ├── filter
│   ├── finish_task_reaping
│   ├── mark_victim
│   ├── oom_score_adj_update
│   ├── reclaim_retry_zone
│   ├── skip_task_reaping
│   ├── start_task_reaping
│   └── wake_reaper
├── page_isolation
│   ├── enable
│   ├── filter
│   └── test_pages_isolated
├── pagemap
│   ├── enable
│   ├── filter
│   ├── mm_lru_activate
│   └── mm_lru_insertion
├── percpu
│   ├── enable
│   ├── filter
│   ├── percpu_alloc_percpu
│   ├── percpu_alloc_percpu_fail
│   ├── percpu_create_chunk
│   ├── percpu_destroy_chunk
│   └── percpu_free_percpu
├── power
│   ├── clock_disable
│   ├── clock_enable
│   ├── clock_set_rate
│   ├── cpu_frequency
│   ├── cpu_frequency_limits
│   ├── cpu_idle
│   ├── device_pm_callback_end
│   ├── device_pm_callback_start
│   ├── dev_pm_qos_add_request
│   ├── dev_pm_qos_remove_request
│   ├── dev_pm_qos_update_request
│   ├── enable
│   ├── filter
│   ├── pm_qos_add_request
│   ├── pm_qos_remove_request
│   ├── pm_qos_update_flags
│   ├── pm_qos_update_request
│   ├── pm_qos_update_target
│   ├── power_domain_target
│   ├── powernv_throttle
│   ├── pstate_sample
│   ├── suspend_resume
│   ├── wakeup_source_activate
│   └── wakeup_source_deactivate
├── preemptirq
│   ├── enable
│   ├── filter
│   ├── irq_disable
│   └── irq_enable
├── printk
│   ├── console
│   ├── enable
│   └── filter
├── pwm
│   ├── enable
│   ├── filter
│   ├── pwm_apply
│   └── pwm_get
├── qdisc
│   ├── enable
│   ├── filter
│   ├── qdisc_create
│   ├── qdisc_dequeue
│   ├── qdisc_destroy
│   └── qdisc_reset
├── random
│   ├── add_device_randomness
│   ├── add_disk_randomness
│   ├── add_input_randomness
│   ├── credit_entropy_bits
│   ├── debit_entropy
│   ├── enable
│   ├── extract_entropy
│   ├── extract_entropy_user
│   ├── filter
│   ├── get_random_bytes
│   ├── get_random_bytes_arch
│   ├── mix_pool_bytes
│   ├── mix_pool_bytes_nolock
│   ├── prandom_u32
│   ├── push_to_pool
│   ├── random_read
│   ├── urandom_read
│   └── xfer_secondary_pool
├── raw_syscalls
│   ├── enable
│   ├── filter
│   ├── sys_enter
│   └── sys_exit
├── rcu
│   ├── enable
│   ├── filter
│   ├── rcu_barrier
│   ├── rcu_batch_end
│   ├── rcu_batch_start
│   ├── rcu_callback
│   ├── rcu_dyntick
│   ├── rcu_exp_funnel_lock
│   ├── rcu_exp_grace_period
│   ├── rcu_fqs
│   ├── rcu_future_grace_period
│   ├── rcu_grace_period
│   ├── rcu_grace_period_init
│   ├── rcu_invoke_callback
│   ├── rcu_invoke_kfree_bulk_callback
│   ├── rcu_invoke_kvfree_callback
│   ├── rcu_kvfree_callback
│   ├── rcu_preempt_task
│   ├── rcu_quiescent_state_report
│   ├── rcu_torture_read
│   ├── rcu_unlock_preempted_task
│   └── rcu_utilization
├── regmap
│   ├── enable
│   ├── filter
│   ├── regcache_drop_region
│   ├── regcache_sync
│   ├── regmap_async_complete_done
│   ├── regmap_async_complete_start
│   ├── regmap_async_io_complete
│   ├── regmap_async_write_start
│   ├── regmap_cache_bypass
│   ├── regmap_cache_only
│   ├── regmap_hw_read_done
│   ├── regmap_hw_read_start
│   ├── regmap_hw_write_done
│   ├── regmap_hw_write_start
│   ├── regmap_reg_read
│   ├── regmap_reg_read_cache
│   └── regmap_reg_write
├── regulator
│   ├── enable
│   ├── filter
│   ├── regulator_bypass_disable
│   ├── regulator_bypass_disable_complete
│   ├── regulator_bypass_enable
│   ├── regulator_bypass_enable_complete
│   ├── regulator_disable
│   ├── regulator_disable_complete
│   ├── regulator_enable
│   ├── regulator_enable_complete
│   ├── regulator_enable_delay
│   ├── regulator_set_voltage
│   └── regulator_set_voltage_complete
├── rpcgss
│   ├── enable
│   ├── filter
│   ├── rpcgss_bad_seqno
│   ├── rpcgss_context
│   ├── rpcgss_createauth
│   ├── rpcgss_ctx_destroy
│   ├── rpcgss_ctx_init
│   ├── rpcgss_get_mic
│   ├── rpcgss_import_ctx
│   ├── rpcgss_need_reencode
│   ├── rpcgss_oid_to_mech
│   ├── rpcgss_seqno
│   ├── rpcgss_svc_accept_upcall
│   ├── rpcgss_svc_authenticate
│   ├── rpcgss_svc_mic
│   ├── rpcgss_svc_seqno_bad
│   ├── rpcgss_svc_seqno_large
│   ├── rpcgss_svc_seqno_low
│   ├── rpcgss_svc_seqno_seen
│   ├── rpcgss_svc_unwrap
│   ├── rpcgss_svc_unwrap_failed
│   ├── rpcgss_unwrap
│   ├── rpcgss_unwrap_failed
│   ├── rpcgss_upcall_msg
│   ├── rpcgss_upcall_result
│   ├── rpcgss_update_slack
│   ├── rpcgss_verify_mic
│   └── rpcgss_wrap
├── rpm
│   ├── enable
│   ├── filter
│   ├── rpm_idle
│   ├── rpm_resume
│   ├── rpm_return_int
│   ├── rpm_suspend
│   └── rpm_usage
├── rseq
│   ├── enable
│   ├── filter
│   ├── rseq_ip_fixup
│   └── rseq_update
├── rtc
│   ├── enable
│   ├── filter
│   ├── rtc_alarm_irq_enable
│   ├── rtc_irq_set_freq
│   ├── rtc_irq_set_state
│   ├── rtc_read_alarm
│   ├── rtc_read_offset
│   ├── rtc_read_time
│   ├── rtc_set_alarm
│   ├── rtc_set_offset
│   ├── rtc_set_time
│   ├── rtc_timer_dequeue
│   ├── rtc_timer_enqueue
│   └── rtc_timer_fired
├── sched
│   ├── enable
│   ├── filter
│   ├── sched_kthread_stop
│   ├── sched_kthread_stop_ret
│   ├── sched_migrate_task
│   ├── sched_move_numa
│   ├── sched_pi_setprio
│   ├── sched_process_exec
│   ├── sched_process_exit
│   ├── sched_process_fork
│   ├── sched_process_free
│   ├── sched_process_hang
│   ├── sched_process_wait
│   ├── sched_stat_blocked
│   ├── sched_stat_iowait
│   ├── sched_stat_runtime
│   ├── sched_stat_sleep
│   ├── sched_stat_wait
│   ├── sched_stick_numa
│   ├── sched_swap_numa
│   ├── sched_switch
│   ├── sched_wait_task
│   ├── sched_wake_idle_without_ipi
│   ├── sched_wakeup
│   ├── sched_wakeup_new
│   └── sched_waking
├── scsi
│   ├── enable
│   ├── filter
│   ├── scsi_dispatch_cmd_done
│   ├── scsi_dispatch_cmd_error
│   ├── scsi_dispatch_cmd_start
│   ├── scsi_dispatch_cmd_timeout
│   └── scsi_eh_wakeup
├── signal
│   ├── enable
│   ├── filter
│   ├── signal_deliver
│   └── signal_generate
├── skb
│   ├── consume_skb
│   ├── enable
│   ├── filter
│   ├── kfree_skb
│   └── skb_copy_datagram_iovec
├── smbus
│   ├── enable
│   ├── filter
│   ├── smbus_read
│   ├── smbus_reply
│   ├── smbus_result
│   └── smbus_write
├── sock
│   ├── enable
│   ├── filter
│   ├── inet_sock_set_state
│   ├── sock_exceed_buf_limit
│   └── sock_rcvqueue_full
├── spi
│   ├── enable
│   ├── filter
│   ├── spi_controller_busy
│   ├── spi_controller_idle
│   ├── spi_message_done
│   ├── spi_message_start
│   ├── spi_message_submit
│   ├── spi_transfer_start
│   └── spi_transfer_stop
├── sunrpc
│   ├── cache_entry_expired
│   ├── cache_entry_make_negative
│   ├── cache_entry_no_listener
│   ├── cache_entry_upcall
│   ├── cache_entry_update
│   ├── enable
│   ├── filter
│   ├── pmap_register
│   ├── rpc__auth_tooweak
│   ├── rpc_bad_callhdr
│   ├── rpc__bad_creds
│   ├── rpc_bad_verifier
│   ├── rpcb_bind_version_err
│   ├── rpcb_getport
│   ├── rpcb_prog_unavail_err
│   ├── rpcb_register
│   ├── rpcb_setport
│   ├── rpcb_timeout_err
│   ├── rpc_buf_alloc
│   ├── rpcb_unreachable_err
│   ├── rpcb_unrecognized_err
│   ├── rpcb_unregister
│   ├── rpc_call_rpcerror
│   ├── rpc_call_status
│   ├── rpc_clnt_clone_err
│   ├── rpc_clnt_free
│   ├── rpc_clnt_killall
│   ├── rpc_clnt_new
│   ├── rpc_clnt_new_err
│   ├── rpc_clnt_release
│   ├── rpc_clnt_replace_xprt
│   ├── rpc_clnt_replace_xprt_err
│   ├── rpc_clnt_shutdown
│   ├── rpc_connect_status
│   ├── rpc__garbage_args
│   ├── rpc__mismatch
│   ├── rpc__proc_unavail
│   ├── rpc__prog_mismatch
│   ├── rpc__prog_unavail
│   ├── rpc_refresh_status
│   ├── rpc_request
│   ├── rpc_retry_refresh_status
│   ├── rpc_socket_close
│   ├── rpc_socket_connect
│   ├── rpc_socket_error
│   ├── rpc_socket_nospace
│   ├── rpc_socket_reset_connection
│   ├── rpc_socket_shutdown
│   ├── rpc_socket_state_change
│   ├── rpc__stale_creds
│   ├── rpc_stats_latency
│   ├── rpc_task_begin
│   ├── rpc_task_complete
│   ├── rpc_task_end
│   ├── rpc_task_run_action
│   ├── rpc_task_signalled
│   ├── rpc_task_sleep
│   ├── rpc_task_sync_sleep
│   ├── rpc_task_sync_wake
│   ├── rpc_task_timeout
│   ├── rpc_task_wakeup
│   ├── rpc_timeout_status
│   ├── rpc__unparsable
│   ├── rpc_xdr_alignment
│   ├── rpc_xdr_overflow
│   ├── rpc_xdr_recvfrom
│   ├── rpc_xdr_reply_pages
│   ├── rpc_xdr_sendto
│   ├── svc_authenticate
│   ├── svc_defer
│   ├── svc_defer_drop
│   ├── svc_defer_queue
│   ├── svc_defer_recv
│   ├── svc_drop
│   ├── svc_handle_xprt
│   ├── svc_noregister
│   ├── svc_process
│   ├── svc_recv
│   ├── svc_register
│   ├── svc_send
│   ├── svcsock_accept_err
│   ├── svcsock_data_ready
│   ├── svcsock_getpeername_err
│   ├── svcsock_marker
│   ├── svcsock_new_socket
│   ├── svcsock_tcp_recv
│   ├── svcsock_tcp_recv_eagain
│   ├── svcsock_tcp_recv_err
│   ├── svcsock_tcp_recv_short
│   ├── svcsock_tcp_send
│   ├── svcsock_tcp_state
│   ├── svcsock_udp_recv
│   ├── svcsock_udp_recv_err
│   ├── svcsock_udp_send
│   ├── svcsock_write_space
│   ├── svc_stats_latency
│   ├── svc_unregister
│   ├── svc_wake_up
│   ├── svc_xdr_recvfrom
│   ├── svc_xdr_sendto
│   ├── svc_xprt_accept
│   ├── svc_xprt_close
│   ├── svc_xprt_create_err
│   ├── svc_xprt_dequeue
│   ├── svc_xprt_detach
│   ├── svc_xprt_do_enqueue
│   ├── svc_xprt_free
│   ├── svc_xprt_no_write_space
│   ├── xprt_connect
│   ├── xprt_create
│   ├── xprt_destroy
│   ├── xprt_disconnect_auto
│   ├── xprt_disconnect_cleanup
│   ├── xprt_disconnect_done
│   ├── xprt_disconnect_force
│   ├── xprt_get_cong
│   ├── xprt_lookup_rqst
│   ├── xprt_ping
│   ├── xprt_put_cong
│   ├── xprt_release_cong
│   ├── xprt_release_xprt
│   ├── xprt_reserve
│   ├── xprt_reserve_cong
│   ├── xprt_reserve_xprt
│   ├── xprt_timer
│   ├── xprt_transmit
│   ├── xs_stream_read_data
│   └── xs_stream_read_request
├── swiotlb
│   ├── enable
│   ├── filter
│   └── swiotlb_bounced
├── task
│   ├── enable
│   ├── filter
│   ├── task_newtask
│   └── task_rename
├── tcp
│   ├── enable
│   ├── filter
│   ├── tcp_destroy_sock
│   ├── tcp_probe
│   ├── tcp_rcv_space_adjust
│   ├── tcp_receive_reset
│   ├── tcp_retransmit_skb
│   ├── tcp_retransmit_synack
│   └── tcp_send_reset
├── thermal
│   ├── cdev_update
│   ├── enable
│   ├── filter
│   ├── thermal_temperature
│   └── thermal_zone_trip
├── timer
│   ├── enable
│   ├── filter
│   ├── hrtimer_cancel
│   ├── hrtimer_expire_entry
│   ├── hrtimer_expire_exit
│   ├── hrtimer_init
│   ├── hrtimer_start
│   ├── itimer_expire
│   ├── itimer_state
│   ├── tick_stop
│   ├── timer_cancel
│   ├── timer_expire_entry
│   ├── timer_expire_exit
│   ├── timer_init
│   └── timer_start
├── udp
│   ├── enable
│   ├── filter
│   └── udp_fail_queue_rcv_skb
├── v3d
│   ├── enable
│   ├── filter
│   ├── v3d_bcl_irq
│   ├── v3d_cache_clean_begin
│   ├── v3d_cache_clean_end
│   ├── v3d_csd_irq
│   ├── v3d_rcl_irq
│   ├── v3d_reset_begin
│   ├── v3d_reset_end
│   ├── v3d_submit_cl
│   ├── v3d_submit_cl_ioctl
│   ├── v3d_submit_csd
│   ├── v3d_submit_csd_ioctl
│   ├── v3d_submit_tfu
│   ├── v3d_submit_tfu_ioctl
│   └── v3d_tfu_irq
├── v4l2
│   ├── enable
│   ├── filter
│   ├── v4l2_dqbuf
│   ├── v4l2_qbuf
│   ├── vb2_v4l2_buf_done
│   ├── vb2_v4l2_buf_queue
│   ├── vb2_v4l2_dqbuf
│   └── vb2_v4l2_qbuf
├── vb2
│   ├── enable
│   ├── filter
│   ├── vb2_buf_done
│   ├── vb2_buf_queue
│   ├── vb2_dqbuf
│   └── vb2_qbuf
├── vc4
│   ├── enable
│   ├── filter
│   ├── vc4_wait_for_seqno_begin
│   └── vc4_wait_for_seqno_end
├── vmscan
│   ├── enable
│   ├── filter
│   ├── mm_shrink_slab_end
│   ├── mm_shrink_slab_start
│   ├── mm_vmscan_direct_reclaim_begin
│   ├── mm_vmscan_direct_reclaim_end
│   ├── mm_vmscan_inactive_list_is_low
│   ├── mm_vmscan_kswapd_sleep
│   ├── mm_vmscan_kswapd_wake
│   ├── mm_vmscan_lru_isolate
│   ├── mm_vmscan_lru_shrink_active
│   ├── mm_vmscan_lru_shrink_inactive
│   ├── mm_vmscan_memcg_reclaim_begin
│   ├── mm_vmscan_memcg_reclaim_end
│   ├── mm_vmscan_memcg_softlimit_reclaim_begin
│   ├── mm_vmscan_memcg_softlimit_reclaim_end
│   ├── mm_vmscan_node_reclaim_begin
│   ├── mm_vmscan_node_reclaim_end
│   ├── mm_vmscan_wakeup_kswapd
│   └── mm_vmscan_writepage
├── workqueue
│   ├── enable
│   ├── filter
│   ├── workqueue_activate_work
│   ├── workqueue_execute_end
│   ├── workqueue_execute_start
│   └── workqueue_queue_work
├── writeback
│   ├── balance_dirty_pages
│   ├── bdi_dirty_ratelimit
│   ├── enable
│   ├── filter
│   ├── flush_foreign
│   ├── global_dirty_state
│   ├── inode_foreign_history
│   ├── inode_switch_wbs
│   ├── sb_clear_inode_writeback
│   ├── sb_mark_inode_writeback
│   ├── track_foreign_dirty
│   ├── wait_on_page_writeback
│   ├── wbc_writepage
│   ├── writeback_bdi_register
│   ├── writeback_congestion_wait
│   ├── writeback_dirty_inode
│   ├── writeback_dirty_inode_enqueue
│   ├── writeback_dirty_inode_start
│   ├── writeback_dirty_page
│   ├── writeback_exec
│   ├── writeback_lazytime
│   ├── writeback_lazytime_iput
│   ├── writeback_mark_inode_dirty
│   ├── writeback_pages_written
│   ├── writeback_queue
│   ├── writeback_queue_io
│   ├── writeback_sb_inodes_requeue
│   ├── writeback_single_inode
│   ├── writeback_single_inode_start
│   ├── writeback_start
│   ├── writeback_wait
│   ├── writeback_wait_iff_congested
│   ├── writeback_wake_background
│   ├── writeback_write_inode
│   ├── writeback_write_inode_start
│   └── writeback_written
├── xdp
│   ├── enable
│   ├── filter
│   ├── mem_connect
│   ├── mem_disconnect
│   ├── mem_return_failed
│   ├── xdp_bulk_tx
│   ├── xdp_cpumap_enqueue
│   ├── xdp_cpumap_kthread
│   ├── xdp_devmap_xmit
│   ├── xdp_exception
│   ├── xdp_redirect
│   ├── xdp_redirect_err
│   ├── xdp_redirect_map
│   └── xdp_redirect_map_err
└── xhci-hcd
    

+ Recent posts