← Documents Documentation/trace/ftrace-uses.rst GitHub 원문 ↗

Linux 6.18.37 · Tracing

ftrace로 함수에 훅 연결하기

ftrace_ops 콜백의 실행 문맥, 재귀·RCU 보호, 레지스터 및 함수 리디렉션 플래그, filter와 notrace 목록의 안전한 갱신 방법을 설명합니다.

Source pathDocumentation/trace/ftrace-uses.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

ftrace-uses.rst:1-348

ftrace_ops 콜백의 실행 문맥, 재귀·RCU 보호, 레지스터 및 함수 리디렉션 플래그, filter와 notrace 목록의 안전한 갱신 방법을 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =================================
2 Using ftrace to hook to functions
3 =================================
4
5 .. Copyright 2017 VMware Inc.
6 .. Author: Steven Rostedt <srostedt@goodmis.org>
7 .. License: The GNU Free Documentation License, Version 1.2
8 .. (dual licensed under the GPL v2)
9
10 Written for: 4.14
11
12 Introduction
13 ============
14
15 The ftrace infrastructure was originally created to attach callbacks to the
16 beginning of functions in order to record and trace the flow of the kernel.
17 But callbacks to the start of a function can have other use cases. Either
18 for live kernel patching, or for security monitoring. This document describes
19 how to use ftrace to implement your own function callbacks.
20
21
22 The ftrace context
23 ==================
24 .. warning::
25
26 The ability to add a callback to almost any function within the
27 kernel comes with risks. A callback can be called from any context
28 (normal, softirq, irq, and NMI). Callbacks can also be called just before
29 going to idle, during CPU bring up and takedown, or going to user space.
30 This requires extra care to what can be done inside a callback. A callback
31 can be called outside the protective scope of RCU.
32
33 There are helper functions to help against recursion, and making sure
34 RCU is watching. These are explained below.
35
36
37 The ftrace_ops structure
38 ========================
39
40 To register a function callback, a ftrace_ops is required. This structure
41 is used to tell ftrace what function should be called as the callback
42 as well as what protections the callback will perform and not require
43 ftrace to handle.
44
45 There is only one field that is needed to be set when registering
46 an ftrace_ops with ftrace:
47
48 .. code-block:: c
49
50 struct ftrace_ops ops = {
51 .func = my_callback_func,
52 .flags = MY_FTRACE_FLAGS
53 .private = any_private_data_structure,
54 };
55
56 Both .flags and .private are optional. Only .func is required.
57
58 To enable tracing call::
59
60 register_ftrace_function(&ops);
61
62 To disable tracing call::
63
64 unregister_ftrace_function(&ops);
65
66 The above is defined by including the header::
67
68 #include <linux/ftrace.h>
69
70 The registered callback will start being called some time after the
71 register_ftrace_function() is called and before it returns. The exact time
72 that callbacks start being called is dependent upon architecture and scheduling
73 of services. The callback itself will have to handle any synchronization if it
74 must begin at an exact moment.
75
76 The unregister_ftrace_function() will guarantee that the callback is
77 no longer being called by functions after the unregister_ftrace_function()
78 returns. Note that to perform this guarantee, the unregister_ftrace_function()
79 may take some time to finish.
80
81
82 The callback function
83 =====================
84
85 The prototype of the callback function is as follows (as of v4.14):
86
87 .. code-block:: c
88
89 void callback_func(unsigned long ip, unsigned long parent_ip,
90 struct ftrace_ops *op, struct pt_regs *regs);
91
92 @ip
93 This is the instruction pointer of the function that is being traced.
94 (where the fentry or mcount is within the function)
95
96 @parent_ip
97 This is the instruction pointer of the function that called the
98 the function being traced (where the call of the function occurred).
99
100 @op
101 This is a pointer to ftrace_ops that was used to register the callback.
102 This can be used to pass data to the callback via the private pointer.
103
104 @regs
105 If the FTRACE_OPS_FL_SAVE_REGS or FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
106 flags are set in the ftrace_ops structure, then this will be pointing
107 to the pt_regs structure like it would be if an breakpoint was placed
108 at the start of the function where ftrace was tracing. Otherwise it
109 either contains garbage, or NULL.
110
111 Protect your callback
112 =====================
113
114 As functions can be called from anywhere, and it is possible that a function
115 called by a callback may also be traced, and call that same callback,
116 recursion protection must be used. There are two helper functions that
117 can help in this regard. If you start your code with:
118
119 .. code-block:: c
120
121 int bit;
122
123 bit = ftrace_test_recursion_trylock(ip, parent_ip);
124 if (bit < 0)
125 return;
126
127 and end it with:
128
129 .. code-block:: c
130
131 ftrace_test_recursion_unlock(bit);
132
133 The code in between will be safe to use, even if it ends up calling a
134 function that the callback is tracing. Note, on success,
135 ftrace_test_recursion_trylock() will disable preemption, and the
136 ftrace_test_recursion_unlock() will enable it again (if it was previously
137 enabled). The instruction pointer (ip) and its parent (parent_ip) is passed to
138 ftrace_test_recursion_trylock() to record where the recursion happened
139 (if CONFIG_FTRACE_RECORD_RECURSION is set).
140
141 Alternatively, if the FTRACE_OPS_FL_RECURSION flag is set on the ftrace_ops
142 (as explained below), then a helper trampoline will be used to test
143 for recursion for the callback and no recursion test needs to be done.
144 But this is at the expense of a slightly more overhead from an extra
145 function call.
146
147 If your callback accesses any data or critical section that requires RCU
148 protection, it is best to make sure that RCU is "watching", otherwise
149 that data or critical section will not be protected as expected. In this
150 case add:
151
152 .. code-block:: c
153
154 if (!rcu_is_watching())
155 return;
156
157 Alternatively, if the FTRACE_OPS_FL_RCU flag is set on the ftrace_ops
158 (as explained below), then a helper trampoline will be used to test
159 for rcu_is_watching for the callback and no other test needs to be done.
160 But this is at the expense of a slightly more overhead from an extra
161 function call.
162
163
164 The ftrace FLAGS
165 ================
166
167 The ftrace_ops flags are all defined and documented in include/linux/ftrace.h.
168 Some of the flags are used for internal infrastructure of ftrace, but the
169 ones that users should be aware of are the following:
170
171 FTRACE_OPS_FL_SAVE_REGS
172 If the callback requires reading or modifying the pt_regs
173 passed to the callback, then it must set this flag. Registering
174 a ftrace_ops with this flag set on an architecture that does not
175 support passing of pt_regs to the callback will fail.
176
177 FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
178 Similar to SAVE_REGS but the registering of a
179 ftrace_ops on an architecture that does not support passing of regs
180 will not fail with this flag set. But the callback must check if
181 regs is NULL or not to determine if the architecture supports it.
182
183 FTRACE_OPS_FL_RECURSION
184 By default, it is expected that the callback can handle recursion.
185 But if the callback is not that worried about overhead, then
186 setting this bit will add the recursion protection around the
187 callback by calling a helper function that will do the recursion
188 protection and only call the callback if it did not recurse.
189
190 Note, if this flag is not set, and recursion does occur, it could
191 cause the system to crash, and possibly reboot via a triple fault.
192
193 Note, if this flag is set, then the callback will always be called
194 with preemption disabled. If it is not set, then it is possible
195 (but not guaranteed) that the callback will be called in
196 preemptible context.
197
198 FTRACE_OPS_FL_IPMODIFY
199 Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to "hijack"
200 the traced function (have another function called instead of the
201 traced function), it requires setting this flag. This is what live
202 kernel patches uses. Without this flag the pt_regs->ip can not be
203 modified.
204
205 Note, only one ftrace_ops with FTRACE_OPS_FL_IPMODIFY set may be
206 registered to any given function at a time.
207
208 FTRACE_OPS_FL_RCU
209 If this is set, then the callback will only be called by functions
210 where RCU is "watching". This is required if the callback function
211 performs any rcu_read_lock() operation.
212
213 RCU stops watching when the system goes idle, the time when a CPU
214 is taken down and comes back online, and when entering from kernel
215 to user space and back to kernel space. During these transitions,
216 a callback may be executed and RCU synchronization will not protect
217 it.
218
219 FTRACE_OPS_FL_PERMANENT
220 If this is set on any ftrace ops, then the tracing cannot disabled by
221 writing 0 to the proc sysctl ftrace_enabled. Equally, a callback with
222 the flag set cannot be registered if ftrace_enabled is 0.
223
224 Livepatch uses it not to lose the function redirection, so the system
225 stays protected.
226
227
228 Filtering which functions to trace
229 ==================================
230
231 If a callback is only to be called from specific functions, a filter must be
232 set up. The filters are added by name, or ip if it is known.
233
234 .. code-block:: c
235
236 int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
237 int len, int reset);
238
239 @ops
240 The ops to set the filter with
241
242 @buf
243 The string that holds the function filter text.
244 @len
245 The length of the string.
246
247 @reset
248 Non-zero to reset all filters before applying this filter.
249
250 Filters denote which functions should be enabled when tracing is enabled.
251 If @buf is NULL and reset is set, all functions will be enabled for tracing.
252
253 The @buf can also be a glob expression to enable all functions that
254 match a specific pattern.
255
256 See Filter Commands in :file:`Documentation/trace/ftrace.rst`.
257
258 To just trace the schedule function:
259
260 .. code-block:: c
261
262 ret = ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0);
263
264 To add more functions, call the ftrace_set_filter() more than once with the
265 @reset parameter set to zero. To remove the current filter set and replace it
266 with new functions defined by @buf, have @reset be non-zero.
267
268 To remove all the filtered functions and trace all functions:
269
270 .. code-block:: c
271
272 ret = ftrace_set_filter(&ops, NULL, 0, 1);
273
274
275 Sometimes more than one function has the same name. To trace just a specific
276 function in this case, ftrace_set_filter_ip() can be used.
277
278 .. code-block:: c
279
280 ret = ftrace_set_filter_ip(&ops, ip, 0, 0);
281
282 Although the ip must be the address where the call to fentry or mcount is
283 located in the function. This function is used by perf and kprobes that
284 gets the ip address from the user (usually using debug info from the kernel).
285
286 If a glob is used to set the filter, functions can be added to a "notrace"
287 list that will prevent those functions from calling the callback.
288 The "notrace" list takes precedence over the "filter" list. If the
289 two lists are non-empty and contain the same functions, the callback will not
290 be called by any function.
291
292 An empty "notrace" list means to allow all functions defined by the filter
293 to be traced.
294
295 .. code-block:: c
296
297 int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
298 int len, int reset);
299
300 This takes the same parameters as ftrace_set_filter() but will add the
301 functions it finds to not be traced. This is a separate list from the
302 filter list, and this function does not modify the filter list.
303
304 A non-zero @reset will clear the "notrace" list before adding functions
305 that match @buf to it.
306
307 Clearing the "notrace" list is the same as clearing the filter list
308
309 .. code-block:: c
310
311 ret = ftrace_set_notrace(&ops, NULL, 0, 1);
312
313 The filter and notrace lists may be changed at any time. If only a set of
314 functions should call the callback, it is best to set the filters before
315 registering the callback. But the changes may also happen after the callback
316 has been registered.
317
318 If a filter is in place, and the @reset is non-zero, and @buf contains a
319 matching glob to functions, the switch will happen during the time of
320 the ftrace_set_filter() call. At no time will all functions call the callback.
321
322 .. code-block:: c
323
324 ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);
325
326 register_ftrace_function(&ops);
327
328 msleep(10);
329
330 ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 1);
331
332 is not the same as:
333
334 .. code-block:: c
335
336 ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);
337
338 register_ftrace_function(&ops);
339
340 msleep(10);
341
342 ftrace_set_filter(&ops, NULL, 0, 1);
343
344 ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 0);
345
346 As the latter will have a short time where all functions will call
347 the callback, between the time of the reset, and the time of the
348 new setting of the filter.
349

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 정보

1-11

이 문서는 VMware Inc.의 2017년 저작물이며 Steven Rostedt가 작성했다. GNU Free Documentation License 1.2와 GPL v2로 이중 라이선스되며, Linux 4.14를 기준으로 작성되었다.

=================================
Using ftrace to hook to functions
=================================

.. Copyright 2017 VMware Inc.
..   Author:   Steven Rostedt <srostedt@goodmis.org>
..  License:   The GNU Free Documentation License, Version 1.2
..               (dual licensed under the GPL v2)

Written for: 4.14

소개

12-21

ftrace 기반 구조는 원래 함수 시작 지점에 콜백을 붙여 커널 실행 흐름을 기록하고 추적하기 위해 만들어졌다. 그러나 함수 진입 콜백은 라이브 커널 패치나 보안 모니터링에도 사용할 수 있다.

이 문서는 사용자가 자신의 함수 콜백을 구현하고 ftrace에 등록하는 방법을 설명한다.

함수 진입 콜백의 활용
함수 시작 지점ftrace 콜백
ftrace 콜백실행 흐름 기록
ftrace 콜백라이브 커널 패치
ftrace 콜백보안 모니터링

같은 ftrace 훅이 추적 외의 커널 기능에도 쓰인다.

Introduction
============

The ftrace infrastructure was originally created to attach callbacks to the
beginning of functions in order to record and trace the flow of the kernel.
But callbacks to the start of a function can have other use cases. Either
for live kernel patching, or for security monitoring. This document describes
how to use ftrace to implement your own function callbacks.

ftrace 실행 문맥

22-36

경고: 거의 모든 커널 함수에 콜백을 추가할 수 있다는 점에는 큰 위험이 따른다. 콜백은 일반 문맥, softirq, irq, NMI 어느 곳에서든 호출될 수 있다.

또한 시스템이 idle에 들어가기 직전, CPU가 온라인 또는 오프라인으로 전환되는 동안, 커널과 사용자 공간 사이를 오갈 때도 콜백이 실행될 수 있다. 이 때문에 콜백 내부에서 허용되는 연산을 매우 신중히 선택해야 한다.

콜백은 RCU 보호 범위 밖에서 실행될 수 있다. ftrace는 재귀를 막고 RCU가 현재 관찰 중인지 확인하는 도우미를 제공하며, 뒤 절에서 사용법을 설명한다.

가능한 콜백 문맥
범주
인터럽트 상태normal, softirq, irq, NMI
CPU 상태 전환idle 진입, CPU bring-up/takedown
권한 경계 전환커널과 사용자 공간 사이 이동
RCURCU가 watching이 아닌 구간 가능

콜백 코드는 모든 문맥을 견딜 수 있어야 한다.

The ftrace context
==================
.. warning::

  The ability to add a callback to almost any function within the
  kernel comes with risks. A callback can be called from any context
  (normal, softirq, irq, and NMI). Callbacks can also be called just before
  going to idle, during CPU bring up and takedown, or going to user space.
  This requires extra care to what can be done inside a callback. A callback
  can be called outside the protective scope of RCU.

There are helper functions to help against recursion, and making sure
RCU is watching. These are explained below.

ftrace_ops 구조체

37-81

함수 콜백을 등록하려면 `struct ftrace_ops`가 필요하다. 이 구조체는 호출할 콜백과 콜백 자체가 담당할 보호 기능을 ftrace에 알려 준다.

필수 필드는 `.func`뿐이다. `.flags`와 `.private`는 선택 사항이며, `.private`에는 콜백이 사용할 임의의 사설 데이터 구조를 연결할 수 있다.

`register_ftrace_function(&ops)`로 추적을 활성화하고 `unregister_ftrace_function(&ops)`로 비활성화한다. 선언을 사용하려면 `<linux/ftrace.h>`를 포함한다.

등록된 콜백은 `register_ftrace_function()` 호출 뒤부터 그 함수가 반환하기 전 사이의 어느 시점에 호출되기 시작한다. 정확한 시작 시점은 아키텍처와 서비스 스케줄링에 달려 있으므로 특정 순간부터 정확히 시작해야 한다면 콜백 사용자가 동기화를 구현해야 한다.

`unregister_ftrace_function()`이 반환한 뒤에는 어떤 함수도 해당 콜백을 더 호출하지 않는다는 보장이 있다. 이 보장을 만들기 위한 동기화 때문에 등록 해제 함수가 완료되는 데 시간이 걸릴 수 있다.

ftrace_ops 필드
필드필수 여부용도
func필수호출할 함수 콜백
flags선택레지스터, 재귀, RCU 등의 동작 지정
private선택콜백에 전달할 사설 데이터

등록에 필요한 필드와 선택 필드를 구분한다.

콜백 수명 주기
ftrace_ops 초기화register_ftrace_function
등록 호출 중 또는 직후콜백 시작
콜백 실행 중unregister_ftrace_function
등록 해제 반환추가 콜백 없음

등록과 해제의 반환 시점에 제공되는 보장을 보여 준다.

The ftrace_ops structure
========================

To register a function callback, a ftrace_ops is required. This structure
is used to tell ftrace what function should be called as the callback
as well as what protections the callback will perform and not require
ftrace to handle.

There is only one field that is needed to be set when registering
an ftrace_ops with ftrace:

.. code-block:: c

 struct ftrace_ops ops = {
       .func			= my_callback_func,
       .flags			= MY_FTRACE_FLAGS
       .private			= any_private_data_structure,
 };

Both .flags and .private are optional. Only .func is required.

To enable tracing call::

    register_ftrace_function(&ops);

To disable tracing call::

    unregister_ftrace_function(&ops);

The above is defined by including the header::

    #include <linux/ftrace.h>

The registered callback will start being called some time after the
register_ftrace_function() is called and before it returns. The exact time
that callbacks start being called is dependent upon architecture and scheduling
of services. The callback itself will have to handle any synchronization if it
must begin at an exact moment.

The unregister_ftrace_function() will guarantee that the callback is
no longer being called by functions after the unregister_ftrace_function()
returns. Note that to perform this guarantee, the unregister_ftrace_function()
may take some time to finish.

콜백 함수

82-110

Linux 4.14 기준 콜백 원형은 `void callback_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)`다.

`ip`는 추적 중인 함수 안에서 `fentry` 또는 `mcount`가 놓인 명령 포인터다. `parent_ip`는 그 함수를 호출한 부모 함수의 호출 지점 명령 포인터다.

`op`는 콜백 등록에 사용한 `ftrace_ops`의 포인터다. 따라서 `op->private`를 통해 등록 시 연결한 데이터를 콜백으로 전달할 수 있다.

`regs`는 `FTRACE_OPS_FL_SAVE_REGS` 또는 `FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED`가 설정된 경우 함수 시작에 브레이크포인트를 둔 것과 유사한 `pt_regs` 문맥을 가리킨다. 이 플래그가 없으면 값은 쓰레기이거나 `NULL`일 수 있으므로 접근해서는 안 된다.

콜백 인자
인자의미
ip추적 함수의 fentry/mcount 위치
parent_ip부모 함수 안의 호출 지점
op등록에 사용한 ftrace_ops
regs플래그로 요청했을 때만 유효한 pt_regs

함수 진입에서 전달되는 주소와 문맥이다.

The callback function
=====================

The prototype of the callback function is as follows (as of v4.14):

.. code-block:: c

   void callback_func(unsigned long ip, unsigned long parent_ip,
                      struct ftrace_ops *op, struct pt_regs *regs);

@ip
	 This is the instruction pointer of the function that is being traced.
      	 (where the fentry or mcount is within the function)

@parent_ip
	This is the instruction pointer of the function that called the
	the function being traced (where the call of the function occurred).

@op
	This is a pointer to ftrace_ops that was used to register the callback.
	This can be used to pass data to the callback via the private pointer.

@regs
	If the FTRACE_OPS_FL_SAVE_REGS or FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
	flags are set in the ftrace_ops structure, then this will be pointing
	to the pt_regs structure like it would be if an breakpoint was placed
	at the start of the function where ftrace was tracing. Otherwise it
	either contains garbage, or NULL.

콜백 보호

111-163

콜백이 호출한 함수도 같은 콜백의 추적 대상일 수 있으므로 재귀 보호가 필수다. 보호하지 않으면 콜백이 자신을 간접적으로 계속 호출할 수 있다.

직접 보호할 때는 시작에서 `ftrace_test_recursion_trylock(ip, parent_ip)`를 호출한다. 반환값이 음수면 재귀이므로 즉시 반환하고, 성공한 경우 본문을 실행한 뒤 반드시 `ftrace_test_recursion_unlock(bit)`을 호출한다.

재귀 잠금 성공은 preemption을 비활성화하고 unlock은 이전에 활성 상태였을 때 다시 켠다. `ip`와 `parent_ip`는 `CONFIG_FTRACE_RECORD_RECURSION` 설정 시 재귀가 발생한 위치를 기록하는 데 쓰인다.

대안으로 `ftrace_ops`에 `FTRACE_OPS_FL_RECURSION`을 설정하면 도우미 트램펄린이 콜백 앞에서 재귀를 검사한다. 콜백 자체의 검사 코드는 필요 없지만 함수 호출 한 번만큼의 오버헤드가 늘어난다.

콜백이 RCU 보호가 필요한 데이터나 임계 구역에 접근한다면 `rcu_is_watching()`을 검사하고 거짓일 때 반환해야 한다. 그렇지 않으면 기대한 RCU 보호가 성립하지 않는다.

`FTRACE_OPS_FL_RCU`를 설정하면 별도 트램펄린이 `rcu_is_watching()`을 확인한 뒤 조건을 만족할 때만 콜백을 부른다. 이 방법도 추가 함수 호출 비용이 있다.

수동 재귀 보호
콜백 진입ftrace_test_recursion_trylock
음수 반환즉시 반환
잠금 성공콜백 본문
콜백 본문ftrace_test_recursion_unlock

잠금 실패 시 콜백을 건너뛰고 성공 경로에서 preemption 상태를 복원한다.

보호 방법 비교
보호직접 검사플래그
재귀trylock/unlockFTRACE_OPS_FL_RECURSION
RCU watchingrcu_is_watching()FTRACE_OPS_FL_RCU

직접 검사와 플래그 기반 트램펄린의 차이다.

Protect your callback
=====================

As functions can be called from anywhere, and it is possible that a function
called by a callback may also be traced, and call that same callback,
recursion protection must be used. There are two helper functions that
can help in this regard. If you start your code with:

.. code-block:: c

	int bit;

	bit = ftrace_test_recursion_trylock(ip, parent_ip);
	if (bit < 0)
		return;

and end it with:

.. code-block:: c

	ftrace_test_recursion_unlock(bit);

The code in between will be safe to use, even if it ends up calling a
function that the callback is tracing. Note, on success,
ftrace_test_recursion_trylock() will disable preemption, and the
ftrace_test_recursion_unlock() will enable it again (if it was previously
enabled). The instruction pointer (ip) and its parent (parent_ip) is passed to
ftrace_test_recursion_trylock() to record where the recursion happened
(if CONFIG_FTRACE_RECORD_RECURSION is set).

Alternatively, if the FTRACE_OPS_FL_RECURSION flag is set on the ftrace_ops
(as explained below), then a helper trampoline will be used to test
for recursion for the callback and no recursion test needs to be done.
But this is at the expense of a slightly more overhead from an extra
function call.

If your callback accesses any data or critical section that requires RCU
protection, it is best to make sure that RCU is "watching", otherwise
that data or critical section will not be protected as expected. In this
case add:

.. code-block:: c

	if (!rcu_is_watching())
		return;

Alternatively, if the FTRACE_OPS_FL_RCU flag is set on the ftrace_ops
(as explained below), then a helper trampoline will be used to test
for rcu_is_watching for the callback and no other test needs to be done.
But this is at the expense of a slightly more overhead from an extra
function call.

ftrace 플래그

164-227

`ftrace_ops` 플래그는 `include/linux/ftrace.h`에 정의되고 문서화되어 있다. 일부는 내부용이며, 사용자가 알아야 할 주요 플래그는 다음과 같다.

`FTRACE_OPS_FL_SAVE_REGS`는 콜백이 전달받은 `pt_regs`를 읽거나 수정해야 할 때 필수다. 레지스터 전달을 지원하지 않는 아키텍처에서 이 플래그로 등록하면 실패한다.

`FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED`는 레지스터 저장을 지원하지 않는 아키텍처에서도 등록 자체는 실패하지 않는다. 대신 콜백이 `regs == NULL`인지 검사해 지원 여부를 판정해야 한다.

`FTRACE_OPS_FL_RECURSION`은 도우미가 콜백을 재귀 보호로 감싼다. 플래그가 없으면 콜백 스스로 재귀를 처리해야 하며, 실패하면 시스템 충돌이나 triple fault에 따른 재부팅까지 일어날 수 있다. 플래그를 설정하면 콜백은 항상 preemption이 비활성화된 상태에서 호출된다. 설정하지 않으면 preemptible 문맥일 수도 있지만 보장되지는 않는다.

`FTRACE_OPS_FL_IPMODIFY`는 `FTRACE_OPS_FL_SAVE_REGS`를 함께 요구한다. 추적 대상 대신 다른 함수를 실행하도록 함수를 가로채려면 이 플래그가 필요하며 라이브 커널 패치가 이 기능을 사용한다. 플래그 없이는 `pt_regs->ip`를 수정할 수 없다. 같은 함수에는 한 시점에 `IPMODIFY` ops 하나만 등록할 수 있다.

`FTRACE_OPS_FL_RCU`는 RCU가 watching 상태인 함수에서만 콜백을 호출한다. 콜백이 `rcu_read_lock()`을 수행한다면 필수다. RCU는 idle, CPU 오프라인과 온라인 전환, 커널과 사용자 공간 전환 중 watching을 멈추므로 이 구간의 콜백은 일반적인 RCU 동기화로 보호되지 않는다.

`FTRACE_OPS_FL_PERMANENT`가 하나라도 설정되면 `/proc` sysctl의 `ftrace_enabled`에 0을 써서 추적을 비활성화할 수 없다. 반대로 `ftrace_enabled`가 0인 상태에서는 이 플래그를 가진 콜백을 등록할 수 없다. 라이브패치는 함수 리디렉션이 사라지지 않아 시스템 보호가 유지되도록 이 플래그를 사용한다.

사용자용 ftrace_ops 플래그
플래그효과주의 사항
SAVE_REGS유효한 pt_regs 전달미지원 아키텍처에서 등록 실패
SAVE_REGS_IF_SUPPORTED가능할 때 pt_regs 전달콜백에서 NULL 검사
RECURSION트램펄린 재귀 보호항상 preemption 비활성
IPMODIFYpt_regs->ip 변경SAVE_REGS 필요, 함수당 하나
RCURCU watching일 때만 호출rcu_read_lock 사용 시 필요
PERMANENT전역 ftrace 비활성화 차단라이브패치 리디렉션 유지

콜백이 요구하는 기능과 등록 제약을 정리한다.

The ftrace FLAGS
================

The ftrace_ops flags are all defined and documented in include/linux/ftrace.h.
Some of the flags are used for internal infrastructure of ftrace, but the
ones that users should be aware of are the following:

FTRACE_OPS_FL_SAVE_REGS
	If the callback requires reading or modifying the pt_regs
	passed to the callback, then it must set this flag. Registering
	a ftrace_ops with this flag set on an architecture that does not
	support passing of pt_regs to the callback will fail.

FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
	Similar to SAVE_REGS but the registering of a
	ftrace_ops on an architecture that does not support passing of regs
	will not fail with this flag set. But the callback must check if
	regs is NULL or not to determine if the architecture supports it.

FTRACE_OPS_FL_RECURSION
	By default, it is expected that the callback can handle recursion.
	But if the callback is not that worried about overhead, then
	setting this bit will add the recursion protection around the
	callback by calling a helper function that will do the recursion
	protection and only call the callback if it did not recurse.

	Note, if this flag is not set, and recursion does occur, it could
	cause the system to crash, and possibly reboot via a triple fault.

	Note, if this flag is set, then the callback will always be called
	with preemption disabled. If it is not set, then it is possible
	(but not guaranteed) that the callback will be called in
	preemptible context.

FTRACE_OPS_FL_IPMODIFY
	Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to "hijack"
	the traced function (have another function called instead of the
	traced function), it requires setting this flag. This is what live
	kernel patches uses. Without this flag the pt_regs->ip can not be
	modified.

	Note, only one ftrace_ops with FTRACE_OPS_FL_IPMODIFY set may be
	registered to any given function at a time.

FTRACE_OPS_FL_RCU
	If this is set, then the callback will only be called by functions
	where RCU is "watching". This is required if the callback function
	performs any rcu_read_lock() operation.

	RCU stops watching when the system goes idle, the time when a CPU
	is taken down and comes back online, and when entering from kernel
	to user space and back to kernel space. During these transitions,
	a callback may be executed and RCU synchronization will not protect
	it.

FTRACE_OPS_FL_PERMANENT
        If this is set on any ftrace ops, then the tracing cannot disabled by
        writing 0 to the proc sysctl ftrace_enabled. Equally, a callback with
        the flag set cannot be registered if ftrace_enabled is 0.

        Livepatch uses it not to lose the function redirection, so the system
        stays protected.

추적할 함수 필터링

228-348

콜백을 특정 함수에서만 호출하려면 이름 또는 알려진 명령 포인터로 필터를 설정한다. `ftrace_set_filter(ops, buf, len, reset)`에서 `ops`는 대상 ops, `buf`는 필터 문자열, `len`은 길이, `reset`은 기존 필터를 먼저 지울지 지정한다.

필터는 추적이 활성화되었을 때 콜백을 부를 함수 집합이다. `buf`가 `NULL`이고 `reset`이 0이 아니면 모든 함수가 추적 대상이 된다. `buf`에는 glob 표현식을 넣어 패턴과 일치하는 함수를 한꺼번에 선택할 수 있으며 자세한 명령은 `Documentation/trace/ftrace.rst`의 Filter Commands를 참고한다.

`schedule`만 추적하려면 문서의 예처럼 `ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0)`을 사용한다. `reset`을 0으로 두고 여러 번 호출하면 기존 집합에 함수를 추가한다. `reset`을 0이 아닌 값으로 두면 기존 집합을 지우고 `buf`가 지정한 새 집합으로 교체한다.

모든 필터를 제거해 모든 함수를 추적하려면 `ftrace_set_filter(&ops, NULL, 0, 1)`을 호출한다.

동일한 이름을 가진 함수가 여러 개일 때 특정 함수 하나만 추적하려면 `ftrace_set_filter_ip()`를 사용한다. 전달하는 IP는 함수 시작 주소 자체가 아니라 함수 안에서 `fentry` 또는 `mcount`를 호출하는 위치여야 한다. perf와 kprobes는 보통 커널 디버그 정보에서 사용자가 지정한 IP를 얻어 이 API를 쓴다.

glob 필터를 사용할 때 콜백을 금지할 함수는 별도의 `notrace` 목록에 넣을 수 있다. `notrace`가 `filter`보다 우선하므로 두 목록이 모두 비어 있지 않고 같은 함수만 담으면 어떤 함수도 콜백을 부르지 않는다. 빈 `notrace` 목록은 필터가 허용한 모든 함수를 추적하도록 허용한다.

`ftrace_set_notrace(ops, buf, len, reset)`는 필터 함수와 같은 인자를 받지만 별도 제외 목록만 수정한다. `reset`이 0이 아니면 기존 `notrace` 목록을 지운 뒤 `buf`와 일치하는 함수를 넣는다. `ftrace_set_notrace(&ops, NULL, 0, 1)`은 제외 목록 전체를 비운다.

`filter`와 `notrace` 목록은 언제든 바꿀 수 있다. 특정 함수 집합만 호출해야 한다면 콜백 등록 전에 필터를 설정하는 편이 좋지만 등록 뒤 변경도 지원된다.

기존 필터가 있는 상태에서 `reset`을 0이 아닌 값으로 하고 실제 함수와 일치하는 비어 있지 않은 glob을 전달하면 `ftrace_set_filter()` 호출 안에서 이전 집합에서 새 집합으로 원자적으로 전환된다. 그 사이 모든 함수가 콜백을 부르는 순간은 없다.

반면 `buf = NULL`, `reset = 1`로 먼저 필터를 비워 모든 함수를 허용한 다음, 별도의 호출에서 `reset = 0`으로 새 함수를 추가하면 두 호출 사이에 잠깐 모든 함수가 콜백을 부른다. 문서의 두 코드 시퀀스가 같지 않은 이유다.

필터 API
API대상 목록reset 효과
ftrace_set_filter호출 허용 함수기존 필터를 지우고 새 필터 적용
ftrace_set_filter_ip특정 fentry/mcount 위치IP 단위 추가 또는 제거
ftrace_set_notrace호출 금지 함수기존 제외 목록을 지우고 새 목록 적용

포함 목록과 제외 목록의 갱신 규칙이다.

원자적 필터 교체
기존 schedule 필터reset=1, try_to_wake_up 전달
reset=1, try_to_wake_up 전달새 필터로 즉시 전환
새 필터로 즉시 전환모든 함수 허용 구간 없음

한 번의 호출에서 일치하는 새 필터로 교체하면 전역 허용 창이 생기지 않는다.

두 단계 필터 교체의 위험
기존 schedule 필터NULL + reset=1
NULL + reset=1모든 함수 허용
모든 함수 허용try_to_wake_up + reset=0
try_to_wake_up + reset=0새 필터 적용

필터를 먼저 비운 뒤 새 필터를 더하면 호출 사이에 모든 함수가 허용된다.

Filtering which functions to trace
==================================

If a callback is only to be called from specific functions, a filter must be
set up. The filters are added by name, or ip if it is known.

.. code-block:: c

   int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
                         int len, int reset);

@ops
	The ops to set the filter with

@buf
	The string that holds the function filter text.
@len
	The length of the string.

@reset
	Non-zero to reset all filters before applying this filter.

Filters denote which functions should be enabled when tracing is enabled.
If @buf is NULL and reset is set, all functions will be enabled for tracing.

The @buf can also be a glob expression to enable all functions that
match a specific pattern.

See Filter Commands in :file:`Documentation/trace/ftrace.rst`.

To just trace the schedule function:

.. code-block:: c

   ret = ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0);

To add more functions, call the ftrace_set_filter() more than once with the
@reset parameter set to zero. To remove the current filter set and replace it
with new functions defined by @buf, have @reset be non-zero.

To remove all the filtered functions and trace all functions:

.. code-block:: c

   ret = ftrace_set_filter(&ops, NULL, 0, 1);


Sometimes more than one function has the same name. To trace just a specific
function in this case, ftrace_set_filter_ip() can be used.

.. code-block:: c

   ret = ftrace_set_filter_ip(&ops, ip, 0, 0);

Although the ip must be the address where the call to fentry or mcount is
located in the function. This function is used by perf and kprobes that
gets the ip address from the user (usually using debug info from the kernel).

If a glob is used to set the filter, functions can be added to a "notrace"
list that will prevent those functions from calling the callback.
The "notrace" list takes precedence over the "filter" list. If the
two lists are non-empty and contain the same functions, the callback will not
be called by any function.

An empty "notrace" list means to allow all functions defined by the filter
to be traced.

.. code-block:: c

   int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
                          int len, int reset);

This takes the same parameters as ftrace_set_filter() but will add the
functions it finds to not be traced. This is a separate list from the
filter list, and this function does not modify the filter list.

A non-zero @reset will clear the "notrace" list before adding functions
that match @buf to it.

Clearing the "notrace" list is the same as clearing the filter list

.. code-block:: c

  ret = ftrace_set_notrace(&ops, NULL, 0, 1);

The filter and notrace lists may be changed at any time. If only a set of
functions should call the callback, it is best to set the filters before
registering the callback. But the changes may also happen after the callback
has been registered.

If a filter is in place, and the @reset is non-zero, and @buf contains a
matching glob to functions, the switch will happen during the time of
the ftrace_set_filter() call. At no time will all functions call the callback.

.. code-block:: c

   ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);

   register_ftrace_function(&ops);

   msleep(10);

   ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 1);

is not the same as:

.. code-block:: c

   ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1);

   register_ftrace_function(&ops);

   msleep(10);

   ftrace_set_filter(&ops, NULL, 0, 1);

   ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 0);

As the latter will have a short time where all functions will call
the callback, between the time of the reset, and the time of the
new setting of the filter.