← Documents Documentation/admin-guide/cgroup-v2.rst GitHub 원문 ↗

Linux 6.18.37 · Administration / Control Groups

Control Group v2

Cgroup v2의 hierarchy model, core interface, CPU·memory·IO·PID·cpuset와 기타 controller, namespace, writeback programming 및 v1 설계 문제와 v2 rationale를 설명합니다.

Source pathDocumentation/admin-guide/cgroup-v2.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

Hierarchy model, operations and delegation

cgroup-v2.rst:1-742

Cgroup v2의 용어, mount와 process·thread 조직, controller enable constraint, delegation containment, 권장 hierarchy organization과 resource distribution model을 정리합니다.

Core interface files and CPU controller

cgroup-v2.rst:743-1090

Interface format convention, cgroup core file과 lifecycle control, CPU accounting·weight·bandwidth·pressure·utilization clamp·idle control을 설명합니다.

Memory controller

cgroup-v2.rst:1091-1956

Memory protection·throttle·hard limit·reclaim·OOM, detailed statistics와 NUMA placement, swap·zswap·pressure, usage guideline과 charge ownership을 다룹니다.

IO controller

cgroup-v2.rst:1957-2353

IO statistics, IOCOST model·QoS, weight·absolute limit·pressure, page-cache writeback attribution, latency protection과 I/O priority policy를 설명합니다.

PID and Cpuset controllers

cgroup-v2.rst:2354-2686

Process-number hard limit와 events, hierarchical CPU·memory-node placement, exclusive CPU allocation과 local·remote·isolated partition state를 다룹니다.

Device, RDMA, DMEM, HugeTLB and Misc controllers

cgroup-v2.rst:2687-2915

Cgroup BPF device access, RDMA와 device-memory accounting, HugeTLB limit·NUMA statistic, Misc scalar resource registration·limit·ownership을 설명합니다.

Other behavior and cgroup namespaces

cgroup-v2.rst:2916-3103

Perf-event와 root process의 non-normative behavior, cgroup namespace root·path virtualization·migration·setns와 namespace-private mount를 설명합니다.

Kernel programming and v2 rationale

cgroup-v2.rst:3104-3407

Filesystem writeback annotation API, 제거된 v1 core feature, multiple hierarchy·thread granularity·inner-node competition·interface 문제와 memory controller 개선 rationale를 정리합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. _cgroup-v2:
2
3 ================
4 Control Group v2
5 ================
6
7 :Date: October, 2015
8 :Author: Tejun Heo <tj@kernel.org>
9
10 This is the authoritative documentation on the design, interface and
11 conventions of cgroup v2. It describes all userland-visible aspects
12 of cgroup including core and specific controller behaviors. All
13 future changes must be reflected in this document. Documentation for
14 v1 is available under :ref:`Documentation/admin-guide/cgroup-v1/index.rst <cgroup-v1>`.
15
16 .. CONTENTS
17
18 [Whenever any new section is added to this document, please also add
19 an entry here.]
20
21 1. Introduction
22 1-1. Terminology
23 1-2. What is cgroup?
24 2. Basic Operations
25 2-1. Mounting
26 2-2. Organizing Processes and Threads
27 2-2-1. Processes
28 2-2-2. Threads
29 2-3. [Un]populated Notification
30 2-4. Controlling Controllers
31 2-4-1. Availability
32 2-4-2. Enabling and Disabling
33 2-4-3. Top-down Constraint
34 2-4-4. No Internal Process Constraint
35 2-5. Delegation
36 2-5-1. Model of Delegation
37 2-5-2. Delegation Containment
38 2-6. Guidelines
39 2-6-1. Organize Once and Control
40 2-6-2. Avoid Name Collisions
41 3. Resource Distribution Models
42 3-1. Weights
43 3-2. Limits
44 3-3. Protections
45 3-4. Allocations
46 4. Interface Files
47 4-1. Format
48 4-2. Conventions
49 4-3. Core Interface Files
50 5. Controllers
51 5-1. CPU
52 5-1-1. CPU Interface Files
53 5-2. Memory
54 5-2-1. Memory Interface Files
55 5-2-2. Usage Guidelines
56 5-2-3. Memory Ownership
57 5-3. IO
58 5-3-1. IO Interface Files
59 5-3-2. Writeback
60 5-3-3. IO Latency
61 5-3-3-1. How IO Latency Throttling Works
62 5-3-3-2. IO Latency Interface Files
63 5-3-4. IO Priority
64 5-4. PID
65 5-4-1. PID Interface Files
66 5-5. Cpuset
67 5.5-1. Cpuset Interface Files
68 5-6. Device controller
69 5-7. RDMA
70 5-7-1. RDMA Interface Files
71 5-8. DMEM
72 5-8-1. DMEM Interface Files
73 5-9. HugeTLB
74 5.9-1. HugeTLB Interface Files
75 5-10. Misc
76 5.10-1 Misc Interface Files
77 5.10-2 Migration and Ownership
78 5-11. Others
79 5-11-1. perf_event
80 5-N. Non-normative information
81 5-N-1. CPU controller root cgroup process behaviour
82 5-N-2. IO controller root cgroup process behaviour
83 6. Namespace
84 6-1. Basics
85 6-2. The Root and Views
86 6-3. Migration and setns(2)
87 6-4. Interaction with Other Namespaces
88 P. Information on Kernel Programming
89 P-1. Filesystem Support for Writeback
90 D. Deprecated v1 Core Features
91 R. Issues with v1 and Rationales for v2
92 R-1. Multiple Hierarchies
93 R-2. Thread Granularity
94 R-3. Competition Between Inner Nodes and Threads
95 R-4. Other Interface Issues
96 R-5. Controller Issues and Remedies
97 R-5-1. Memory
98
99
100 Introduction
101 ============
102
103 Terminology
104 -----------
105
106 "cgroup" stands for "control group" and is never capitalized. The
107 singular form is used to designate the whole feature and also as a
108 qualifier as in "cgroup controllers". When explicitly referring to
109 multiple individual control groups, the plural form "cgroups" is used.
110
111
112 What is cgroup?
113 ---------------
114
115 cgroup is a mechanism to organize processes hierarchically and
116 distribute system resources along the hierarchy in a controlled and
117 configurable manner.
118
119 cgroup is largely composed of two parts - the core and controllers.
120 cgroup core is primarily responsible for hierarchically organizing
121 processes. A cgroup controller is usually responsible for
122 distributing a specific type of system resource along the hierarchy
123 although there are utility controllers which serve purposes other than
124 resource distribution.
125
126 cgroups form a tree structure and every process in the system belongs
127 to one and only one cgroup. All threads of a process belong to the
128 same cgroup. On creation, all processes are put in the cgroup that
129 the parent process belongs to at the time. A process can be migrated
130 to another cgroup. Migration of a process doesn't affect already
131 existing descendant processes.
132
133 Following certain structural constraints, controllers may be enabled or
134 disabled selectively on a cgroup. All controller behaviors are
135 hierarchical - if a controller is enabled on a cgroup, it affects all
136 processes which belong to the cgroups consisting the inclusive
137 sub-hierarchy of the cgroup. When a controller is enabled on a nested
138 cgroup, it always restricts the resource distribution further. The
139 restrictions set closer to the root in the hierarchy can not be
140 overridden from further away.
141
142
143 Basic Operations
144 ================
145
146 Mounting
147 --------
148
149 Unlike v1, cgroup v2 has only single hierarchy. The cgroup v2
150 hierarchy can be mounted with the following mount command::
151
152 # mount -t cgroup2 none $MOUNT_POINT
153
154 cgroup2 filesystem has the magic number 0x63677270 ("cgrp"). All
155 controllers which support v2 and are not bound to a v1 hierarchy are
156 automatically bound to the v2 hierarchy and show up at the root.
157 Controllers which are not in active use in the v2 hierarchy can be
158 bound to other hierarchies. This allows mixing v2 hierarchy with the
159 legacy v1 multiple hierarchies in a fully backward compatible way.
160
161 A controller can be moved across hierarchies only after the controller
162 is no longer referenced in its current hierarchy. Because per-cgroup
163 controller states are destroyed asynchronously and controllers may
164 have lingering references, a controller may not show up immediately on
165 the v2 hierarchy after the final umount of the previous hierarchy.
166 Similarly, a controller should be fully disabled to be moved out of
167 the unified hierarchy and it may take some time for the disabled
168 controller to become available for other hierarchies; furthermore, due
169 to inter-controller dependencies, other controllers may need to be
170 disabled too.
171
172 While useful for development and manual configurations, moving
173 controllers dynamically between the v2 and other hierarchies is
174 strongly discouraged for production use. It is recommended to decide
175 the hierarchies and controller associations before starting using the
176 controllers after system boot.
177
178 During transition to v2, system management software might still
179 automount the v1 cgroup filesystem and so hijack all controllers
180 during boot, before manual intervention is possible. To make testing
181 and experimenting easier, the kernel parameter cgroup_no_v1= allows
182 disabling controllers in v1 and make them always available in v2.
183
184 cgroup v2 currently supports the following mount options.
185
186 nsdelegate
187 Consider cgroup namespaces as delegation boundaries. This
188 option is system wide and can only be set on mount or modified
189 through remount from the init namespace. The mount option is
190 ignored on non-init namespace mounts. Please refer to the
191 Delegation section for details.
192
193 favordynmods
194 Reduce the latencies of dynamic cgroup modifications such as
195 task migrations and controller on/offs at the cost of making
196 hot path operations such as forks and exits more expensive.
197 The static usage pattern of creating a cgroup, enabling
198 controllers, and then seeding it with CLONE_INTO_CGROUP is
199 not affected by this option.
200
201 memory_localevents
202 Only populate memory.events with data for the current cgroup,
203 and not any subtrees. This is legacy behaviour, the default
204 behaviour without this option is to include subtree counts.
205 This option is system wide and can only be set on mount or
206 modified through remount from the init namespace. The mount
207 option is ignored on non-init namespace mounts.
208
209 memory_recursiveprot
210 Recursively apply memory.min and memory.low protection to
211 entire subtrees, without requiring explicit downward
212 propagation into leaf cgroups. This allows protecting entire
213 subtrees from one another, while retaining free competition
214 within those subtrees. This should have been the default
215 behavior but is a mount-option to avoid regressing setups
216 relying on the original semantics (e.g. specifying bogusly
217 high 'bypass' protection values at higher tree levels).
218
219 memory_hugetlb_accounting
220 Count HugeTLB memory usage towards the cgroup's overall
221 memory usage for the memory controller (for the purpose of
222 statistics reporting and memory protetion). This is a new
223 behavior that could regress existing setups, so it must be
224 explicitly opted in with this mount option.
225
226 A few caveats to keep in mind:
227
228 * There is no HugeTLB pool management involved in the memory
229 controller. The pre-allocated pool does not belong to anyone.
230 Specifically, when a new HugeTLB folio is allocated to
231 the pool, it is not accounted for from the perspective of the
232 memory controller. It is only charged to a cgroup when it is
233 actually used (for e.g at page fault time). Host memory
234 overcommit management has to consider this when configuring
235 hard limits. In general, HugeTLB pool management should be
236 done via other mechanisms (such as the HugeTLB controller).
237 * Failure to charge a HugeTLB folio to the memory controller
238 results in SIGBUS. This could happen even if the HugeTLB pool
239 still has pages available (but the cgroup limit is hit and
240 reclaim attempt fails).
241 * Charging HugeTLB memory towards the memory controller affects
242 memory protection and reclaim dynamics. Any userspace tuning
243 (of low, min limits for e.g) needs to take this into account.
244 * HugeTLB pages utilized while this option is not selected
245 will not be tracked by the memory controller (even if cgroup
246 v2 is remounted later on).
247
248 pids_localevents
249 The option restores v1-like behavior of pids.events:max, that is only
250 local (inside cgroup proper) fork failures are counted. Without this
251 option pids.events.max represents any pids.max enforcemnt across
252 cgroup's subtree.
253
254
255
256 Organizing Processes and Threads
257 --------------------------------
258
259 Processes
260 ~~~~~~~~~
261
262 Initially, only the root cgroup exists to which all processes belong.
263 A child cgroup can be created by creating a sub-directory::
264
265 # mkdir $CGROUP_NAME
266
267 A given cgroup may have multiple child cgroups forming a tree
268 structure. Each cgroup has a read-writable interface file
269 "cgroup.procs". When read, it lists the PIDs of all processes which
270 belong to the cgroup one-per-line. The PIDs are not ordered and the
271 same PID may show up more than once if the process got moved to
272 another cgroup and then back or the PID got recycled while reading.
273
274 A process can be migrated into a cgroup by writing its PID to the
275 target cgroup's "cgroup.procs" file. Only one process can be migrated
276 on a single write(2) call. If a process is composed of multiple
277 threads, writing the PID of any thread migrates all threads of the
278 process.
279
280 When a process forks a child process, the new process is born into the
281 cgroup that the forking process belongs to at the time of the
282 operation. After exit, a process stays associated with the cgroup
283 that it belonged to at the time of exit until it's reaped; however, a
284 zombie process does not appear in "cgroup.procs" and thus can't be
285 moved to another cgroup.
286
287 A cgroup which doesn't have any children or live processes can be
288 destroyed by removing the directory. Note that a cgroup which doesn't
289 have any children and is associated only with zombie processes is
290 considered empty and can be removed::
291
292 # rmdir $CGROUP_NAME
293
294 "/proc/$PID/cgroup" lists a process's cgroup membership. If legacy
295 cgroup is in use in the system, this file may contain multiple lines,
296 one for each hierarchy. The entry for cgroup v2 is always in the
297 format "0::$PATH"::
298
299 # cat /proc/842/cgroup
300 ...
301 0::/test-cgroup/test-cgroup-nested
302
303 If the process becomes a zombie and the cgroup it was associated with
304 is removed subsequently, " (deleted)" is appended to the path::
305
306 # cat /proc/842/cgroup
307 ...
308 0::/test-cgroup/test-cgroup-nested (deleted)
309
310
311 Threads
312 ~~~~~~~
313
314 cgroup v2 supports thread granularity for a subset of controllers to
315 support use cases requiring hierarchical resource distribution across
316 the threads of a group of processes. By default, all threads of a
317 process belong to the same cgroup, which also serves as the resource
318 domain to host resource consumptions which are not specific to a
319 process or thread. The thread mode allows threads to be spread across
320 a subtree while still maintaining the common resource domain for them.
321
322 Controllers which support thread mode are called threaded controllers.
323 The ones which don't are called domain controllers.
324
325 Marking a cgroup threaded makes it join the resource domain of its
326 parent as a threaded cgroup. The parent may be another threaded
327 cgroup whose resource domain is further up in the hierarchy. The root
328 of a threaded subtree, that is, the nearest ancestor which is not
329 threaded, is called threaded domain or thread root interchangeably and
330 serves as the resource domain for the entire subtree.
331
332 Inside a threaded subtree, threads of a process can be put in
333 different cgroups and are not subject to the no internal process
334 constraint - threaded controllers can be enabled on non-leaf cgroups
335 whether they have threads in them or not.
336
337 As the threaded domain cgroup hosts all the domain resource
338 consumptions of the subtree, it is considered to have internal
339 resource consumptions whether there are processes in it or not and
340 can't have populated child cgroups which aren't threaded. Because the
341 root cgroup is not subject to no internal process constraint, it can
342 serve both as a threaded domain and a parent to domain cgroups.
343
344 The current operation mode or type of the cgroup is shown in the
345 "cgroup.type" file which indicates whether the cgroup is a normal
346 domain, a domain which is serving as the domain of a threaded subtree,
347 or a threaded cgroup.
348
349 On creation, a cgroup is always a domain cgroup and can be made
350 threaded by writing "threaded" to the "cgroup.type" file. The
351 operation is single direction::
352
353 # echo threaded > cgroup.type
354
355 Once threaded, the cgroup can't be made a domain again. To enable the
356 thread mode, the following conditions must be met.
357
358 - As the cgroup will join the parent's resource domain. The parent
359 must either be a valid (threaded) domain or a threaded cgroup.
360
361 - When the parent is an unthreaded domain, it must not have any domain
362 controllers enabled or populated domain children. The root is
363 exempt from this requirement.
364
365 Topology-wise, a cgroup can be in an invalid state. Please consider
366 the following topology::
367
368 A (threaded domain) - B (threaded) - C (domain, just created)
369
370 C is created as a domain but isn't connected to a parent which can
371 host child domains. C can't be used until it is turned into a
372 threaded cgroup. "cgroup.type" file will report "domain (invalid)" in
373 these cases. Operations which fail due to invalid topology use
374 EOPNOTSUPP as the errno.
375
376 A domain cgroup is turned into a threaded domain when one of its child
377 cgroup becomes threaded or threaded controllers are enabled in the
378 "cgroup.subtree_control" file while there are processes in the cgroup.
379 A threaded domain reverts to a normal domain when the conditions
380 clear.
381
382 When read, "cgroup.threads" contains the list of the thread IDs of all
383 threads in the cgroup. Except that the operations are per-thread
384 instead of per-process, "cgroup.threads" has the same format and
385 behaves the same way as "cgroup.procs". While "cgroup.threads" can be
386 written to in any cgroup, as it can only move threads inside the same
387 threaded domain, its operations are confined inside each threaded
388 subtree.
389
390 The threaded domain cgroup serves as the resource domain for the whole
391 subtree, and, while the threads can be scattered across the subtree,
392 all the processes are considered to be in the threaded domain cgroup.
393 "cgroup.procs" in a threaded domain cgroup contains the PIDs of all
394 processes in the subtree and is not readable in the subtree proper.
395 However, "cgroup.procs" can be written to from anywhere in the subtree
396 to migrate all threads of the matching process to the cgroup.
397
398 Only threaded controllers can be enabled in a threaded subtree. When
399 a threaded controller is enabled inside a threaded subtree, it only
400 accounts for and controls resource consumptions associated with the
401 threads in the cgroup and its descendants. All consumptions which
402 aren't tied to a specific thread belong to the threaded domain cgroup.
403
404 Because a threaded subtree is exempt from no internal process
405 constraint, a threaded controller must be able to handle competition
406 between threads in a non-leaf cgroup and its child cgroups. Each
407 threaded controller defines how such competitions are handled.
408
409 Currently, the following controllers are threaded and can be enabled
410 in a threaded cgroup::
411
412 - cpu
413 - cpuset
414 - perf_event
415 - pids
416
417 [Un]populated Notification
418 --------------------------
419
420 Each non-root cgroup has a "cgroup.events" file which contains
421 "populated" field indicating whether the cgroup's sub-hierarchy has
422 live processes in it. Its value is 0 if there is no live process in
423 the cgroup and its descendants; otherwise, 1. poll and [id]notify
424 events are triggered when the value changes. This can be used, for
425 example, to start a clean-up operation after all processes of a given
426 sub-hierarchy have exited. The populated state updates and
427 notifications are recursive. Consider the following sub-hierarchy
428 where the numbers in the parentheses represent the numbers of processes
429 in each cgroup::
430
431 A(4) - B(0) - C(1)
432 \ D(0)
433
434 A, B and C's "populated" fields would be 1 while D's 0. After the one
435 process in C exits, B and C's "populated" fields would flip to "0" and
436 file modified events will be generated on the "cgroup.events" files of
437 both cgroups.
438
439
440 Controlling Controllers
441 -----------------------
442
443 Availability
444 ~~~~~~~~~~~~
445
446 A controller is available in a cgroup when it is supported by the kernel (i.e.,
447 compiled in, not disabled and not attached to a v1 hierarchy) and listed in the
448 "cgroup.controllers" file. Availability means the controller's interface files
449 are exposed in the cgroup’s directory, allowing the distribution of the target
450 resource to be observed or controlled within that cgroup.
451
452 Enabling and Disabling
453 ~~~~~~~~~~~~~~~~~~~~~~
454
455 Each cgroup has a "cgroup.controllers" file which lists all
456 controllers available for the cgroup to enable::
457
458 # cat cgroup.controllers
459 cpu io memory
460
461 No controller is enabled by default. Controllers can be enabled and
462 disabled by writing to the "cgroup.subtree_control" file::
463
464 # echo "+cpu +memory -io" > cgroup.subtree_control
465
466 Only controllers which are listed in "cgroup.controllers" can be
467 enabled. When multiple operations are specified as above, either they
468 all succeed or fail. If multiple operations on the same controller
469 are specified, the last one is effective.
470
471 Enabling a controller in a cgroup indicates that the distribution of
472 the target resource across its immediate children will be controlled.
473 Consider the following sub-hierarchy. The enabled controllers are
474 listed in parentheses::
475
476 A(cpu,memory) - B(memory) - C()
477 \ D()
478
479 As A has "cpu" and "memory" enabled, A will control the distribution
480 of CPU cycles and memory to its children, in this case, B. As B has
481 "memory" enabled but not "CPU", C and D will compete freely on CPU
482 cycles but their division of memory available to B will be controlled.
483
484 As a controller regulates the distribution of the target resource to
485 the cgroup's children, enabling it creates the controller's interface
486 files in the child cgroups. In the above example, enabling "cpu" on B
487 would create the "cpu." prefixed controller interface files in C and
488 D. Likewise, disabling "memory" from B would remove the "memory."
489 prefixed controller interface files from C and D. This means that the
490 controller interface files - anything which doesn't start with
491 "cgroup." are owned by the parent rather than the cgroup itself.
492
493
494 Top-down Constraint
495 ~~~~~~~~~~~~~~~~~~~
496
497 Resources are distributed top-down and a cgroup can further distribute
498 a resource only if the resource has been distributed to it from the
499 parent. This means that all non-root "cgroup.subtree_control" files
500 can only contain controllers which are enabled in the parent's
501 "cgroup.subtree_control" file. A controller can be enabled only if
502 the parent has the controller enabled and a controller can't be
503 disabled if one or more children have it enabled.
504
505
506 No Internal Process Constraint
507 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
508
509 Non-root cgroups can distribute domain resources to their children
510 only when they don't have any processes of their own. In other words,
511 only domain cgroups which don't contain any processes can have domain
512 controllers enabled in their "cgroup.subtree_control" files.
513
514 This guarantees that, when a domain controller is looking at the part
515 of the hierarchy which has it enabled, processes are always only on
516 the leaves. This rules out situations where child cgroups compete
517 against internal processes of the parent.
518
519 The root cgroup is exempt from this restriction. Root contains
520 processes and anonymous resource consumption which can't be associated
521 with any other cgroups and requires special treatment from most
522 controllers. How resource consumption in the root cgroup is governed
523 is up to each controller (for more information on this topic please
524 refer to the Non-normative information section in the Controllers
525 chapter).
526
527 Note that the restriction doesn't get in the way if there is no
528 enabled controller in the cgroup's "cgroup.subtree_control". This is
529 important as otherwise it wouldn't be possible to create children of a
530 populated cgroup. To control resource distribution of a cgroup, the
531 cgroup must create children and transfer all its processes to the
532 children before enabling controllers in its "cgroup.subtree_control"
533 file.
534
535
536 Delegation
537 ----------
538
539 Model of Delegation
540 ~~~~~~~~~~~~~~~~~~~
541
542 A cgroup can be delegated in two ways. First, to a less privileged
543 user by granting write access of the directory and its "cgroup.procs",
544 "cgroup.threads" and "cgroup.subtree_control" files to the user.
545 Second, if the "nsdelegate" mount option is set, automatically to a
546 cgroup namespace on namespace creation.
547
548 Because the resource control interface files in a given directory
549 control the distribution of the parent's resources, the delegatee
550 shouldn't be allowed to write to them. For the first method, this is
551 achieved by not granting access to these files. For the second, files
552 outside the namespace should be hidden from the delegatee by the means
553 of at least mount namespacing, and the kernel rejects writes to all
554 files on a namespace root from inside the cgroup namespace, except for
555 those files listed in "/sys/kernel/cgroup/delegate" (including
556 "cgroup.procs", "cgroup.threads", "cgroup.subtree_control", etc.).
557
558 The end results are equivalent for both delegation types. Once
559 delegated, the user can build sub-hierarchy under the directory,
560 organize processes inside it as it sees fit and further distribute the
561 resources it received from the parent. The limits and other settings
562 of all resource controllers are hierarchical and regardless of what
563 happens in the delegated sub-hierarchy, nothing can escape the
564 resource restrictions imposed by the parent.
565
566 Currently, cgroup doesn't impose any restrictions on the number of
567 cgroups in or nesting depth of a delegated sub-hierarchy; however,
568 this may be limited explicitly in the future.
569
570
571 Delegation Containment
572 ~~~~~~~~~~~~~~~~~~~~~~
573
574 A delegated sub-hierarchy is contained in the sense that processes
575 can't be moved into or out of the sub-hierarchy by the delegatee.
576
577 For delegations to a less privileged user, this is achieved by
578 requiring the following conditions for a process with a non-root euid
579 to migrate a target process into a cgroup by writing its PID to the
580 "cgroup.procs" file.
581
582 - The writer must have write access to the "cgroup.procs" file.
583
584 - The writer must have write access to the "cgroup.procs" file of the
585 common ancestor of the source and destination cgroups.
586
587 The above two constraints ensure that while a delegatee may migrate
588 processes around freely in the delegated sub-hierarchy it can't pull
589 in from or push out to outside the sub-hierarchy.
590
591 For an example, let's assume cgroups C0 and C1 have been delegated to
592 user U0 who created C00, C01 under C0 and C10 under C1 as follows and
593 all processes under C0 and C1 belong to U0::
594
595 ~~~~~~~~~~~~~ - C0 - C00
596 ~ cgroup ~ \ C01
597 ~ hierarchy ~
598 ~~~~~~~~~~~~~ - C1 - C10
599
600 Let's also say U0 wants to write the PID of a process which is
601 currently in C10 into "C00/cgroup.procs". U0 has write access to the
602 file; however, the common ancestor of the source cgroup C10 and the
603 destination cgroup C00 is above the points of delegation and U0 would
604 not have write access to its "cgroup.procs" files and thus the write
605 will be denied with -EACCES.
606
607 For delegations to namespaces, containment is achieved by requiring
608 that both the source and destination cgroups are reachable from the
609 namespace of the process which is attempting the migration. If either
610 is not reachable, the migration is rejected with -ENOENT.
611
612
613 Guidelines
614 ----------
615
616 Organize Once and Control
617 ~~~~~~~~~~~~~~~~~~~~~~~~~
618
619 Migrating a process across cgroups is a relatively expensive operation
620 and stateful resources such as memory are not moved together with the
621 process. This is an explicit design decision as there often exist
622 inherent trade-offs between migration and various hot paths in terms
623 of synchronization cost.
624
625 As such, migrating processes across cgroups frequently as a means to
626 apply different resource restrictions is discouraged. A workload
627 should be assigned to a cgroup according to the system's logical and
628 resource structure once on start-up. Dynamic adjustments to resource
629 distribution can be made by changing controller configuration through
630 the interface files.
631
632
633 Avoid Name Collisions
634 ~~~~~~~~~~~~~~~~~~~~~
635
636 Interface files for a cgroup and its children cgroups occupy the same
637 directory and it is possible to create children cgroups which collide
638 with interface files.
639
640 All cgroup core interface files are prefixed with "cgroup." and each
641 controller's interface files are prefixed with the controller name and
642 a dot. A controller's name is composed of lower case alphabets and
643 '_'s but never begins with an '_' so it can be used as the prefix
644 character for collision avoidance. Also, interface file names won't
645 start or end with terms which are often used in categorizing workloads
646 such as job, service, slice, unit or workload.
647
648 cgroup doesn't do anything to prevent name collisions and it's the
649 user's responsibility to avoid them.
650
651
652 Resource Distribution Models
653 ============================
654
655 cgroup controllers implement several resource distribution schemes
656 depending on the resource type and expected use cases. This section
657 describes major schemes in use along with their expected behaviors.
658
659
660 Weights
661 -------
662
663 A parent's resource is distributed by adding up the weights of all
664 active children and giving each the fraction matching the ratio of its
665 weight against the sum. As only children which can make use of the
666 resource at the moment participate in the distribution, this is
667 work-conserving. Due to the dynamic nature, this model is usually
668 used for stateless resources.
669
670 All weights are in the range [1, 10000] with the default at 100. This
671 allows symmetric multiplicative biases in both directions at fine
672 enough granularity while staying in the intuitive range.
673
674 As long as the weight is in range, all configuration combinations are
675 valid and there is no reason to reject configuration changes or
676 process migrations.
677
678 "cpu.weight" proportionally distributes CPU cycles to active children
679 and is an example of this type.
680
681
682 .. _cgroupv2-limits-distributor:
683
684 Limits
685 ------
686
687 A child can only consume up to the configured amount of the resource.
688 Limits can be over-committed - the sum of the limits of children can
689 exceed the amount of resource available to the parent.
690
691 Limits are in the range [0, max] and defaults to "max", which is noop.
692
693 As limits can be over-committed, all configuration combinations are
694 valid and there is no reason to reject configuration changes or
695 process migrations.
696
697 "io.max" limits the maximum BPS and/or IOPS that a cgroup can consume
698 on an IO device and is an example of this type.
699
700 .. _cgroupv2-protections-distributor:
701
702 Protections
703 -----------
704
705 A cgroup is protected up to the configured amount of the resource
706 as long as the usages of all its ancestors are under their
707 protected levels. Protections can be hard guarantees or best effort
708 soft boundaries. Protections can also be over-committed in which case
709 only up to the amount available to the parent is protected among
710 children.
711
712 Protections are in the range [0, max] and defaults to 0, which is
713 noop.
714
715 As protections can be over-committed, all configuration combinations
716 are valid and there is no reason to reject configuration changes or
717 process migrations.
718
719 "memory.low" implements best-effort memory protection and is an
720 example of this type.
721
722
723 Allocations
724 -----------
725
726 A cgroup is exclusively allocated a certain amount of a finite
727 resource. Allocations can't be over-committed - the sum of the
728 allocations of children can not exceed the amount of resource
729 available to the parent.
730
731 Allocations are in the range [0, max] and defaults to 0, which is no
732 resource.
733
734 As allocations can't be over-committed, some configuration
735 combinations are invalid and should be rejected. Also, if the
736 resource is mandatory for execution of processes, process migrations
737 may be rejected.
738
739 "cpu.rt.max" hard-allocates realtime slices and is an example of this
740 type.
741
742
743 Interface Files
744 ===============
745
746 Format
747 ------
748
749 All interface files should be in one of the following formats whenever
750 possible::
751
752 New-line separated values
753 (when only one value can be written at once)
754
755 VAL0\n
756 VAL1\n
757 ...
758
759 Space separated values
760 (when read-only or multiple values can be written at once)
761
762 VAL0 VAL1 ...\n
763
764 Flat keyed
765
766 KEY0 VAL0\n
767 KEY1 VAL1\n
768 ...
769
770 Nested keyed
771
772 KEY0 SUB_KEY0=VAL00 SUB_KEY1=VAL01...
773 KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11...
774 ...
775
776 For a writable file, the format for writing should generally match
777 reading; however, controllers may allow omitting later fields or
778 implement restricted shortcuts for most common use cases.
779
780 For both flat and nested keyed files, only the values for a single key
781 can be written at a time. For nested keyed files, the sub key pairs
782 may be specified in any order and not all pairs have to be specified.
783
784
785 Conventions
786 -----------
787
788 - Settings for a single feature should be contained in a single file.
789
790 - The root cgroup should be exempt from resource control and thus
791 shouldn't have resource control interface files.
792
793 - The default time unit is microseconds. If a different unit is ever
794 used, an explicit unit suffix must be present.
795
796 - A parts-per quantity should use a percentage decimal with at least
797 two digit fractional part - e.g. 13.40.
798
799 - If a controller implements weight based resource distribution, its
800 interface file should be named "weight" and have the range [1,
801 10000] with 100 as the default. The values are chosen to allow
802 enough and symmetric bias in both directions while keeping it
803 intuitive (the default is 100%).
804
805 - If a controller implements an absolute resource guarantee and/or
806 limit, the interface files should be named "min" and "max"
807 respectively. If a controller implements best effort resource
808 guarantee and/or limit, the interface files should be named "low"
809 and "high" respectively.
810
811 In the above four control files, the special token "max" should be
812 used to represent upward infinity for both reading and writing.
813
814 - If a setting has a configurable default value and keyed specific
815 overrides, the default entry should be keyed with "default" and
816 appear as the first entry in the file.
817
818 The default value can be updated by writing either "default $VAL" or
819 "$VAL".
820
821 When writing to update a specific override, "default" can be used as
822 the value to indicate removal of the override. Override entries
823 with "default" as the value must not appear when read.
824
825 For example, a setting which is keyed by major:minor device numbers
826 with integer values may look like the following::
827
828 # cat cgroup-example-interface-file
829 default 150
830 8:0 300
831
832 The default value can be updated by::
833
834 # echo 125 > cgroup-example-interface-file
835
836 or::
837
838 # echo "default 125" > cgroup-example-interface-file
839
840 An override can be set by::
841
842 # echo "8:16 170" > cgroup-example-interface-file
843
844 and cleared by::
845
846 # echo "8:0 default" > cgroup-example-interface-file
847 # cat cgroup-example-interface-file
848 default 125
849 8:16 170
850
851 - For events which are not very high frequency, an interface file
852 "events" should be created which lists event key value pairs.
853 Whenever a notifiable event happens, file modified event should be
854 generated on the file.
855
856
857 Core Interface Files
858 --------------------
859
860 All cgroup core files are prefixed with "cgroup."
861
862 cgroup.type
863 A read-write single value file which exists on non-root
864 cgroups.
865
866 When read, it indicates the current type of the cgroup, which
867 can be one of the following values.
868
869 - "domain" : A normal valid domain cgroup.
870
871 - "domain threaded" : A threaded domain cgroup which is
872 serving as the root of a threaded subtree.
873
874 - "domain invalid" : A cgroup which is in an invalid state.
875 It can't be populated or have controllers enabled. It may
876 be allowed to become a threaded cgroup.
877
878 - "threaded" : A threaded cgroup which is a member of a
879 threaded subtree.
880
881 A cgroup can be turned into a threaded cgroup by writing
882 "threaded" to this file.
883
884 cgroup.procs
885 A read-write new-line separated values file which exists on
886 all cgroups.
887
888 When read, it lists the PIDs of all processes which belong to
889 the cgroup one-per-line. The PIDs are not ordered and the
890 same PID may show up more than once if the process got moved
891 to another cgroup and then back or the PID got recycled while
892 reading.
893
894 A PID can be written to migrate the process associated with
895 the PID to the cgroup. The writer should match all of the
896 following conditions.
897
898 - It must have write access to the "cgroup.procs" file.
899
900 - It must have write access to the "cgroup.procs" file of the
901 common ancestor of the source and destination cgroups.
902
903 When delegating a sub-hierarchy, write access to this file
904 should be granted along with the containing directory.
905
906 In a threaded cgroup, reading this file fails with EOPNOTSUPP
907 as all the processes belong to the thread root. Writing is
908 supported and moves every thread of the process to the cgroup.
909
910 cgroup.threads
911 A read-write new-line separated values file which exists on
912 all cgroups.
913
914 When read, it lists the TIDs of all threads which belong to
915 the cgroup one-per-line. The TIDs are not ordered and the
916 same TID may show up more than once if the thread got moved to
917 another cgroup and then back or the TID got recycled while
918 reading.
919
920 A TID can be written to migrate the thread associated with the
921 TID to the cgroup. The writer should match all of the
922 following conditions.
923
924 - It must have write access to the "cgroup.threads" file.
925
926 - The cgroup that the thread is currently in must be in the
927 same resource domain as the destination cgroup.
928
929 - It must have write access to the "cgroup.procs" file of the
930 common ancestor of the source and destination cgroups.
931
932 When delegating a sub-hierarchy, write access to this file
933 should be granted along with the containing directory.
934
935 cgroup.controllers
936 A read-only space separated values file which exists on all
937 cgroups.
938
939 It shows space separated list of all controllers available to
940 the cgroup. The controllers are not ordered.
941
942 cgroup.subtree_control
943 A read-write space separated values file which exists on all
944 cgroups. Starts out empty.
945
946 When read, it shows space separated list of the controllers
947 which are enabled to control resource distribution from the
948 cgroup to its children.
949
950 Space separated list of controllers prefixed with '+' or '-'
951 can be written to enable or disable controllers. A controller
952 name prefixed with '+' enables the controller and '-'
953 disables. If a controller appears more than once on the list,
954 the last one is effective. When multiple enable and disable
955 operations are specified, either all succeed or all fail.
956
957 cgroup.events
958 A read-only flat-keyed file which exists on non-root cgroups.
959 The following entries are defined. Unless specified
960 otherwise, a value change in this file generates a file
961 modified event.
962
963 populated
964 1 if the cgroup or its descendants contains any live
965 processes; otherwise, 0.
966 frozen
967 1 if the cgroup is frozen; otherwise, 0.
968
969 cgroup.max.descendants
970 A read-write single value files. The default is "max".
971
972 Maximum allowed number of descent cgroups.
973 If the actual number of descendants is equal or larger,
974 an attempt to create a new cgroup in the hierarchy will fail.
975
976 cgroup.max.depth
977 A read-write single value files. The default is "max".
978
979 Maximum allowed descent depth below the current cgroup.
980 If the actual descent depth is equal or larger,
981 an attempt to create a new child cgroup will fail.
982
983 cgroup.stat
984 A read-only flat-keyed file with the following entries:
985
986 nr_descendants
987 Total number of visible descendant cgroups.
988
989 nr_dying_descendants
990 Total number of dying descendant cgroups. A cgroup becomes
991 dying after being deleted by a user. The cgroup will remain
992 in dying state for some time undefined time (which can depend
993 on system load) before being completely destroyed.
994
995 A process can't enter a dying cgroup under any circumstances,
996 a dying cgroup can't revive.
997
998 A dying cgroup can consume system resources not exceeding
999 limits, which were active at the moment of cgroup deletion.
1001 nr_subsys_<cgroup_subsys>
1002 Total number of live cgroup subsystems (e.g memory
1003 cgroup) at and beneath the current cgroup.
1005 nr_dying_subsys_<cgroup_subsys>
1006 Total number of dying cgroup subsystems (e.g. memory
1007 cgroup) at and beneath the current cgroup.
1009 cgroup.stat.local
1010 A read-only flat-keyed file which exists in non-root cgroups.
1011 The following entry is defined:
1013 frozen_usec
1014 Cumulative time that this cgroup has spent between freezing and
1015 thawing, regardless of whether by self or ancestor groups.
1016 NB: (not) reaching "frozen" state is not accounted here.
1018 Using the following ASCII representation of a cgroup's freezer
1019 state, ::
1021 1 _____
1022 frozen 0 __/ \__
1023 ab cd
1025 the duration being measured is the span between a and c.
1027 cgroup.freeze
1028 A read-write single value file which exists on non-root cgroups.
1029 Allowed values are "0" and "1". The default is "0".
1031 Writing "1" to the file causes freezing of the cgroup and all
1032 descendant cgroups. This means that all belonging processes will
1033 be stopped and will not run until the cgroup will be explicitly
1034 unfrozen. Freezing of the cgroup may take some time; when this action
1035 is completed, the "frozen" value in the cgroup.events control file
1036 will be updated to "1" and the corresponding notification will be
1037 issued.
1039 A cgroup can be frozen either by its own settings, or by settings
1040 of any ancestor cgroups. If any of ancestor cgroups is frozen, the
1041 cgroup will remain frozen.
1043 Processes in the frozen cgroup can be killed by a fatal signal.
1044 They also can enter and leave a frozen cgroup: either by an explicit
1045 move by a user, or if freezing of the cgroup races with fork().
1046 If a process is moved to a frozen cgroup, it stops. If a process is
1047 moved out of a frozen cgroup, it becomes running.
1049 Frozen status of a cgroup doesn't affect any cgroup tree operations:
1050 it's possible to delete a frozen (and empty) cgroup, as well as
1051 create new sub-cgroups.
1053 cgroup.kill
1054 A write-only single value file which exists in non-root cgroups.
1055 The only allowed value is "1".
1057 Writing "1" to the file causes the cgroup and all descendant cgroups to
1058 be killed. This means that all processes located in the affected cgroup
1059 tree will be killed via SIGKILL.
1061 Killing a cgroup tree will deal with concurrent forks appropriately and
1062 is protected against migrations.
1064 In a threaded cgroup, writing this file fails with EOPNOTSUPP as
1065 killing cgroups is a process directed operation, i.e. it affects
1066 the whole thread-group.
1068 cgroup.pressure
1069 A read-write single value file that allowed values are "0" and "1".
1070 The default is "1".
1072 Writing "0" to the file will disable the cgroup PSI accounting.
1073 Writing "1" to the file will re-enable the cgroup PSI accounting.
1075 This control attribute is not hierarchical, so disable or enable PSI
1076 accounting in a cgroup does not affect PSI accounting in descendants
1077 and doesn't need pass enablement via ancestors from root.
1079 The reason this control attribute exists is that PSI accounts stalls for
1080 each cgroup separately and aggregates it at each level of the hierarchy.
1081 This may cause non-negligible overhead for some workloads when under
1082 deep level of the hierarchy, in which case this control attribute can
1083 be used to disable PSI accounting in the non-leaf cgroups.
1085 irq.pressure
1086 A read-write nested-keyed file.
1088 Shows pressure stall information for IRQ/SOFTIRQ. See
1089 :ref:`Documentation/accounting/psi.rst <psi>` for details.
1091 Controllers
1092 ===========
1094 .. _cgroup-v2-cpu:
1096 CPU
1097 ---
1099 The "cpu" controllers regulates distribution of CPU cycles. This
1100 controller implements weight and absolute bandwidth limit models for
1101 normal scheduling policy and absolute bandwidth allocation model for
1102 realtime scheduling policy.
1104 In all the above models, cycles distribution is defined only on a temporal
1105 base and it does not account for the frequency at which tasks are executed.
1106 The (optional) utilization clamping support allows to hint the schedutil
1107 cpufreq governor about the minimum desired frequency which should always be
1108 provided by a CPU, as well as the maximum desired frequency, which should not
1109 be exceeded by a CPU.
1111 WARNING: cgroup2 cpu controller doesn't yet support the (bandwidth) control of
1112 realtime processes. For a kernel built with the CONFIG_RT_GROUP_SCHED option
1113 enabled for group scheduling of realtime processes, the cpu controller can only
1114 be enabled when all RT processes are in the root cgroup. Be aware that system
1115 management software may already have placed RT processes into non-root cgroups
1116 during the system boot process, and these processes may need to be moved to the
1117 root cgroup before the cpu controller can be enabled with a
1118 CONFIG_RT_GROUP_SCHED enabled kernel.
1120 With CONFIG_RT_GROUP_SCHED disabled, this limitation does not apply and some of
1121 the interface files either affect realtime processes or account for them. See
1122 the following section for details. Only the cpu controller is affected by
1123 CONFIG_RT_GROUP_SCHED. Other controllers can be used for the resource control of
1124 realtime processes irrespective of CONFIG_RT_GROUP_SCHED.
1127 CPU Interface Files
1128 ~~~~~~~~~~~~~~~~~~~
1130 The interaction of a process with the cpu controller depends on its scheduling
1131 policy and the underlying scheduler. From the point of view of the cpu controller,
1132 processes can be categorized as follows:
1134 * Processes under the fair-class scheduler
1135 * Processes under a BPF scheduler with the ``cgroup_set_weight`` callback
1136 * Everything else: ``SCHED_{FIFO,RR,DEADLINE}`` and processes under a BPF scheduler
1137 without the ``cgroup_set_weight`` callback
1139 For details on when a process is under the fair-class scheduler or a BPF scheduler,
1140 check out :ref:`Documentation/scheduler/sched-ext.rst <sched-ext>`.
1142 For each of the following interface files, the above categories
1143 will be referred to. All time durations are in microseconds.
1145 cpu.stat
1146 A read-only flat-keyed file.
1147 This file exists whether the controller is enabled or not.
1149 It always reports the following three stats, which account for all the
1150 processes in the cgroup:
1152 - usage_usec
1153 - user_usec
1154 - system_usec
1156 and the following five when the controller is enabled, which account for
1157 only the processes under the fair-class scheduler:
1159 - nr_periods
1160 - nr_throttled
1161 - throttled_usec
1162 - nr_bursts
1163 - burst_usec
1165 cpu.weight
1166 A read-write single value file which exists on non-root
1167 cgroups. The default is "100".
1169 For non idle groups (cpu.idle = 0), the weight is in the
1170 range [1, 10000].
1172 If the cgroup has been configured to be SCHED_IDLE (cpu.idle = 1),
1173 then the weight will show as a 0.
1175 This file affects only processes under the fair-class scheduler and a BPF
1176 scheduler with the ``cgroup_set_weight`` callback depending on what the
1177 callback actually does.
1179 cpu.weight.nice
1180 A read-write single value file which exists on non-root
1181 cgroups. The default is "0".
1183 The nice value is in the range [-20, 19].
1185 This interface file is an alternative interface for
1186 "cpu.weight" and allows reading and setting weight using the
1187 same values used by nice(2). Because the range is smaller and
1188 granularity is coarser for the nice values, the read value is
1189 the closest approximation of the current weight.
1191 This file affects only processes under the fair-class scheduler and a BPF
1192 scheduler with the ``cgroup_set_weight`` callback depending on what the
1193 callback actually does.
1195 cpu.max
1196 A read-write two value file which exists on non-root cgroups.
1197 The default is "max 100000".
1199 The maximum bandwidth limit. It's in the following format::
1201 $MAX $PERIOD
1203 which indicates that the group may consume up to $MAX in each
1204 $PERIOD duration. "max" for $MAX indicates no limit. If only
1205 one number is written, $MAX is updated.
1207 This file affects only processes under the fair-class scheduler.
1209 cpu.max.burst
1210 A read-write single value file which exists on non-root
1211 cgroups. The default is "0".
1213 The burst in the range [0, $MAX].
1215 This file affects only processes under the fair-class scheduler.
1217 cpu.pressure
1218 A read-write nested-keyed file.
1220 Shows pressure stall information for CPU. See
1221 :ref:`Documentation/accounting/psi.rst <psi>` for details.
1223 This file accounts for all the processes in the cgroup.
1225 cpu.uclamp.min
1226 A read-write single value file which exists on non-root cgroups.
1227 The default is "0", i.e. no utilization boosting.
1229 The requested minimum utilization (protection) as a percentage
1230 rational number, e.g. 12.34 for 12.34%.
1232 This interface allows reading and setting minimum utilization clamp
1233 values similar to the sched_setattr(2). This minimum utilization
1234 value is used to clamp the task specific minimum utilization clamp,
1235 including those of realtime processes.
1237 The requested minimum utilization (protection) is always capped by
1238 the current value for the maximum utilization (limit), i.e.
1239 `cpu.uclamp.max`.
1241 This file affects all the processes in the cgroup.
1243 cpu.uclamp.max
1244 A read-write single value file which exists on non-root cgroups.
1245 The default is "max". i.e. no utilization capping
1247 The requested maximum utilization (limit) as a percentage rational
1248 number, e.g. 98.76 for 98.76%.
1250 This interface allows reading and setting maximum utilization clamp
1251 values similar to the sched_setattr(2). This maximum utilization
1252 value is used to clamp the task specific maximum utilization clamp,
1253 including those of realtime processes.
1255 This file affects all the processes in the cgroup.
1257 cpu.idle
1258 A read-write single value file which exists on non-root cgroups.
1259 The default is 0.
1261 This is the cgroup analog of the per-task SCHED_IDLE sched policy.
1262 Setting this value to a 1 will make the scheduling policy of the
1263 cgroup SCHED_IDLE. The threads inside the cgroup will retain their
1264 own relative priorities, but the cgroup itself will be treated as
1265 very low priority relative to its peers.
1267 This file affects only processes under the fair-class scheduler.
1269 Memory
1270 ------
1272 The "memory" controller regulates distribution of memory. Memory is
1273 stateful and implements both limit and protection models. Due to the
1274 intertwining between memory usage and reclaim pressure and the
1275 stateful nature of memory, the distribution model is relatively
1276 complex.
1278 While not completely water-tight, all major memory usages by a given
1279 cgroup are tracked so that the total memory consumption can be
1280 accounted and controlled to a reasonable extent. Currently, the
1281 following types of memory usages are tracked.
1283 - Userland memory - page cache and anonymous memory.
1285 - Kernel data structures such as dentries and inodes.
1287 - TCP socket buffers.
1289 The above list may expand in the future for better coverage.
1292 Memory Interface Files
1293 ~~~~~~~~~~~~~~~~~~~~~~
1295 All memory amounts are in bytes. If a value which is not aligned to
1296 PAGE_SIZE is written, the value may be rounded up to the closest
1297 PAGE_SIZE multiple when read back.
1299 memory.current
1300 A read-only single value file which exists on non-root
1301 cgroups.
1303 The total amount of memory currently being used by the cgroup
1304 and its descendants.
1306 memory.min
1307 A read-write single value file which exists on non-root
1308 cgroups. The default is "0".
1310 Hard memory protection. If the memory usage of a cgroup
1311 is within its effective min boundary, the cgroup's memory
1312 won't be reclaimed under any conditions. If there is no
1313 unprotected reclaimable memory available, OOM killer
1314 is invoked. Above the effective min boundary (or
1315 effective low boundary if it is higher), pages are reclaimed
1316 proportionally to the overage, reducing reclaim pressure for
1317 smaller overages.
1319 Effective min boundary is limited by memory.min values of
1320 all ancestor cgroups. If there is memory.min overcommitment
1321 (child cgroup or cgroups are requiring more protected memory
1322 than parent will allow), then each child cgroup will get
1323 the part of parent's protection proportional to its
1324 actual memory usage below memory.min.
1326 Putting more memory than generally available under this
1327 protection is discouraged and may lead to constant OOMs.
1329 If a memory cgroup is not populated with processes,
1330 its memory.min is ignored.
1332 memory.low
1333 A read-write single value file which exists on non-root
1334 cgroups. The default is "0".
1336 Best-effort memory protection. If the memory usage of a
1337 cgroup is within its effective low boundary, the cgroup's
1338 memory won't be reclaimed unless there is no reclaimable
1339 memory available in unprotected cgroups.
1340 Above the effective low boundary (or
1341 effective min boundary if it is higher), pages are reclaimed
1342 proportionally to the overage, reducing reclaim pressure for
1343 smaller overages.
1345 Effective low boundary is limited by memory.low values of
1346 all ancestor cgroups. If there is memory.low overcommitment
1347 (child cgroup or cgroups are requiring more protected memory
1348 than parent will allow), then each child cgroup will get
1349 the part of parent's protection proportional to its
1350 actual memory usage below memory.low.
1352 Putting more memory than generally available under this
1353 protection is discouraged.
1355 memory.high
1356 A read-write single value file which exists on non-root
1357 cgroups. The default is "max".
1359 Memory usage throttle limit. If a cgroup's usage goes
1360 over the high boundary, the processes of the cgroup are
1361 throttled and put under heavy reclaim pressure.
1363 Going over the high limit never invokes the OOM killer and
1364 under extreme conditions the limit may be breached. The high
1365 limit should be used in scenarios where an external process
1366 monitors the limited cgroup to alleviate heavy reclaim
1367 pressure.
1369 If memory.high is opened with O_NONBLOCK then the synchronous
1370 reclaim is bypassed. This is useful for admin processes that
1371 need to dynamically adjust the job's memory limits without
1372 expending their own CPU resources on memory reclamation. The
1373 job will trigger the reclaim and/or get throttled on its
1374 next charge request.
1376 Please note that with O_NONBLOCK, there is a chance that the
1377 target memory cgroup may take indefinite amount of time to
1378 reduce usage below the limit due to delayed charge request or
1379 busy-hitting its memory to slow down reclaim.
1381 memory.max
1382 A read-write single value file which exists on non-root
1383 cgroups. The default is "max".
1385 Memory usage hard limit. This is the main mechanism to limit
1386 memory usage of a cgroup. If a cgroup's memory usage reaches
1387 this limit and can't be reduced, the OOM killer is invoked in
1388 the cgroup. Under certain circumstances, the usage may go
1389 over the limit temporarily.
1391 In default configuration regular 0-order allocations always
1392 succeed unless OOM killer chooses current task as a victim.
1394 Some kinds of allocations don't invoke the OOM killer.
1395 Caller could retry them differently, return into userspace
1396 as -ENOMEM or silently ignore in cases like disk readahead.
1398 If memory.max is opened with O_NONBLOCK, then the synchronous
1399 reclaim and oom-kill are bypassed. This is useful for admin
1400 processes that need to dynamically adjust the job's memory limits
1401 without expending their own CPU resources on memory reclamation.
1402 The job will trigger the reclaim and/or oom-kill on its next
1403 charge request.
1405 Please note that with O_NONBLOCK, there is a chance that the
1406 target memory cgroup may take indefinite amount of time to
1407 reduce usage below the limit due to delayed charge request or
1408 busy-hitting its memory to slow down reclaim.
1410 memory.reclaim
1411 A write-only nested-keyed file which exists for all cgroups.
1413 This is a simple interface to trigger memory reclaim in the
1414 target cgroup.
1416 Example::
1418 echo "1G" > memory.reclaim
1420 Please note that the kernel can over or under reclaim from
1421 the target cgroup. If less bytes are reclaimed than the
1422 specified amount, -EAGAIN is returned.
1424 Please note that the proactive reclaim (triggered by this
1425 interface) is not meant to indicate memory pressure on the
1426 memory cgroup. Therefore socket memory balancing triggered by
1427 the memory reclaim normally is not exercised in this case.
1428 This means that the networking layer will not adapt based on
1429 reclaim induced by memory.reclaim.
1431 The following nested keys are defined.
1433 ========== ================================
1434 swappiness Swappiness value to reclaim with
1435 ========== ================================
1437 Specifying a swappiness value instructs the kernel to perform
1438 the reclaim with that swappiness value. Note that this has the
1439 same semantics as vm.swappiness applied to memcg reclaim with
1440 all the existing limitations and potential future extensions.
1442 The valid range for swappiness is [0-200, max], setting
1443 swappiness=max exclusively reclaims anonymous memory.
1445 memory.peak
1446 A read-write single value file which exists on non-root cgroups.
1448 The max memory usage recorded for the cgroup and its descendants since
1449 either the creation of the cgroup or the most recent reset for that FD.
1451 A write of any non-empty string to this file resets it to the
1452 current memory usage for subsequent reads through the same
1453 file descriptor.
1455 memory.oom.group
1456 A read-write single value file which exists on non-root
1457 cgroups. The default value is "0".
1459 Determines whether the cgroup should be treated as
1460 an indivisible workload by the OOM killer. If set,
1461 all tasks belonging to the cgroup or to its descendants
1462 (if the memory cgroup is not a leaf cgroup) are killed
1463 together or not at all. This can be used to avoid
1464 partial kills to guarantee workload integrity.
1466 Tasks with the OOM protection (oom_score_adj set to -1000)
1467 are treated as an exception and are never killed.
1469 If the OOM killer is invoked in a cgroup, it's not going
1470 to kill any tasks outside of this cgroup, regardless
1471 memory.oom.group values of ancestor cgroups.
1473 memory.events
1474 A read-only flat-keyed file which exists on non-root cgroups.
1475 The following entries are defined. Unless specified
1476 otherwise, a value change in this file generates a file
1477 modified event.
1479 Note that all fields in this file are hierarchical and the
1480 file modified event can be generated due to an event down the
1481 hierarchy. For the local events at the cgroup level see
1482 memory.events.local.
1484 low
1485 The number of times the cgroup is reclaimed due to
1486 high memory pressure even though its usage is under
1487 the low boundary. This usually indicates that the low
1488 boundary is over-committed.
1490 high
1491 The number of times processes of the cgroup are
1492 throttled and routed to perform direct memory reclaim
1493 because the high memory boundary was exceeded. For a
1494 cgroup whose memory usage is capped by the high limit
1495 rather than global memory pressure, this event's
1496 occurrences are expected.
1498 max
1499 The number of times the cgroup's memory usage was
1500 about to go over the max boundary. If direct reclaim
1501 fails to bring it down, the cgroup goes to OOM state.
1503 oom
1504 The number of time the cgroup's memory usage was
1505 reached the limit and allocation was about to fail.
1507 This event is not raised if the OOM killer is not
1508 considered as an option, e.g. for failed high-order
1509 allocations or if caller asked to not retry attempts.
1511 oom_kill
1512 The number of processes belonging to this cgroup
1513 killed by any kind of OOM killer.
1515 oom_group_kill
1516 The number of times a group OOM has occurred.
1518 memory.events.local
1519 Similar to memory.events but the fields in the file are local
1520 to the cgroup i.e. not hierarchical. The file modified event
1521 generated on this file reflects only the local events.
1523 memory.stat
1524 A read-only flat-keyed file which exists on non-root cgroups.
1526 This breaks down the cgroup's memory footprint into different
1527 types of memory, type-specific details, and other information
1528 on the state and past events of the memory management system.
1530 All memory amounts are in bytes.
1532 The entries are ordered to be human readable, and new entries
1533 can show up in the middle. Don't rely on items remaining in a
1534 fixed position; use the keys to look up specific values!
1536 If the entry has no per-node counter (or not show in the
1537 memory.numa_stat). We use 'npn' (non-per-node) as the tag
1538 to indicate that it will not show in the memory.numa_stat.
1540 anon
1541 Amount of memory used in anonymous mappings such as
1542 brk(), sbrk(), and mmap(MAP_ANONYMOUS). Note that
1543 some kernel configurations might account complete larger
1544 allocations (e.g., THP) if only some, but not all the
1545 memory of such an allocation is mapped anymore.
1547 file
1548 Amount of memory used to cache filesystem data,
1549 including tmpfs and shared memory.
1551 kernel (npn)
1552 Amount of total kernel memory, including
1553 (kernel_stack, pagetables, percpu, vmalloc, slab) in
1554 addition to other kernel memory use cases.
1556 kernel_stack
1557 Amount of memory allocated to kernel stacks.
1559 pagetables
1560 Amount of memory allocated for page tables.
1562 sec_pagetables
1563 Amount of memory allocated for secondary page tables,
1564 this currently includes KVM mmu allocations on x86
1565 and arm64 and IOMMU page tables.
1567 percpu (npn)
1568 Amount of memory used for storing per-cpu kernel
1569 data structures.
1571 sock (npn)
1572 Amount of memory used in network transmission buffers
1574 vmalloc (npn)
1575 Amount of memory used for vmap backed memory.
1577 shmem
1578 Amount of cached filesystem data that is swap-backed,
1579 such as tmpfs, shm segments, shared anonymous mmap()s
1581 zswap
1582 Amount of memory consumed by the zswap compression backend.
1584 zswapped
1585 Amount of application memory swapped out to zswap.
1587 file_mapped
1588 Amount of cached filesystem data mapped with mmap(). Note
1589 that some kernel configurations might account complete
1590 larger allocations (e.g., THP) if only some, but not
1591 not all the memory of such an allocation is mapped.
1593 file_dirty
1594 Amount of cached filesystem data that was modified but
1595 not yet written back to disk
1597 file_writeback
1598 Amount of cached filesystem data that was modified and
1599 is currently being written back to disk
1601 swapcached
1602 Amount of swap cached in memory. The swapcache is accounted
1603 against both memory and swap usage.
1605 anon_thp
1606 Amount of memory used in anonymous mappings backed by
1607 transparent hugepages
1609 file_thp
1610 Amount of cached filesystem data backed by transparent
1611 hugepages
1613 shmem_thp
1614 Amount of shm, tmpfs, shared anonymous mmap()s backed by
1615 transparent hugepages
1617 inactive_anon, active_anon, inactive_file, active_file, unevictable
1618 Amount of memory, swap-backed and filesystem-backed,
1619 on the internal memory management lists used by the
1620 page reclaim algorithm.
1622 As these represent internal list state (eg. shmem pages are on anon
1623 memory management lists), inactive_foo + active_foo may not be equal to
1624 the value for the foo counter, since the foo counter is type-based, not
1625 list-based.
1627 slab_reclaimable
1628 Part of "slab" that might be reclaimed, such as
1629 dentries and inodes.
1631 slab_unreclaimable
1632 Part of "slab" that cannot be reclaimed on memory
1633 pressure.
1635 slab (npn)
1636 Amount of memory used for storing in-kernel data
1637 structures.
1639 workingset_refault_anon
1640 Number of refaults of previously evicted anonymous pages.
1642 workingset_refault_file
1643 Number of refaults of previously evicted file pages.
1645 workingset_activate_anon
1646 Number of refaulted anonymous pages that were immediately
1647 activated.
1649 workingset_activate_file
1650 Number of refaulted file pages that were immediately activated.
1652 workingset_restore_anon
1653 Number of restored anonymous pages which have been detected as
1654 an active workingset before they got reclaimed.
1656 workingset_restore_file
1657 Number of restored file pages which have been detected as an
1658 active workingset before they got reclaimed.
1660 workingset_nodereclaim
1661 Number of times a shadow node has been reclaimed
1663 pswpin (npn)
1664 Number of pages swapped into memory
1666 pswpout (npn)
1667 Number of pages swapped out of memory
1669 pgscan (npn)
1670 Amount of scanned pages (in an inactive LRU list)
1672 pgsteal (npn)
1673 Amount of reclaimed pages
1675 pgscan_kswapd (npn)
1676 Amount of scanned pages by kswapd (in an inactive LRU list)
1678 pgscan_direct (npn)
1679 Amount of scanned pages directly (in an inactive LRU list)
1681 pgscan_khugepaged (npn)
1682 Amount of scanned pages by khugepaged (in an inactive LRU list)
1684 pgscan_proactive (npn)
1685 Amount of scanned pages proactively (in an inactive LRU list)
1687 pgsteal_kswapd (npn)
1688 Amount of reclaimed pages by kswapd
1690 pgsteal_direct (npn)
1691 Amount of reclaimed pages directly
1693 pgsteal_khugepaged (npn)
1694 Amount of reclaimed pages by khugepaged
1696 pgsteal_proactive (npn)
1697 Amount of reclaimed pages proactively
1699 pgfault (npn)
1700 Total number of page faults incurred
1702 pgmajfault (npn)
1703 Number of major page faults incurred
1705 pgrefill (npn)
1706 Amount of scanned pages (in an active LRU list)
1708 pgactivate (npn)
1709 Amount of pages moved to the active LRU list
1711 pgdeactivate (npn)
1712 Amount of pages moved to the inactive LRU list
1714 pglazyfree (npn)
1715 Amount of pages postponed to be freed under memory pressure
1717 pglazyfreed (npn)
1718 Amount of reclaimed lazyfree pages
1720 swpin_zero
1721 Number of pages swapped into memory and filled with zero, where I/O
1722 was optimized out because the page content was detected to be zero
1723 during swapout.
1725 swpout_zero
1726 Number of zero-filled pages swapped out with I/O skipped due to the
1727 content being detected as zero.
1729 zswpin
1730 Number of pages moved in to memory from zswap.
1732 zswpout
1733 Number of pages moved out of memory to zswap.
1735 zswpwb
1736 Number of pages written from zswap to swap.
1738 thp_fault_alloc (npn)
1739 Number of transparent hugepages which were allocated to satisfy
1740 a page fault. This counter is not present when CONFIG_TRANSPARENT_HUGEPAGE
1741 is not set.
1743 thp_collapse_alloc (npn)
1744 Number of transparent hugepages which were allocated to allow
1745 collapsing an existing range of pages. This counter is not
1746 present when CONFIG_TRANSPARENT_HUGEPAGE is not set.
1748 thp_swpout (npn)
1749 Number of transparent hugepages which are swapout in one piece
1750 without splitting.
1752 thp_swpout_fallback (npn)
1753 Number of transparent hugepages which were split before swapout.
1754 Usually because failed to allocate some continuous swap space
1755 for the huge page.
1757 numa_pages_migrated (npn)
1758 Number of pages migrated by NUMA balancing.
1760 numa_pte_updates (npn)
1761 Number of pages whose page table entries are modified by
1762 NUMA balancing to produce NUMA hinting faults on access.
1764 numa_hint_faults (npn)
1765 Number of NUMA hinting faults.
1767 pgdemote_kswapd
1768 Number of pages demoted by kswapd.
1770 pgdemote_direct
1771 Number of pages demoted directly.
1773 pgdemote_khugepaged
1774 Number of pages demoted by khugepaged.
1776 pgdemote_proactive
1777 Number of pages demoted by proactively.
1779 hugetlb
1780 Amount of memory used by hugetlb pages. This metric only shows
1781 up if hugetlb usage is accounted for in memory.current (i.e.
1782 cgroup is mounted with the memory_hugetlb_accounting option).
1784 memory.numa_stat
1785 A read-only nested-keyed file which exists on non-root cgroups.
1787 This breaks down the cgroup's memory footprint into different
1788 types of memory, type-specific details, and other information
1789 per node on the state of the memory management system.
1791 This is useful for providing visibility into the NUMA locality
1792 information within an memcg since the pages are allowed to be
1793 allocated from any physical node. One of the use case is evaluating
1794 application performance by combining this information with the
1795 application's CPU allocation.
1797 All memory amounts are in bytes.
1799 The output format of memory.numa_stat is::
1801 type N0=<bytes in node 0> N1=<bytes in node 1> ...
1803 The entries are ordered to be human readable, and new entries
1804 can show up in the middle. Don't rely on items remaining in a
1805 fixed position; use the keys to look up specific values!
1807 The entries can refer to the memory.stat.
1809 memory.swap.current
1810 A read-only single value file which exists on non-root
1811 cgroups.
1813 The total amount of swap currently being used by the cgroup
1814 and its descendants.
1816 memory.swap.high
1817 A read-write single value file which exists on non-root
1818 cgroups. The default is "max".
1820 Swap usage throttle limit. If a cgroup's swap usage exceeds
1821 this limit, all its further allocations will be throttled to
1822 allow userspace to implement custom out-of-memory procedures.
1824 This limit marks a point of no return for the cgroup. It is NOT
1825 designed to manage the amount of swapping a workload does
1826 during regular operation. Compare to memory.swap.max, which
1827 prohibits swapping past a set amount, but lets the cgroup
1828 continue unimpeded as long as other memory can be reclaimed.
1830 Healthy workloads are not expected to reach this limit.
1832 memory.swap.peak
1833 A read-write single value file which exists on non-root cgroups.
1835 The max swap usage recorded for the cgroup and its descendants since
1836 the creation of the cgroup or the most recent reset for that FD.
1838 A write of any non-empty string to this file resets it to the
1839 current memory usage for subsequent reads through the same
1840 file descriptor.
1842 memory.swap.max
1843 A read-write single value file which exists on non-root
1844 cgroups. The default is "max".
1846 Swap usage hard limit. If a cgroup's swap usage reaches this
1847 limit, anonymous memory of the cgroup will not be swapped out.
1849 memory.swap.events
1850 A read-only flat-keyed file which exists on non-root cgroups.
1851 The following entries are defined. Unless specified
1852 otherwise, a value change in this file generates a file
1853 modified event.
1855 high
1856 The number of times the cgroup's swap usage was over
1857 the high threshold.
1859 max
1860 The number of times the cgroup's swap usage was about
1861 to go over the max boundary and swap allocation
1862 failed.
1864 fail
1865 The number of times swap allocation failed either
1866 because of running out of swap system-wide or max
1867 limit.
1869 When reduced under the current usage, the existing swap
1870 entries are reclaimed gradually and the swap usage may stay
1871 higher than the limit for an extended period of time. This
1872 reduces the impact on the workload and memory management.
1874 memory.zswap.current
1875 A read-only single value file which exists on non-root
1876 cgroups.
1878 The total amount of memory consumed by the zswap compression
1879 backend.
1881 memory.zswap.max
1882 A read-write single value file which exists on non-root
1883 cgroups. The default is "max".
1885 Zswap usage hard limit. If a cgroup's zswap pool reaches this
1886 limit, it will refuse to take any more stores before existing
1887 entries fault back in or are written out to disk.
1889 memory.zswap.writeback
1890 A read-write single value file. The default value is "1".
1891 Note that this setting is hierarchical, i.e. the writeback would be
1892 implicitly disabled for child cgroups if the upper hierarchy
1893 does so.
1895 When this is set to 0, all swapping attempts to swapping devices
1896 are disabled. This included both zswap writebacks, and swapping due
1897 to zswap store failures. If the zswap store failures are recurring
1898 (for e.g if the pages are incompressible), users can observe
1899 reclaim inefficiency after disabling writeback (because the same
1900 pages might be rejected again and again).
1902 Note that this is subtly different from setting memory.swap.max to
1903 0, as it still allows for pages to be written to the zswap pool.
1904 This setting has no effect if zswap is disabled, and swapping
1905 is allowed unless memory.swap.max is set to 0.
1907 memory.pressure
1908 A read-only nested-keyed file.
1910 Shows pressure stall information for memory. See
1911 :ref:`Documentation/accounting/psi.rst <psi>` for details.
1914 Usage Guidelines
1915 ~~~~~~~~~~~~~~~~
1917 "memory.high" is the main mechanism to control memory usage.
1918 Over-committing on high limit (sum of high limits > available memory)
1919 and letting global memory pressure to distribute memory according to
1920 usage is a viable strategy.
1922 Because breach of the high limit doesn't trigger the OOM killer but
1923 throttles the offending cgroup, a management agent has ample
1924 opportunities to monitor and take appropriate actions such as granting
1925 more memory or terminating the workload.
1927 Determining whether a cgroup has enough memory is not trivial as
1928 memory usage doesn't indicate whether the workload can benefit from
1929 more memory. For example, a workload which writes data received from
1930 network to a file can use all available memory but can also operate as
1931 performant with a small amount of memory. A measure of memory
1932 pressure - how much the workload is being impacted due to lack of
1933 memory - is necessary to determine whether a workload needs more
1934 memory; unfortunately, memory pressure monitoring mechanism isn't
1935 implemented yet.
1938 Memory Ownership
1939 ~~~~~~~~~~~~~~~~
1941 A memory area is charged to the cgroup which instantiated it and stays
1942 charged to the cgroup until the area is released. Migrating a process
1943 to a different cgroup doesn't move the memory usages that it
1944 instantiated while in the previous cgroup to the new cgroup.
1946 A memory area may be used by processes belonging to different cgroups.
1947 To which cgroup the area will be charged is in-deterministic; however,
1948 over time, the memory area is likely to end up in a cgroup which has
1949 enough memory allowance to avoid high reclaim pressure.
1951 If a cgroup sweeps a considerable amount of memory which is expected
1952 to be accessed repeatedly by other cgroups, it may make sense to use
1953 POSIX_FADV_DONTNEED to relinquish the ownership of memory areas
1954 belonging to the affected files to ensure correct memory ownership.
1957 IO
1958 --
1960 The "io" controller regulates the distribution of IO resources. This
1961 controller implements both weight based and absolute bandwidth or IOPS
1962 limit distribution; however, weight based distribution is available
1963 only if cfq-iosched is in use and neither scheme is available for
1964 blk-mq devices.
1967 IO Interface Files
1968 ~~~~~~~~~~~~~~~~~~
1970 io.stat
1971 A read-only nested-keyed file.
1973 Lines are keyed by $MAJ:$MIN device numbers and not ordered.
1974 The following nested keys are defined.
1976 ====== =====================
1977 rbytes Bytes read
1978 wbytes Bytes written
1979 rios Number of read IOs
1980 wios Number of write IOs
1981 dbytes Bytes discarded
1982 dios Number of discard IOs
1983 ====== =====================
1985 An example read output follows::
1987 8:16 rbytes=1459200 wbytes=314773504 rios=192 wios=353 dbytes=0 dios=0
1988 8:0 rbytes=90430464 wbytes=299008000 rios=8950 wios=1252 dbytes=50331648 dios=3021
1990 io.cost.qos
1991 A read-write nested-keyed file which exists only on the root
1992 cgroup.
1994 This file configures the Quality of Service of the IO cost
1995 model based controller (CONFIG_BLK_CGROUP_IOCOST) which
1996 currently implements "io.weight" proportional control. Lines
1997 are keyed by $MAJ:$MIN device numbers and not ordered. The
1998 line for a given device is populated on the first write for
1999 the device on "io.cost.qos" or "io.cost.model". The following
2000 nested keys are defined.
2002 ====== =====================================
2003 enable Weight-based control enable
2004 ctrl "auto" or "user"
2005 rpct Read latency percentile [0, 100]
2006 rlat Read latency threshold
2007 wpct Write latency percentile [0, 100]
2008 wlat Write latency threshold
2009 min Minimum scaling percentage [1, 10000]
2010 max Maximum scaling percentage [1, 10000]
2011 ====== =====================================
2013 The controller is disabled by default and can be enabled by
2014 setting "enable" to 1. "rpct" and "wpct" parameters default
2015 to zero and the controller uses internal device saturation
2016 state to adjust the overall IO rate between "min" and "max".
2018 When a better control quality is needed, latency QoS
2019 parameters can be configured. For example::
2021 8:16 enable=1 ctrl=auto rpct=95.00 rlat=75000 wpct=95.00 wlat=150000 min=50.00 max=150.0
2023 shows that on sdb, the controller is enabled, will consider
2024 the device saturated if the 95th percentile of read completion
2025 latencies is above 75ms or write 150ms, and adjust the overall
2026 IO issue rate between 50% and 150% accordingly.
2028 The lower the saturation point, the better the latency QoS at
2029 the cost of aggregate bandwidth. The narrower the allowed
2030 adjustment range between "min" and "max", the more conformant
2031 to the cost model the IO behavior. Note that the IO issue
2032 base rate may be far off from 100% and setting "min" and "max"
2033 blindly can lead to a significant loss of device capacity or
2034 control quality. "min" and "max" are useful for regulating
2035 devices which show wide temporary behavior changes - e.g. a
2036 ssd which accepts writes at the line speed for a while and
2037 then completely stalls for multiple seconds.
2039 When "ctrl" is "auto", the parameters are controlled by the
2040 kernel and may change automatically. Setting "ctrl" to "user"
2041 or setting any of the percentile and latency parameters puts
2042 it into "user" mode and disables the automatic changes. The
2043 automatic mode can be restored by setting "ctrl" to "auto".
2045 io.cost.model
2046 A read-write nested-keyed file which exists only on the root
2047 cgroup.
2049 This file configures the cost model of the IO cost model based
2050 controller (CONFIG_BLK_CGROUP_IOCOST) which currently
2051 implements "io.weight" proportional control. Lines are keyed
2052 by $MAJ:$MIN device numbers and not ordered. The line for a
2053 given device is populated on the first write for the device on
2054 "io.cost.qos" or "io.cost.model". The following nested keys
2055 are defined.
2057 ===== ================================
2058 ctrl "auto" or "user"
2059 model The cost model in use - "linear"
2060 ===== ================================
2062 When "ctrl" is "auto", the kernel may change all parameters
2063 dynamically. When "ctrl" is set to "user" or any other
2064 parameters are written to, "ctrl" become "user" and the
2065 automatic changes are disabled.
2067 When "model" is "linear", the following model parameters are
2068 defined.
2070 ============= ========================================
2071 [r|w]bps The maximum sequential IO throughput
2072 [r|w]seqiops The maximum 4k sequential IOs per second
2073 [r|w]randiops The maximum 4k random IOs per second
2074 ============= ========================================
2076 From the above, the builtin linear model determines the base
2077 costs of a sequential and random IO and the cost coefficient
2078 for the IO size. While simple, this model can cover most
2079 common device classes acceptably.
2081 The IO cost model isn't expected to be accurate in absolute
2082 sense and is scaled to the device behavior dynamically.
2084 If needed, tools/cgroup/iocost_coef_gen.py can be used to
2085 generate device-specific coefficients.
2087 io.weight
2088 A read-write flat-keyed file which exists on non-root cgroups.
2089 The default is "default 100".
2091 The first line is the default weight applied to devices
2092 without specific override. The rest are overrides keyed by
2093 $MAJ:$MIN device numbers and not ordered. The weights are in
2094 the range [1, 10000] and specifies the relative amount IO time
2095 the cgroup can use in relation to its siblings.
2097 The default weight can be updated by writing either "default
2098 $WEIGHT" or simply "$WEIGHT". Overrides can be set by writing
2099 "$MAJ:$MIN $WEIGHT" and unset by writing "$MAJ:$MIN default".
2101 An example read output follows::
2103 default 100
2104 8:16 200
2105 8:0 50
2107 io.max
2108 A read-write nested-keyed file which exists on non-root
2109 cgroups.
2111 BPS and IOPS based IO limit. Lines are keyed by $MAJ:$MIN
2112 device numbers and not ordered. The following nested keys are
2113 defined.
2115 ===== ==================================
2116 rbps Max read bytes per second
2117 wbps Max write bytes per second
2118 riops Max read IO operations per second
2119 wiops Max write IO operations per second
2120 ===== ==================================
2122 When writing, any number of nested key-value pairs can be
2123 specified in any order. "max" can be specified as the value
2124 to remove a specific limit. If the same key is specified
2125 multiple times, the outcome is undefined.
2127 BPS and IOPS are measured in each IO direction and IOs are
2128 delayed if limit is reached. Temporary bursts are allowed.
2130 Setting read limit at 2M BPS and write at 120 IOPS for 8:16::
2132 echo "8:16 rbps=2097152 wiops=120" > io.max
2134 Reading returns the following::
2136 8:16 rbps=2097152 wbps=max riops=max wiops=120
2138 Write IOPS limit can be removed by writing the following::
2140 echo "8:16 wiops=max" > io.max
2142 Reading now returns the following::
2144 8:16 rbps=2097152 wbps=max riops=max wiops=max
2146 io.pressure
2147 A read-only nested-keyed file.
2149 Shows pressure stall information for IO. See
2150 :ref:`Documentation/accounting/psi.rst <psi>` for details.
2153 Writeback
2154 ~~~~~~~~~
2156 Page cache is dirtied through buffered writes and shared mmaps and
2157 written asynchronously to the backing filesystem by the writeback
2158 mechanism. Writeback sits between the memory and IO domains and
2159 regulates the proportion of dirty memory by balancing dirtying and
2160 write IOs.
2162 The io controller, in conjunction with the memory controller,
2163 implements control of page cache writeback IOs. The memory controller
2164 defines the memory domain that dirty memory ratio is calculated and
2165 maintained for and the io controller defines the io domain which
2166 writes out dirty pages for the memory domain. Both system-wide and
2167 per-cgroup dirty memory states are examined and the more restrictive
2168 of the two is enforced.
2170 cgroup writeback requires explicit support from the underlying
2171 filesystem. Currently, cgroup writeback is implemented on ext2, ext4,
2172 btrfs, f2fs, and xfs. On other filesystems, all writeback IOs are
2173 attributed to the root cgroup.
2175 There are inherent differences in memory and writeback management
2176 which affects how cgroup ownership is tracked. Memory is tracked per
2177 page while writeback per inode. For the purpose of writeback, an
2178 inode is assigned to a cgroup and all IO requests to write dirty pages
2179 from the inode are attributed to that cgroup.
2181 As cgroup ownership for memory is tracked per page, there can be pages
2182 which are associated with different cgroups than the one the inode is
2183 associated with. These are called foreign pages. The writeback
2184 constantly keeps track of foreign pages and, if a particular foreign
2185 cgroup becomes the majority over a certain period of time, switches
2186 the ownership of the inode to that cgroup.
2188 While this model is enough for most use cases where a given inode is
2189 mostly dirtied by a single cgroup even when the main writing cgroup
2190 changes over time, use cases where multiple cgroups write to a single
2191 inode simultaneously are not supported well. In such circumstances, a
2192 significant portion of IOs are likely to be attributed incorrectly.
2193 As memory controller assigns page ownership on the first use and
2194 doesn't update it until the page is released, even if writeback
2195 strictly follows page ownership, multiple cgroups dirtying overlapping
2196 areas wouldn't work as expected. It's recommended to avoid such usage
2197 patterns.
2199 The sysctl knobs which affect writeback behavior are applied to cgroup
2200 writeback as follows.
2202 vm.dirty_background_ratio, vm.dirty_ratio
2203 These ratios apply the same to cgroup writeback with the
2204 amount of available memory capped by limits imposed by the
2205 memory controller and system-wide clean memory.
2207 vm.dirty_background_bytes, vm.dirty_bytes
2208 For cgroup writeback, this is calculated into ratio against
2209 total available memory and applied the same way as
2210 vm.dirty[_background]_ratio.
2213 IO Latency
2214 ~~~~~~~~~~
2216 This is a cgroup v2 controller for IO workload protection. You provide a group
2217 with a latency target, and if the average latency exceeds that target the
2218 controller will throttle any peers that have a lower latency target than the
2219 protected workload.
2221 The limits are only applied at the peer level in the hierarchy. This means that
2222 in the diagram below, only groups A, B, and C will influence each other, and
2223 groups D and F will influence each other. Group G will influence nobody::
2225 [root]
2226 / | \
2227 A B C
2228 / \ |
2229 D F G
2232 So the ideal way to configure this is to set io.latency in groups A, B, and C.
2233 Generally you do not want to set a value lower than the latency your device
2234 supports. Experiment to find the value that works best for your workload.
2235 Start at higher than the expected latency for your device and watch the
2236 avg_lat value in io.stat for your workload group to get an idea of the
2237 latency you see during normal operation. Use the avg_lat value as a basis for
2238 your real setting, setting at 10-15% higher than the value in io.stat.
2240 How IO Latency Throttling Works
2241 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2243 io.latency is work conserving; so as long as everybody is meeting their latency
2244 target the controller doesn't do anything. Once a group starts missing its
2245 target it begins throttling any peer group that has a higher target than itself.
2246 This throttling takes 2 forms:
2248 - Queue depth throttling. This is the number of outstanding IO's a group is
2249 allowed to have. We will clamp down relatively quickly, starting at no limit
2250 and going all the way down to 1 IO at a time.
2252 - Artificial delay induction. There are certain types of IO that cannot be
2253 throttled without possibly adversely affecting higher priority groups. This
2254 includes swapping and metadata IO. These types of IO are allowed to occur
2255 normally, however they are "charged" to the originating group. If the
2256 originating group is being throttled you will see the use_delay and delay
2257 fields in io.stat increase. The delay value is how many microseconds that are
2258 being added to any process that runs in this group. Because this number can
2259 grow quite large if there is a lot of swapping or metadata IO occurring we
2260 limit the individual delay events to 1 second at a time.
2262 Once the victimized group starts meeting its latency target again it will start
2263 unthrottling any peer groups that were throttled previously. If the victimized
2264 group simply stops doing IO the global counter will unthrottle appropriately.
2266 IO Latency Interface Files
2267 ~~~~~~~~~~~~~~~~~~~~~~~~~~
2269 io.latency
2270 This takes a similar format as the other controllers.
2272 "MAJOR:MINOR target=<target time in microseconds>"
2274 io.stat
2275 If the controller is enabled you will see extra stats in io.stat in
2276 addition to the normal ones.
2278 depth
2279 This is the current queue depth for the group.
2281 avg_lat
2282 This is an exponential moving average with a decay rate of 1/exp
2283 bound by the sampling interval. The decay rate interval can be
2284 calculated by multiplying the win value in io.stat by the
2285 corresponding number of samples based on the win value.
2287 win
2288 The sampling window size in milliseconds. This is the minimum
2289 duration of time between evaluation events. Windows only elapse
2290 with IO activity. Idle periods extend the most recent window.
2292 IO Priority
2293 ~~~~~~~~~~~
2295 A single attribute controls the behavior of the I/O priority cgroup policy,
2296 namely the io.prio.class attribute. The following values are accepted for
2297 that attribute:
2299 no-change
2300 Do not modify the I/O priority class.
2302 promote-to-rt
2303 For requests that have a non-RT I/O priority class, change it into RT.
2304 Also change the priority level of these requests to 4. Do not modify
2305 the I/O priority of requests that have priority class RT.
2307 restrict-to-be
2308 For requests that do not have an I/O priority class or that have I/O
2309 priority class RT, change it into BE. Also change the priority level
2310 of these requests to 0. Do not modify the I/O priority class of
2311 requests that have priority class IDLE.
2313 idle
2314 Change the I/O priority class of all requests into IDLE, the lowest
2315 I/O priority class.
2317 none-to-rt
2318 Deprecated. Just an alias for promote-to-rt.
2320 The following numerical values are associated with the I/O priority policies:
2322 +----------------+---+
2323 | no-change | 0 |
2324 +----------------+---+
2325 | promote-to-rt | 1 |
2326 +----------------+---+
2327 | restrict-to-be | 2 |
2328 +----------------+---+
2329 | idle | 3 |
2330 +----------------+---+
2332 The numerical value that corresponds to each I/O priority class is as follows:
2334 +-------------------------------+---+
2335 | IOPRIO_CLASS_NONE | 0 |
2336 +-------------------------------+---+
2337 | IOPRIO_CLASS_RT (real-time) | 1 |
2338 +-------------------------------+---+
2339 | IOPRIO_CLASS_BE (best effort) | 2 |
2340 +-------------------------------+---+
2341 | IOPRIO_CLASS_IDLE | 3 |
2342 +-------------------------------+---+
2344 The algorithm to set the I/O priority class for a request is as follows:
2346 - If I/O priority class policy is promote-to-rt, change the request I/O
2347 priority class to IOPRIO_CLASS_RT and change the request I/O priority
2348 level to 4.
2349 - If I/O priority class policy is not promote-to-rt, translate the I/O priority
2350 class policy into a number, then change the request I/O priority class
2351 into the maximum of the I/O priority class policy number and the numerical
2352 I/O priority class.
2354 PID
2355 ---
2357 The process number controller is used to allow a cgroup to stop any
2358 new tasks from being fork()'d or clone()'d after a specified limit is
2359 reached.
2361 The number of tasks in a cgroup can be exhausted in ways which other
2362 controllers cannot prevent, thus warranting its own controller. For
2363 example, a fork bomb is likely to exhaust the number of tasks before
2364 hitting memory restrictions.
2366 Note that PIDs used in this controller refer to TIDs, process IDs as
2367 used by the kernel.
2370 PID Interface Files
2371 ~~~~~~~~~~~~~~~~~~~
2373 pids.max
2374 A read-write single value file which exists on non-root
2375 cgroups. The default is "max".
2377 Hard limit of number of processes.
2379 pids.current
2380 A read-only single value file which exists on non-root cgroups.
2382 The number of processes currently in the cgroup and its
2383 descendants.
2385 pids.peak
2386 A read-only single value file which exists on non-root cgroups.
2388 The maximum value that the number of processes in the cgroup and its
2389 descendants has ever reached.
2391 pids.events
2392 A read-only flat-keyed file which exists on non-root cgroups. Unless
2393 specified otherwise, a value change in this file generates a file
2394 modified event. The following entries are defined.
2396 max
2397 The number of times the cgroup's total number of processes hit the pids.max
2398 limit (see also pids_localevents).
2400 pids.events.local
2401 Similar to pids.events but the fields in the file are local
2402 to the cgroup i.e. not hierarchical. The file modified event
2403 generated on this file reflects only the local events.
2405 Organisational operations are not blocked by cgroup policies, so it is
2406 possible to have pids.current > pids.max. This can be done by either
2407 setting the limit to be smaller than pids.current, or attaching enough
2408 processes to the cgroup such that pids.current is larger than
2409 pids.max. However, it is not possible to violate a cgroup PID policy
2410 through fork() or clone(). These will return -EAGAIN if the creation
2411 of a new process would cause a cgroup policy to be violated.
2414 Cpuset
2415 ------
2417 The "cpuset" controller provides a mechanism for constraining
2418 the CPU and memory node placement of tasks to only the resources
2419 specified in the cpuset interface files in a task's current cgroup.
2420 This is especially valuable on large NUMA systems where placing jobs
2421 on properly sized subsets of the systems with careful processor and
2422 memory placement to reduce cross-node memory access and contention
2423 can improve overall system performance.
2425 The "cpuset" controller is hierarchical. That means the controller
2426 cannot use CPUs or memory nodes not allowed in its parent.
2429 Cpuset Interface Files
2430 ~~~~~~~~~~~~~~~~~~~~~~
2432 cpuset.cpus
2433 A read-write multiple values file which exists on non-root
2434 cpuset-enabled cgroups.
2436 It lists the requested CPUs to be used by tasks within this
2437 cgroup. The actual list of CPUs to be granted, however, is
2438 subjected to constraints imposed by its parent and can differ
2439 from the requested CPUs.
2441 The CPU numbers are comma-separated numbers or ranges.
2442 For example::
2444 # cat cpuset.cpus
2445 0-4,6,8-10
2447 An empty value indicates that the cgroup is using the same
2448 setting as the nearest cgroup ancestor with a non-empty
2449 "cpuset.cpus" or all the available CPUs if none is found.
2451 The value of "cpuset.cpus" stays constant until the next update
2452 and won't be affected by any CPU hotplug events.
2454 cpuset.cpus.effective
2455 A read-only multiple values file which exists on all
2456 cpuset-enabled cgroups.
2458 It lists the onlined CPUs that are actually granted to this
2459 cgroup by its parent. These CPUs are allowed to be used by
2460 tasks within the current cgroup.
2462 If "cpuset.cpus" is empty, the "cpuset.cpus.effective" file shows
2463 all the CPUs from the parent cgroup that can be available to
2464 be used by this cgroup. Otherwise, it should be a subset of
2465 "cpuset.cpus" unless none of the CPUs listed in "cpuset.cpus"
2466 can be granted. In this case, it will be treated just like an
2467 empty "cpuset.cpus".
2469 Its value will be affected by CPU hotplug events.
2471 cpuset.mems
2472 A read-write multiple values file which exists on non-root
2473 cpuset-enabled cgroups.
2475 It lists the requested memory nodes to be used by tasks within
2476 this cgroup. The actual list of memory nodes granted, however,
2477 is subjected to constraints imposed by its parent and can differ
2478 from the requested memory nodes.
2480 The memory node numbers are comma-separated numbers or ranges.
2481 For example::
2483 # cat cpuset.mems
2484 0-1,3
2486 An empty value indicates that the cgroup is using the same
2487 setting as the nearest cgroup ancestor with a non-empty
2488 "cpuset.mems" or all the available memory nodes if none
2489 is found.
2491 The value of "cpuset.mems" stays constant until the next update
2492 and won't be affected by any memory nodes hotplug events.
2494 Setting a non-empty value to "cpuset.mems" causes memory of
2495 tasks within the cgroup to be migrated to the designated nodes if
2496 they are currently using memory outside of the designated nodes.
2498 There is a cost for this memory migration. The migration
2499 may not be complete and some memory pages may be left behind.
2500 So it is recommended that "cpuset.mems" should be set properly
2501 before spawning new tasks into the cpuset. Even if there is
2502 a need to change "cpuset.mems" with active tasks, it shouldn't
2503 be done frequently.
2505 cpuset.mems.effective
2506 A read-only multiple values file which exists on all
2507 cpuset-enabled cgroups.
2509 It lists the onlined memory nodes that are actually granted to
2510 this cgroup by its parent. These memory nodes are allowed to
2511 be used by tasks within the current cgroup.
2513 If "cpuset.mems" is empty, it shows all the memory nodes from the
2514 parent cgroup that will be available to be used by this cgroup.
2515 Otherwise, it should be a subset of "cpuset.mems" unless none of
2516 the memory nodes listed in "cpuset.mems" can be granted. In this
2517 case, it will be treated just like an empty "cpuset.mems".
2519 Its value will be affected by memory nodes hotplug events.
2521 cpuset.cpus.exclusive
2522 A read-write multiple values file which exists on non-root
2523 cpuset-enabled cgroups.
2525 It lists all the exclusive CPUs that are allowed to be used
2526 to create a new cpuset partition. Its value is not used
2527 unless the cgroup becomes a valid partition root. See the
2528 "cpuset.cpus.partition" section below for a description of what
2529 a cpuset partition is.
2531 When the cgroup becomes a partition root, the actual exclusive
2532 CPUs that are allocated to that partition are listed in
2533 "cpuset.cpus.exclusive.effective" which may be different
2534 from "cpuset.cpus.exclusive". If "cpuset.cpus.exclusive"
2535 has previously been set, "cpuset.cpus.exclusive.effective"
2536 is always a subset of it.
2538 Users can manually set it to a value that is different from
2539 "cpuset.cpus". One constraint in setting it is that the list of
2540 CPUs must be exclusive with respect to "cpuset.cpus.exclusive"
2541 and "cpuset.cpus.exclusive.effective" of its siblings. Another
2542 constraint is that it cannot be a superset of "cpuset.cpus"
2543 of its sibling in order to leave at least one CPU available to
2544 that sibling when the exclusive CPUs are taken away.
2546 For a parent cgroup, any one of its exclusive CPUs can only
2547 be distributed to at most one of its child cgroups. Having an
2548 exclusive CPU appearing in two or more of its child cgroups is
2549 not allowed (the exclusivity rule). A value that violates the
2550 exclusivity rule will be rejected with a write error.
2552 The root cgroup is a partition root and all its available CPUs
2553 are in its exclusive CPU set.
2555 cpuset.cpus.exclusive.effective
2556 A read-only multiple values file which exists on all non-root
2557 cpuset-enabled cgroups.
2559 This file shows the effective set of exclusive CPUs that
2560 can be used to create a partition root. The content
2561 of this file will always be a subset of its parent's
2562 "cpuset.cpus.exclusive.effective" if its parent is not the root
2563 cgroup. It will also be a subset of "cpuset.cpus.exclusive"
2564 if it is set. If "cpuset.cpus.exclusive" is not set, it is
2565 treated to have an implicit value of "cpuset.cpus" in the
2566 formation of local partition.
2568 cpuset.cpus.isolated
2569 A read-only and root cgroup only multiple values file.
2571 This file shows the set of all isolated CPUs used in existing
2572 isolated partitions. It will be empty if no isolated partition
2573 is created.
2575 cpuset.cpus.partition
2576 A read-write single value file which exists on non-root
2577 cpuset-enabled cgroups. This flag is owned by the parent cgroup
2578 and is not delegatable.
2580 It accepts only the following input values when written to.
2582 ========== =====================================
2583 "member" Non-root member of a partition
2584 "root" Partition root
2585 "isolated" Partition root without load balancing
2586 ========== =====================================
2588 A cpuset partition is a collection of cpuset-enabled cgroups with
2589 a partition root at the top of the hierarchy and its descendants
2590 except those that are separate partition roots themselves and
2591 their descendants. A partition has exclusive access to the
2592 set of exclusive CPUs allocated to it. Other cgroups outside
2593 of that partition cannot use any CPUs in that set.
2595 There are two types of partitions - local and remote. A local
2596 partition is one whose parent cgroup is also a valid partition
2597 root. A remote partition is one whose parent cgroup is not a
2598 valid partition root itself. Writing to "cpuset.cpus.exclusive"
2599 is optional for the creation of a local partition as its
2600 "cpuset.cpus.exclusive" file will assume an implicit value that
2601 is the same as "cpuset.cpus" if it is not set. Writing the
2602 proper "cpuset.cpus.exclusive" values down the cgroup hierarchy
2603 before the target partition root is mandatory for the creation
2604 of a remote partition.
2606 Currently, a remote partition cannot be created under a local
2607 partition. All the ancestors of a remote partition root except
2608 the root cgroup cannot be a partition root.
2610 The root cgroup is always a partition root and its state cannot
2611 be changed. All other non-root cgroups start out as "member".
2613 When set to "root", the current cgroup is the root of a new
2614 partition or scheduling domain. The set of exclusive CPUs is
2615 determined by the value of its "cpuset.cpus.exclusive.effective".
2617 When set to "isolated", the CPUs in that partition will be in
2618 an isolated state without any load balancing from the scheduler
2619 and excluded from the unbound workqueues. Tasks placed in such
2620 a partition with multiple CPUs should be carefully distributed
2621 and bound to each of the individual CPUs for optimal performance.
2623 A partition root ("root" or "isolated") can be in one of the
2624 two possible states - valid or invalid. An invalid partition
2625 root is in a degraded state where some state information may
2626 be retained, but behaves more like a "member".
2628 All possible state transitions among "member", "root" and
2629 "isolated" are allowed.
2631 On read, the "cpuset.cpus.partition" file can show the following
2632 values.
2634 ============================= =====================================
2635 "member" Non-root member of a partition
2636 "root" Partition root
2637 "isolated" Partition root without load balancing
2638 "root invalid (<reason>)" Invalid partition root
2639 "isolated invalid (<reason>)" Invalid isolated partition root
2640 ============================= =====================================
2642 In the case of an invalid partition root, a descriptive string on
2643 why the partition is invalid is included within parentheses.
2645 For a local partition root to be valid, the following conditions
2646 must be met.
2648 1) The parent cgroup is a valid partition root.
2649 2) The "cpuset.cpus.exclusive.effective" file cannot be empty,
2650 though it may contain offline CPUs.
2651 3) The "cpuset.cpus.effective" cannot be empty unless there is
2652 no task associated with this partition.
2654 For a remote partition root to be valid, all the above conditions
2655 except the first one must be met.
2657 External events like hotplug or changes to "cpuset.cpus" or
2658 "cpuset.cpus.exclusive" can cause a valid partition root to
2659 become invalid and vice versa. Note that a task cannot be
2660 moved to a cgroup with empty "cpuset.cpus.effective".
2662 A valid non-root parent partition may distribute out all its CPUs
2663 to its child local partitions when there is no task associated
2664 with it.
2666 Care must be taken to change a valid partition root to "member"
2667 as all its child local partitions, if present, will become
2668 invalid causing disruption to tasks running in those child
2669 partitions. These inactivated partitions could be recovered if
2670 their parent is switched back to a partition root with a proper
2671 value in "cpuset.cpus" or "cpuset.cpus.exclusive".
2673 Poll and inotify events are triggered whenever the state of
2674 "cpuset.cpus.partition" changes. That includes changes caused
2675 by write to "cpuset.cpus.partition", cpu hotplug or other
2676 changes that modify the validity status of the partition.
2677 This will allow user space agents to monitor unexpected changes
2678 to "cpuset.cpus.partition" without the need to do continuous
2679 polling.
2681 A user can pre-configure certain CPUs to an isolated state
2682 with load balancing disabled at boot time with the "isolcpus"
2683 kernel boot command line option. If those CPUs are to be put
2684 into a partition, they have to be used in an isolated partition.
2687 Device controller
2688 -----------------
2690 Device controller manages access to device files. It includes both
2691 creation of new device files (using mknod), and access to the
2692 existing device files.
2694 Cgroup v2 device controller has no interface files and is implemented
2695 on top of cgroup BPF. To control access to device files, a user may
2696 create bpf programs of type BPF_PROG_TYPE_CGROUP_DEVICE and attach
2697 them to cgroups with BPF_CGROUP_DEVICE flag. On an attempt to access a
2698 device file, corresponding BPF programs will be executed, and depending
2699 on the return value the attempt will succeed or fail with -EPERM.
2701 A BPF_PROG_TYPE_CGROUP_DEVICE program takes a pointer to the
2702 bpf_cgroup_dev_ctx structure, which describes the device access attempt:
2703 access type (mknod/read/write) and device (type, major and minor numbers).
2704 If the program returns 0, the attempt fails with -EPERM, otherwise it
2705 succeeds.
2707 An example of BPF_PROG_TYPE_CGROUP_DEVICE program may be found in
2708 tools/testing/selftests/bpf/progs/dev_cgroup.c in the kernel source tree.
2711 RDMA
2712 ----
2714 The "rdma" controller regulates the distribution and accounting of
2715 RDMA resources.
2717 RDMA Interface Files
2718 ~~~~~~~~~~~~~~~~~~~~
2720 rdma.max
2721 A readwrite nested-keyed file that exists for all the cgroups
2722 except root that describes current configured resource limit
2723 for a RDMA/IB device.
2725 Lines are keyed by device name and are not ordered.
2726 Each line contains space separated resource name and its configured
2727 limit that can be distributed.
2729 The following nested keys are defined.
2731 ========== =============================
2732 hca_handle Maximum number of HCA Handles
2733 hca_object Maximum number of HCA Objects
2734 ========== =============================
2736 An example for mlx4 and ocrdma device follows::
2738 mlx4_0 hca_handle=2 hca_object=2000
2739 ocrdma1 hca_handle=3 hca_object=max
2741 rdma.current
2742 A read-only file that describes current resource usage.
2743 It exists for all the cgroup except root.
2745 An example for mlx4 and ocrdma device follows::
2747 mlx4_0 hca_handle=1 hca_object=20
2748 ocrdma1 hca_handle=1 hca_object=23
2750 DMEM
2751 ----
2753 The "dmem" controller regulates the distribution and accounting of
2754 device memory regions. Because each memory region may have its own page size,
2755 which does not have to be equal to the system page size, the units are always bytes.
2757 DMEM Interface Files
2758 ~~~~~~~~~~~~~~~~~~~~
2760 dmem.max, dmem.min, dmem.low
2761 A readwrite nested-keyed file that exists for all the cgroups
2762 except root that describes current configured resource limit
2763 for a region.
2765 An example for xe follows::
2767 drm/0000:03:00.0/vram0 1073741824
2768 drm/0000:03:00.0/stolen max
2770 The semantics are the same as for the memory cgroup controller, and are
2771 calculated in the same way.
2773 dmem.capacity
2774 A read-only file that describes maximum region capacity.
2775 It only exists on the root cgroup. Not all memory can be
2776 allocated by cgroups, as the kernel reserves some for
2777 internal use.
2779 An example for xe follows::
2781 drm/0000:03:00.0/vram0 8514437120
2782 drm/0000:03:00.0/stolen 67108864
2784 dmem.current
2785 A read-only file that describes current resource usage.
2786 It exists for all the cgroup except root.
2788 An example for xe follows::
2790 drm/0000:03:00.0/vram0 12550144
2791 drm/0000:03:00.0/stolen 8650752
2793 HugeTLB
2794 -------
2796 The HugeTLB controller allows to limit the HugeTLB usage per control group and
2797 enforces the controller limit during page fault.
2799 HugeTLB Interface Files
2800 ~~~~~~~~~~~~~~~~~~~~~~~
2802 hugetlb.<hugepagesize>.current
2803 Show current usage for "hugepagesize" hugetlb. It exists for all
2804 the cgroup except root.
2806 hugetlb.<hugepagesize>.max
2807 Set/show the hard limit of "hugepagesize" hugetlb usage.
2808 The default value is "max". It exists for all the cgroup except root.
2810 hugetlb.<hugepagesize>.events
2811 A read-only flat-keyed file which exists on non-root cgroups.
2813 max
2814 The number of allocation failure due to HugeTLB limit
2816 hugetlb.<hugepagesize>.events.local
2817 Similar to hugetlb.<hugepagesize>.events but the fields in the file
2818 are local to the cgroup i.e. not hierarchical. The file modified event
2819 generated on this file reflects only the local events.
2821 hugetlb.<hugepagesize>.numa_stat
2822 Similar to memory.numa_stat, it shows the numa information of the
2823 hugetlb pages of <hugepagesize> in this cgroup. Only active in
2824 use hugetlb pages are included. The per-node values are in bytes.
2826 Misc
2827 ----
2829 The Miscellaneous cgroup provides the resource limiting and tracking
2830 mechanism for the scalar resources which cannot be abstracted like the other
2831 cgroup resources. Controller is enabled by the CONFIG_CGROUP_MISC config
2832 option.
2834 A resource can be added to the controller via enum misc_res_type{} in the
2835 include/linux/misc_cgroup.h file and the corresponding name via misc_res_name[]
2836 in the kernel/cgroup/misc.c file. Provider of the resource must set its
2837 capacity prior to using the resource by calling misc_cg_set_capacity().
2839 Once a capacity is set then the resource usage can be updated using charge and
2840 uncharge APIs. All of the APIs to interact with misc controller are in
2841 include/linux/misc_cgroup.h.
2843 Misc Interface Files
2844 ~~~~~~~~~~~~~~~~~~~~
2846 Miscellaneous controller provides 3 interface files. If two misc resources (res_a and res_b) are registered then:
2848 misc.capacity
2849 A read-only flat-keyed file shown only in the root cgroup. It shows
2850 miscellaneous scalar resources available on the platform along with
2851 their quantities::
2853 $ cat misc.capacity
2854 res_a 50
2855 res_b 10
2857 misc.current
2858 A read-only flat-keyed file shown in the all cgroups. It shows
2859 the current usage of the resources in the cgroup and its children.::
2861 $ cat misc.current
2862 res_a 3
2863 res_b 0
2865 misc.peak
2866 A read-only flat-keyed file shown in all cgroups. It shows the
2867 historical maximum usage of the resources in the cgroup and its
2868 children.::
2870 $ cat misc.peak
2871 res_a 10
2872 res_b 8
2874 misc.max
2875 A read-write flat-keyed file shown in the non root cgroups. Allowed
2876 maximum usage of the resources in the cgroup and its children.::
2878 $ cat misc.max
2879 res_a max
2880 res_b 4
2882 Limit can be set by::
2884 # echo res_a 1 > misc.max
2886 Limit can be set to max by::
2888 # echo res_a max > misc.max
2890 Limits can be set higher than the capacity value in the misc.capacity
2891 file.
2893 misc.events
2894 A read-only flat-keyed file which exists on non-root cgroups. The
2895 following entries are defined. Unless specified otherwise, a value
2896 change in this file generates a file modified event. All fields in
2897 this file are hierarchical.
2899 max
2900 The number of times the cgroup's resource usage was
2901 about to go over the max boundary.
2903 misc.events.local
2904 Similar to misc.events but the fields in the file are local to the
2905 cgroup i.e. not hierarchical. The file modified event generated on
2906 this file reflects only the local events.
2908 Migration and Ownership
2909 ~~~~~~~~~~~~~~~~~~~~~~~
2911 A miscellaneous scalar resource is charged to the cgroup in which it is used
2912 first, and stays charged to that cgroup until that resource is freed. Migrating
2913 a process to a different cgroup does not move the charge to the destination
2914 cgroup where the process has moved.
2916 Others
2917 ------
2919 perf_event
2920 ~~~~~~~~~~
2922 perf_event controller, if not mounted on a legacy hierarchy, is
2923 automatically enabled on the v2 hierarchy so that perf events can
2924 always be filtered by cgroup v2 path. The controller can still be
2925 moved to a legacy hierarchy after v2 hierarchy is populated.
2928 Non-normative information
2929 -------------------------
2931 This section contains information that isn't considered to be a part of
2932 the stable kernel API and so is subject to change.
2935 CPU controller root cgroup process behaviour
2936 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2938 When distributing CPU cycles in the root cgroup each thread in this
2939 cgroup is treated as if it was hosted in a separate child cgroup of the
2940 root cgroup. This child cgroup weight is dependent on its thread nice
2941 level.
2943 For details of this mapping see sched_prio_to_weight array in
2944 kernel/sched/core.c file (values from this array should be scaled
2945 appropriately so the neutral - nice 0 - value is 100 instead of 1024).
2948 IO controller root cgroup process behaviour
2949 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2951 Root cgroup processes are hosted in an implicit leaf child node.
2952 When distributing IO resources this implicit child node is taken into
2953 account as if it was a normal child cgroup of the root cgroup with a
2954 weight value of 200.
2957 Namespace
2958 =========
2960 Basics
2961 ------
2963 cgroup namespace provides a mechanism to virtualize the view of the
2964 "/proc/$PID/cgroup" file and cgroup mounts. The CLONE_NEWCGROUP clone
2965 flag can be used with clone(2) and unshare(2) to create a new cgroup
2966 namespace. The process running inside the cgroup namespace will have
2967 its "/proc/$PID/cgroup" output restricted to cgroupns root. The
2968 cgroupns root is the cgroup of the process at the time of creation of
2969 the cgroup namespace.
2971 Without cgroup namespace, the "/proc/$PID/cgroup" file shows the
2972 complete path of the cgroup of a process. In a container setup where
2973 a set of cgroups and namespaces are intended to isolate processes the
2974 "/proc/$PID/cgroup" file may leak potential system level information
2975 to the isolated processes. For example::
2977 # cat /proc/self/cgroup
2978 0::/batchjobs/container_id1
2980 The path '/batchjobs/container_id1' can be considered as system-data
2981 and undesirable to expose to the isolated processes. cgroup namespace
2982 can be used to restrict visibility of this path. For example, before
2983 creating a cgroup namespace, one would see::
2985 # ls -l /proc/self/ns/cgroup
2986 lrwxrwxrwx 1 root root 0 2014-07-15 10:37 /proc/self/ns/cgroup -> cgroup:[4026531835]
2987 # cat /proc/self/cgroup
2988 0::/batchjobs/container_id1
2990 After unsharing a new namespace, the view changes::
2992 # ls -l /proc/self/ns/cgroup
2993 lrwxrwxrwx 1 root root 0 2014-07-15 10:35 /proc/self/ns/cgroup -> cgroup:[4026532183]
2994 # cat /proc/self/cgroup
2995 0::/
2997 When some thread from a multi-threaded process unshares its cgroup
2998 namespace, the new cgroupns gets applied to the entire process (all
2999 the threads). This is natural for the v2 hierarchy; however, for the
3000 legacy hierarchies, this may be unexpected.
3002 A cgroup namespace is alive as long as there are processes inside or
3003 mounts pinning it. When the last usage goes away, the cgroup
3004 namespace is destroyed. The cgroupns root and the actual cgroups
3005 remain.
3008 The Root and Views
3009 ------------------
3011 The 'cgroupns root' for a cgroup namespace is the cgroup in which the
3012 process calling unshare(2) is running. For example, if a process in
3013 /batchjobs/container_id1 cgroup calls unshare, cgroup
3014 /batchjobs/container_id1 becomes the cgroupns root. For the
3015 init_cgroup_ns, this is the real root ('/') cgroup.
3017 The cgroupns root cgroup does not change even if the namespace creator
3018 process later moves to a different cgroup::
3020 # ~/unshare -c # unshare cgroupns in some cgroup
3021 # cat /proc/self/cgroup
3022 0::/
3023 # mkdir sub_cgrp_1
3024 # echo 0 > sub_cgrp_1/cgroup.procs
3025 # cat /proc/self/cgroup
3026 0::/sub_cgrp_1
3028 Each process gets its namespace-specific view of "/proc/$PID/cgroup"
3030 Processes running inside the cgroup namespace will be able to see
3031 cgroup paths (in /proc/self/cgroup) only inside their root cgroup.
3032 From within an unshared cgroupns::
3034 # sleep 100000 &
3035 [1] 7353
3036 # echo 7353 > sub_cgrp_1/cgroup.procs
3037 # cat /proc/7353/cgroup
3038 0::/sub_cgrp_1
3040 From the initial cgroup namespace, the real cgroup path will be
3041 visible::
3043 $ cat /proc/7353/cgroup
3044 0::/batchjobs/container_id1/sub_cgrp_1
3046 From a sibling cgroup namespace (that is, a namespace rooted at a
3047 different cgroup), the cgroup path relative to its own cgroup
3048 namespace root will be shown. For instance, if PID 7353's cgroup
3049 namespace root is at '/batchjobs/container_id2', then it will see::
3051 # cat /proc/7353/cgroup
3052 0::/../container_id2/sub_cgrp_1
3054 Note that the relative path always starts with '/' to indicate that
3055 its relative to the cgroup namespace root of the caller.
3058 Migration and setns(2)
3059 ----------------------
3061 Processes inside a cgroup namespace can move into and out of the
3062 namespace root if they have proper access to external cgroups. For
3063 example, from inside a namespace with cgroupns root at
3064 /batchjobs/container_id1, and assuming that the global hierarchy is
3065 still accessible inside cgroupns::
3067 # cat /proc/7353/cgroup
3068 0::/sub_cgrp_1
3069 # echo 7353 > batchjobs/container_id2/cgroup.procs
3070 # cat /proc/7353/cgroup
3071 0::/../container_id2
3073 Note that this kind of setup is not encouraged. A task inside cgroup
3074 namespace should only be exposed to its own cgroupns hierarchy.
3076 setns(2) to another cgroup namespace is allowed when:
3078 (a) the process has CAP_SYS_ADMIN against its current user namespace
3079 (b) the process has CAP_SYS_ADMIN against the target cgroup
3080 namespace's userns
3082 No implicit cgroup changes happen with attaching to another cgroup
3083 namespace. It is expected that the someone moves the attaching
3084 process under the target cgroup namespace root.
3087 Interaction with Other Namespaces
3088 ---------------------------------
3090 Namespace specific cgroup hierarchy can be mounted by a process
3091 running inside a non-init cgroup namespace::
3093 # mount -t cgroup2 none $MOUNT_POINT
3095 This will mount the unified cgroup hierarchy with cgroupns root as the
3096 filesystem root. The process needs CAP_SYS_ADMIN against its user and
3097 mount namespaces.
3099 The virtualization of /proc/self/cgroup file combined with restricting
3100 the view of cgroup hierarchy by namespace-private cgroupfs mount
3101 provides a properly isolated cgroup view inside the container.
3104 Information on Kernel Programming
3105 =================================
3107 This section contains kernel programming information in the areas
3108 where interacting with cgroup is necessary. cgroup core and
3109 controllers are not covered.
3112 Filesystem Support for Writeback
3113 --------------------------------
3115 A filesystem can support cgroup writeback by updating
3116 address_space_operations->writepages() to annotate bio's using the
3117 following two functions.
3119 wbc_init_bio(@wbc, @bio)
3120 Should be called for each bio carrying writeback data and
3121 associates the bio with the inode's owner cgroup and the
3122 corresponding request queue. This must be called after
3123 a queue (device) has been associated with the bio and
3124 before submission.
3126 wbc_account_cgroup_owner(@wbc, @folio, @bytes)
3127 Should be called for each data segment being written out.
3128 While this function doesn't care exactly when it's called
3129 during the writeback session, it's the easiest and most
3130 natural to call it as data segments are added to a bio.
3132 With writeback bio's annotated, cgroup support can be enabled per
3133 super_block by setting SB_I_CGROUPWB in ->s_iflags. This allows for
3134 selective disabling of cgroup writeback support which is helpful when
3135 certain filesystem features, e.g. journaled data mode, are
3136 incompatible.
3138 wbc_init_bio() binds the specified bio to its cgroup. Depending on
3139 the configuration, the bio may be executed at a lower priority and if
3140 the writeback session is holding shared resources, e.g. a journal
3141 entry, may lead to priority inversion. There is no one easy solution
3142 for the problem. Filesystems can try to work around specific problem
3143 cases by skipping wbc_init_bio() and using bio_associate_blkg()
3144 directly.
3147 Deprecated v1 Core Features
3148 ===========================
3150 - Multiple hierarchies including named ones are not supported.
3152 - All v1 mount options are not supported.
3154 - The "tasks" file is removed and "cgroup.procs" is not sorted.
3156 - "cgroup.clone_children" is removed.
3158 - /proc/cgroups is meaningless for v2. Use "cgroup.controllers" or
3159 "cgroup.stat" files at the root instead.
3162 Issues with v1 and Rationales for v2
3163 ====================================
3165 Multiple Hierarchies
3166 --------------------
3168 cgroup v1 allowed an arbitrary number of hierarchies and each
3169 hierarchy could host any number of controllers. While this seemed to
3170 provide a high level of flexibility, it wasn't useful in practice.
3172 For example, as there is only one instance of each controller, utility
3173 type controllers such as freezer which can be useful in all
3174 hierarchies could only be used in one. The issue is exacerbated by
3175 the fact that controllers couldn't be moved to another hierarchy once
3176 hierarchies were populated. Another issue was that all controllers
3177 bound to a hierarchy were forced to have exactly the same view of the
3178 hierarchy. It wasn't possible to vary the granularity depending on
3179 the specific controller.
3181 In practice, these issues heavily limited which controllers could be
3182 put on the same hierarchy and most configurations resorted to putting
3183 each controller on its own hierarchy. Only closely related ones, such
3184 as the cpu and cpuacct controllers, made sense to be put on the same
3185 hierarchy. This often meant that userland ended up managing multiple
3186 similar hierarchies repeating the same steps on each hierarchy
3187 whenever a hierarchy management operation was necessary.
3189 Furthermore, support for multiple hierarchies came at a steep cost.
3190 It greatly complicated cgroup core implementation but more importantly
3191 the support for multiple hierarchies restricted how cgroup could be
3192 used in general and what controllers was able to do.
3194 There was no limit on how many hierarchies there might be, which meant
3195 that a thread's cgroup membership couldn't be described in finite
3196 length. The key might contain any number of entries and was unlimited
3197 in length, which made it highly awkward to manipulate and led to
3198 addition of controllers which existed only to identify membership,
3199 which in turn exacerbated the original problem of proliferating number
3200 of hierarchies.
3202 Also, as a controller couldn't have any expectation regarding the
3203 topologies of hierarchies other controllers might be on, each
3204 controller had to assume that all other controllers were attached to
3205 completely orthogonal hierarchies. This made it impossible, or at
3206 least very cumbersome, for controllers to cooperate with each other.
3208 In most use cases, putting controllers on hierarchies which are
3209 completely orthogonal to each other isn't necessary. What usually is
3210 called for is the ability to have differing levels of granularity
3211 depending on the specific controller. In other words, hierarchy may
3212 be collapsed from leaf towards root when viewed from specific
3213 controllers. For example, a given configuration might not care about
3214 how memory is distributed beyond a certain level while still wanting
3215 to control how CPU cycles are distributed.
3218 Thread Granularity
3219 ------------------
3221 cgroup v1 allowed threads of a process to belong to different cgroups.
3222 This didn't make sense for some controllers and those controllers
3223 ended up implementing different ways to ignore such situations but
3224 much more importantly it blurred the line between API exposed to
3225 individual applications and system management interface.
3227 Generally, in-process knowledge is available only to the process
3228 itself; thus, unlike service-level organization of processes,
3229 categorizing threads of a process requires active participation from
3230 the application which owns the target process.
3232 cgroup v1 had an ambiguously defined delegation model which got abused
3233 in combination with thread granularity. cgroups were delegated to
3234 individual applications so that they can create and manage their own
3235 sub-hierarchies and control resource distributions along them. This
3236 effectively raised cgroup to the status of a syscall-like API exposed
3237 to lay programs.
3239 First of all, cgroup has a fundamentally inadequate interface to be
3240 exposed this way. For a process to access its own knobs, it has to
3241 extract the path on the target hierarchy from /proc/self/cgroup,
3242 construct the path by appending the name of the knob to the path, open
3243 and then read and/or write to it. This is not only extremely clunky
3244 and unusual but also inherently racy. There is no conventional way to
3245 define transaction across the required steps and nothing can guarantee
3246 that the process would actually be operating on its own sub-hierarchy.
3248 cgroup controllers implemented a number of knobs which would never be
3249 accepted as public APIs because they were just adding control knobs to
3250 system-management pseudo filesystem. cgroup ended up with interface
3251 knobs which were not properly abstracted or refined and directly
3252 revealed kernel internal details. These knobs got exposed to
3253 individual applications through the ill-defined delegation mechanism
3254 effectively abusing cgroup as a shortcut to implementing public APIs
3255 without going through the required scrutiny.
3257 This was painful for both userland and kernel. Userland ended up with
3258 misbehaving and poorly abstracted interfaces and kernel exposing and
3259 locked into constructs inadvertently.
3262 Competition Between Inner Nodes and Threads
3263 -------------------------------------------
3265 cgroup v1 allowed threads to be in any cgroups which created an
3266 interesting problem where threads belonging to a parent cgroup and its
3267 children cgroups competed for resources. This was nasty as two
3268 different types of entities competed and there was no obvious way to
3269 settle it. Different controllers did different things.
3271 The cpu controller considered threads and cgroups as equivalents and
3272 mapped nice levels to cgroup weights. This worked for some cases but
3273 fell flat when children wanted to be allocated specific ratios of CPU
3274 cycles and the number of internal threads fluctuated - the ratios
3275 constantly changed as the number of competing entities fluctuated.
3276 There also were other issues. The mapping from nice level to weight
3277 wasn't obvious or universal, and there were various other knobs which
3278 simply weren't available for threads.
3280 The io controller implicitly created a hidden leaf node for each
3281 cgroup to host the threads. The hidden leaf had its own copies of all
3282 the knobs with ``leaf_`` prefixed. While this allowed equivalent
3283 control over internal threads, it was with serious drawbacks. It
3284 always added an extra layer of nesting which wouldn't be necessary
3285 otherwise, made the interface messy and significantly complicated the
3286 implementation.
3288 The memory controller didn't have a way to control what happened
3289 between internal tasks and child cgroups and the behavior was not
3290 clearly defined. There were attempts to add ad-hoc behaviors and
3291 knobs to tailor the behavior to specific workloads which would have
3292 led to problems extremely difficult to resolve in the long term.
3294 Multiple controllers struggled with internal tasks and came up with
3295 different ways to deal with it; unfortunately, all the approaches were
3296 severely flawed and, furthermore, the widely different behaviors
3297 made cgroup as a whole highly inconsistent.
3299 This clearly is a problem which needs to be addressed from cgroup core
3300 in a uniform way.
3303 Other Interface Issues
3304 ----------------------
3306 cgroup v1 grew without oversight and developed a large number of
3307 idiosyncrasies and inconsistencies. One issue on the cgroup core side
3308 was how an empty cgroup was notified - a userland helper binary was
3309 forked and executed for each event. The event delivery wasn't
3310 recursive or delegatable. The limitations of the mechanism also led
3311 to in-kernel event delivery filtering mechanism further complicating
3312 the interface.
3314 Controller interfaces were problematic too. An extreme example is
3315 controllers completely ignoring hierarchical organization and treating
3316 all cgroups as if they were all located directly under the root
3317 cgroup. Some controllers exposed a large amount of inconsistent
3318 implementation details to userland.
3320 There also was no consistency across controllers. When a new cgroup
3321 was created, some controllers defaulted to not imposing extra
3322 restrictions while others disallowed any resource usage until
3323 explicitly configured. Configuration knobs for the same type of
3324 control used widely differing naming schemes and formats. Statistics
3325 and information knobs were named arbitrarily and used different
3326 formats and units even in the same controller.
3328 cgroup v2 establishes common conventions where appropriate and updates
3329 controllers so that they expose minimal and consistent interfaces.
3332 Controller Issues and Remedies
3333 ------------------------------
3335 Memory
3336 ~~~~~~
3338 The original lower boundary, the soft limit, is defined as a limit
3339 that is per default unset. As a result, the set of cgroups that
3340 global reclaim prefers is opt-in, rather than opt-out. The costs for
3341 optimizing these mostly negative lookups are so high that the
3342 implementation, despite its enormous size, does not even provide the
3343 basic desirable behavior. First off, the soft limit has no
3344 hierarchical meaning. All configured groups are organized in a global
3345 rbtree and treated like equal peers, regardless where they are located
3346 in the hierarchy. This makes subtree delegation impossible. Second,
3347 the soft limit reclaim pass is so aggressive that it not just
3348 introduces high allocation latencies into the system, but also impacts
3349 system performance due to overreclaim, to the point where the feature
3350 becomes self-defeating.
3352 The memory.low boundary on the other hand is a top-down allocated
3353 reserve. A cgroup enjoys reclaim protection when it's within its
3354 effective low, which makes delegation of subtrees possible. It also
3355 enjoys having reclaim pressure proportional to its overage when
3356 above its effective low.
3358 The original high boundary, the hard limit, is defined as a strict
3359 limit that can not budge, even if the OOM killer has to be called.
3360 But this generally goes against the goal of making the most out of the
3361 available memory. The memory consumption of workloads varies during
3362 runtime, and that requires users to overcommit. But doing that with a
3363 strict upper limit requires either a fairly accurate prediction of the
3364 working set size or adding slack to the limit. Since working set size
3365 estimation is hard and error prone, and getting it wrong results in
3366 OOM kills, most users tend to err on the side of a looser limit and
3367 end up wasting precious resources.
3369 The memory.high boundary on the other hand can be set much more
3370 conservatively. When hit, it throttles allocations by forcing them
3371 into direct reclaim to work off the excess, but it never invokes the
3372 OOM killer. As a result, a high boundary that is chosen too
3373 aggressively will not terminate the processes, but instead it will
3374 lead to gradual performance degradation. The user can monitor this
3375 and make corrections until the minimal memory footprint that still
3376 gives acceptable performance is found.
3378 In extreme cases, with many concurrent allocations and a complete
3379 breakdown of reclaim progress within the group, the high boundary can
3380 be exceeded. But even then it's mostly better to satisfy the
3381 allocation from the slack available in other groups or the rest of the
3382 system than killing the group. Otherwise, memory.max is there to
3383 limit this type of spillover and ultimately contain buggy or even
3384 malicious applications.
3386 Setting the original memory.limit_in_bytes below the current usage was
3387 subject to a race condition, where concurrent charges could cause the
3388 limit setting to fail. memory.max on the other hand will first set the
3389 limit to prevent new charges, and then reclaim and OOM kill until the
3390 new limit is met - or the task writing to memory.max is killed.
3392 The combined memory+swap accounting and limiting is replaced by real
3393 control over swap space.
3395 The main argument for a combined memory+swap facility in the original
3396 cgroup design was that global or parental pressure would always be
3397 able to swap all anonymous memory of a child group, regardless of the
3398 child's own (possibly untrusted) configuration. However, untrusted
3399 groups can sabotage swapping by other means - such as referencing its
3400 anonymous memory in a tight loop - and an admin can not assume full
3401 swappability when overcommitting untrusted jobs.
3403 For trusted jobs, on the other hand, a combined counter is not an
3404 intuitive userspace interface, and it flies in the face of the idea
3405 that cgroup controllers should account and limit specific physical
3406 resources. Swap space is a resource like all others in the system,
3407 and that's why unified hierarchy allows distributing it separately.

3. 한국어 전문 번역

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

문서의 지위와 전체 목차

1-99

이 문서는 2015년 10월 Tejun Heo <tj@kernel.org>가 작성한 cgroup v2의 설계, interface와 convention에 관한 authoritative documentation입니다. Core와 controller별 동작을 포함해 userland에서 볼 수 있는 cgroup의 모든 측면을 설명하며, 앞으로의 모든 변경 사항도 이 문서에 반영해야 합니다.

Cgroup v1 문서는 `Documentation/admin-guide/cgroup-v1/index.rst`의 `cgroup-v1` reference에서 볼 수 있습니다. 이 문서에 새 section을 추가할 때에는 아래 contents에도 반드시 entry를 추가해야 합니다.

Control Group v2 contents
Section주제와 하위 절
1. Introduction1-1 용어, 1-2 cgroup이란 무엇인가
2. Basic Operations2-1 Mounting; 2-2 process와 thread 조직(Processes, Threads); 2-3 [Un]populated notification; 2-4 controller 제어(Availability, Enabling and Disabling, Top-down Constraint, No Internal Process Constraint); 2-5 Delegation(Model, Containment); 2-6 Guidelines(Organize Once and Control, Avoid Name Collisions)
3. Resource Distribution Models3-1 Weights, 3-2 Limits, 3-3 Protections, 3-4 Allocations
4. Interface Files4-1 Format, 4-2 Conventions, 4-3 Core Interface Files
5-1. CPUCPU와 5-1-1 CPU Interface Files
5-2. MemoryMemory Interface Files, Usage Guidelines, Memory Ownership
5-3. IOIO Interface Files, Writeback, IO Latency(동작 방식과 interface), IO Priority
5-4. PIDPID와 PID Interface Files
5-5. CpusetCpuset과 Cpuset Interface Files
5-6. Device controllerDevice controller
5-7. RDMARDMA와 RDMA Interface Files
5-8. DMEMDMEM과 DMEM Interface Files
5-9. HugeTLBHugeTLB와 HugeTLB Interface Files
5-10. MiscMisc Interface Files, Migration and Ownership
5-11. Othersperf_event
5-N. Non-normative informationRoot cgroup process에 대한 CPU controller 동작과 IO controller 동작
6. NamespaceBasics, The Root and Views, Migration and setns(2), Interaction with Other Namespaces
P. Kernel ProgrammingFilesystem Support for Writeback
D. Deprecated v1 Core Features사용 중단된 v1 core 기능
R. v1 issues and v2 rationalesMultiple Hierarchies, Thread Granularity, inner node와 thread의 경쟁, 기타 interface 문제, controller 문제와 해결책(Memory)

원문의 전체 목차를 번호와 계층을 유지해 한국어로 정리했습니다.

용어와 cgroup의 계층 모델

100-142

`cgroup`은 `control group`을 뜻하며 절대로 대문자로 쓰지 않습니다. 단수형은 기능 전체를 가리킬 때와 `cgroup controllers`처럼 qualifier로 쓸 때 사용합니다. 여러 개의 개별 control group을 명시적으로 가리킬 때에는 복수형 `cgroups`를 사용합니다.

Cgroup은 process를 계층적으로 조직하고, 그 hierarchy를 따라 system resource를 제어 가능하고 설정 가능한 방식으로 분배하는 mechanism입니다.

Cgroup은 크게 core와 controllers 두 부분으로 구성됩니다. Cgroup core는 process의 계층적 조직을 주로 담당합니다. Cgroup controller는 대개 특정 system resource를 hierarchy를 따라 분배하지만, resource 분배 이외의 목적을 제공하는 utility controller도 있습니다.

Core and controller roles
ComponentPrimary responsibility
cgroup coreProcess를 tree hierarchy로 조직
cgroup controller특정 resource를 hierarchy에 분배하거나 utility 기능 제공

Cgroup 기능을 이루는 두 축입니다.

Cgroups는 tree structure를 이루며 system의 모든 process는 정확히 하나의 cgroup에만 속합니다. 한 process의 모든 thread도 같은 cgroup에 속합니다. Process가 생성될 때에는 생성 시점의 parent process가 속한 cgroup에 배치됩니다.

Process를 다른 cgroup으로 migrate할 수 있지만, 이 migration은 이미 존재하는 descendant process에는 영향을 주지 않습니다.

정해진 structural constraint를 따르면 controller를 cgroup별로 선택해 enable하거나 disable할 수 있습니다. 모든 controller 동작은 hierarchical합니다. 어떤 cgroup에서 controller를 enable하면 그 cgroup을 포함한 sub-hierarchy의 cgroup에 속한 모든 process에 영향을 줍니다.

Nested cgroup에서 controller를 enable하면 resource distribution을 항상 더 제한합니다. Root에 더 가까운 곳에서 설정한 restriction을 더 먼 descendant가 override할 수 없습니다.

Hierarchical resource restriction
Root cgroup restrictionChild inherits effective restrictionNested controller adds tighter restrictionDescendant cannot override ancestor

Ancestor 정책은 descendant로 내려갈수록 유지되거나 더 엄격해질 수만 있습니다.

단일 hierarchy mount와 controller binding

143-183

V1과 달리 cgroup v2에는 hierarchy가 하나만 있습니다. 다음 명령으로 cgroup v2 hierarchy를 mount할 수 있습니다.

  # mount -t cgroup2 none $MOUNT_POINT

`cgroup2` filesystem의 magic number는 `0x63677270`(`"cgrp"`)입니다. V2를 지원하고 v1 hierarchy에 bind되지 않은 모든 controller는 자동으로 v2 hierarchy에 bind되어 root에 나타납니다.

V2 hierarchy에서 active하게 사용하지 않는 controller는 다른 hierarchy에 bind할 수 있습니다. 따라서 v2 hierarchy와 legacy v1 multiple hierarchy를 완전한 backward compatibility를 유지하며 함께 사용할 수 있습니다.

Controller는 현재 hierarchy에서 더 이상 reference되지 않을 때에만 hierarchy 사이를 이동할 수 있습니다. Per-cgroup controller state는 asynchronously 파괴되고 lingering reference가 남을 수 있으므로, 이전 hierarchy를 마지막으로 unmount한 직후에도 controller가 v2 hierarchy에 즉시 나타나지 않을 수 있습니다.

마찬가지로 unified hierarchy 밖으로 옮길 controller는 완전히 disable해야 하며, disable된 controller가 다른 hierarchy에서 사용 가능해질 때까지 시간이 걸릴 수 있습니다. Controller 사이의 dependency 때문에 다른 controller까지 disable해야 할 수도 있습니다.

Controller movement between hierarchies
Controller bound to current hierarchyDisable controllerRemove all current referencesWait for asynchronous state destructionController becomes availableBind to another hierarchy

Controller state와 reference가 완전히 정리되어야 다른 hierarchy에서 사용할 수 있습니다.

V2와 다른 hierarchy 사이에서 controller를 동적으로 옮기는 기능은 development와 manual configuration에는 유용하지만 production에서는 강하게 권장하지 않습니다. System boot 뒤 controller 사용을 시작하기 전에 hierarchy와 controller association을 결정하는 것이 좋습니다.

V2로 전환하는 동안 system-management software가 boot 과정에서 v1 cgroup filesystem을 자동 mount해 수동 개입 전에 모든 controller를 가져갈 수 있습니다. Test와 experiment를 쉽게 하려면 kernel parameter `cgroup_no_v1=`로 v1의 controller를 disable해 항상 v2에서 사용할 수 있게 할 수 있습니다.

Cgroup v2 mount options

184-255

Cgroup v2는 현재 다음 mount option을 지원합니다.

Cgroup v2 mount options
Option동작
nsdelegateCgroup namespace를 delegation boundary로 간주합니다. System-wide option이며 init namespace에서 mount하거나 remount할 때만 설정·변경할 수 있습니다. Non-init namespace mount에서는 무시됩니다. 자세한 내용은 Delegation 절을 참조합니다.
favordynmodsFork와 exit 같은 hot-path operation을 더 비싸게 만드는 대신 task migration과 controller on/off 같은 dynamic cgroup modification latency를 줄입니다. Cgroup 생성, controller enable, CLONE_INTO_CGROUP으로 process를 넣는 static pattern은 영향을 받지 않습니다.
memory_localevents`memory.events`를 subtree가 아닌 current cgroup data로만 채웁니다. 이는 legacy behavior이며 option이 없을 때의 default는 subtree count 포함입니다. System-wide option으로 init namespace의 mount/remount에서만 설정할 수 있고 non-init mount에서는 무시됩니다.
memory_recursiveprotLeaf cgroup으로 protection을 명시적으로 전파하지 않아도 `memory.min`과 `memory.low`를 전체 subtree에 recursively 적용합니다. Subtree끼리는 보호하면서 각 subtree 내부에서는 자유롭게 경쟁하게 합니다.
memory_hugetlb_accountingStatistics reporting과 memory protection을 위해 HugeTLB usage를 memory controller의 전체 cgroup memory usage에 포함합니다. 기존 설정을 regress할 수 있는 새 동작이므로 명시적으로 opt in해야 합니다.
pids_localevents`pids.events:max`를 v1과 같은 local behavior로 되돌려 cgroup 자체의 fork failure만 셉니다. Option이 없으면 `pids.events.max`는 cgroup subtree 전체에서 `pids.max`가 강제된 횟수를 나타냅니다.

각 option이 바꾸는 동작과 적용 범위입니다.

`memory_recursiveprot`의 동작은 원래 default여야 했지만, 상위 tree level에 부정확하게 큰 `bypass` protection 값을 두는 등 기존 semantics에 의존하는 설정을 regress하지 않도록 mount option으로 제공됩니다.

memory_hugetlb_accounting caveats
Caveat설명
No pool ownershipMemory controller는 HugeTLB pool을 관리하지 않으며 pre-allocated pool은 누구에게도 속하지 않습니다. 새 HugeTLB folio를 pool에 넣을 때에는 account하지 않고 page fault 등 실제 사용 시점에 cgroup에 charge합니다.
Host overcommitHard limit을 설정할 때 host memory overcommit 관리가 pre-allocated pool 특성을 고려해야 합니다. 일반적인 HugeTLB pool 관리는 HugeTLB controller 같은 다른 mechanism을 사용해야 합니다.
Charge failureHugeTLB folio를 memory controller에 charge하지 못하면 `SIGBUS`가 발생합니다. Pool에 page가 남아 있어도 cgroup limit에 닿고 reclaim이 실패하면 발생할 수 있습니다.
Protection and reclaimHugeTLB charge는 memory protection과 reclaim dynamics에 영향을 줍니다. `low`, `min` limit 같은 userspace tuning도 이를 고려해야 합니다.
No retroactive trackingOption을 선택하지 않은 동안 사용된 HugeTLB page는 나중에 cgroup v2를 remount해도 memory controller가 추적하지 않습니다.

HugeTLB를 memory controller accounting에 넣을 때 고려할 네 가지 사항입니다.

HugeTLB memory-controller charge
Pre-allocate HugeTLB folio into poolNo memory-controller owner or chargeCgroup uses folio at page faultCharge cgroup memory usageApply statistics, protection and reclaim effects
Charge exceeds cgroup limitReclaim attemptReclaim failsSIGBUS even if pool has free pages

Pool allocation과 실제 cgroup charge는 서로 다른 시점에 일어납니다.

Process 조직과 migration lifecycle

256-310

처음에는 모든 process가 속한 root cgroup만 존재합니다. Subdirectory를 만들면 child cgroup을 생성할 수 있습니다.

  # mkdir $CGROUP_NAME

하나의 cgroup은 여러 child cgroup을 가져 tree structure를 이룰 수 있습니다. 각 cgroup에는 read/write 가능한 `cgroup.procs` interface file이 있습니다. 이 file을 읽으면 해당 cgroup에 속한 모든 process PID가 한 줄에 하나씩 표시됩니다.

PID는 정렬되지 않습니다. 읽는 동안 process가 다른 cgroup으로 이동했다가 돌아오거나 PID가 recycle되면 같은 PID가 두 번 이상 나타날 수 있습니다.

Target cgroup의 `cgroup.procs`에 PID를 쓰면 process를 그 cgroup으로 migrate합니다. 한 번의 `write(2)` call로는 process 하나만 이동할 수 있습니다. Process가 여러 thread로 구성되어 있으면 어느 thread의 PID를 쓰더라도 process의 모든 thread가 함께 이동합니다.

Process가 child를 fork하면 새 process는 fork 시점에 parent가 속한 cgroup에서 태어납니다. Exit한 process는 reap될 때까지 exit 당시 cgroup과 연결되어 있습니다. 다만 zombie process는 `cgroup.procs`에 나타나지 않으므로 다른 cgroup으로 옮길 수 없습니다.

Process cgroup lifecycle
Parent process in cgroup Afork()Child is born in cgroup AWrite PID to cgroup B/cgroup.procsAll process threads migrate to B
Process exits in cgroup BZombie remains associated with BHidden from cgroup.procs and cannot migrateReaped

생성, migration, exit와 reap 단계에서 cgroup membership이 어떻게 유지되는지 보여 줍니다.

Child cgroup과 live process가 없는 cgroup은 directory를 제거해 파괴할 수 있습니다. Child가 없고 zombie process만 연결된 cgroup도 empty로 간주하므로 제거할 수 있습니다.

  # rmdir $CGROUP_NAME

`/proc/$PID/cgroup`은 process의 cgroup membership을 나열합니다. System에서 legacy cgroup도 사용하면 hierarchy마다 한 줄씩 여러 entry가 있을 수 있습니다. Cgroup v2 entry는 항상 `0::$PATH` 형식입니다.

  # cat /proc/842/cgroup
  ...
  0::/test-cgroup/test-cgroup-nested

Process가 zombie가 된 뒤 그 process와 연결된 cgroup이 제거되면 path 뒤에 ` (deleted)`가 붙습니다.

  # cat /proc/842/cgroup
  ...
  0::/test-cgroup/test-cgroup-nested (deleted)
Process-facing cgroup interfaces
Interface or operationBehavior
mkdir $CGROUP_NAMEChild cgroup 생성
Read cgroup.procsCurrent cgroup process PID를 순서 보장 없이 출력
Write PID to cgroup.procs한 process의 모든 thread를 target으로 이동
/proc/$PID/cgroupHierarchy별 membership; v2 entry는 `0::$PATH`
rmdir $CGROUP_NAMEChild와 live process가 없는 cgroup 제거

Process membership을 조작하거나 확인하는 주요 interface입니다.

Thread mode와 threaded domain topology

311-380

Cgroup v2는 process group의 thread 사이에 resource를 계층적으로 분배해야 하는 use case를 위해 일부 controller에서 thread granularity를 지원합니다. Default로 한 process의 모든 thread는 같은 cgroup에 속하며, 이 cgroup은 process나 thread에 특정되지 않은 resource consumption을 수용하는 resource domain이기도 합니다.

Thread mode를 사용하면 thread를 subtree 여러 곳에 나누어 놓으면서도 공통 resource domain을 유지할 수 있습니다. Thread mode를 지원하는 controller는 `threaded controller`, 지원하지 않는 controller는 `domain controller`라고 합니다.

Controller and cgroup modes
TermMeaning
Threaded controllerThread mode를 지원하는 controller
Domain controllerThread mode를 지원하지 않는 controller
Threaded cgroupParent resource domain에 참여하는 cgroup
Threaded domain / thread rootThreaded subtree에서 threaded가 아닌 가장 가까운 ancestor이며 전체 subtree의 resource domain

Thread-aware resource 분배에 등장하는 용어입니다.

Cgroup을 threaded로 표시하면 threaded cgroup으로서 parent의 resource domain에 합류합니다. Parent도 threaded일 수 있으며, 이 경우 실제 resource domain은 hierarchy 더 위에 있습니다. Threaded subtree의 root, 즉 threaded가 아닌 가장 가까운 ancestor를 `threaded domain` 또는 `thread root`라고 하며 전체 subtree의 resource domain 역할을 합니다.

Threaded subtree resource domain
A: threaded domain / thread rootB: threaded cgroupC: threaded cgroupThreads may be distributed across A/B/CDomain resource consumption belongs to A

여러 threaded cgroup이 가장 가까운 non-threaded ancestor의 domain을 공유합니다.

Threaded subtree 안에서는 한 process의 thread를 서로 다른 cgroup에 둘 수 있으며 no-internal-process constraint를 적용받지 않습니다. 따라서 non-leaf cgroup에 thread가 있든 없든 threaded controller를 enable할 수 있습니다.

Threaded domain cgroup은 subtree의 모든 domain resource consumption을 수용하므로 실제 process가 없어도 internal consumption이 있는 것으로 간주됩니다. 그 결과 threaded가 아닌 populated child cgroup을 가질 수 없습니다. Root cgroup은 no-internal-process constraint를 받지 않으므로 threaded domain인 동시에 domain cgroup의 parent가 될 수 있습니다.

현재 cgroup의 operation mode 또는 type은 `cgroup.type`에 나타납니다. 이 file은 normal domain, threaded subtree의 domain 역할을 하는 domain, threaded cgroup 가운데 어느 상태인지 보여 줍니다.

cgroup.type states
Reported stateMeaning
domain일반 domain cgroup
domain threadedThreaded subtree의 resource domain
threadedParent의 threaded domain에 참여
domain (invalid)Domain child를 수용할 수 없는 threaded parent 아래 새 domain

Thread topology에서 관찰할 수 있는 type과 상태입니다.

Cgroup은 생성될 때 항상 domain이며 `cgroup.type`에 `threaded`를 쓰면 threaded로 바꿀 수 있습니다. 이 변경은 한 방향뿐이므로 한 번 threaded가 되면 다시 domain으로 바꿀 수 없습니다.

  # echo threaded > cgroup.type

Thread mode를 enable하려면 cgroup이 parent resource domain에 합류할 수 있어야 합니다. Parent는 valid (threaded) domain이거나 threaded cgroup이어야 합니다. Parent가 unthreaded domain이면 domain controller가 enable되어 있지 않고 populated domain child도 없어야 합니다. Root는 이 요구 사항에서 제외됩니다.

Topology 관점에서는 invalid cgroup이 생길 수 있습니다. 원문의 예에서 `A`는 threaded domain, `B`는 threaded이고, 그 아래 새로 생성된 `C`는 아직 domain입니다.

Invalid threaded topology
A: threaded domainB: threadedC: newly created domainC reports domain (invalid)Write threaded to C/cgroup.typeC becomes usable

새 child는 domain으로 태어나지만 threaded parent는 domain child를 수용할 수 없습니다.

`C`는 domain child를 수용할 수 있는 parent에 연결되어 있지 않으므로 threaded cgroup으로 바꾸기 전까지 사용할 수 없습니다. 이 경우 `cgroup.type`은 `domain (invalid)`를 보고하고 invalid topology로 실패한 operation은 errno `EOPNOTSUPP`를 사용합니다.

Child 중 하나가 threaded가 되거나, cgroup 안에 process가 있는 상태에서 `cgroup.subtree_control`에 threaded controller를 enable하면 domain cgroup은 threaded domain으로 바뀝니다. 이 조건이 사라지면 threaded domain은 normal domain으로 돌아갑니다.

Thread interface와 resource accounting

381-416

`cgroup.threads`를 읽으면 cgroup의 모든 thread ID가 나옵니다. Operation 단위가 process 대신 thread라는 점을 제외하면 `cgroup.procs`와 형식과 동작이 같습니다.

`cgroup.threads`는 어느 cgroup에서나 쓸 수 있지만 같은 threaded domain 안에서만 thread를 옮길 수 있으므로 각 threaded subtree 내부로 operation 범위가 제한됩니다.

Threaded domain cgroup이 전체 subtree의 resource domain 역할을 합니다. Thread가 subtree 여러 곳에 흩어져 있어도 모든 process는 threaded domain cgroup에 있는 것으로 간주됩니다.

cgroup.procs and cgroup.threads in thread mode
InterfaceRead behaviorWrite behavior
cgroup.threadsCurrent cgroup의 thread ID같은 threaded domain 안에서 thread 하나 이동
Thread-root cgroup.procs전체 threaded subtree의 process PIDMatching process의 모든 thread 이동
Subtree-proper cgroup.procs읽기 불가Subtree 어느 위치에서나 쓰기 가능

Threaded subtree 안에서 두 migration interface의 의미입니다.

Threaded domain의 `cgroup.procs`에는 subtree의 모든 process PID가 들어 있고 subtree proper에서는 읽을 수 없습니다. 하지만 subtree 어디에서나 `cgroup.procs`에 쓸 수 있으며 matching process의 모든 thread를 해당 cgroup으로 migrate합니다.

Threaded subtree에서는 threaded controller만 enable할 수 있습니다. Threaded controller를 enable하면 그 cgroup과 descendant thread에 연결된 resource consumption만 account하고 control합니다. 특정 thread에 연결되지 않은 consumption은 모두 threaded domain cgroup에 속합니다.

Threaded resource accounting
Thread-specific resource consumptionAccount to thread's cgroupAggregate through threaded descendants
Consumption not tied to a threadAccount to threaded domain cgroup

Thread-specific consumption과 domain consumption의 owner가 갈립니다.

Threaded subtree는 no-internal-process constraint에서 제외되므로 threaded controller는 non-leaf cgroup의 thread와 child cgroup 사이의 경쟁을 처리할 수 있어야 합니다. 각 threaded controller가 이 경쟁을 처리하는 방식을 정의합니다.

현재 threaded cgroup에서 enable할 수 있는 threaded controller는 `cpu`, `cpuset`, `perf_event`, `pids`입니다.

Threaded controllers
ControllerThread-mode status
cpuThreaded
cpusetThreaded
perf_eventThreaded
pidsThreaded

현재 thread mode를 지원하는 controller 목록입니다.

Recursive populated notification

417-439

모든 non-root cgroup에는 sub-hierarchy에 live process가 있는지를 나타내는 `populated` field가 든 `cgroup.events` file이 있습니다. 해당 cgroup과 descendant에 live process가 없으면 값은 `0`, 하나라도 있으면 `1`입니다.

값이 바뀌면 `poll`과 `[id]notify` event가 trigger됩니다. 이를 이용하면 특정 sub-hierarchy의 모든 process가 exit한 뒤 cleanup operation을 시작할 수 있습니다. Populated 상태 update와 notification은 recursive합니다.

Recursive populated example
CgroupOwn process countDescendant live processpopulated
A4B와 C에도 존재1
B0C에 1개1
C1없음1
D0없음0

원문의 A-B-C/D hierarchy와 각 cgroup의 process count·populated 값을 구조화했습니다.

Recursive notification after C exits
C process count 1 -> 0C populated 1 -> 0B has no remaining live descendantB populated 1 -> 0Generate modified events for B/cgroup.events and C/cgroup.events

C의 마지막 process가 exit하면 ancestor B에도 상태 변화가 전달됩니다.

예제에서 `A(4) - B(0) - C(1)`이고 B 아래에 `D(0)`도 있습니다. A, B, C의 `populated`는 `1`, D는 `0`입니다. C의 process 하나가 exit하면 B와 C의 값이 `0`으로 바뀌고 두 cgroup의 `cgroup.events`에 file-modified event가 발생합니다.

Controller availability와 enable·disable

440-493

Controller가 kernel에서 지원되고, 즉 compile되어 있으며 disable되지 않았고 v1 hierarchy에 attach되지 않았으며, `cgroup.controllers`에 나열되어 있으면 해당 cgroup에서 available합니다.

Available하다는 것은 controller interface file이 cgroup directory에 노출되어 그 cgroup 안에서 target resource distribution을 관찰하거나 제어할 수 있다는 뜻입니다.

Controller availability criteria
CriterionRequired state
Kernel supportCompiled in
Disable stateNot disabled
Legacy bindingNot attached to a v1 hierarchy
VisibilityListed in cgroup.controllers

네 조건이 모두 만족되어야 cgroup에서 controller를 enable할 수 있습니다.

각 cgroup의 `cgroup.controllers`는 해당 cgroup에서 enable할 수 있는 available controller를 모두 나열합니다.

  # cat cgroup.controllers
  cpu io memory

Default로 enable된 controller는 없습니다. `cgroup.subtree_control`에 `+controller` 또는 `-controller`를 써서 enable하거나 disable합니다.

  # echo "+cpu +memory -io" > cgroup.subtree_control

`cgroup.controllers`에 나열된 controller만 enable할 수 있습니다. 한 write에 여러 operation을 지정하면 모두 성공하거나 모두 실패합니다. 같은 controller에 여러 operation을 지정하면 마지막 operation이 유효합니다.

Cgroup에서 controller를 enable한다는 것은 immediate child 사이의 target resource distribution을 그 cgroup이 control한다는 뜻입니다.

Enabled-controller topology
A enables cpu + memoryA controls CPU and memory delivered to child B
B enables memory onlyChildren C and D compete freely for CPUB controls C/D division of B's memory

원문의 A-B-C/D hierarchy에서 CPU와 memory 경쟁 범위를 구조화했습니다.

예제 hierarchy에서 A는 `cpu`와 `memory`를 enable해 child B에 주는 CPU cycle과 memory를 control합니다. B는 `memory`만 enable하므로 C와 D는 CPU cycle을 자유롭게 경쟁하지만 B에 주어진 memory를 나누는 방식은 control됩니다.

Controller가 resource를 child에 분배하므로 controller를 enable하면 child cgroup에 해당 controller interface file이 생성됩니다. B에서 `cpu`를 enable하면 C와 D에 `cpu.` prefix file이 생기고, B에서 `memory`를 disable하면 C와 D의 `memory.` prefix file이 제거됩니다.

따라서 `cgroup.`으로 시작하지 않는 controller interface file은 그 file이 보이는 cgroup 자체가 아니라 parent가 소유합니다.

Controller-file ownership
Parent operationEffect in each immediate child
Enable cpuCreate `cpu.` prefixed controller files
Disable memoryRemove `memory.` prefixed controller files
Any non-cgroup. interfaceOwned and governed by the parent cgroup

Parent의 subtree_control operation이 child directory를 바꿉니다.

Top-down과 no-internal-process constraint

494-535

Resource는 top-down으로 분배됩니다. Cgroup은 parent에게서 분배받은 resource만 child에 다시 분배할 수 있습니다.

Top-down controller constraint
Parent cgroup.subtree_control enables controllerController becomes distributable by childChild may enable for its children
One or more children keep controller enabledParent cannot disable that controller

Parent가 enable한 controller만 descendant가 이어서 enable할 수 있습니다.

그러므로 root가 아닌 `cgroup.subtree_control`에는 parent의 `cgroup.subtree_control`에서 enable한 controller만 들어갈 수 있습니다. Parent가 enable한 controller만 child가 enable할 수 있고, child 하나 이상이 enable한 controller는 parent가 disable할 수 없습니다.

Non-root cgroup은 자기 process가 하나도 없을 때에만 domain resource를 child에 분배할 수 있습니다. 즉 process가 없는 domain cgroup만 `cgroup.subtree_control`에 domain controller를 enable할 수 있습니다.

이 규칙은 domain controller가 enable된 hierarchy 영역에서 process가 항상 leaf에만 있도록 보장합니다. 따라서 child cgroup과 parent 내부 process가 서로 경쟁하는 상황을 배제합니다.

No Internal Process Constraint
Cgroup stateMay enable domain controller for children?
Non-root with own processesNo
Non-root without own processesYes, if top-down rule also allows
Root with processesYes; root is exempt
Populated cgroup with empty subtree_controlMay still create child cgroups

Domain controller를 child에 분배할 때의 규칙과 예외입니다.

Root cgroup은 이 restriction에서 제외됩니다. Root에는 다른 cgroup에 연결할 수 없는 process와 anonymous resource consumption이 있어 대부분 controller의 특별 처리가 필요합니다. Root resource consumption을 어떻게 제어할지는 각 controller가 정하며 Controllers 장의 Non-normative information 절에서 더 설명합니다.

Cgroup의 `cgroup.subtree_control`에 enable된 controller가 없으면 이 restriction은 방해가 되지 않습니다. 그렇지 않으면 populated cgroup 아래에 child를 만드는 것 자체가 불가능하기 때문에 중요한 예외입니다.

Cgroup의 resource distribution을 control하려면 child를 만들고 자기 process를 모두 child로 옮긴 다음 `cgroup.subtree_control`에 controller를 enable해야 합니다.

Preparing a populated cgroup for resource control
Populated parent with no enabled subtree controllerCreate child cgroupsMove all parent processes into childrenParent becomes process-freeEnable domain controllers in cgroup.subtree_control

Internal process를 leaf child로 옮긴 뒤에야 domain controller를 enable합니다.

Delegation 방식과 권한 경계

536-570

Cgroup은 두 가지 방식으로 delegate할 수 있습니다. 첫째, directory와 그 안의 `cgroup.procs`, `cgroup.threads`, `cgroup.subtree_control` file에 대한 write access를 less-privileged user에게 부여합니다. 둘째, `nsdelegate` mount option이 설정되어 있으면 cgroup namespace를 만들 때 자동으로 delegate합니다.

Two delegation methods
MethodDelegation triggerWritable control surface
Less-privileged userDirectory와 core delegation file에 write access 부여cgroup.procs, cgroup.threads, cgroup.subtree_control 등
Cgroup namespace`nsdelegate`가 설정된 상태에서 namespace 생성/sys/kernel/cgroup/delegate에 나열된 namespace-root file

명시적 file permission과 namespace 생성 기반 위임은 최종적으로 같은 권한 모델을 만듭니다.

어떤 directory의 resource-control interface file은 parent resource의 distribution을 제어하므로 delegatee가 이 file에 write할 수 없어야 합니다. 첫 번째 방식에서는 해당 file access를 주지 않아 이를 보장합니다.

두 번째 방식에서는 최소한 mount namespacing으로 namespace 밖 file을 delegatee에게 숨겨야 합니다. Kernel은 cgroup namespace 안에서 namespace root의 모든 file write를 거부하지만, `/sys/kernel/cgroup/delegate`에 나열된 `cgroup.procs`, `cgroup.threads`, `cgroup.subtree_control` 등의 file은 예외입니다.

Delegation authority boundary
Parent owns resource-controller settingsDelegate directory or cgroup namespaceExpose only delegation-safe core filesDelegatee builds sub-hierarchyOrganize processes and redistribute received resourcesParent restrictions remain authoritative

Delegatee는 받은 resource를 subtree 안에서만 재분배하며 parent restriction을 벗어날 수 없습니다.

두 delegation type의 최종 결과는 같습니다. 위임이 끝나면 user는 directory 아래에 sub-hierarchy를 만들고 process를 원하는 방식으로 조직하며 parent에게 받은 resource를 더 세분해 분배할 수 있습니다.

모든 resource controller의 limit과 다른 setting은 hierarchical합니다. Delegated sub-hierarchy 안에서 어떤 일을 하더라도 parent가 부과한 resource restriction을 벗어날 수 없습니다.

현재 cgroup은 delegated sub-hierarchy의 cgroup 수나 nesting depth를 제한하지 않습니다. 다만 향후 명시적 limit이 추가될 수 있습니다.

Delegated subtree의 migration containment

571-612

Delegated sub-hierarchy는 delegatee가 process를 subtree 밖에서 안으로 끌어오거나 안에서 밖으로 내보낼 수 없다는 의미에서 containment됩니다.

Less-privileged user에게 delegate한 경우 non-root euid process가 target PID를 `cgroup.procs`에 써서 migrate하려면 다음 두 조건을 만족해야 합니다.

Non-root migration permissions
Required write accessPurpose
Destination cgroup.procsTarget cgroup에 process를 배치할 권한 확인
Source/destination common ancestor cgroup.procsDelegation boundary를 넘는 pull-in 또는 push-out 방지

Writer는 destination file뿐 아니라 source와 destination의 common ancestor에도 권한이 있어야 합니다.

첫째 writer는 destination의 `cgroup.procs`에 write access가 있어야 합니다. 둘째 source cgroup과 destination cgroup의 common ancestor에 있는 `cgroup.procs`에도 write access가 있어야 합니다.

이 두 constraint 덕분에 delegatee는 delegated sub-hierarchy 안에서 process를 자유롭게 옮길 수 있지만 외부 process를 끌어오거나 내부 process를 외부로 밀어낼 수 없습니다.

예제에서는 user `U0`에게 cgroup `C0`과 `C1`을 delegate했습니다. U0는 C0 아래에 `C00`, `C01`을 만들고 C1 아래에 `C10`을 만들었으며, C0와 C1 아래의 모든 process는 U0 소유입니다.

Delegated C0/C1 hierarchy
Hierarchy root not writable by U0Delegation point C0C00 and C01 created by U0
Hierarchy root not writable by U0Delegation point C1C10 created by U0
Process currently in C10Attempt write PID to C00/cgroup.procsCommon ancestor is above C0/C1 delegation pointsU0 lacks ancestor cgroup.procs write accessReject with -EACCES

원문의 ASCII hierarchy와 C10에서 C00으로 이동하려는 경로를 구조화했습니다.

U0가 현재 C10에 있는 process PID를 `C00/cgroup.procs`에 쓰려 한다고 가정합니다. U0는 destination file에는 write access가 있지만 C10과 C00의 common ancestor가 두 delegation point보다 위에 있고 그 ancestor의 `cgroup.procs`에는 write access가 없습니다. 따라서 write는 `-EACCES`로 거부됩니다.

Namespace delegation에서는 migration을 시도하는 process의 namespace에서 source와 destination cgroup이 모두 reachable해야 containment가 보장됩니다. 둘 중 하나라도 reachable하지 않으면 migration은 `-ENOENT`로 거부됩니다.

Containment rejection results
Delegation typeContainment checkFailure
Less-privileged userCommon ancestor cgroup.procs write access-EACCES
Cgroup namespaceSource와 destination 모두 namespace에서 reachable-ENOENT

Delegation 방식별 boundary 위반의 검사와 error입니다.

한 번 조직하고 이름 충돌 피하기

613-651

Process를 cgroup 사이에서 migrate하는 operation은 비교적 비싸고 memory 같은 stateful resource가 process와 함께 이동하지 않습니다. Migration과 여러 hot path 사이에는 synchronization cost에 관한 본질적 trade-off가 자주 존재하므로 이는 명시적인 design decision입니다.

따라서 서로 다른 resource restriction을 적용하려고 process를 cgroup 사이에서 자주 migrate하는 방식은 권장하지 않습니다. Workload는 시작할 때 system의 logical structure와 resource structure에 따라 한 번 cgroup에 배치해야 합니다.

Resource distribution을 동적으로 조정해야 할 때에는 process를 옮기는 대신 interface file을 통해 controller configuration을 바꿉니다.

Organize once and control
Workload startsAssign once by logical/resource structureKeep process placement stableAdjust controller interface filesChange resource distribution without migration

Workload placement와 runtime tuning을 분리하는 권장 pattern입니다.

Cgroup interface file과 child cgroup은 같은 directory를 사용하므로 interface file과 충돌하는 이름의 child cgroup을 만들 수 있습니다.

Interface naming conventions
Name classConvention
Core interface`cgroup.` prefix
Controller interfaceController name과 dot prefix
Controller nameLowercase alphabet과 `_`로 구성되지만 `_`로 시작하지 않음
Reserved-looking workload termsInterface filename 시작·끝에 job, service, slice, unit, workload를 사용하지 않음
Child cgroup nameKernel이 충돌을 막지 않으므로 user가 안전한 이름 선택

Core와 controller prefix 및 workload-category 단어 회피 규칙입니다.

모든 cgroup core interface file은 `cgroup.` prefix를 사용하고 각 controller interface는 controller name과 dot를 prefix로 사용합니다. Controller name은 lowercase alphabet과 `_`로 구성되지만 `_`로 시작하지 않으므로 `_`를 collision-avoidance prefix character로 사용할 수 있습니다.

또한 interface filename은 workload를 분류할 때 자주 쓰는 `job`, `service`, `slice`, `unit`, `workload` 같은 term으로 시작하거나 끝나지 않습니다.

Cgroup 자체는 name collision을 막지 않으므로 이를 피하는 책임은 user에게 있습니다.

Operational guidelines
GuidelineAvoidUse instead
Organize onceFrequent process migration and stateful-resource mismatchController configuration update
Avoid name collisionsChild directory and interface filename collisionPrefix convention을 고려한 user-managed naming

두 guideline이 방지하려는 비용과 충돌입니다.

Resource distribution model과 Weights

652-681

Cgroup controller는 resource type과 예상 use case에 따라 여러 resource distribution scheme을 구현합니다. 이 절은 주요 scheme과 기대 동작을 설명합니다.

Weight model에서는 active child의 weight를 모두 더하고, 각 child의 weight가 합계에서 차지하는 비율만큼 parent resource를 나눕니다. 현재 resource를 사용할 수 있는 child만 분배에 참여하므로 work-conserving입니다.

참여 child가 동적으로 바뀌는 특성 때문에 이 model은 보통 stateless resource에 사용합니다.

Weight-based distribution
Collect active childrenSum child weightsCompute child weight / active sumDistribute parent resource proportionallyUnused share remains available to active peers

Active child만 합계와 비율 계산에 참여합니다.

모든 weight 범위는 `[1, 10000]`이고 default는 `100`입니다. 직관적인 범위를 유지하면서도 양쪽 방향의 대칭적 multiplicative bias를 충분히 세밀하게 표현할 수 있습니다.

Weight가 범위 안에 있는 한 모든 configuration combination이 valid하므로 configuration change나 process migration을 거부할 이유가 없습니다.

`cpu.weight`는 active child에 CPU cycle을 비례 분배하는 대표 예입니다.

Weight model properties
PropertyValue
Range[1, 10000]
Default100
Overcommit conceptNot applicable; proportional shares
ParticipationActive children only
BehaviorWork-conserving
Examplecpu.weight

Weight scheme의 범위, default와 대표 interface입니다.

Limits와 Protections

682-722

Limit model에서 child는 설정된 양까지만 resource를 사용할 수 있습니다. Child limit의 합이 parent가 사용할 수 있는 resource보다 커도 되므로 limit은 overcommit할 수 있습니다.

Limit 범위는 `[0, max]`이고 default `max`는 아무 제한도 하지 않는 noop입니다. Overcommit할 수 있으므로 모든 configuration combination이 valid하며 configuration change나 process migration을 거부할 이유가 없습니다.

`io.max`는 cgroup이 IO device에서 소비할 수 있는 maximum BPS 및/또는 IOPS를 제한하는 예입니다.

Protection model에서는 모든 ancestor usage가 각자의 protected level 아래에 있는 동안 설정된 resource 양까지 cgroup을 보호합니다. Protection은 hard guarantee일 수도 있고 best-effort soft boundary일 수도 있습니다.

Protection도 overcommit할 수 있으며, 이 경우 child 사이에서 parent에게 실제 available한 양까지만 보호됩니다.

Hierarchical protection eligibility
Check target cgroup configured protectionCheck each ancestor usage against protected levelAll ancestors under levelProtect target usage up to configured amount
Child protections overcommittedCap aggregate protection at parent available amountDistribute effective protection among children

Cgroup protection은 모든 ancestor가 자기 protected level 아래에 있을 때 유효합니다.

Protection 범위는 `[0, max]`이고 default `0`은 noop입니다. Overcommit이 허용되므로 모든 configuration combination이 valid하고 configuration change나 process migration을 거부할 이유가 없습니다.

`memory.low`는 best-effort memory protection을 구현하는 대표 예입니다.

Limits and protections compared
ModelMeaningRangeDefaultExample
LimitsChild가 소비할 수 있는 maximum[0, max]max (noop)io.max
ProtectionsAncestor 조건 아래 보호되는 amount[0, max]0 (noop)memory.low

두 model은 모두 overcommit을 허용하지만 설정의 의미와 default가 다릅니다.

Exclusive Allocations

723-742

Allocation model에서는 finite resource의 일정량을 cgroup에 exclusive하게 할당합니다. Child allocation 합이 parent에게 available한 resource를 넘을 수 없으므로 allocation은 overcommit할 수 없습니다.

Allocation 범위는 `[0, max]`이고 default `0`은 resource가 하나도 할당되지 않았다는 뜻입니다.

Overcommit할 수 없으므로 일부 configuration combination은 invalid하며 거부해야 합니다. 해당 resource가 process execution에 필수라면 process migration도 거부될 수 있습니다.

`cpu.rt.max`는 realtime slice를 hard allocation하는 대표 예입니다.

Allocation model properties
PropertyValue
Range[0, max]
Default0 (no resource)
OvercommitNot allowed
Invalid configurationRejected
Process migrationMay be rejected if resource is mandatory
Examplecpu.rt.max

Exclusive finite-resource assignment의 validation 특성입니다.

Allocation validation
Request child allocationSum sibling allocations plus requestCompare with parent available finite resourceWithin amount: accept
Sum exceeds parent amountReject invalid configurationPotentially reject process migration

Child allocation 합계를 parent available amount와 비교합니다.

Interface file format

743-784

가능한 경우 모든 cgroup interface file은 다음 형식 중 하나를 사용해야 합니다.

  New-line separated values
  (when only one value can be written at once)

	VAL0\n
	VAL1\n
	...

  Space separated values
  (when read-only or multiple values can be written at once)

	VAL0 VAL1 ...\n

  Flat keyed

	KEY0 VAL0\n
	KEY1 VAL1\n
	...

  Nested keyed

	KEY0 SUB_KEY0=VAL00 SUB_KEY1=VAL01...
	KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11...
	...
Canonical interface formats
FormatRepresentationTypical use
New-line separated values한 줄에 VAL 하나한 번에 value 하나만 쓸 수 있을 때
Space separated values한 줄에 VAL0 VAL1 ...Read-only이거나 여러 value를 한 번에 쓸 수 있을 때
Flat keyedKEY VAL 한 쌍씩 한 줄Key별 단일 value
Nested keyedKEY 뒤에 SUB_KEY=VAL pair 목록Key마다 여러 named field

원문의 네 형식을 write cardinality와 record 구조로 정리했습니다.

Writable file은 일반적으로 read와 write 형식이 같아야 합니다. 다만 controller는 뒤쪽 field 생략을 허용하거나 가장 흔한 use case를 위한 제한된 shortcut을 구현할 수 있습니다.

Flat-keyed와 nested-keyed file 모두 한 번에 key 하나의 value만 쓸 수 있습니다. Nested-keyed file에서는 sub-key pair 순서를 자유롭게 지정할 수 있고 모든 pair를 다 쓸 필요도 없습니다.

Interface naming과 value convention

785-856

단일 feature의 setting은 file 하나에 담아야 합니다. Root cgroup은 resource control에서 제외되어야 하므로 resource-control interface file을 가져서는 안 됩니다.

Default time unit은 microsecond입니다. 다른 unit을 사용한다면 반드시 명시적 unit suffix를 붙여야 합니다. Parts-per quantity는 소수부가 최소 두 자리인 percentage decimal, 예를 들어 `13.40`을 사용해야 합니다.

Common value conventions
FeatureConvention
TimeDefault microseconds; otherwise explicit unit suffix
Parts-per quantityPercentage decimal with >=2 fractional digits
WeightFile `weight`, range [1, 10000], default 100
Absolute guaranteeFile `min`
Absolute limitFile `max`
Best-effort guaranteeFile `low`
Best-effort limitFile `high`
Upward infinitySpecial token `max` for read and write

Time, ratio, weight와 guarantee/limit naming 규칙입니다.

Weight-based distribution을 구현한 controller는 interface file 이름을 `weight`로 하고 범위 `[1, 10000]`, default `100`을 사용해야 합니다. Default를 100%로 보는 직관적인 범위 안에서 양방향으로 충분하고 대칭적인 bias를 허용하기 위한 값입니다.

Absolute resource guarantee와 limit은 각각 `min`, `max`, best-effort guarantee와 limit은 각각 `low`, `high`라는 file 이름을 사용해야 합니다. 이 네 control file에서 위쪽 무한대를 나타낼 때에는 read와 write 모두 special token `max`를 사용합니다.

Configurable default와 key별 override가 있는 setting은 default entry의 key를 `default`로 지정하고 file의 첫 entry에 놓아야 합니다. Default value는 `default $VAL` 또는 `$VAL`을 써서 update할 수 있습니다.

특정 override를 update할 때 value로 `default`를 쓰면 해당 override를 제거한다는 뜻입니다. 읽을 때에는 value가 `default`인 override entry가 나타나서는 안 됩니다.

Default and override lifecycle
default 150Write 125 or default 125Default becomes 125
Write 8:16 170Create device overrideRead default 125 plus 8:16 170
Write 8:0 defaultRemove 8:0 overrideNo override with value default appears on read

Default update, device override 생성과 제거가 file readback에 반영되는 방식입니다.

Major:minor device number를 key로 하고 integer value를 저장하는 예제는 처음에 default `150`, device `8:0` override `300`을 보여 줍니다.

    # cat cgroup-example-interface-file
    default 150
    8:0 300

다음 두 write는 모두 default를 `125`로 update합니다.

    # echo 125 > cgroup-example-interface-file
    # echo "default 125" > cgroup-example-interface-file

Device `8:16`의 override를 `170`으로 설정할 수 있습니다.

    # echo "8:16 170" > cgroup-example-interface-file

`8:0` override를 `default` write로 제거한 뒤 file에는 default `125`와 `8:16 170`만 남습니다.

    # echo "8:0 default" > cgroup-example-interface-file
    # cat cgroup-example-interface-file
    default 125
    8:16 170

빈도가 매우 높지 않은 event에는 event key-value pair를 나열하는 `events` interface file을 만들어야 합니다. Notify 가능한 event가 발생할 때마다 이 file에 file-modified event를 생성해야 합니다.

Convention goals
AreaResult
Feature groupingOne feature per file
Root behaviorNo ordinary resource-control files
UnitsPredictable defaults and explicit exceptions
Control namesShared weight/min/max/low/high vocabulary
Keyed defaultsFirst-entry default plus sparse overrides
EventsKey-value counters with modified notifications

Interface convention이 사용자에게 제공하는 일관성입니다.

Low-frequency event notification
Notifiable event occursUpdate key value in events fileGenerate file modified eventUserspace poll/notify observes change

Counter update와 userspace notification의 순서입니다.

cgroup.type과 cgroup.procs

857-909

모든 cgroup core file에는 `cgroup.` prefix가 붙습니다.

`cgroup.type`은 non-root cgroup에 존재하는 read/write single-value file입니다. 읽으면 cgroup의 current type을 보고합니다.

cgroup.type values
ValueMeaning
domainNormal valid domain cgroup
domain threadedThreaded subtree의 root 역할을 하는 threaded domain
domain invalidPopulate하거나 controller를 enable할 수 없는 invalid state; threaded 전환은 허용될 수 있음
threadedThreaded subtree에 속한 threaded cgroup

Core interface가 보고하는 네 cgroup type입니다.

`cgroup.type`에 `threaded`를 쓰면 cgroup을 threaded cgroup으로 바꿀 수 있습니다.

`cgroup.procs`는 모든 cgroup에 존재하는 read/write new-line-separated-values file입니다. 읽으면 cgroup에 속한 process PID를 한 줄에 하나씩 나열합니다. PID는 정렬되지 않으며 migration 왕복이나 read 중 PID recycling 때문에 같은 PID가 여러 번 나올 수 있습니다.

PID를 쓰면 해당 process를 cgroup으로 migrate합니다. Writer는 `cgroup.procs` file과 source/destination common ancestor의 `cgroup.procs` file 모두에 write access가 있어야 합니다.

cgroup.procs access rules
Operation or contextRule
ReadUnordered PID list; duplicate PID possible
Write PIDMigrate the process and all its threads
Permission 1Write access to destination cgroup.procs
Permission 2Write access to source/destination common ancestor cgroup.procs
DelegationGrant write access together with containing directory
Read in threaded cgroupFail with EOPNOTSUPP; processes belong to thread root
Write in threaded cgroupSupported; move every thread of process

Read, write와 delegation 시의 동작입니다.

Sub-hierarchy를 delegate할 때에는 containing directory와 함께 이 file의 write access도 부여해야 합니다.

Threaded cgroup에서는 모든 process가 thread root에 속하므로 `cgroup.procs` read가 `EOPNOTSUPP`로 실패합니다. Write는 지원되며 process의 모든 thread를 해당 cgroup으로 이동합니다.

Thread migration과 controller set

910-956

`cgroup.threads`는 모든 cgroup에 있는 read/write new-line-separated-values file입니다. 읽으면 cgroup에 속한 thread TID를 한 줄에 하나씩 나열합니다. TID는 정렬되지 않고 migration 왕복이나 read 중 TID recycling으로 같은 TID가 여러 번 나올 수 있습니다.

TID를 쓰면 해당 thread를 cgroup으로 migrate합니다. Writer는 `cgroup.threads`에 write access가 있어야 하고, source와 destination cgroup이 같은 resource domain에 있어야 하며, 두 cgroup의 common ancestor `cgroup.procs`에도 write access가 있어야 합니다.

Sub-hierarchy를 delegate할 때에는 containing directory와 함께 `cgroup.threads` write access도 부여해야 합니다.

Thread and controller core files
FileAccess / formatMeaning
cgroup.threadsRead/write, newline valuesTID list and same-resource-domain thread migration
cgroup.controllersRead-only, space valuesAvailable controller list; order unspecified
cgroup.subtree_controlRead/write, space values; initially emptyController set distributing resource to children

세 core file의 access mode, format과 핵심 의미입니다.

`cgroup.controllers`는 모든 cgroup에 있는 read-only space-separated-values file이며, 해당 cgroup에서 available한 controller를 순서 보장 없이 나열합니다.

`cgroup.subtree_control`은 모든 cgroup에 존재하는 read/write space-separated-values file이며 처음에는 비어 있습니다. 읽으면 cgroup에서 child로 resource를 분배하도록 enable된 controller를 나열합니다.

`+` 또는 `-` prefix가 붙은 controller 목록을 쓰면 enable 또는 disable합니다. 같은 controller가 여러 번 나오면 마지막 항목이 유효합니다. 한 write에 여러 enable/disable operation이 있으면 모두 성공하거나 모두 실패합니다.

Atomic subtree-control update
Write space-separated +controller/-controller listResolve repeated names using last operationValidate every requested changeAll valid: commit all
Any operation invalidFail entire writeCommit none

Controller list parsing과 commit 규칙입니다.

Events, descendant limit와 cgroup.stat

957-1008

`cgroup.events`는 non-root cgroup에 존재하는 read-only flat-keyed file입니다. 별도 설명이 없으면 이 file의 value가 바뀔 때 file-modified event가 생성됩니다.

cgroup.events fields
FieldValue 1Value 0
populatedCgroup 또는 descendant에 live process가 있음Live process가 없음
frozenCgroup이 frozenFrozen 아님

Live process와 freezer 상태를 알리는 field입니다.

`cgroup.max.descendants`는 read/write single-value file이고 default는 `max`입니다. 허용할 descendant cgroup의 maximum number를 정합니다. 실제 descendant 수가 이 값 이상이면 hierarchy에서 새 cgroup 생성이 실패합니다.

`cgroup.max.depth`도 read/write single-value file이고 default `max`입니다. Current cgroup 아래에서 허용할 maximum descendant depth를 정합니다. 실제 depth가 값 이상이면 새 child cgroup 생성이 실패합니다.

Cgroup hierarchy limits
FileDefaultLimitCreation fails when
cgroup.max.descendantsmaxVisible descendant cgroup countActual count >= configured value
cgroup.max.depthmaxDepth below current cgroupActual depth >= configured value

Descendant count와 depth limit의 실패 조건입니다.

`cgroup.stat`은 read-only flat-keyed file입니다. `nr_descendants`는 visible descendant cgroup의 total number입니다.

`nr_dying_descendants`는 dying descendant cgroup의 total number입니다. User가 cgroup을 삭제하면 dying 상태가 되고 system load 등에 따라 정해지지 않은 시간 동안 이 상태에 머문 뒤 완전히 파괴됩니다.

어떤 상황에서도 process는 dying cgroup에 들어갈 수 없고 dying cgroup은 revive할 수 없습니다. Dying cgroup은 삭제 시점에 active하던 limit을 넘지 않는 범위에서 system resource를 소비할 수 있습니다.

`nr_subsys_<cgroup_subsys>`는 current cgroup과 그 아래의 live cgroup subsystem, 예를 들어 memory cgroup의 total number입니다. `nr_dying_subsys_<cgroup_subsys>`는 같은 범위의 dying cgroup subsystem total입니다.

cgroup.stat entries
EntryMeaning
nr_descendantsVisible descendant cgroup total
nr_dying_descendantsDeleted but not yet destroyed cgroup total
nr_subsys_<cgroup_subsys>Live subsystem instances at and below current cgroup
nr_dying_subsys_<cgroup_subsys>Dying subsystem instances at and below current cgroup

Hierarchy와 subsystem lifecycle counter입니다.

Local frozen time과 cgroup.freeze

1009-1052

`cgroup.stat.local`은 non-root cgroup에 존재하는 read-only flat-keyed file입니다. `frozen_usec`는 self 또는 ancestor group에 의해 freeze되었는지와 관계없이 이 cgroup이 freezing 시작부터 thawing까지 보낸 누적 시간입니다.

실제로 `frozen` 상태에 도달했는지 또는 도달하지 못했는지는 이 counter에서 따로 account하지 않습니다. 원문의 freezer-state ASCII representation에서 측정 시간은 point `a`부터 `c`까지입니다. 즉 frozen bit가 올라가는 `b`보다 앞에서 시작하고 내려가는 `d`보다 앞에서 끝납니다.

frozen_usec timing interval
a: freezing begins, timer startsb: frozen changes 0 -> 1frozen state remains 1c: thawing begins, timer stopsd: frozen changes 1 -> 0

원문의 파형을 state transition과 측정 구간으로 재구성했습니다.

`cgroup.freeze`는 non-root cgroup의 read/write single-value file입니다. 허용값은 `0`과 `1`, default는 `0`입니다.

`1`을 쓰면 cgroup과 모든 descendant를 freeze합니다. 모든 process가 정지해 명시적으로 unfreeze할 때까지 실행되지 않습니다. Freeze 완료에는 시간이 걸릴 수 있으며, 완료되면 `cgroup.events`의 `frozen`이 `1`로 update되고 notification이 발생합니다.

Cgroup은 자기 setting 또는 어느 ancestor setting으로도 freeze될 수 있습니다. Ancestor 중 하나라도 frozen이면 해당 cgroup은 계속 frozen 상태입니다.

Hierarchical freeze operation
Write 1 to cgroup.freezeStop processes in cgroup and descendantsWait for asynchronous completionSet cgroup.events frozen=1Issue notification
Any ancestor remains frozenDescendant remains frozen regardless of own setting

Request, completion notification과 ancestor dominance를 보여 줍니다.

Frozen cgroup의 process도 fatal signal로 kill할 수 있습니다. User의 명시적 move 또는 freeze와 `fork()`의 race 때문에 frozen cgroup에 들어가거나 나올 수도 있습니다. Frozen cgroup으로 이동한 process는 정지하고 밖으로 이동한 process는 실행 상태가 됩니다.

Cgroup의 frozen status는 cgroup tree operation에 영향을 주지 않습니다. Frozen 상태라도 empty cgroup을 삭제하거나 새 sub-cgroup을 만들 수 있습니다.

Freezer behavior summary
OperationBehavior
Fatal signalFrozen process를 kill할 수 있음
Move into frozen cgroupProcess stops
Move out of frozen cgroupProcess runs
fork() racing with freezeNew process가 frozen tree에 들어갈 수 있음
Delete frozen empty cgroupAllowed
Create sub-cgroup under frozen cgroupAllowed

Freeze가 process와 tree operation에 미치는 영향입니다.

cgroup.kill과 PSI pressure

1053-1090

`cgroup.kill`은 non-root cgroup에 있는 write-only single-value file이며 허용값은 `1`뿐입니다.

`1`을 쓰면 해당 cgroup과 모든 descendant cgroup을 kill합니다. 영향받는 cgroup tree의 모든 process에 `SIGKILL`을 전달합니다. Cgroup tree kill은 concurrent fork를 올바르게 처리하고 migration으로부터 보호됩니다.

Threaded cgroup에서 이 file에 쓰면 `EOPNOTSUPP`로 실패합니다. Cgroup kill은 process-directed operation이므로 thread-group 전체에 영향을 주기 때문입니다.

Atomic cgroup-tree kill
Write 1 to cgroup.killProtect operation against migrationsTrack concurrent forksSend SIGKILL to all processes in cgroup and descendantsComplete tree kill
Write from threaded cgroupReject with EOPNOTSUPPProcess-directed operation must cover whole thread-group

Concurrent fork와 migration을 고려하며 process tree 전체를 종료합니다.

`cgroup.pressure`는 read/write single-value file이며 허용값은 `0`과 `1`, default는 `1`입니다. `0`을 쓰면 cgroup PSI accounting을 disable하고 `1`을 쓰면 다시 enable합니다.

이 control attribute는 hierarchical하지 않습니다. 한 cgroup에서 PSI accounting을 disable하거나 enable해도 descendant PSI에는 영향을 주지 않으며 root에서 ancestor를 따라 enablement를 전달할 필요도 없습니다.

PSI는 cgroup마다 stall을 별도로 account하고 hierarchy 각 level에서 aggregate하므로 deep hierarchy의 일부 workload에는 무시할 수 없는 overhead가 생길 수 있습니다. 이때 non-leaf cgroup의 PSI accounting을 disable하는 데 `cgroup.pressure`를 사용할 수 있습니다.

Non-hierarchical PSI control
Deep cgroup hierarchyPer-cgroup stall accountingAggregate at every hierarchy levelPotential non-negligible overheadWrite 0 to non-leaf cgroup.pressureDisable only that cgroup's PSI accounting

각 cgroup의 pressure accounting switch는 descendant와 독립적입니다.

`irq.pressure`는 read/write nested-keyed file이며 IRQ/SOFTIRQ의 pressure stall information을 보여 줍니다. 자세한 내용은 `Documentation/accounting/psi.rst`의 `psi` reference를 참조하십시오.

Kill and pressure interfaces
FileAccess / valuesBehavior
cgroup.killWrite-only; only 1SIGKILL entire cgroup subtree; unsupported in threaded cgroup
cgroup.pressureRead/write 0 or 1; default 1Enable/disable local cgroup PSI accounting, non-hierarchical
irq.pressureRead/write nested-keyedIRQ/SOFTIRQ pressure stall information

마지막 세 core interface의 access, default와 핵심 동작입니다.

CPU controller model과 realtime 제약

1091-1126

`cpu` controller는 CPU cycle distribution을 조절합니다. Normal scheduling policy에는 weight model과 absolute bandwidth limit model을 구현하고, realtime scheduling policy에는 absolute bandwidth allocation model을 구현합니다.

CPU resource models
Scheduling policyImplemented models
NormalWeight and absolute bandwidth limit
RealtimeAbsolute bandwidth allocation

Scheduling policy별 CPU controller distribution model입니다.

모든 model에서 cycle distribution은 시간만을 기준으로 정의되고 task가 실행되는 frequency는 account하지 않습니다.

Optional utilization-clamping support는 `schedutil` cpufreq governor에 CPU가 항상 제공해야 할 minimum desired frequency와 넘지 않아야 할 maximum desired frequency hint를 전달합니다.

주의: cgroup2 CPU controller는 아직 realtime process의 bandwidth control을 지원하지 않습니다. Realtime process group scheduling용 `CONFIG_RT_GROUP_SCHED` option이 enable된 kernel에서는 모든 RT process가 root cgroup에 있을 때에만 CPU controller를 enable할 수 있습니다.

System-management software가 boot 과정에서 RT process를 이미 non-root cgroup에 배치했을 수 있습니다. 이 경우 `CONFIG_RT_GROUP_SCHED` kernel에서 CPU controller를 enable하기 전에 해당 process를 root cgroup으로 이동해야 합니다.

Enabling CPU controller with CONFIG_RT_GROUP_SCHED
Kernel has CONFIG_RT_GROUP_SCHED enabledFind all realtime processesAny RT process in non-root cgroup?Move those RT processes to rootEnable cgroup2 cpu controller

Realtime process placement를 검사하고 필요한 migration을 수행합니다.

`CONFIG_RT_GROUP_SCHED`가 disable되어 있으면 이 limitation은 적용되지 않고 일부 interface file은 realtime process에 영향을 주거나 이를 account합니다. 자세한 범위는 다음 CPU Interface Files 절에 나옵니다.

`CONFIG_RT_GROUP_SCHED`의 영향을 받는 것은 CPU controller뿐입니다. 다른 controller는 이 option과 관계없이 realtime process resource control에 사용할 수 있습니다.

CONFIG_RT_GROUP_SCHED scope
ConfigurationCPU controllerOther controllers
Enabled모든 RT process가 root에 있어야 enable 가능RT resource control에 사용 가능
DisabledRoot-placement limitation 없음; 일부 file이 RT를 affect/accountRT resource control에 사용 가능

Build option이 controller 사용에 미치는 범위입니다.

CPU scheduler category, stat과 weight

1127-1194

Process와 CPU controller의 상호작용은 scheduling policy와 underlying scheduler에 따라 다릅니다. CPU controller 관점에서 process는 세 category로 나뉩니다.

CPU-controller process categories
CategoryProcesses
Fair classFair-class scheduler 아래 process
BPF weighted`cgroup_set_weight` callback을 가진 BPF scheduler 아래 process
Everything else`SCHED_FIFO`, `SCHED_RR`, `SCHED_DEADLINE` 및 callback 없는 BPF scheduler

이후 interface 설명에서 사용하는 세 scheduler category입니다.

Fair-class 또는 BPF scheduler 적용 시점의 자세한 내용은 `Documentation/scheduler/sched-ext.rst`의 `sched-ext` reference를 참조하십시오. 다음 interface 설명은 위 category를 사용하며 모든 time duration unit은 microsecond입니다.

`cpu.stat`은 read-only flat-keyed file이며 controller enable 여부와 관계없이 존재합니다.

cpu.stat counters
AvailabilityAccounting scopeCounters
AlwaysAll processes in cgroupusage_usec, user_usec, system_usec
When cpu controller enabledFair-class processes onlynr_periods, nr_throttled, throttled_usec, nr_bursts, burst_usec

항상 보고되는 전체-process counter와 controller enable 시 fair-class 전용 counter입니다.

`cpu.weight`는 non-root cgroup에 있는 read/write single-value file이고 default는 `100`입니다. Non-idle group(`cpu.idle = 0`)의 weight 범위는 `[1, 10000]`입니다. Cgroup이 `SCHED_IDLE`(`cpu.idle = 1`)로 설정되면 weight는 `0`으로 표시됩니다.

이 file은 fair-class scheduler process와 `cgroup_set_weight` callback을 가진 BPF scheduler process에만 영향을 줍니다. BPF 쪽 실제 영향은 callback 구현에 따라 달라집니다.

`cpu.weight.nice`는 non-root cgroup의 read/write single-value file이고 default `0`, nice 범위는 `[-20, 19]`입니다.

이는 `cpu.weight`의 alternative interface로 `nice(2)`와 같은 value를 사용해 weight를 읽고 설정하게 합니다. Nice range가 더 작고 granularity가 거칠기 때문에 read value는 current weight에 가장 가까운 approximation입니다.

`cpu.weight.nice`도 fair-class와 `cgroup_set_weight` callback이 있는 BPF scheduler process에만 영향을 주며 BPF 동작은 callback 구현에 달려 있습니다.

CPU weight interfaces
FileDefaultRangeNotes
cpu.weight100[1, 10000], or 0 for SCHED_IDLENative proportional weight
cpu.weight.nice0[-20, 19]Coarser nice(2)-compatible approximation

Native weight와 nice-compatible interface를 비교합니다.

CPU bandwidth, burst와 pressure

1195-1224

`cpu.max`는 non-root cgroup의 read/write two-value file이고 default는 `max 100000`입니다. Maximum bandwidth limit은 다음 형식입니다.

	  $MAX $PERIOD

Group은 각 `$PERIOD` duration마다 최대 `$MAX`만큼 사용할 수 있습니다. `$MAX`의 `max`는 limit이 없다는 뜻입니다. 숫자 하나만 쓰면 `$MAX`만 update합니다. 이 file은 fair-class scheduler process에만 영향을 줍니다.

cpu.max bandwidth window
Start $PERIOD windowAllow CPU usageAccumulate consumed timeReach $MAXThrottle fair-class group until next period
$MAX = maxNo bandwidth limit

Period마다 quota를 소비하고 다음 period에 다시 사용할 수 있습니다.

`cpu.max.burst`는 non-root cgroup의 read/write single-value file이며 default `0`, burst 범위는 `[0, $MAX]`입니다. Fair-class scheduler process에만 영향을 줍니다.

`cpu.pressure`는 read/write nested-keyed file로 CPU pressure stall information을 보여 줍니다. 자세한 내용은 `Documentation/accounting/psi.rst`의 `psi` reference를 참조하십시오. 이 file은 cgroup의 모든 process를 account합니다.

CPU bandwidth and pressure files
FileDefault / rangeScope
cpu.maxmax 100000; $MAX $PERIODFair-class processes
cpu.max.burst0; [0, $MAX]Fair-class processes
cpu.pressureNested-keyed PSIAll processes in cgroup

Bandwidth 제한과 pressure accounting의 대상 범위가 다릅니다.

Utilization clamp와 cgroup SCHED_IDLE

1225-1268

`cpu.uclamp.min`은 non-root cgroup의 read/write single-value file입니다. Default `0`은 utilization boosting이 없다는 뜻입니다. Requested minimum utilization(protection)은 `12.34`처럼 percentage rational number로 표현합니다.

이 interface는 `sched_setattr(2)`와 비슷하게 minimum utilization clamp를 읽고 설정합니다. 이 값은 realtime process를 포함한 task-specific minimum utilization clamp를 제한하는 데 사용됩니다.

Requested minimum utilization은 항상 current maximum utilization limit인 `cpu.uclamp.max`로 cap됩니다. `cpu.uclamp.min`은 cgroup의 모든 process에 영향을 줍니다.

`cpu.uclamp.max`도 non-root cgroup의 read/write single-value file이며 default `max`는 utilization capping이 없다는 뜻입니다. Requested maximum utilization(limit)은 `98.76`처럼 percentage rational number로 표현합니다.

이 interface는 `sched_setattr(2)`와 비슷하게 maximum utilization clamp를 읽고 설정하며 realtime process를 포함한 task-specific maximum clamp를 제한합니다. Cgroup의 모든 process에 영향을 줍니다.

Utilization clamp composition
Task-specific minimum clampApply cgroup cpu.uclamp.min protectionCap by current cpu.uclamp.maxEffective minimum utilization
Task-specific maximum clampApply cgroup cpu.uclamp.max limitEffective maximum utilization

Cgroup clamp가 task-specific request와 결합되고 minimum은 maximum을 넘지 못합니다.

`cpu.idle`은 non-root cgroup의 read/write single-value file이고 default는 `0`입니다. 이는 per-task `SCHED_IDLE` scheduling policy의 cgroup analog입니다.

`1`로 설정하면 cgroup scheduling policy가 `SCHED_IDLE`이 됩니다. Cgroup 내부 thread는 서로 간의 relative priority를 유지하지만 cgroup 자체는 peer보다 매우 낮은 priority로 취급됩니다. Fair-class scheduler process에만 영향을 줍니다.

CPU utilization and idle controls
FileDefaultValue semanticsScope
cpu.uclamp.min0Minimum utilization percentage; no boosting at 0All processes including realtime
cpu.uclamp.maxmaxMaximum utilization percentage; no capping at maxAll processes including realtime
cpu.idle01 makes cgroup SCHED_IDLEFair-class processes

세 file의 default, 표현과 process 범위입니다.

Stateful Memory controller 개요

1269-1291

`memory` controller는 memory distribution을 조절합니다. Memory는 stateful resource이며 limit model과 protection model을 모두 구현합니다.

Memory usage와 reclaim pressure가 서로 얽혀 있고 memory 자체가 stateful이므로 distribution model은 비교적 복잡합니다.

Stateful memory distribution
Track cgroup memory ownership and usageApply protection modelApply configured limitsReact to reclaim pressureAccount resulting state over time

사용량을 추적하고 protection·limit·reclaim을 함께 적용하는 관계입니다.

완전히 빈틈없는 coverage는 아니지만 given cgroup의 주요 memory usage를 모두 추적하여 total memory consumption을 합리적인 수준까지 account하고 control합니다.

현재 추적하는 memory usage type은 userland page cache와 anonymous memory, dentry와 inode 같은 kernel data structure, TCP socket buffer입니다. 더 나은 coverage를 위해 이 목록은 향후 늘어날 수 있습니다.

Tracked memory usage
Usage classExamples
Userland memoryPage cache and anonymous memory
Kernel data structuresDentries and inodes
Network memoryTCP socket buffers

현재 memory controller accounting 대상입니다.

memory.current, min과 low protection

1292-1354

모든 memory amount unit은 byte입니다. `PAGE_SIZE`에 align되지 않은 값을 쓰면 readback에서 가장 가까운 `PAGE_SIZE` multiple로 올림될 수 있습니다.

`memory.current`는 non-root cgroup의 read-only single-value file로, 해당 cgroup과 descendant가 현재 사용하는 total memory amount를 보여 줍니다.

`memory.min`은 non-root cgroup의 read/write single-value file이고 default는 `0`입니다. 이는 hard memory protection입니다.

Cgroup usage가 effective min boundary 안에 있으면 어떤 조건에서도 그 memory를 reclaim하지 않습니다. Unprotected reclaimable memory가 없으면 OOM killer를 invoke합니다.

Effective min boundary, 또는 더 높다면 effective low boundary보다 위의 page는 boundary 초과량에 비례해 reclaim됩니다. 초과량이 작을수록 reclaim pressure도 줄어듭니다.

Effective min boundary는 모든 ancestor cgroup의 `memory.min`으로 제한됩니다. Child가 parent 허용량보다 더 많은 protected memory를 요구해 overcommit되면, 각 child는 자기 `memory.min` 아래 actual usage 비율에 따라 parent protection 일부를 받습니다.

일반적으로 available한 양보다 많은 memory를 이 protection 아래 두는 것은 권장하지 않으며 constant OOM을 일으킬 수 있습니다. Process가 populate하지 않은 memory cgroup의 `memory.min`은 무시됩니다.

`memory.low`는 non-root cgroup의 read/write single-value file이고 default `0`이며 best-effort memory protection을 제공합니다.

Usage가 effective low boundary 안에 있으면 unprotected cgroup에 reclaimable memory가 전혀 없는 경우에만 이 cgroup의 memory를 reclaim합니다. Effective low boundary, 또는 더 높다면 effective min boundary보다 위의 page는 초과량에 비례해 reclaim합니다.

Effective low boundary도 모든 ancestor의 `memory.low`로 제한됩니다. Overcommit이면 child의 `memory.low` 아래 actual usage 비율에 따라 parent protection을 나눕니다. 일반 available memory보다 큰 protection을 설정하는 것은 권장하지 않습니다.

Memory protection interfaces
FileDefaultProtectionWhen protected memory is reclaimed
memory.min0HardNever inside effective min; OOM if no unprotected reclaimable memory
memory.low0Best effortOnly when no reclaimable memory remains in unprotected cgroups

Hard min과 best-effort low의 reclaim·OOM 차이입니다.

Hierarchical memory protection
Read child configured min/lowCap by every ancestor boundaryCheck parent protection overcommitNo overcommit: effective configured protection
Children request more than parent allowsMeasure actual usage below each child boundaryDivide parent protection proportionallyApply effective protection

Ancestor cap과 overcommit 시 proportional sharing을 적용합니다.

memory.high와 memory.max

1355-1409

`memory.high`는 non-root cgroup의 read/write single-value file이며 default는 `max`입니다. Memory usage throttle limit으로, usage가 high boundary를 넘으면 cgroup process를 throttle하고 heavy reclaim pressure에 둡니다.

High limit 초과는 OOM killer를 invoke하지 않으며 extreme condition에서는 limit을 넘은 상태가 허용될 수 있습니다. 이 limit은 external process가 제한된 cgroup을 monitor하면서 heavy reclaim pressure를 완화하는 scenario에 사용해야 합니다.

`memory.high`를 `O_NONBLOCK`으로 open하면 synchronous reclaim을 bypass합니다. Admin process가 자기 CPU resource를 memory reclaim에 쓰지 않고 job memory limit을 동적으로 조정할 때 유용합니다. Job의 다음 charge request가 reclaim을 trigger하거나 throttle됩니다.

`O_NONBLOCK`에서는 charge request가 지연되거나 target이 memory를 계속 바쁘게 touch해 reclaim이 느려지면 usage가 limit 아래로 내려가는 데 무한히 오래 걸릴 수 있습니다.

`memory.max`는 non-root cgroup의 read/write single-value file이며 default `max`입니다. Cgroup memory usage를 제한하는 주 mechanism인 hard limit입니다.

Usage가 limit에 닿고 줄일 수 없으면 해당 cgroup에서 OOM killer를 invoke합니다. 특정 상황에서는 usage가 일시적으로 limit을 넘을 수 있습니다.

Default configuration에서 일반 0-order allocation은 OOM killer가 current task를 victim으로 선택하지 않는 한 항상 성공합니다. 일부 allocation은 OOM killer를 invoke하지 않으며 caller가 다른 방식으로 retry하거나 `-ENOMEM`을 userspace에 반환하거나 disk readahead처럼 조용히 무시할 수 있습니다.

`memory.max`를 `O_NONBLOCK`으로 open하면 synchronous reclaim과 OOM kill을 모두 bypass합니다. Admin process 대신 job의 다음 charge request가 reclaim 또는 OOM kill을 trigger합니다. Charge가 지연되거나 reclaim이 느리면 usage 감소가 무기한 늦어질 수 있습니다.

Memory throttle and hard limits
FileDefaultEnforcementOOM behavior
memory.highmaxThrottle processes and apply heavy reclaim pressureNever invokes OOM killer
memory.maxmaxHard usage limit with reclaimInvokes cgroup OOM if usage cannot be reduced

High와 max boundary의 enforcement와 OOM behavior입니다.

O_NONBLOCK limit update
Admin opens memory.high with O_NONBLOCKUpdate limit without synchronous reclaimJob next chargeTrigger reclaim and/or throttle
Admin opens memory.max with O_NONBLOCKUpdate limit without synchronous reclaim or OOM killJob next chargeTrigger reclaim and/or OOM kill

Admin write에서 synchronous work를 피하고 target job의 next charge로 넘깁니다.

Proactive reclaim과 peak usage

1410-1454

`memory.reclaim`은 모든 cgroup에 있는 write-only nested-keyed file로 target cgroup의 memory reclaim을 trigger하는 단순 interface입니다.

	  echo "1G" > memory.reclaim

Kernel은 지정한 양보다 많이 또는 적게 reclaim할 수 있습니다. Reclaim한 byte가 지정량보다 적으면 `-EAGAIN`을 반환합니다.

이 interface가 trigger하는 proactive reclaim은 memory cgroup에 memory pressure가 있다는 신호가 아닙니다. 따라서 일반 memory reclaim에서 동작하는 socket-memory balancing은 보통 수행하지 않으며 networking layer도 `memory.reclaim`에 의한 reclaim을 보고 적응하지 않습니다.

Nested key `swappiness`는 reclaim에 사용할 swappiness value를 지정합니다. `vm.swappiness`를 memcg reclaim에 적용한 것과 같은 semantics와 기존 limitation 및 향후 extension을 가집니다.

Valid range는 `[0-200, max]`이고 `swappiness=max`는 anonymous memory만 exclusive하게 reclaim합니다.

memory.reclaim operation
Write amount and optional swappinessTrigger proactive memcg reclaimKernel may over- or under-reclaimActual < requested: return -EAGAIN
Proactive reclaimDoes not signal ordinary memory pressureSkip normal socket-memory balancing responseNetworking layer does not adapt

Requested byte와 actual reclaim 결과 및 networking exception입니다.

memory.reclaim swappiness
KeyRangeSpecial behavior
swappiness[0-200, max]max exclusively reclaims anonymous memory

Nested key의 범위와 special value입니다.

`memory.peak`는 non-root cgroup에 있는 read/write single-value file입니다. Cgroup 생성 또는 해당 FD에서 가장 최근 reset 이후 cgroup과 descendant가 기록한 maximum memory usage입니다.

비어 있지 않은 어떤 문자열이든 이 file에 쓰면 같은 file descriptor를 통한 이후 read에 대해 current memory usage로 reset됩니다.

memory.peak reset scope
OperationResult
ReadCreation 또는 this FD의 latest reset 이후 descendant-inclusive maximum
Write any non-empty stringReset subsequent reads through same FD to current usage baseline

Reset은 file descriptor별 read state에 적용됩니다.

OOM group과 memory event counters

1455-1522

`memory.oom.group`은 non-root cgroup의 read/write single-value file이며 default `0`입니다. 설정하면 OOM killer가 cgroup을 indivisible workload로 취급합니다.

해당 cgroup과, leaf가 아니라면 descendant에 속한 모든 task를 함께 kill하거나 전혀 kill하지 않습니다. Partial kill을 방지해 workload integrity를 보장할 수 있습니다.

`oom_score_adj`가 `-1000`인 OOM-protected task는 예외로 절대 kill하지 않습니다. 어떤 cgroup에서 OOM killer가 invoke되면 ancestor의 `memory.oom.group` 값과 관계없이 그 cgroup 밖 task를 kill하지 않습니다.

Group OOM decision
Cgroup enters OOMmemory.oom.group enabledSelect cgroup and descendant workload as one unitExclude tasks with oom_score_adj=-1000Kill all remaining tasks together or none
Cgroup-local OOM killerNever select tasks outside invoking cgroup

Workload integrity와 protected-task exception을 함께 적용합니다.

`memory.events`는 non-root cgroup의 read-only flat-keyed file입니다. 별도 설명이 없으면 value change가 file-modified event를 생성합니다.

모든 field는 hierarchical하므로 hierarchy 아래의 event 때문에 current file notification이 발생할 수 있습니다. Cgroup level의 local event는 `memory.events.local`을 사용합니다.

memory.events counters
CounterCounted event
lowUsage가 low boundary 아래인데 high pressure로 reclaim된 횟수; 보통 low overcommit을 나타냄
highHigh boundary 초과로 process가 throttle되고 direct reclaim을 수행한 횟수
maxUsage가 max boundary를 넘기 직전이었던 횟수; direct reclaim 실패 시 OOM
oomUsage가 limit에 닿아 allocation이 실패하기 직전이었던 횟수
oom_kill어떤 종류의 OOM killer든 이 cgroup 소속 process를 kill한 수
oom_group_killGroup OOM이 발생한 횟수

Protection, throttle, limit과 OOM event의 의미입니다.

`low`는 low boundary 아래인데도 high memory pressure로 reclaim된 횟수이며 대개 low boundary overcommit을 뜻합니다.

`high`는 high boundary 초과로 process가 throttle되고 direct memory reclaim을 수행한 횟수입니다. Global pressure가 아니라 high limit이 usage를 cap하는 cgroup에서는 이 event가 발생하는 것이 정상입니다.

`max`는 usage가 max boundary를 넘으려 한 횟수이며 direct reclaim으로 줄이지 못하면 OOM state로 갑니다. `oom`은 usage가 limit에 닿아 allocation이 실패하기 직전이었던 횟수입니다.

High-order allocation failure나 caller가 retry하지 말라고 요청한 경우처럼 OOM killer를 option으로 고려하지 않으면 `oom` event는 발생하지 않습니다.

`oom_kill`은 어떤 종류의 OOM killer든 이 cgroup 소속 process를 kill한 수이고 `oom_group_kill`은 group OOM이 발생한 횟수입니다.

`memory.events.local`은 `memory.events`와 비슷하지만 field가 hierarchical하지 않고 해당 cgroup local event만 담습니다. 이 file의 modified event도 local event만 반영합니다.

Hierarchical and local memory events
FileCounter scopeModified event source
memory.eventsCurrent cgroup plus descendantsAny subtree event
memory.events.localCurrent cgroup onlyLocal event only

두 event file의 propagation 범위입니다.

memory.stat footprint, LRU와 slab counters

1523-1638

`memory.stat`은 non-root cgroup에 존재하는 read-only flat-keyed file입니다. Cgroup memory footprint를 memory type, type별 detail, memory-management system의 current state와 past event로 분해합니다. 모든 memory amount unit은 byte입니다.

Entry는 사람이 읽기 좋은 순서로 배치되지만 새 entry가 중간에 추가될 수 있습니다. Item의 fixed position에 의존하지 말고 반드시 key로 specific value를 찾으십시오.

Per-node counter가 없거나 `memory.numa_stat`에 나타나지 않는 entry에는 `npn`(non-per-node) tag를 붙입니다.

memory.stat primary footprint counters
CounternpnMeaning
anonNobrk(), sbrk(), mmap(MAP_ANONYMOUS) 같은 anonymous mapping; 일부 THP configuration은 일부만 mapped여도 큰 allocation 전체를 account할 수 있음
fileNotmpfs와 shared memory를 포함한 filesystem data cache
kernelYeskernel_stack, pagetables, percpu, vmalloc, slab 및 기타 kernel memory total
kernel_stackNoKernel stack allocation
pagetablesNoPage table allocation
sec_pagetablesNoSecondary page table; x86/arm64 KVM MMU allocation과 IOMMU page table 포함
percpuYesPer-CPU kernel data structure
sockYesNetwork transmission buffer
vmallocYesvmap-backed memory

Anonymous, file과 kernel memory의 기본 분류입니다.

Cached, zswap and mapped-file counters
CounterMeaning
shmemtmpfs, shm segment, shared anonymous mmap() 같은 swap-backed cached filesystem data
zswapZswap compression backend가 소비한 memory
zswappedZswap으로 swap out된 application memory
file_mappedmmap()된 cached filesystem data; 일부 THP configuration은 큰 allocation 전체를 account할 수 있음
file_dirty수정됐지만 disk에 아직 writeback되지 않은 cached data
file_writeback현재 disk로 writeback 중인 modified cached data
swapcachedMemory에 cache된 swap; memory usage와 swap usage 양쪽에 account

Swap-backed cache, zswap와 file mapping/writeback 상태입니다.

Transparent-hugepage footprint
CounterMeaning
anon_thpTransparent hugepage-backed anonymous mapping
file_thpTransparent hugepage-backed cached filesystem data
shmem_thpTransparent hugepage-backed shm, tmpfs, shared anonymous mmap()

Anonymous, file과 shmem의 THP-backed usage입니다.

`inactive_anon`, `active_anon`, `inactive_file`, `active_file`, `unevictable`은 page-reclaim algorithm이 사용하는 internal memory-management list에 있는 swap-backed 및 filesystem-backed memory amount입니다.

이 값은 type이 아니라 internal list state를 나타냅니다. 예를 들어 shmem page도 anon management list에 있으므로 `inactive_foo + active_foo`가 type-based `foo` counter와 같지 않을 수 있습니다.

LRU and slab counters
CounterMeaning
inactive_anon, active_anonAnonymous-side internal reclaim list memory
inactive_file, active_fileFile-side internal reclaim list memory
unevictableInternal unevictable-list memory
slab_reclaimableDentry와 inode처럼 reclaim할 수 있는 slab 일부
slab_unreclaimableMemory pressure에도 reclaim할 수 없는 slab 일부
slab (npn)In-kernel data structure를 저장하는 total memory

Internal reclaim list와 kernel object cache 상태입니다.

Workingset, reclaim와 page-event counters

1639-1718
Workingset counters
CounterMeaning
workingset_refault_anonPreviously evicted anonymous page refault 수
workingset_refault_filePreviously evicted file page refault 수
workingset_activate_anonRefault 직후 즉시 activate된 anonymous page 수
workingset_activate_fileRefault 직후 즉시 activate된 file page 수
workingset_restore_anonReclaim 전에 active workingset으로 판별되어 restore된 anonymous page 수
workingset_restore_fileReclaim 전에 active workingset으로 판별되어 restore된 file page 수
workingset_nodereclaimShadow node가 reclaim된 횟수

Evicted page의 refault·activation·restore와 shadow-node reclaim입니다.

Swap, scan and reclaim counters
CounternpnMeaning
pswpinYesMemory로 swap in된 page 수
pswpoutYesMemory 밖으로 swap out된 page 수
pgscanYesInactive LRU에서 scan한 page amount
pgstealYesReclaim한 page amount
pgscan_kswapdYeskswapd가 inactive LRU에서 scan
pgscan_directYesDirect inactive-LRU scan
pgscan_khugepagedYeskhugepaged inactive-LRU scan
pgscan_proactiveYesProactive inactive-LRU scan
pgsteal_kswapdYeskswapd가 reclaim
pgsteal_directYesDirect reclaim
pgsteal_khugepagedYeskhugepaged가 reclaim
pgsteal_proactiveYesProactive reclaim

Swap 이동과 inactive LRU scan/reclaim 주체를 구분합니다.

Page scan to reclaim accounting
Select inactive LRU pagesScan by kswapd/direct/khugepaged/proactive pathIncrement matching pgscan_*Reclaim succeedsIncrement matching pgsteal_*

Scanner별 pgscan과 successful reclaim pgsteal counter의 관계입니다.

Fault, refill and LRU transition counters
CounternpnMeaning
pgfaultYesTotal page fault 수
pgmajfaultYesMajor page fault 수
pgrefillYesActive LRU에서 scan한 page amount
pgactivateYesActive LRU로 옮긴 page amount
pgdeactivateYesInactive LRU로 옮긴 page amount
pglazyfreeYesMemory pressure 때 free하도록 postpone한 page amount
pglazyfreedYesReclaim된 lazyfree page amount

Page fault와 active/inactive LRU 이동 및 lazyfree입니다.

Zero swap, zswap, THP, NUMA와 demotion

1719-1783
Zero-page swap and zswap movement
CounterMeaning
swpin_zeroSwapout 때 content가 zero임을 알아 I/O를 생략했던 page를 zero-filled memory로 swap in한 수
swpout_zeroZero-filled content를 감지해 I/O 없이 swap out한 page 수
zswpinZswap에서 memory로 이동한 page 수
zswpoutMemory에서 zswap으로 이동한 page 수
zswpwbZswap에서 swap으로 write된 page 수

Zero detection으로 I/O를 생략한 swap과 zswap 이동 counter입니다.

Transparent-hugepage event counters
CounternpnMeaning
thp_fault_allocYesPage fault를 만족하기 위해 allocate한 THP 수; CONFIG_TRANSPARENT_HUGEPAGE가 없으면 counter도 없음
thp_collapse_allocYesExisting page range collapse를 위해 allocate한 THP 수; option이 없으면 counter도 없음
thp_swpoutYesSplit하지 않고 한 덩어리로 swap out한 THP 수
thp_swpout_fallbackYes주로 contiguous swap space allocation 실패로 swapout 전 split한 THP 수

`CONFIG_TRANSPARENT_HUGEPAGE`와 swapout 방식에 따른 counter입니다.

NUMA balancing and demotion counters
CounternpnMeaning
numa_pages_migratedYesNUMA balancing이 migrate한 page 수
numa_pte_updatesYesAccess 시 NUMA hinting fault를 만들도록 PTE를 수정한 page 수
numa_hint_faultsYesNUMA hinting fault 수
pgdemote_kswapdNokswapd가 demote한 page 수
pgdemote_directNoDirect path가 demote한 page 수
pgdemote_khugepagedNokhugepaged가 demote한 page 수
pgdemote_proactiveNoProactive path가 demote한 page 수

NUMA hinting과 reclaim path별 page demotion을 구분합니다.

`hugetlb`는 HugeTLB page가 사용하는 memory amount입니다. Cgroup을 `memory_hugetlb_accounting` option으로 mount해 HugeTLB usage가 `memory.current`에 account되는 경우에만 이 metric이 나타납니다.

Conditional hugetlb metric
Mount with memory_hugetlb_accountingCharge used HugeTLB pages to memory.currentExpose hugetlb amount in memory.stat
Mount without optionNo memory-controller HugeTLB accountingNo hugetlb metric in memory.stat

Mount option이 memory.current accounting과 memory.stat visibility를 함께 제어합니다.

NUMA locality와 swap interfaces

1784-1873

`memory.numa_stat`은 non-root cgroup의 read-only nested-keyed file입니다. Cgroup memory footprint를 memory type과 type별 detail로 나누고 memory-management state를 node별로 보여 줍니다.

Memcg page는 어느 physical node에서든 allocate될 수 있으므로 이 file은 memcg 안의 NUMA locality를 관찰하는 데 유용합니다. Application CPU allocation과 이 정보를 결합해 application performance를 평가하는 것이 use case 중 하나입니다.

모든 memory amount unit은 byte이며 output format은 다음과 같습니다.

	  type N0=<bytes in node 0> N1=<bytes in node 1> ...

Entry는 사람이 읽기 좋은 순서지만 중간에 새 entry가 추가될 수 있으므로 fixed position에 의존하지 말고 key로 찾으십시오. Entry는 `memory.stat` counter를 참조할 수 있습니다.

NUMA locality evaluation
Read memory.numa_stat by type and nodeRead application CPU allocationCompare memory nodes with execution CPUsEvaluate NUMA locality and performance

Node별 memory placement와 CPU placement를 함께 보아 workload locality를 평가합니다.

`memory.swap.current`는 non-root cgroup의 read-only single-value file로 cgroup과 descendant가 현재 사용하는 total swap amount를 보여 줍니다.

`memory.swap.high`는 non-root cgroup의 read/write single-value file이며 default `max`입니다. Swap usage가 이 throttle limit을 넘으면 userspace가 custom OOM procedure를 구현할 수 있도록 이후 모든 allocation을 throttle합니다.

이 limit은 cgroup의 point of no return을 표시하며 정상 operation 중 workload swapping amount를 관리하려는 용도가 아닙니다. Healthy workload는 이 limit에 닿지 않아야 합니다.

`memory.swap.peak`는 non-root cgroup의 read/write single-value file입니다. Cgroup 생성 또는 해당 FD의 latest reset 이후 cgroup과 descendant가 기록한 maximum swap usage입니다. Non-empty string을 쓰면 같은 FD의 이후 read 기준을 current memory usage로 reset합니다.

FD-local swap peak reset
Open memory.swap.peak as FD ARead peak since cgroup creation or FD A resetWrite any non-empty string through FD AReset FD A baseline to current swap usageFuture reads through FD A report peak since that reset
Read through another FDKeep that FD's independent peak baseline

Reset은 file 전체의 global state가 아니라 write에 사용한 file descriptor의 이후 read 기준만 바꿉니다.

`memory.swap.max`는 non-root cgroup의 read/write single-value file이며 default `max`입니다. Swap usage hard limit으로, usage가 이 값에 닿으면 cgroup의 anonymous memory를 더 이상 swap out하지 않습니다.

Swap usage interfaces
FileAccess / defaultMeaning
memory.swap.currentRead-onlyCgroup+descendant current swap usage
memory.swap.highRead/write; maxPoint-of-no-return throttle for custom userspace OOM
memory.swap.peakRead/write; FD-resettableCreation 또는 same-FD reset 이후 maximum usage
memory.swap.maxRead/write; maxHard limit preventing further anonymous swapout

Current, throttle, peak와 hard limit의 목적입니다.

`memory.swap.events`는 non-root cgroup의 read-only flat-keyed file입니다. 별도 설명이 없으면 value change가 file-modified event를 생성합니다.

memory.swap.events counters
CounterMeaning
highSwap usage가 high threshold를 넘은 횟수
maxUsage가 max boundary를 넘으려 해 swap allocation이 실패한 횟수
failSystem-wide swap 고갈 또는 max limit 때문에 allocation이 실패한 횟수

Swap high, max와 allocation failure를 구분합니다.

Limit을 current usage 아래로 낮추면 existing swap entry를 점진적으로 reclaim하므로 usage가 오랫동안 limit보다 높게 유지될 수 있습니다. 이는 workload와 memory management에 미치는 충격을 줄입니다.

Gradual convergence after lowering swap limit
Set swap limit below current usageBlock or constrain new swap allocationGradually reclaim existing swap entriesUsage may remain above limit for an extended periodEventually converge with lower workload impact

즉시 강제 회수하지 않고 existing entry를 서서히 줄입니다.

Zswap limit·writeback과 memory pressure

1874-1913

`memory.zswap.current`는 non-root cgroup의 read-only single-value file로 zswap compression backend가 소비하는 total memory amount를 보여 줍니다.

`memory.zswap.max`는 non-root cgroup의 read/write single-value file이며 default `max`입니다. Zswap usage hard limit으로, pool이 limit에 닿으면 existing entry가 fault back되거나 disk로 write될 때까지 새 store를 거부합니다.

`memory.zswap.writeback`은 read/write single-value file이고 default `1`입니다. 이 setting은 hierarchical하므로 upper hierarchy에서 writeback을 disable하면 child cgroup도 암묵적으로 disable됩니다.

`0`으로 설정하면 zswap writeback과 zswap store failure 때문에 발생하는 swapping을 포함해 swapping device로 향하는 모든 swap attempt를 disable합니다.

Page가 incompressible해서 zswap store failure가 반복되면 writeback을 disable한 뒤 같은 page가 계속 거부되어 reclaim inefficiency가 나타날 수 있습니다.

Hierarchical zswap writeback disable
Ancestor writes 0 to memory.zswap.writebackDisable ancestor zswap writebackImplicitly disable child writebackReject swapping-device attempts from zswap writeback/store failure
Repeated incompressible pagesRepeated zswap store rejectionPotential reclaim inefficiency

Ancestor setting이 descendant의 disk writeback 가능성을 제거합니다.

이는 `memory.swap.max=0`과 미묘하게 다릅니다. Writeback을 disable해도 page를 zswap pool에는 쓸 수 있습니다. Zswap이 disable되어 있으면 이 setting은 효과가 없고, `memory.swap.max=0`이 아닌 한 일반 swapping은 허용됩니다.

Zswap and swap controls compared
SettingZswap pool storesSwap-device writes
memory.zswap.writeback=0AllowedDisabled for writeback and zswap store failure
memory.swap.max=0Zswap pool may still be usedSwapping prohibited
Zswap disabledNot applicableAllowed unless memory.swap.max=0

Compressed pool 사용과 backing swap-device 사용을 분리합니다.

`memory.pressure`는 read-only nested-keyed file로 memory pressure stall information을 보여 줍니다. 자세한 내용은 `Documentation/accounting/psi.rst`의 `psi` reference를 참조하십시오.

Zswap and pressure interfaces
FileAccess / defaultPurpose
memory.zswap.currentRead-onlyCompression-backend memory
memory.zswap.maxRead/write; maxZswap-pool hard limit
memory.zswap.writebackRead/write; 1; hierarchicalBacking-device write permission
memory.pressureRead-only nested-keyedMemory PSI

Memory 후반 interface의 access와 default입니다.

Memory usage control guideline

1914-1937

`memory.high`는 memory usage를 control하는 주 mechanism입니다. High limit 합계가 available memory보다 큰 overcommit을 허용하고 global memory pressure가 usage에 따라 memory를 분배하도록 두는 것도 viable strategy입니다.

High limit breach는 OOM killer를 trigger하지 않고 offending cgroup을 throttle합니다. 따라서 management agent는 상태를 monitor하면서 memory를 더 주거나 workload를 terminate하는 적절한 action을 취할 기회가 충분합니다.

Managed memory.high strategy
Configure overcommitted memory.high valuesLet global pressure distribute by usageWorkload breaches high boundaryThrottle instead of OOM killManagement agent observes pressureGrant memory or terminate workload

High limit overcommit과 external agent의 remediation loop입니다.

Memory usage만으로 cgroup에 memory가 충분한지 판단하기는 쉽지 않습니다. Usage는 workload가 memory를 더 받으면 이익을 보는지 알려 주지 않기 때문입니다.

예를 들어 network에서 받은 data를 file에 쓰는 workload는 available memory를 모두 사용할 수 있지만 적은 memory로도 충분한 performance를 낼 수 있습니다.

Workload가 memory 부족으로 얼마나 영향받는지를 나타내는 memory pressure measure가 있어야 더 많은 memory가 필요한지 판단할 수 있습니다. 하지만 이 문서가 설명하는 memory-pressure monitoring mechanism은 아직 구현되지 않았습니다.

Memory sizing signals
SignalWhat it tellsLimitation
Memory usageCurrent footprintMore memory의 benefit 여부를 모름
Memory pressureLack of memory가 workload에 미치는 impactDocumented monitoring mechanism not yet implemented

Usage 자체와 pressure signal의 정보 차이입니다.

Memory area ownership과 migration

1938-1956

Memory area는 이를 instantiate한 cgroup에 charge되고 area가 release될 때까지 그 cgroup에 계속 charge됩니다. Process를 다른 cgroup으로 migrate해도 이전 cgroup에 있을 때 instantiate한 memory usage는 새 cgroup으로 이동하지 않습니다.

Memory charge persists across process migration
Process in cgroup A instantiates memory areaCharge area to cgroup AMigrate process to cgroup BArea remains charged to ARelease areaUncharge A

Process location과 memory-area owner는 독립적으로 유지됩니다.

하나의 memory area를 서로 다른 cgroup의 process가 사용할 수 있습니다. 이때 어느 cgroup에 charge될지는 deterministic하지 않습니다. 다만 시간이 지나면 high reclaim pressure를 피할 만큼 memory allowance가 충분한 cgroup에 area가 귀속될 가능성이 큽니다.

Shared memory ownership tendency
Processes in multiple cgroups access shared areaInitial charge owner is nondeterministicReclaim pressure acts on constrained ownerArea is released and instantiated againLikely settles in cgroup with sufficient allowance

여러 cgroup이 공유하는 area는 reclaim과 재사용을 거치며 여유가 있는 owner 쪽으로 수렴할 수 있습니다.

어떤 cgroup이 상당한 memory를 sweep하고 그 memory를 다른 cgroup이 반복 access할 것으로 예상된다면 `POSIX_FADV_DONTNEED`를 사용해 해당 file의 memory-area ownership을 relinquish하는 것이 올바른 ownership을 보장하는 데 도움이 될 수 있습니다.

Ownership correction case
SituationActionExpected result
Cgroup sweeps file memory later reused by peersCall POSIX_FADV_DONTNEED on affected filesRelinquish stale area ownership for future correct charging

File cache를 대량으로 먼저 touch한 cgroup이 ownership을 놓아야 하는 상황입니다.

IO controller와 io.stat

1957-1989

`io` controller는 IO resource의 distribution을 조절합니다. Weight 기반 distribution과 absolute bandwidth 또는 IOPS limit distribution을 모두 구현하지만, weight 기반 distribution은 `cfq-iosched`를 사용할 때만 제공되며 `blk-mq` device에서는 어느 방식도 제공되지 않습니다.

IO distribution schemes
SchemeControl basisAvailability
Weight-based distributionSibling 사이의 relative IO timecfq-iosched 사용 시에만 available
Absolute limit distributionBandwidth 또는 IOPS ceilingblk-mq device에서는 unavailable

원문이 설명하는 controller 방식과 availability constraint입니다.

`io.stat`은 read-only nested-keyed file입니다. 각 line은 `$MAJ:$MIN` device number를 key로 사용하며 순서는 정해져 있지 않습니다.

io.stat nested keys
KeyMeaning
rbytes읽은 byte 수
wbytes쓴 byte 수
riosRead IO 수
wiosWrite IO 수
dbytesDiscard한 byte 수
diosDiscard IO 수

Device별 read, write와 discard activity를 byte와 operation 수로 나눕니다.

`io.stat` read output 예시는 다음과 같습니다.

	  8:16 rbytes=1459200 wbytes=314773504 rios=192 wios=353 dbytes=0 dios=0
	  8:0 rbytes=90430464 wbytes=299008000 rios=8950 wios=1252 dbytes=50331648 dios=3021

IOCOST Quality of Service

1990-2044

`io.cost.qos`는 root cgroup에만 존재하는 read/write nested-keyed file입니다. 현재 `io.weight` proportional control을 구현하는 IO cost model 기반 controller(`CONFIG_BLK_CGROUP_IOCOST`)의 Quality of Service를 설정합니다.

Line은 `$MAJ:$MIN` device number를 key로 사용하며 순서가 없습니다. 특정 device의 line은 그 device에 대해 `io.cost.qos` 또는 `io.cost.model`에 처음 write할 때 채워집니다.

io.cost.qos nested keys
KeyMeaning / range
enableWeight-based control enable
ctrl`auto` 또는 `user`
rpctRead latency percentile [0, 100]
rlatRead latency threshold
wpctWrite latency percentile [0, 100]
wlatWrite latency threshold
minMinimum scaling percentage [1, 10000]
maxMaximum scaling percentage [1, 10000]

Controller enable, mode, latency QoS와 issue-rate scaling range를 구성합니다.

Controller는 default로 disable되어 있으며 `enable=1`로 enable합니다. `rpct`와 `wpct`의 default는 0이고, 이때 controller는 internal device saturation state를 사용해 overall IO rate를 `min`과 `max` 사이에서 조절합니다.

더 나은 control quality가 필요하면 latency QoS parameter를 설정할 수 있습니다. 다음 예시는 sdb에 해당하는 device `8:16` 설정입니다.

	  8:16 enable=1 ctrl=auto rpct=95.00 rlat=75000 wpct=95.00 wlat=150000 min=50.00 max=150.0

이 설정은 controller를 enable하고, read completion latency의 95th percentile이 75 ms를 넘거나 write latency의 95th percentile이 150 ms를 넘으면 device가 saturated되었다고 판단합니다. 그 결과 overall IO issue rate를 50%에서 150% 사이에서 조절합니다.

Latency QoS feedback loop
Collect read and write completion latencyEvaluate configured percentilesCompare with rlat and wlat thresholdsDetect device saturationScale IO issue rate between min and max

Percentile latency로 saturation을 판단하고 허용 범위에서 issue rate를 조절합니다.

Saturation point를 낮출수록 aggregate bandwidth를 희생하는 대신 latency QoS가 좋아집니다. `min`과 `max` 사이 adjustment range를 좁힐수록 IO behavior가 cost model에 더 잘 맞습니다.

IO issue base rate는 100%와 크게 다를 수 있으므로 `min`과 `max`를 근거 없이 설정하면 device capacity 또는 control quality를 크게 잃을 수 있습니다. 이 두 값은 잠시 line speed로 write를 받다가 수초 동안 완전히 stall하는 SSD처럼 temporary behavior change 폭이 큰 device를 조절하는 데 유용합니다.

QoS tuning trade-offs
TuningBenefitCost / risk
Lower saturation pointBetter latency QoSLower aggregate bandwidth
Narrower min-max rangeBehavior conforms more closely to cost modelMay lose capacity or control quality if base rate is misjudged
Wide adaptive rangeTracks large temporary device changesLess tightly bound to static model

Threshold와 scaling range가 latency, bandwidth와 model conformity에 미치는 영향입니다.

`ctrl=auto`이면 kernel이 parameter를 control하며 자동으로 바꿀 수 있습니다. `ctrl=user`를 설정하거나 percentile·latency parameter 중 하나라도 설정하면 `user` mode로 전환되어 automatic change가 disable됩니다. `ctrl=auto`를 쓰면 automatic mode로 복원됩니다.

IOCOST QoS control mode
ctrl=autoKernel may tune parameters dynamicallyWrite ctrl=user or any percentile/latency parameterEnter user modeDisable automatic changes
User modeWrite ctrl=autoRestore automatic mode

Parameter write가 automatic tuning을 user-managed tuning으로 전환합니다.

IOCOST linear cost model

2045-2086

`io.cost.model`은 root cgroup에만 존재하는 read/write nested-keyed file입니다. 현재 `io.weight` proportional control을 구현하는 IO cost model 기반 controller(`CONFIG_BLK_CGROUP_IOCOST`)의 cost model을 설정합니다.

Line은 순서 없는 `$MAJ:$MIN` device key로 구성됩니다. 특정 device line은 `io.cost.qos` 또는 `io.cost.model`에 그 device를 처음 write할 때 생성됩니다.

io.cost.model base keys
KeyMeaning
ctrl`auto` 또는 `user`
model사용 중인 cost model, 현재 `linear`

Model control mode와 사용 중인 model type입니다.

`ctrl=auto`이면 kernel이 모든 parameter를 dynamic하게 바꿀 수 있습니다. `ctrl=user`를 설정하거나 다른 parameter를 write하면 `ctrl`이 `user`가 되고 automatic change가 disable됩니다.

Linear model parameters
ParameterMeaning
[r|w]bpsMaximum sequential IO throughput
[r|w]seqiopsMaximum 4 KiB sequential IOs per second
[r|w]randiopsMaximum 4 KiB random IOs per second

`[r|w]`는 read와 write 각각에 대응하며 4 KiB IO 특성을 사용합니다.

Builtin linear model은 이 값들로 sequential·random IO의 base cost와 IO size에 대한 cost coefficient를 결정합니다. 단순한 model이지만 대부분의 일반적인 device class를 충분히 다룰 수 있습니다.

IO cost model은 absolute하게 정확할 것으로 기대하지 않으며 device behavior에 맞춰 dynamic하게 scale됩니다. 필요하면 `tools/cgroup/iocost_coef_gen.py`로 device-specific coefficient를 생성할 수 있습니다.

Linear cost derivation
Provide throughput and 4 KiB IOPS parametersDerive sequential and random base costsDerive IO-size cost coefficientScale model to observed device behavior
Need device-specific coefficientsRun tools/cgroup/iocost_coef_gen.pyUse generated model parameters

Measured device limits에서 IO cost를 만들고 runtime behavior에 맞춰 scale합니다.

Device별 proportional IO weight

2087-2106

`io.weight`는 non-root cgroup에 존재하는 read/write flat-keyed file이며 default는 `default 100`입니다.

첫 line은 specific override가 없는 device에 적용할 default weight입니다. 나머지 line은 순서 없는 `$MAJ:$MIN` device override입니다. Weight 범위는 [1, 10000]이며 sibling과 비교해 cgroup이 사용할 수 있는 relative IO time을 지정합니다.

io.weight write forms
OperationWrite form
Set default`default $WEIGHT` 또는 `$WEIGHT`
Set device override`$MAJ:$MIN $WEIGHT`
Remove device override`$MAJ:$MIN default`

Default와 device-specific override를 설정하고 해제하는 형식입니다.

`io.weight` read output 예시는 다음과 같습니다.

	  default 100
	  8:16 200
	  8:0 50
Weight lookup and allocation
IO request targets deviceLook up $MAJ:$MIN overrideOverride existsUse device-specific weightAllocate relative IO time among siblings
No overrideUse default weightAllocate relative IO time among siblings

Device override가 있으면 우선 사용하고, 없으면 default를 sibling-relative share로 적용합니다.

Absolute IO limit와 pressure

2107-2152

`io.max`는 non-root cgroup에 존재하는 read/write nested-keyed file입니다. BPS와 IOPS 기반 IO limit을 설정하며 line은 순서 없는 `$MAJ:$MIN` device key를 사용합니다.

io.max nested keys
KeyMeaning
rbpsMaximum read bytes per second
wbpsMaximum write bytes per second
riopsMaximum read IO operations per second
wiopsMaximum write IO operations per second

Read와 write 방향별 byte-rate·operation-rate ceiling입니다.

Write할 때 nested key-value pair를 원하는 수만큼 임의 순서로 지정할 수 있습니다. 특정 limit을 제거하려면 value로 `max`를 지정합니다. 같은 key를 여러 번 지정한 결과는 undefined입니다.

BPS와 IOPS는 IO direction별로 측정하며 limit에 도달하면 IO를 delay합니다. Temporary burst는 허용됩니다.

Device `8:16`의 read limit을 2 MiB/s BPS로, write limit을 120 IOPS로 설정합니다.

	  echo "8:16 rbps=2097152 wiops=120" > io.max

Read하면 다음과 같이 설정하지 않은 limit은 `max`로 나타납니다.

	  8:16 rbps=2097152 wbps=max riops=max wiops=120

Write IOPS limit은 다음 write로 제거할 수 있습니다.

	  echo "8:16 wiops=max" > io.max

이후 read output은 다음과 같습니다.

	  8:16 rbps=2097152 wbps=max riops=max wiops=max
io.max enforcement
Issue IO on a deviceClassify read or write directionMeasure BPS and IOPSAllow temporary burstReach configured limitDelay IO
Write key=maxRemove that specific limit

Direction별 rate를 측정하고 burst를 허용하면서 초과 IO를 지연합니다.

`io.pressure`는 read-only nested-keyed file로 IO pressure stall information을 보여 줍니다. 자세한 내용은 `Documentation/accounting/psi.rst`의 `psi` reference를 참조하십시오.

Page-cache writeback domain과 attribution

2153-2186

Page cache는 buffered write와 shared mmap을 통해 dirty 상태가 되고, writeback mechanism이 이를 backing filesystem에 asynchronous하게 씁니다. Writeback은 memory domain과 IO domain 사이에서 dirtying과 write IO의 균형을 맞춰 dirty memory 비율을 조절합니다.

Page-cache writeback path
Buffered write or shared mmapDirty page cacheWriteback balances dirtying and write IOAsynchronously write to backing filesystem

Dirtying 속도와 backing IO를 조정해 dirty-memory proportion을 유지합니다.

`io` controller는 memory controller와 함께 page-cache writeback IO를 control합니다. Memory controller는 dirty memory ratio를 계산하고 유지할 memory domain을 정의하고, IO controller는 그 memory domain의 dirty page를 write out할 IO domain을 정의합니다.

System-wide dirty-memory state와 per-cgroup state를 모두 검사하며 둘 중 더 restrictive한 조건을 enforce합니다.

Writeback control domains
LayerRole
Memory controllerDefines memory domain for dirty-memory ratio calculation and maintenance
IO controllerDefines IO domain that writes dirty pages for that memory domain
Effective enforcementMore restrictive of system-wide and per-cgroup dirty states

Memory accounting 범위와 write attribution 범위를 서로 다른 controller가 담당합니다.

Cgroup writeback에는 underlying filesystem의 explicit support가 필요합니다. 현재 `ext2`, `ext4`, `btrfs`, `f2fs`, `xfs`가 지원합니다. 그 밖의 filesystem에서는 모든 writeback IO가 root cgroup에 귀속됩니다.

Filesystem writeback attribution
Filesystem supportAttribution
ext2, ext4, btrfs, f2fs, xfsPer-cgroup writeback supported
Other filesystemsAll writeback IO attributed to root cgroup

Filesystem support 여부가 per-cgroup attribution 가능성을 결정합니다.

Memory와 writeback management는 ownership 추적 단위가 본질적으로 다릅니다. Memory는 page별로 추적하지만 writeback은 inode별로 추적합니다. Writeback에서는 inode 하나를 cgroup에 assign하고, 그 inode의 dirty page를 쓰는 모든 IO request를 해당 cgroup에 귀속합니다.

Page ownership cgroup이 inode ownership cgroup과 다른 page를 `foreign pages`라고 합니다. Writeback은 foreign page를 계속 추적하고 특정 foreign cgroup이 일정 기간 majority가 되면 inode ownership을 그 cgroup으로 전환합니다.

Foreign-page ownership switch
Track memory ownership per pageTrack writeback ownership per inodeDetect pages owned by another cgroupCount them as foreign pagesForeign cgroup remains majority over timeSwitch inode ownership to that cgroup

Per-page memory ownership과 per-inode writeback ownership의 차이를 majority tracking으로 보정합니다.

Concurrent writer limitation과 dirty sysctl

2187-2212

한 inode를 주로 하나의 cgroup이 dirty하는 일반적인 use case에서는 main writer cgroup이 시간에 따라 바뀌더라도 이 model로 충분합니다. 그러나 여러 cgroup이 하나의 inode를 동시에 write하는 use case는 잘 지원되지 않아 IO의 상당 부분이 잘못 귀속될 수 있습니다.

Memory controller는 첫 사용 시 page ownership을 정한 뒤 page가 release될 때까지 갱신하지 않습니다. 따라서 writeback이 page ownership을 엄격히 따르더라도 여러 cgroup이 겹치는 영역을 dirty하는 패턴은 예상대로 동작하지 않습니다. 이런 usage pattern은 피하는 것이 좋습니다.

Writeback ownership suitability
PatternExpected behavior
One cgroup mostly dirties an inodeSupported well, including ownership changes over time
Multiple cgroups concurrently dirty one inodeSignificant IO may be attributed incorrectly; avoid this pattern
Multiple cgroups dirty overlapping page rangesPer-page first-use ownership also prevents expected attribution

Writer pattern에 따른 inode-based attribution의 정확도입니다.

Writeback behavior에 영향을 주는 sysctl knob는 cgroup writeback에 다음과 같이 적용됩니다.

Dirty-memory sysctl application
KnobCgroup writeback behavior
vm.dirty_background_ratio, vm.dirty_ratioMemory-controller limit와 system-wide clean memory로 available memory를 cap한 뒤 같은 ratio 적용
vm.dirty_background_bytes, vm.dirty_bytesTotal available memory에 대한 ratio로 환산한 뒤 vm.dirty[_background]_ratio와 같은 방식으로 적용

System knob를 cgroup별 available-memory 범위에 맞춰 적용합니다.

IO Latency protection hierarchy

2213-2239

IO Latency는 IO workload를 보호하는 cgroup v2 controller입니다. Group에 latency target을 지정하면 average latency가 target을 넘을 때 controller가 protected workload보다 낮은 priority, 즉 더 높은 latency target을 가진 peer를 throttle합니다.

Limit은 hierarchy에서 peer level에만 적용됩니다. 원문 구조에서 A·B·C는 서로에게 영향을 주고, A 아래의 D·F도 서로에게 영향을 줍니다. C 아래에 sibling이 없는 G는 어느 group에도 영향을 주지 않습니다.

Peer-only IO latency hierarchy
rootAD
rootAF
rootB
rootCG
Peer set: A, B, CA, B, C influence one another
Peer set: D, FD and F influence one another
Peer set under C: G onlyG influences nobody

원문의 ASCII hierarchy를 sibling influence group과 parent-child 관계가 보이도록 재구성했습니다.

따라서 이상적인 구성은 A, B, C에 `io.latency`를 설정하는 것입니다. 일반적으로 device가 지원하는 latency보다 낮은 값을 설정해서는 안 되며 workload에 맞는 값을 experiment로 찾아야 합니다.

먼저 device의 expected latency보다 높은 값으로 시작하고 workload group의 `io.stat`에서 `avg_lat`를 관찰해 normal operation latency를 파악합니다. 실제 target은 이 `avg_lat`를 기준으로 10~15% 높게 설정합니다.

Latency target calibration
Start above expected device latencyRun representative workloadObserve avg_lat in io.statEstablish normal-operation latencySet io.latency target 10-15% above avg_lat

Device capability와 observed workload latency에서 안전한 target을 찾는 절차입니다.

IO latency throttling과 recovery

2240-2265

`io.latency`는 work-conserving 방식입니다. 모든 group이 latency target을 만족하는 동안 controller는 개입하지 않습니다. 한 group이 target을 놓치기 시작하면 그 group보다 높은 target을 가진 peer group을 throttle합니다.

Work-conserving latency protection
All peers meet latency targetsController stays inactiveA protected group misses its targetFind peers with higher latency targetsThrottle those peers

Target miss가 생길 때에만 lower-priority peer의 IO를 제한합니다.

Throttle은 다음 두 형태로 이루어집니다.

IO latency throttle mechanisms
MechanismOperation
Queue depth throttling허용 outstanding IO 수를 no limit에서 빠르게 줄여 최저 한 번에 1 IO까지 clamp
Artificial delay inductionSwapping·metadata IO는 정상 수행하되 originating group에 charge하고 그 group process에 delay 추가

일반 IO와 직접 제한하기 어려운 IO를 서로 다른 방식으로 제어합니다.

Queue depth throttling은 group이 보유할 수 있는 outstanding IO 수를 제한합니다. No limit에서 시작해 비교적 빠르게 줄이며 최종적으로 한 번에 1 IO까지 clamp할 수 있습니다.

Swapping과 metadata IO처럼 throttle하면 higher-priority group에 악영향을 줄 수 있는 IO는 정상적으로 수행하도록 허용하지만 originating group에 charge합니다. 해당 group이 throttle 중이면 `io.stat`의 `use_delay`와 `delay`가 증가합니다.

`delay`는 이 group에서 실행되는 각 process에 추가되는 microsecond 수입니다. Swapping 또는 metadata IO가 많으면 값이 크게 늘 수 있으므로 individual delay event는 한 번에 1초로 제한합니다.

피해를 받은 group이 다시 latency target을 만족하면 이전에 throttle된 peer를 unthrottle하기 시작합니다. 피해 group이 IO를 완전히 멈춰도 global counter가 그에 맞게 unthrottle합니다.

Latency recovery
Protected group meets target againBegin unthrottling affected peersRestore peer IO capacity
Protected group stops IOGlobal counter observes inactivityUnthrottle peers appropriately

Protected workload가 회복하거나 idle해지면 peer restriction을 해제합니다.

IO Latency interface files

2266-2291

`io.latency`는 다른 controller와 비슷한 형식을 사용하며 device와 target time을 microsecond 단위로 지정합니다.

		"MAJOR:MINOR target=<target time in microseconds>"

Controller가 enable되면 `io.stat`에 일반 statistic과 함께 아래 field가 추가됩니다.

IO latency statistics
FieldMeaning
depthGroup의 current queue depth
avg_latSampling interval로 bound되고 decay rate가 1/exp인 exponential moving average
winMillisecond 단위 sampling window이며 evaluation event 사이 minimum duration

현재 queue restriction, smoothed latency와 evaluation window를 노출합니다.

`avg_lat`의 decay-rate interval은 `io.stat`의 `win` 값에 해당 `win` 값에 따른 sample 수를 곱해 계산할 수 있습니다.

`win` window는 IO activity가 있을 때만 경과합니다. Idle period는 가장 최근 window를 연장합니다.

I/O priority cgroup policies

2292-2319

I/O priority cgroup policy 동작은 단일 attribute인 `io.prio.class`가 control합니다. 이 attribute가 받는 값은 다음과 같습니다.

io.prio.class policy values
PolicyBehavior
no-changeI/O priority class를 수정하지 않음
promote-to-rtNon-RT request를 RT로 바꾸고 priority level을 4로 변경; 이미 RT인 request는 수정하지 않음
restrict-to-beClass가 없거나 RT인 request를 BE level 0으로 변경; IDLE request는 수정하지 않음
idle모든 request를 가장 낮은 I/O priority class인 IDLE로 변경
none-to-rtDeprecated; promote-to-rt의 alias

Request의 기존 I/O priority class를 유지하거나 RT, BE, IDLE 방향으로 제한합니다.

I/O priority numeric mapping과 변환

2320-2353

I/O priority policy에 연결되는 numerical value는 다음과 같습니다. Deprecated alias인 `none-to-rt`는 `promote-to-rt`와 같은 동작을 가리킵니다.

I/O priority policy numbers
PolicyNumber
no-change0
promote-to-rt1
restrict-to-be2
idle3

원문의 ASCII 표를 동일한 mapping의 구조화 표로 옮겼습니다.

각 I/O priority class의 numerical value는 다음과 같습니다.

I/O priority class numbers
ClassNumber
IOPRIO_CLASS_NONE0
IOPRIO_CLASS_RT (real-time)1
IOPRIO_CLASS_BE (best effort)2
IOPRIO_CLASS_IDLE3

Number가 커질수록 RT에서 BE, IDLE 방향으로 제한됩니다.

Request의 I/O priority class를 설정하는 algorithm은 다음과 같습니다. Policy가 `promote-to-rt`이면 request class를 `IOPRIO_CLASS_RT`로 바꾸고 request I/O priority level을 4로 변경합니다.

Policy가 `promote-to-rt`가 아니면 policy를 number로 변환한 뒤, policy number와 현재 numerical I/O priority class 중 maximum으로 request class를 바꿉니다.

I/O priority class algorithm
Receive IO request and io.prio.class policyPolicy is promote-to-rtSet class to IOPRIO_CLASS_RTSet priority level to 4
Policy is not promote-to-rtTranslate policy to numeric valueRead current class numeric valueTake maximum(policy, current class)Set request class to resulting value

RT promotion은 별도로 처리하고 나머지는 numeric maximum으로 priority ceiling을 적용합니다.

PID controller와 task exhaustion

2354-2369

Process number controller는 지정된 limit에 도달한 뒤 cgroup에서 새 task가 `fork()` 또는 `clone()`되는 것을 막을 수 있게 합니다.

Cgroup의 task 수는 다른 controller가 막을 수 없는 방식으로 고갈될 수 있으므로 전용 controller가 필요합니다. 예를 들어 fork bomb은 memory restriction에 닿기 전에 task 수를 먼저 고갈시킬 가능성이 큽니다.

이 controller에서 사용하는 PID는 kernel이 process ID로 사용하는 TID를 뜻합니다.

PID controller protection
Tasks consume PID/TID capacityReach configured process-number limitReject new fork() or clone()Prevent task-count exhaustion
Fork bombMay exhaust tasks before memory limitRequires PID controller

Memory limit보다 먼저 고갈될 수 있는 task identifier를 별도 hard limit으로 보호합니다.

PID interface files와 policy enforcement

2370-2413
PID interface files
FileAccess / defaultMeaning
pids.maxRead/write single value; maxProcess 수 hard limit
pids.currentRead-only single valueCgroup과 descendant의 current process 수
pids.peakRead-only single valueCgroup과 descendant가 기록한 all-time maximum process 수
pids.eventsRead-only flat-keyedHierarchical PID event counters
pids.events.localRead-only flat-keyed현재 cgroup에만 local한 event counters

Non-root cgroup의 process hard limit, usage, peak와 event를 제공합니다.

`pids.events`는 별도 설명이 없으면 value change 시 file-modified event를 생성합니다. `max` entry는 cgroup의 total process 수가 `pids.max` limit에 도달한 횟수이며 `pids_localevents`도 참조해야 합니다.

`pids.events.local`은 `pids.events`와 비슷하지만 field가 hierarchical하지 않고 현재 cgroup에 local합니다. 이 file에서 발생하는 file-modified event도 local event만 반영합니다.

Cgroup policy는 organisational operation을 막지 않으므로 `pids.current > pids.max`가 될 수 있습니다. Current보다 작은 limit을 설정하거나 충분히 많은 process를 cgroup에 attach하면 이런 상태가 됩니다.

그러나 `fork()`나 `clone()`으로 PID policy를 위반할 수는 없습니다. 새 process 생성이 cgroup policy를 위반하면 이 call들은 `-EAGAIN`을 반환합니다.

PID limit edge cases
Lower pids.max below pids.currentAllow organisational changeObserve pids.current > pids.max
Attach enough existing processesAllow organisational changeObserve pids.current > pids.max
fork() or clone() would exceed policyReject creationReturn -EAGAIN

Organisation 변경은 over-limit 상태를 만들 수 있지만 새 task 생성은 hard limit을 넘지 못합니다.

Cpuset placement과 hierarchy

2414-2428

`cpuset` controller는 task의 current cgroup에 있는 cpuset interface file이 지정한 resource만 사용하도록 task의 CPU와 memory-node placement를 제한합니다.

이는 large NUMA system에서 특히 유용합니다. Job을 적절한 크기의 system subset에 배치하고 processor·memory placement를 신중히 정해 cross-node memory access와 contention을 줄이면 전체 system performance를 높일 수 있습니다.

`cpuset` controller는 hierarchical하므로 parent가 허용하지 않은 CPU 또는 memory node를 사용할 수 없습니다.

Hierarchical cpuset placement
Task requests CPUs and memory nodes through current cgroupApply parent cpuset constraintsRestrict to allowed CPU and NUMA nodesReduce cross-node access and contentionImprove system-wide placement efficiency

Requested placement는 parent allowance와 online resource에 의해 실제 grant로 좁혀집니다.

Requested CPUs와 effective CPUs

2429-2470

`cpuset.cpus`는 non-root cpuset-enabled cgroup에 존재하는 read/write multiple-values file입니다. Cgroup 안 task가 사용할 requested CPU를 나열하지만 실제 grant 목록은 parent constraint를 받으므로 requested 목록과 다를 수 있습니다.

CPU number는 comma-separated number 또는 range로 표현합니다.

	  # cat cpuset.cpus
	  0-4,6,8-10

Empty value이면 가장 가까운 non-empty `cpuset.cpus` ancestor의 setting을 사용합니다. 그런 ancestor가 없으면 available CPU 전체를 사용합니다.

`cpuset.cpus` 값은 다음 update까지 일정하게 유지되며 CPU hotplug event의 영향을 받지 않습니다.

`cpuset.cpus.effective`는 모든 cpuset-enabled cgroup에 존재하는 read-only multiple-values file입니다. Parent가 실제 grant한 online CPU를 나열하며 current cgroup task가 사용할 수 있는 CPU입니다.

`cpuset.cpus`가 empty이면 `cpuset.cpus.effective`는 parent cgroup에서 이 cgroup에 available한 모든 CPU를 보여 줍니다. Empty가 아니면 보통 `cpuset.cpus`의 subset입니다.

Requested 목록의 CPU를 하나도 grant할 수 없으면 empty `cpuset.cpus`와 같은 방식으로 처리합니다. `cpuset.cpus.effective`는 CPU hotplug event의 영향을 받습니다.

Requested and effective CPUs
FileStateHotplug behavior
cpuset.cpusRequested CPUs; empty이면 nearest ancestor 또는 all available 상속다음 explicit update까지 constant
cpuset.cpus.effectiveParent가 실제 grant한 online CPUsCPU hotplug에 따라 변경

Configuration state와 runtime grant state의 차이입니다.

CPU grant resolution
Read cpuset.cpus requestRequest is non-emptyIntersect with parent allowance and online CPUsExpose granted set in cpuset.cpus.effective
Request is empty or none can be grantedUse nearest non-empty ancestor settingFallback to all available CPUs if no ancestor settingExpose available parent CPUs as effective

Requested set, ancestor fallback와 parent constraint에서 effective set을 계산합니다.

Requested memory nodes와 migration

2471-2520

`cpuset.mems`는 non-root cpuset-enabled cgroup에 존재하는 read/write multiple-values file입니다. Cgroup task가 사용할 requested memory node를 나열하지만 실제 grant 목록은 parent constraint에 따라 다를 수 있습니다.

Memory-node number는 comma-separated number 또는 range로 표현합니다.

	  # cat cpuset.mems
	  0-1,3

Empty value이면 가장 가까운 non-empty `cpuset.mems` ancestor의 setting을 사용하며, 그런 ancestor가 없으면 available memory node 전체를 사용합니다.

`cpuset.mems` 값은 다음 update까지 일정하고 memory-node hotplug event의 영향을 받지 않습니다.

`cpuset.mems`에 non-empty value를 설정하면 cgroup task가 지정 범위 밖의 memory를 사용하고 있을 때 그 memory를 지정 node로 migrate합니다. Migration에는 cost가 들고 완전하지 않을 수 있어 일부 memory page가 남을 수 있습니다.

따라서 새 task를 cpuset에 spawn하기 전에 `cpuset.mems`를 올바르게 설정하는 것이 좋습니다. Active task가 있는 상태에서 바꿔야 하더라도 자주 변경해서는 안 됩니다.

Memory-node update and migration
Write non-empty cpuset.memsFind task memory outside designated nodesAttempt migration to designated nodesPay migration costSome pages may remain behind
Preparing a new cpuset workloadSet cpuset.mems firstSpawn tasks afterwardAvoid frequent active changes

Active workload의 node set을 바꾸면 best-effort page migration이 발생합니다.

`cpuset.mems.effective`는 모든 cpuset-enabled cgroup에 존재하는 read-only multiple-values file입니다. Parent가 실제 grant한 online memory node를 나열하며 current cgroup task가 사용할 수 있습니다.

`cpuset.mems`가 empty이면 parent cgroup에서 available한 모든 memory node를 보여 줍니다. Non-empty이면 보통 `cpuset.mems`의 subset이며, 요청 node를 하나도 grant할 수 없으면 empty request처럼 처리합니다.

`cpuset.mems.effective` 값은 memory-node hotplug event의 영향을 받습니다.

Requested and effective memory nodes
FileStateHotplug behavior
cpuset.memsRequested nodes; empty이면 nearest ancestor 또는 all available 상속다음 explicit update까지 constant
cpuset.mems.effectiveParent가 실제 grant한 online memory nodesMemory-node hotplug에 따라 변경

Configured NUMA-node request와 runtime online grant를 구분합니다.

Memory-node grant resolution
Read cpuset.mems requestRequest is non-emptyIntersect with parent allowance and online nodesExpose granted set in cpuset.mems.effective
Request is empty or none can be grantedUse nearest non-empty ancestor settingFallback to all available nodesExpose available parent nodes as effective

Parent constraint와 online state가 effective memory nodes를 결정합니다.

Exclusive CPU request와 sibling rule

2521-2554

`cpuset.cpus.exclusive`는 non-root cpuset-enabled cgroup에 존재하는 read/write multiple-values file입니다. 새 cpuset partition을 만드는 데 사용할 수 있는 exclusive CPU를 나열하며, cgroup이 valid partition root가 되기 전에는 이 값이 사용되지 않습니다.

Cgroup이 partition root가 되면 실제로 partition에 allocate된 exclusive CPU는 `cpuset.cpus.exclusive.effective`에 나타나며 requested `cpuset.cpus.exclusive`와 다를 수 있습니다. Requested 값이 설정되어 있다면 effective 값은 항상 그 subset입니다.

Exclusive CPU request and grant
FileRoleWhen effective
cpuset.cpus.exclusiveRequested exclusive CPUs for a new partitionValid partition root가 된 뒤 사용
cpuset.cpus.exclusive.effectiveActually allocated exclusive CPUsPartition formation과 parent constraints 반영

Partition 후보 CPU와 실제 partition allocation을 구분합니다.

사용자는 `cpuset.cpus`와 다른 값을 수동 설정할 수 있습니다. 다만 sibling의 `cpuset.cpus.exclusive`와 `cpuset.cpus.exclusive.effective`에 대해 CPU 목록이 exclusive해야 합니다.

또한 exclusive CPU를 떼어 간 뒤에도 sibling에 최소 한 CPU가 남도록, 이 목록은 sibling의 `cpuset.cpus`를 전부 포함하는 superset이 될 수 없습니다.

Parent cgroup의 exclusive CPU 하나는 child cgroup 하나에만 distribute할 수 있습니다. 같은 exclusive CPU가 둘 이상의 child에 나타나는 것은 exclusivity rule 위반이며 해당 write는 error로 reject됩니다.

Exclusive CPU validation
Write cpuset.cpus.exclusiveCheck overlap with sibling exclusive/effective setsCheck request is not a superset of sibling cpuset.cpusEnsure each parent-exclusive CPU maps to at most one childAccept valid request
Any exclusivity rule failsReject write with an error

Requested set은 sibling overlap과 CPU starvation을 모두 피해야 합니다.

Root cgroup은 partition root이며 available CPU 전체가 root의 exclusive CPU set에 포함됩니다.

Effective exclusive와 isolated CPU 집계

2555-2574

`cpuset.cpus.exclusive.effective`는 모든 non-root cpuset-enabled cgroup에 존재하는 read-only multiple-values file입니다. Partition root를 만들 때 사용할 수 있는 effective exclusive CPU set을 보여 줍니다.

Parent가 root가 아니면 이 값은 parent의 `cpuset.cpus.exclusive.effective` subset입니다. Local `cpuset.cpus.exclusive`가 설정되어 있으면 그 subset이기도 합니다.

Local partition을 만들 때 `cpuset.cpus.exclusive`가 설정되지 않았다면 `cpuset.cpus`와 같은 implicit value가 있는 것으로 처리합니다.

`cpuset.cpus.isolated`는 root cgroup에만 존재하는 read-only multiple-values file입니다. Existing isolated partition에서 사용하는 모든 isolated CPU set을 보여 주며 isolated partition이 없으면 empty입니다.

Effective and isolated CPU sets
FileScopeValue
cpuset.cpus.exclusive.effectiveAll non-root cpuset-enabled cgroupsParent effective와 local request의 subset; unset request는 local partition에서 cpuset.cpus로 간주
cpuset.cpus.isolatedRoot cgroup onlyAll CPUs used by current isolated partitions

Partition formation용 grant와 system-wide isolated aggregate를 제공합니다.

Cpuset partition과 local·remote 형성

2575-2609

`cpuset.cpus.partition`은 non-root cpuset-enabled cgroup에 존재하는 read/write single-value file입니다. 이 flag는 parent cgroup이 소유하며 delegatable하지 않습니다.

cpuset.cpus.partition write values
ValueMeaning
memberPartition의 non-root member
rootPartition root
isolatedLoad balancing이 없는 partition root

Write 시 허용되는 세 state입니다.

Cpuset partition은 hierarchy 맨 위의 partition root와 그 descendant인 cpuset-enabled cgroup의 collection입니다. 별도 partition root와 그 descendant는 이 collection에서 제외됩니다.

Partition은 allocate된 exclusive CPU set에 exclusive access합니다. Partition 밖의 다른 cgroup은 이 set의 CPU를 사용할 수 없습니다.

Partition boundary
Partition rootInclude cpuset-enabled descendantsEncounter nested partition rootExclude nested root and its descendants
Allocate exclusive CPU setAllow only cgroups inside partitionBlock outside cgroups from those CPUs

Nested partition root는 parent partition collection에서 새 독립 경계를 만듭니다.

Partition에는 local과 remote 두 type이 있습니다. Local partition은 parent cgroup도 valid partition root인 경우이고, remote partition은 parent가 valid partition root가 아닌 경우입니다.

Local and remote partitions
TypeParentExclusive setup
LocalParent is a valid partition rootcpuset.cpus.exclusive는 optional; unset이면 cpuset.cpus를 implicit value로 사용
RemoteParent is not a valid partition rootTarget까지 hierarchy를 따라 proper cpuset.cpus.exclusive 값을 미리 설정해야 함

Parent state와 exclusive CPU 사전 구성 요구가 다릅니다.

현재 remote partition은 local partition 아래에 만들 수 없습니다. Remote partition root의 ancestor 중 root cgroup을 제외한 어느 것도 partition root일 수 없습니다.

Partition state와 isolated operation

2610-2643

Root cgroup은 항상 partition root이며 state를 바꿀 수 없습니다. 그 밖의 모든 non-root cgroup은 `member`로 시작합니다.

`root`로 설정하면 current cgroup이 새 partition 또는 scheduling domain의 root가 됩니다. Exclusive CPU set은 `cpuset.cpus.exclusive.effective` 값으로 결정됩니다.

`isolated`로 설정하면 partition CPU는 scheduler load balancing이 없는 isolated state가 되고 unbound workqueue에서도 제외됩니다. 여러 CPU를 가진 isolated partition의 task는 optimal performance를 위해 각 CPU에 신중히 distribute하고 bind해야 합니다.

Partition operating states
StateBehavior
memberNon-root member of an enclosing partition
rootNew partition and scheduling-domain root using effective exclusive CPUs
isolatedPartition root without scheduler load balancing and unbound workqueue use

Member, balanced root와 isolated root의 runtime behavior입니다.

Partition root(`root` 또는 `isolated`)는 valid 또는 invalid일 수 있습니다. Invalid root는 일부 state information을 유지할 수 있지만 `member`처럼 동작하는 degraded state입니다.

`member`, `root`, `isolated` 사이의 모든 state transition이 허용됩니다.

Partition state transitions
memberrootisolatedmember
memberisolatedrootmember
root or isolatedValidity conditions failInvalid degraded state
Invalid degraded stateConditions recoverValid root or isolated

Writable state는 서로 자유롭게 전환되지만 root 계열은 별도로 validity를 가집니다.

`cpuset.cpus.partition`을 read하면 `member`, `root`, `isolated`, `root invalid (<reason>)`, `isolated invalid (<reason>)` 중 하나가 나타납니다. Invalid partition root에는 invalid 이유를 설명하는 string이 parentheses 안에 포함됩니다.

cpuset.cpus.partition read values
Read valueMeaning
memberNon-root member of a partition
rootValid partition root
isolatedValid partition root without load balancing
root invalid (<reason>)Invalid partition root with reason
isolated invalid (<reason>)Invalid isolated partition root with reason

Configured mode와 validity reason을 한 값에 함께 표시합니다.

Partition validity, monitoring과 recovery

2644-2686

Local partition root가 valid하려면 다음 조건을 모두 만족해야 합니다.

Partition validity conditions
ConditionLocalRemote
Parent cgroup is a valid partition rootRequiredNot required
cpuset.cpus.exclusive.effective is non-emptyRequired; offline CPUs may be includedRequired; offline CPUs may be included
cpuset.cpus.effective is non-emptyRequired unless partition has no associated taskRequired unless partition has no associated task

Remote root는 local 조건에서 valid-parent requirement만 제외합니다.

Hotplug, `cpuset.cpus` 또는 `cpuset.cpus.exclusive` 변경 같은 external event는 valid partition root를 invalid로 만들거나 반대로 invalid root를 valid로 만들 수 있습니다. `cpuset.cpus.effective`가 empty인 cgroup으로는 task를 이동할 수 없습니다.

External validity changes
CPU hotplug or cpuset configuration changeRecompute effective and exclusive CPU setsRe-evaluate validity conditionsTransition valid to invalid or invalid to valid
Target cpuset.cpus.effective is emptyReject task migration into cgroup

Resource availability와 configuration change가 partition validity를 재평가합니다.

Valid non-root parent partition에 associated task가 없으면 CPU 전체를 child local partition에 distribute할 수 있습니다.

Valid partition root를 `member`로 바꾸면 child local partition이 모두 invalid가 되어 그 안에서 실행 중인 task에 disruption을 줄 수 있으므로 주의해야 합니다.

비활성화된 child partition은 parent를 다시 partition root로 바꾸고 `cpuset.cpus` 또는 `cpuset.cpus.exclusive`를 올바르게 설정하면 recover할 수 있습니다.

Child partition invalidation and recovery
Valid parent partition rootChange parent to memberInvalidate child local partitionsDisrupt tasks in child partitions
Switch parent back to partition rootRestore proper cpuset.cpus or cpuset.cpus.exclusiveRecover child partitions

Parent mode 변경은 local child validity에 연쇄적으로 영향을 줍니다.

`cpuset.cpus.partition` state가 바뀔 때마다 poll과 inotify event가 trigger됩니다. 직접 write, CPU hotplug 또는 validity status를 바꾸는 다른 변경이 모두 포함되므로 userspace agent는 continuous polling 없이 unexpected change를 monitor할 수 있습니다.

Partition state notification
Partition write, CPU hotplug, or validity-changing updateChange cpuset.cpus.partition stateTrigger poll and inotify eventsNotify userspace agent without continuous polling

여러 원인의 state change를 event-driven userspace monitoring에 연결합니다.

`isolcpus` kernel boot command-line option으로 일부 CPU를 boot 시 load balancing이 disable된 isolated state로 미리 구성할 수 있습니다. 이 CPU를 partition에 넣으려면 isolated partition에서 사용해야 합니다.

Cgroup BPF 기반 device access control

2687-2710

Device controller는 device file access를 관리합니다. `mknod`를 사용한 새 device file 생성과 existing device file access를 모두 포함합니다.

Cgroup v2 device controller에는 interface file이 없으며 cgroup BPF 위에 구현됩니다. Device file access를 control하려면 `BPF_PROG_TYPE_CGROUP_DEVICE` type의 BPF program을 만들고 `BPF_CGROUP_DEVICE` flag로 cgroup에 attach할 수 있습니다.

Device file access를 시도하면 해당 BPF program이 실행됩니다. Return value가 0이면 attempt가 `-EPERM`으로 실패하고, 0이 아니면 성공합니다.

Cgroup device access decision
Attempt mknod, read, or write on device fileRun attached BPF_PROG_TYPE_CGROUP_DEVICE programsProgram returns 0Fail with -EPERM
Program returns non-zeroAllow device access

Device operation마다 attached cgroup BPF program이 허용 여부를 결정합니다.

`BPF_PROG_TYPE_CGROUP_DEVICE` program은 device access attempt를 설명하는 `bpf_cgroup_dev_ctx` structure pointer를 받습니다. Context에는 access type(`mknod`/`read`/`write`)과 device type·major·minor number가 들어 있습니다.

bpf_cgroup_dev_ctx inputs
Field groupValues
Access typemknod, read, write
Device identitytype, major number, minor number

BPF policy가 판단할 device access context입니다.

Example `BPF_PROG_TYPE_CGROUP_DEVICE` program은 kernel source tree의 `tools/testing/selftests/bpf/progs/dev_cgroup.c`에서 볼 수 있습니다.

RDMA resource limit와 accounting

2711-2749

`rdma` controller는 RDMA resource의 distribution과 accounting을 조절합니다.

`rdma.max`는 root를 제외한 모든 cgroup에 존재하는 read/write nested-keyed file로 RDMA/IB device에 설정된 current resource limit을 설명합니다. Line은 순서 없는 device-name key이며, space-separated resource name과 distribute 가능한 configured limit을 포함합니다.

rdma.max nested keys
KeyMeaning
hca_handleMaximum number of HCA Handles
hca_objectMaximum number of HCA Objects

RDMA device별 HCA handle과 object 수를 제한합니다.

`mlx4`와 `ocrdma` device의 `rdma.max` 예시는 다음과 같습니다.

	  mlx4_0 hca_handle=2 hca_object=2000
	  ocrdma1 hca_handle=3 hca_object=max

`rdma.current`는 current resource usage를 설명하는 read-only file이며 root를 제외한 모든 cgroup에 존재합니다.

	  mlx4_0 hca_handle=1 hca_object=20
	  ocrdma1 hca_handle=1 hca_object=23
RDMA interface scope
FileAccessMeaning
rdma.maxRead/write; non-rootConfigured distributable limit
rdma.currentRead-only; non-rootCurrent resource usage

Configured ceiling과 observed usage를 같은 device/resource key로 비교합니다.

Device memory region accounting

2750-2792

`dmem` controller는 device memory region의 distribution과 accounting을 조절합니다. Region마다 system page size와 같지 않은 고유 page size를 사용할 수 있으므로 unit은 항상 byte입니다.

`dmem.max`, `dmem.min`, `dmem.low`는 root를 제외한 모든 cgroup에 존재하는 read/write nested-keyed file로 region별 configured resource limit을 설명합니다.

`xe` device 예시는 다음과 같습니다.

	  drm/0000:03:00.0/vram0 1073741824
	  drm/0000:03:00.0/stolen max

이 interface의 semantics와 계산 방식은 memory cgroup controller의 `max`, `min`, `low`와 같습니다.

`dmem.capacity`는 maximum region capacity를 보여 주는 read-only file이며 root cgroup에만 존재합니다. Kernel이 internal use를 위해 일부 memory를 reserve하므로 모든 capacity를 cgroup이 allocate할 수 있는 것은 아닙니다.

	  drm/0000:03:00.0/vram0 8514437120
	  drm/0000:03:00.0/stolen 67108864

`dmem.current`는 current resource usage를 보여 주는 read-only file이며 root를 제외한 모든 cgroup에 존재합니다.

	  drm/0000:03:00.0/vram0 12550144
	  drm/0000:03:00.0/stolen 8650752
DMEM interface files
FileScopeMeaning
dmem.max, dmem.min, dmem.lowRead/write; non-rootPer-region control with memory-controller semantics
dmem.capacityRead-only; root onlyMaximum region capacity before considering cgroup allocation eligibility
dmem.currentRead-only; non-rootCurrent region usage

Region limit, platform capacity와 current cgroup usage의 scope입니다.

Device-memory accounting units
Device exposes memory regionsEach region may use a different page sizeAvoid system-page-size assumptionsReport and limit all values in bytes

Region-specific page size 차이를 숨기기 위해 모든 interface가 byte로 통일됩니다.

HugeTLB limit와 NUMA statistics

2793-2825

HugeTLB controller는 control group별 HugeTLB usage를 제한하며 page fault 중 controller limit을 enforce합니다.

HugeTLB interface files
FileMeaning
hugetlb.<hugepagesize>.currentCurrent usage; non-root cgroups
hugetlb.<hugepagesize>.maxHard usage limit; default max; non-root cgroups
hugetlb.<hugepagesize>.eventsHierarchical read-only event counters
hugetlb.<hugepagesize>.events.localCurrent cgroup에 local한 read-only event counters
hugetlb.<hugepagesize>.numa_statActive in-use HugeTLB pages의 per-node byte statistics

Huge page size별 usage, hard limit, event와 NUMA placement를 제공합니다.

`hugetlb.<hugepagesize>.events`의 `max` entry는 HugeTLB limit 때문에 allocation이 실패한 횟수입니다.

`hugetlb.<hugepagesize>.events.local`은 hierarchical하지 않고 current cgroup에 local합니다. 이 file의 file-modified event도 local event만 반영합니다.

`hugetlb.<hugepagesize>.numa_stat`은 `memory.numa_stat`과 비슷하게 이 cgroup의 `<hugepagesize>` HugeTLB page에 대한 NUMA information을 보여 줍니다. Active하게 사용 중인 page만 포함하며 per-node value unit은 byte입니다.

HugeTLB limit enforcement
Page fault requests HugeTLB pageCheck hugetlb.<hugepagesize>.maxLimit allows allocationCharge current usage
Limit blocks allocationFail allocationIncrement events:max

Huge page allocation과 page fault 경로에서 hard limit failure를 event로 기록합니다.

Misc scalar resource registration

2826-2842

Miscellaneous cgroup은 다른 cgroup resource처럼 abstract할 수 없는 scalar resource를 limit하고 track하는 mechanism을 제공합니다. Controller는 `CONFIG_CGROUP_MISC` config option으로 enable됩니다.

Resource는 `include/linux/misc_cgroup.h`의 `enum misc_res_type{}`에 추가하고 대응 name은 `kernel/cgroup/misc.c`의 `misc_res_name[]`에 추가합니다.

Resource provider는 resource를 사용하기 전에 `misc_cg_set_capacity()`를 call해 capacity를 설정해야 합니다. Capacity가 설정되면 charge와 uncharge API로 usage를 갱신할 수 있습니다.

Misc controller와 상호작용하는 모든 API는 `include/linux/misc_cgroup.h`에 있습니다.

Misc resource lifecycle
Add enum misc_res_type{} entryAdd misc_res_name[] entryCall misc_cg_set_capacity()Charge resource usageUncharge released usage

새 scalar resource를 등록하고 capacity를 설정한 뒤 usage를 account합니다.

Misc implementation locations
PurposeSymbol / path
Resource typeenum misc_res_type{} in include/linux/misc_cgroup.h
Resource namemisc_res_name[] in kernel/cgroup/misc.c
Capacity setupmisc_cg_set_capacity()
Controller APIsinclude/linux/misc_cgroup.h

Resource type, name와 controller API의 source location입니다.

Misc capacity, usage, limit와 events

2843-2907

원문은 Miscellaneous controller가 3개 interface file을 제공한다고 서술한 뒤, 두 resource `res_a`, `res_b`가 등록된 경우의 다음 interface들을 설명합니다.

`misc.capacity`는 root cgroup에만 표시되는 read-only flat-keyed file로 platform에서 available한 miscellaneous scalar resource와 quantity를 보여 줍니다.

	  $ cat misc.capacity
	  res_a 50
	  res_b 10

`misc.current`는 모든 cgroup에 표시되는 read-only flat-keyed file로 cgroup과 child의 current resource usage를 보여 줍니다.

	  $ cat misc.current
	  res_a 3
	  res_b 0

`misc.peak`는 모든 cgroup에 표시되는 read-only flat-keyed file로 cgroup과 child가 기록한 historical maximum resource usage를 보여 줍니다.

	  $ cat misc.peak
	  res_a 10
	  res_b 8

`misc.max`는 non-root cgroup에 표시되는 read/write flat-keyed file로 cgroup과 child의 allowed maximum usage를 설정합니다.

	  $ cat misc.max
	  res_a max
	  res_b 4

Limit은 다음과 같이 specific value로 설정할 수 있습니다.

	  # echo res_a 1 > misc.max

다음과 같이 `max`로 되돌릴 수도 있습니다.

	  # echo res_a max > misc.max

`misc.max` limit은 `misc.capacity`에 표시된 capacity value보다 높게 설정할 수 있습니다.

Misc resource interfaces
FileScope / accessMeaning
misc.capacityRoot only; read-onlyPlatform resource quantities
misc.currentAll cgroups; read-onlyCurrent usage of cgroup and children
misc.peakAll cgroups; read-onlyHistorical maximum usage of cgroup and children
misc.maxNon-root; read/writeMaximum allowed usage of cgroup and children

Platform capacity, hierarchical usage·peak, configurable ceiling을 구분합니다.

`misc.events`는 non-root cgroup의 read-only flat-keyed file입니다. 별도 설명이 없으면 value change가 file-modified event를 생성하고 모든 field는 hierarchical합니다. `max`는 resource usage가 max boundary를 넘으려 한 횟수입니다.

`misc.events.local`은 `misc.events`와 비슷하지만 field가 current cgroup에 local하고 hierarchical하지 않습니다. 이 file의 file-modified event도 local event만 반영합니다.

Misc max event accounting
Usage is about to exceed misc.maxBlock or account max-boundary eventIncrement hierarchical misc.events:maxGenerate file-modified event
Inspect current cgroup onlyRead misc.events.localObserve local events and local notifications

Resource ceiling attempt를 hierarchy와 local view로 각각 노출합니다.

Misc resource charge ownership

2908-2915

Miscellaneous scalar resource는 처음 사용된 cgroup에 charge되며 resource가 free될 때까지 그 cgroup에 계속 charge됩니다. Process를 다른 cgroup으로 migrate해도 charge는 process가 이동한 destination cgroup으로 옮겨지지 않습니다.

Misc charge ownership
Process first uses miscellaneous resource in cgroup ACharge resource to cgroup AMigrate process to cgroup BKeep charge in cgroup AFree resourceRemove charge from cgroup A

Process membership과 resource charge ownership은 migration 이후에도 분리되어 유지됩니다.

Other controller: perf_event

2916-2927

`perf_event` controller가 legacy hierarchy에 mount되어 있지 않으면 v2 hierarchy에서 automatic하게 enable됩니다. 따라서 perf event를 항상 cgroup v2 path로 filter할 수 있습니다.

V2 hierarchy가 populated된 뒤에도 controller를 legacy hierarchy로 이동할 수 있습니다.

perf_event hierarchy placement
perf_event is not mounted on legacy hierarchyAutomatically enable on v2Filter perf events by cgroup v2 path
V2 hierarchy becomes populatedController may still move to legacy hierarchy

Legacy mount 여부에 따른 automatic v2 enable과 이후 이동 가능성을 나타냅니다.

Root cgroup CPU·IO process behavior

2928-2956

이 section은 stable kernel API의 일부로 간주되지 않는 non-normative information을 담으므로 변경될 수 있습니다.

Root cgroup에서 CPU cycle을 distribute할 때 각 thread는 root의 별도 child cgroup에 host된 것처럼 처리됩니다. 이 implicit child weight는 thread nice level에 따라 달라집니다.

Mapping detail은 `kernel/sched/core.c`의 `sched_prio_to_weight` array를 참조하십시오. 이 array 값은 neutral `nice 0` 값이 1024 대신 100이 되도록 적절히 scale해야 합니다.

Root cgroup process는 IO distribution에서 implicit leaf child node에 host됩니다. 이 node는 weight 200인 일반 root child cgroup처럼 resource distribution에 포함됩니다.

Root process distribution models
ControllerImplicit representationWeight
CPUEach thread behaves as a separate child cgroupDerived from nice via sched_prio_to_weight; nice 0 scaled to 100
IOAll root processes hosted in an implicit leaf child node200

Root 안의 직접 process를 controller별 implicit child entity로 취급합니다.

Cgroup namespace basics와 lifetime

2957-3006

Cgroup namespace는 `/proc/$PID/cgroup` file과 cgroup mount view를 virtualize하는 mechanism입니다. `CLONE_NEWCGROUP` clone flag를 `clone(2)`와 `unshare(2)`에 사용해 새 cgroup namespace를 만들 수 있습니다.

Namespace 안 process의 `/proc/$PID/cgroup` output은 cgroupns root로 제한됩니다. Cgroupns root는 cgroup namespace를 만들 당시 process가 속한 cgroup입니다.

Cgroup namespace creation
Process belongs to a cgroupCall clone(2) or unshare(2) with CLONE_NEWCGROUPCreate cgroup namespaceCapture current cgroup as cgroupns rootRestrict /proc/$PID/cgroup and mount views to that root

Creation 시점의 cgroup이 새 namespace의 stable root view가 됩니다.

Cgroup namespace가 없으면 `/proc/$PID/cgroup`은 process cgroup의 complete path를 보여 줍니다. Container처럼 cgroup과 namespace로 process를 isolate하는 환경에서는 이 path가 system-level information을 leak할 수 있습니다.

예를 들어 다음 path는 isolated process에 노출하기 곤란한 system data일 수 있습니다.

  # cat /proc/self/cgroup
  0::/batchjobs/container_id1

새 cgroup namespace를 만들기 전에는 namespace inode와 complete cgroup path가 다음과 같이 보입니다.

  # ls -l /proc/self/ns/cgroup
  lrwxrwxrwx 1 root root 0 2014-07-15 10:37 /proc/self/ns/cgroup -> cgroup:[4026531835]
  # cat /proc/self/cgroup
  0::/batchjobs/container_id1

새 namespace를 `unshare`한 뒤에는 namespace inode가 바뀌고 cgroup view의 root가 `/`로 보입니다.

  # ls -l /proc/self/ns/cgroup
  lrwxrwxrwx 1 root root 0 2014-07-15 10:35 /proc/self/ns/cgroup -> cgroup:[4026532183]
  # cat /proc/self/cgroup
  0::/
Cgroup path visibility
View/proc/self/cgroup resultExposure
Without cgroup namespaceFull host path such as /batchjobs/container_id1May leak system-level placement
Inside new cgroup namespace0::/ at namespace rootHost prefix hidden

Namespace 도입 전후 container가 보는 cgroup path 범위입니다.

Multi-threaded process의 어느 thread가 cgroup namespace를 unshare하면 새 cgroupns는 process 전체, 즉 모든 thread에 적용됩니다. 이는 v2 hierarchy에서는 자연스럽지만 legacy hierarchy에서는 예상 밖일 수 있습니다.

Cgroup namespace 안에 process가 있거나 mount가 namespace를 pin하는 동안 namespace는 유지됩니다. 마지막 usage가 사라지면 namespace만 destroy되고 cgroupns root와 actual cgroup은 남습니다.

Cgroup namespace lifetime
Processes exist inside namespace or mounts pin itKeep cgroup namespace aliveLast process and mount reference disappearsDestroy namespace objectKeep cgroupns root and actual cgroups

Process와 mount reference가 namespace object의 lifetime을 결정합니다.

Namespace root와 caller-specific views

3007-3057

Cgroup namespace의 `cgroupns root`는 `unshare(2)`를 call한 process가 실행 중인 cgroup입니다. 예를 들어 `/batchjobs/container_id1`의 process가 unshare하면 그 cgroup이 root가 됩니다. `init_cgroup_ns`에서는 real root(`/`)가 root입니다.

Namespace creator process가 나중에 다른 cgroup으로 이동해도 cgroupns root는 바뀌지 않습니다.

  # ~/unshare -c # unshare cgroupns in some cgroup
  # cat /proc/self/cgroup
  0::/
  # mkdir sub_cgrp_1
  # echo 0 > sub_cgrp_1/cgroup.procs
  # cat /proc/self/cgroup
  0::/sub_cgrp_1
Stable cgroupns root
Create namespace in /batchjobs/container_id1Fix cgroupns root at container_id1Move creator into sub_cgrp_1Show creator as /sub_cgrp_1Keep namespace root unchanged

Creator 이동은 process-relative path만 바꾸고 namespace root identity는 바꾸지 않습니다.

각 process는 `/proc/$PID/cgroup`에 대해 namespace-specific view를 얻습니다. Cgroup namespace 안 process는 자신의 root cgroup 내부 path만 볼 수 있습니다.

Unshared cgroup namespace 안에서 child process를 `sub_cgrp_1`으로 이동하면 다음과 같이 namespace-relative path가 보입니다.

  # sleep 100000 &
  [1] 7353
  # echo 7353 > sub_cgrp_1/cgroup.procs
  # cat /proc/7353/cgroup
  0::/sub_cgrp_1

Initial cgroup namespace에서는 같은 process의 real cgroup path가 보입니다.

  $ cat /proc/7353/cgroup
  0::/batchjobs/container_id1/sub_cgrp_1

다른 cgroup에 root를 둔 sibling cgroup namespace에서는 caller 자신의 cgroup namespace root에 상대적인 path를 보여 줍니다. 원문 예시는 다음과 같습니다.

  # cat /proc/7353/cgroup
  0::/../container_id2/sub_cgrp_1

Relative path는 caller의 cgroup namespace root에 상대적임을 나타내기 위해 항상 `/`로 시작합니다.

Caller-specific cgroup path views
Caller viewPath form
Target's unshared namespacePath below its cgroupns root
Initial namespaceFull real cgroup path
Sibling namespaceRelative path from sibling cgroupns root

같은 PID도 reader의 cgroup namespace에 따라 다른 path로 표시됩니다.

Namespace 밖 migration과 setns(2)

3058-3086

Cgroup namespace 안 process는 external cgroup에 proper access가 있으면 namespace root 안팎으로 이동할 수 있습니다. 다음 예시는 cgroupns root가 `/batchjobs/container_id1`이고 global hierarchy가 namespace 안에서도 accessible한 경우입니다.

  # cat /proc/7353/cgroup
  0::/sub_cgrp_1
  # echo 7353 > batchjobs/container_id2/cgroup.procs
  # cat /proc/7353/cgroup
  0::/../container_id2

이런 setup은 권장되지 않습니다. Cgroup namespace 안 task에는 자신의 cgroupns hierarchy만 노출해야 합니다.

External cgroup migration risk
Expose global hierarchy inside cgroup namespaceTask has access to external cgroupWrite PID to external cgroup.procsMove task outside namespace rootShow external location as relative path
Recommended setupExpose only task's own cgroupns hierarchy

Global hierarchy 노출은 namespace root 밖 이동과 상대 path 노출을 가능하게 합니다.

다른 cgroup namespace로 `setns(2)`하려면 process가 current user namespace에 대해 `CAP_SYS_ADMIN`을 가져야 하고 target cgroup namespace의 userns에 대해서도 `CAP_SYS_ADMIN`을 가져야 합니다.

setns(2) permission requirements
Capability checkRequired
CAP_SYS_ADMIN against current user namespaceYes
CAP_SYS_ADMIN against target cgroup namespace usernsYes

두 user-namespace 관점의 capability가 모두 필요합니다.

다른 cgroup namespace에 attach해도 implicit cgroup change는 일어나지 않습니다. Attach한 process는 별도로 target cgroup namespace root 아래로 이동시켜야 합니다.

Namespace-private cgroupfs mount

3087-3103

Non-init cgroup namespace 안에서 실행하는 process는 namespace-specific cgroup hierarchy를 mount할 수 있습니다.

  # mount -t cgroup2 none $MOUNT_POINT

이 mount는 cgroupns root를 filesystem root로 삼아 unified cgroup hierarchy를 mount합니다. Process는 자신의 user namespace와 mount namespace에 대해 `CAP_SYS_ADMIN`이 필요합니다.

`/proc/self/cgroup` virtualization과 namespace-private cgroupfs mount로 cgroup hierarchy view를 제한하면 container 안에 제대로 isolate된 cgroup view를 제공할 수 있습니다.

Isolated container cgroup view
Create non-init cgroup namespaceVirtualize /proc/self/cgroupMount cgroup2 with cgroupns root as filesystem rootKeep mount namespace privateExpose isolated cgroup view inside container

Proc path virtualization과 private filesystem root restriction을 결합합니다.

Kernel programming information scope

3104-3111

이 section은 cgroup과 interaction해야 하는 영역의 kernel programming information을 담습니다. Cgroup core와 controller 자체의 구현은 다루지 않습니다.

Filesystem cgroup writeback support

3112-3146

Filesystem은 `address_space_operations->writepages()`를 update해 다음 두 function으로 bio를 annotate하면 cgroup writeback을 지원할 수 있습니다.

Cgroup writeback annotation functions
FunctionCall pointEffect
wbc_init_bio(@wbc, @bio)Queue(device)를 bio에 associate한 뒤, submission 전에 각 writeback bio마다Bio를 inode owner cgroup과 corresponding request queue에 associate
wbc_account_cgroup_owner(@wbc, @folio, @bytes)각 written data segment마다; bio에 segment를 추가할 때가 가장 자연스러움Data segment의 cgroup owner를 account

Bio-level owner binding과 data-segment-level ownership accounting을 나눕니다.

Writeback bio annotation order
Create writeback bioAssociate request queue or deviceCall wbc_init_bio(@wbc, @bio)Add data segments and call wbc_account_cgroup_owner()Submit bio

`wbc_init_bio()`의 필수 ordering과 segment accounting 위치입니다.

Writeback bio가 annotate되면 `super_block`의 `->s_iflags`에 `SB_I_CGROUPWB`를 설정해 cgroup support를 enable할 수 있습니다. Journaled data mode처럼 특정 filesystem feature가 incompatible할 때 cgroup writeback support를 선택적으로 disable하는 데 유용합니다.

`wbc_init_bio()`는 specified bio를 cgroup에 bind합니다. Configuration에 따라 bio가 lower priority로 실행될 수 있고, writeback session이 journal entry 같은 shared resource를 hold하고 있으면 priority inversion이 발생할 수 있습니다.

이 문제에는 하나의 쉬운 solution이 없습니다. Filesystem은 특정 문제 case에서 `wbc_init_bio()`를 생략하고 `bio_associate_blkg()`를 직접 사용해 우회할 수 있습니다.

Writeback priority inversion risk
Bind bio to cgroup with wbc_init_bio()Execute bio at lower priorityHold shared resource such as journal entryBlock higher-priority workPriority inversion
Filesystem-specific problematic caseSkip wbc_init_bio()Use bio_associate_blkg() directly

Shared resource를 잡은 lower-priority bio가 higher-priority work를 막을 수 있습니다.

Deprecated v1 core features

3147-3161

Cgroup v2에서는 다음 v1 core feature를 지원하지 않거나 제거했습니다.

Deprecated v1 core features
V1 featureV2 status / replacement
Multiple hierarchies, including named hierarchiesNot supported
All v1 mount optionsNot supported
tasks file and sorted cgroup.procstasks removed; cgroup.procs is not sorted
cgroup.clone_childrenRemoved
/proc/cgroupsMeaningless for v2; use root cgroup.controllers or cgroup.stat

V2에서 제거된 hierarchy, mount와 core interface behavior입니다.

V1 multiple-hierarchy 문제와 v2 rationale

3162-3217

Cgroup v1은 arbitrary number의 hierarchy를 허용했고 각 hierarchy가 임의 수의 controller를 host할 수 있었습니다. 겉보기에는 매우 flexible했지만 실제로는 유용하지 않았습니다.

각 controller instance는 하나뿐이므로 모든 hierarchy에서 유용한 freezer 같은 utility controller도 한 hierarchy에서만 사용할 수 있었습니다. Hierarchy가 populated되면 controller를 다른 hierarchy로 이동할 수도 없었습니다.

한 hierarchy에 bind된 모든 controller는 정확히 같은 hierarchy view를 강제받았고 controller별로 granularity를 다르게 할 수 없었습니다.

V1 multiple-hierarchy constraints
ConstraintConsequence
One instance per controllerUtility controller can serve only one hierarchy
No controller move after populationEarly placement becomes effectively permanent
Controllers on one hierarchy share an identical topologyCannot vary granularity per controller
Unlimited number of hierarchiesThread membership key has unbounded length
Unknown topology of other controllersControllers must assume orthogonal hierarchies and cannot cooperate easily

표면적 flexibility가 실제 controller placement와 operation을 제한한 이유입니다.

결국 같은 hierarchy에 둘 수 있는 controller 조합이 크게 제한되어 대부분의 configuration은 controller마다 별도 hierarchy를 사용했습니다. `cpu`와 `cpuacct`처럼 밀접한 controller만 함께 두는 것이 자연스러웠습니다.

Userland는 비슷한 hierarchy 여러 개를 관리하며 hierarchy operation마다 같은 step을 반복해야 했습니다. Multiple hierarchy support는 cgroup core implementation을 크게 복잡하게 만들었고 cgroup의 일반적 사용 방식과 controller 기능까지 제한했습니다.

Hierarchy proliferation feedback loop
Controller placement constraintsPut most controllers on separate hierarchiesRepeat management operations in userlandCreate unbounded membership descriptionsAdd controllers only to identify membershipProliferate hierarchies further

Controller별 분리와 membership 식별용 controller가 hierarchy 수를 더 늘렸습니다.

Hierarchy 수에 limit이 없어서 thread의 cgroup membership을 finite length로 표현할 수 없었습니다. Key는 임의 수의 entry를 가져 길이 제한이 없었고 조작하기 매우 불편했습니다. Membership 식별만 하는 controller까지 추가되어 hierarchy 증가 문제를 더 악화시켰습니다.

Controller는 다른 controller hierarchy의 topology를 예상할 수 없어서 모두가 완전히 orthogonal hierarchy에 있다고 가정해야 했습니다. 이 때문에 controller cooperation이 불가능하거나 매우 번거로웠습니다.

대부분의 use case에서 완전히 orthogonal한 hierarchy는 필요하지 않습니다. 실제 요구는 controller별 granularity 차이이며, 특정 controller view에서는 leaf에서 root 방향으로 hierarchy를 collapse할 수 있어야 합니다.

예를 들어 어떤 level 아래 memory distribution은 구분하지 않으면서 CPU cycle distribution은 계속 세밀하게 control할 수 있어야 합니다.

Controller-specific granularity
Single process hierarchyMemory controller collapses lower levelsStop distinguishing memory below chosen level
Same process hierarchyCPU controller retains deeper levelsContinue detailed CPU-cycle distribution

V2가 필요한 핵심은 별도 hierarchy가 아니라 controller view별 subtree collapse입니다.

V1 thread granularity와 delegation 문제

3218-3261

Cgroup v1은 한 process의 thread가 서로 다른 cgroup에 속하도록 허용했습니다. 일부 controller에는 이 구성이 의미가 없어 각자 무시하는 방식을 구현했고, 더 중요하게는 individual application에 노출하는 API와 system-management interface의 경계를 흐렸습니다.

일반적으로 in-process knowledge는 process 자신만 가지고 있습니다. 따라서 service-level process organization과 달리 process thread를 분류하려면 target process를 소유한 application의 active participation이 필요합니다.

Process and thread organization
GranularityKnowledge ownerManagement implication
Service or processSystem managementCan organize externally
Threads inside one processOwning applicationRequires active application participation

System manager가 알 수 있는 service 경계와 application만 아는 in-process 경계를 구분합니다.

V1의 모호한 delegation model은 thread granularity와 결합되어 남용되었습니다. Individual application에 cgroup을 delegate해 자체 sub-hierarchy를 만들고 관리하며 resource distribution을 control하게 했고, 결과적으로 cgroup을 일반 program에 노출되는 syscall-like API 수준으로 끌어올렸습니다.

하지만 cgroup interface는 이 용도로 노출하기에 근본적으로 부적절했습니다. Process가 자신의 knob에 접근하려면 `/proc/self/cgroup`에서 target hierarchy path를 추출하고, knob name을 append해 path를 만들고, file을 open한 뒤 read/write해야 했습니다.

이 절차는 매우 clunky하고 이례적일 뿐 아니라 본질적으로 racy합니다. 여러 step을 하나의 transaction으로 정의할 conventional 방법이 없고 process가 실제로 자신의 sub-hierarchy를 조작한다는 보장도 없습니다.

Racy self-service knob access
Read /proc/self/cgroupExtract target hierarchy pathAppend knob nameOpen constructed pathRead or write knob
Membership or hierarchy changes between stepsOperate on stale or unintended pathNo transaction guarantee

Application이 own cgroup knob를 찾는 multi-step path construction에는 atomicity가 없습니다.

Controller는 public API였다면 받아들여지지 않았을 knob를 system-management pseudo filesystem에 추가했습니다. 제대로 abstract하거나 refine하지 않은 채 kernel internal detail을 직접 노출한 knob가 ill-defined delegation을 통해 application에 전달되어, 필요한 scrutiny 없이 public API를 만드는 shortcut처럼 cgroup이 악용되었습니다.

그 결과 userland는 잘못 동작하고 poor하게 abstract된 interface를 떠안았고, kernel은 의도치 않게 노출한 construct에 호환성 제약으로 묶였습니다.

Ill-defined delegation cost
Expose kernel-oriented controller knobDelegate sub-hierarchy to applicationTreat knob as public application APIBypass normal API scrutinyLock kernel and userland into poor abstraction

System-management knob의 application API화가 양쪽에 장기 호환성 부담을 남겼습니다.

Inner node와 thread competition

3262-3302

Cgroup v1은 thread를 어느 cgroup에도 둘 수 있어 parent cgroup의 thread와 child cgroup이 resource를 두고 경쟁하는 문제가 생겼습니다. 서로 다른 type의 entity가 경쟁했으며 명확한 해결 방식이 없어 controller마다 다르게 처리했습니다.

V1 internal-task approaches
ControllerApproachFailure mode
CPUTreat threads and cgroups as equivalent; map nice to weightsInternal thread count 변화가 child CPU ratio를 계속 바꿈; mapping이 불명확하고 thread에 없는 knob 존재
IOCreate hidden leaf node with leaf_-prefixed knob copiesUnnecessary nesting, messy interface, complex implementation
MemoryNo clear control between internal tasks and child cgroupsUndefined behavior and workload-specific ad-hoc knobs

CPU, IO와 memory controller가 parent task와 child cgroup competition을 서로 다르게 처리했습니다.

CPU controller는 thread와 cgroup을 equivalent하게 보고 nice level을 cgroup weight로 map했습니다. 일부 case에서는 동작했지만 child가 특정 CPU-cycle ratio를 원하고 internal thread 수가 변하면 경쟁 entity 수에 따라 ratio가 계속 바뀌었습니다.

Nice-to-weight mapping도 obvious하거나 universal하지 않았고 thread에는 사용할 수 없는 다른 knob도 많았습니다.

IO controller는 thread를 host할 hidden leaf node를 각 cgroup에 implicit하게 만들고 모든 knob의 `leaf_` prefix copy를 제공했습니다. Internal thread를 동등하게 control할 수 있었지만 불필요한 nesting layer, messy interface와 큰 implementation complexity를 초래했습니다.

Memory controller는 internal task와 child cgroup 사이 동작을 control할 방법이 없고 behavior도 명확하지 않았습니다. 특정 workload에 맞춘 ad-hoc behavior와 knob를 추가하려는 시도는 장기적으로 해결하기 매우 어려운 문제로 이어질 수 있었습니다.

여러 controller가 internal task를 각기 다른 심각한 결함이 있는 방식으로 다뤄 cgroup 전체가 매우 inconsistent해졌습니다. 이 문제는 cgroup core가 uniform하게 해결해야 합니다.

Why core must resolve internal tasks
Allow parent threads to compete with child cgroupsLeave entity comparison undefinedEach controller invents a workaroundAccumulate flawed and incompatible behaviorRequire a uniform cgroup-core rule

Controller별 workaround가 interface와 semantics 분화를 키웠습니다.

V1 interface inconsistency와 v2 convention

3303-3331

Cgroup v1은 oversight 없이 성장하며 많은 idiosyncrasy와 inconsistency를 만들었습니다.

Cgroup core의 한 문제는 empty cgroup notification이었습니다. Event마다 userland helper binary를 fork하고 execute했으며 event delivery는 recursive하지도 delegatable하지도 않았습니다. 이 mechanism의 한계 때문에 in-kernel event-delivery filtering까지 추가되어 interface가 더 복잡해졌습니다.

Controller interface도 문제가 있었습니다. 극단적으로 hierarchy organization을 완전히 무시하고 모든 cgroup을 root 바로 아래에 있는 것처럼 취급하는 controller가 있었으며, 일부는 inconsistent한 implementation detail을 userland에 대량 노출했습니다.

Controller 사이 consistency도 없었습니다. 새 cgroup 생성 시 일부 controller는 추가 restriction을 두지 않았지만 다른 controller는 explicit configuration 전에는 resource usage를 모두 금지했습니다.

같은 type의 control도 configuration knob name과 format이 크게 달랐고 statistic·information knob는 arbitrary한 name과 서로 다른 format·unit을 사용했으며 같은 controller 안에서도 일관되지 않았습니다.

V1 interface inconsistencies
AreaV1 issue
Empty-cgroup eventsFork/exec helper per event; not recursive or delegatable; extra in-kernel filtering
Hierarchy semanticsSome controllers flatten all cgroups under root
New-cgroup defaultsSome unrestricted, others deny all usage until configured
Configuration interfaceDifferent names and formats for equivalent controls
Statistics and informationArbitrary names, formats and units, even within one controller

Core notification부터 controller defaults와 statistics까지 공통 convention이 없었습니다.

Cgroup v2는 적절한 영역에 common convention을 정립하고 controller가 minimal하고 consistent한 interface를 expose하도록 update합니다.

V2 interface remedy
Identify shared control and reporting patternsEstablish common conventionsRemove unnecessary implementation detailsExpose minimal consistent controller interfaces

공통 convention과 최소 interface가 controller 간 예측 가능성을 회복합니다.

Memory controller issues와 v2 remedies

3332-3407

Original lower boundary인 soft limit은 default로 unset이므로 global reclaim이 선호하는 cgroup set이 opt-out이 아니라 opt-in입니다. 대부분 negative lookup을 optimize하는 cost가 너무 커서 implementation은 매우 큰데도 기본적으로 바람직한 behavior조차 제공하지 못합니다.

Soft limit에는 hierarchical meaning이 없습니다. Configured group은 hierarchy 위치와 무관하게 global rbtree에 equal peer로 organize되어 subtree delegation이 불가능합니다.

Soft-limit reclaim pass는 지나치게 aggressive하여 high allocation latency와 overreclaim에 따른 system-performance 저하를 일으켜 feature 자체의 목적을 무너뜨립니다.

반면 `memory.low` boundary는 top-down으로 allocate되는 reserve입니다. Cgroup은 effective low 안에 있을 때 reclaim protection을 받아 subtree delegation이 가능하고, effective low를 넘으면 overage에 비례한 reclaim pressure를 받습니다.

Lower memory boundary comparison
BoundaryAllocation modelReclaim behavior
V1 soft limitUnset by default; opt-in global rbtree of equal peersNon-hierarchical, aggressive pass, high latency and overreclaim
V2 memory.lowTop-down allocated reserve with effective lowProtected within reserve; proportional pressure on overage

V1 soft limit과 v2 memory.low의 hierarchy·reclaim semantics 차이입니다.

Original high boundary인 hard limit은 OOM killer를 call해야 하더라도 움직일 수 없는 strict limit입니다. 이는 available memory를 최대한 활용하려는 목표와 대체로 충돌합니다.

Runtime workload memory consumption은 변하므로 overcommit이 필요하지만 strict upper limit에서는 working-set size를 매우 정확히 예측하거나 slack을 추가해야 합니다. Working-set estimation은 어렵고 error-prone하며 틀리면 OOM kill이 발생하므로 사용자는 보통 느슨한 limit을 택해 귀중한 resource를 낭비합니다.

반면 `memory.high`는 훨씬 conservative하게 설정할 수 있습니다. Boundary에 닿으면 allocation을 direct reclaim으로 보내 excess를 줄이도록 throttle하지만 OOM killer는 call하지 않습니다.

따라서 너무 aggressive한 high boundary는 process를 terminate하지 않고 gradual performance degradation을 만듭니다. User는 이를 monitor하고 acceptable performance를 유지하는 minimal memory footprint를 찾을 때까지 조정할 수 있습니다.

Finding an effective memory.high
Set memory.high conservativelyHit high boundaryThrottle allocations through direct reclaimObserve gradual performance degradationAdjust boundaryFind minimal acceptable footprint

OOM 대신 관찰 가능한 performance degradation으로 working set을 조정합니다.

Concurrent allocation이 많고 group 안 reclaim progress가 완전히 무너지면 high boundary를 넘을 수 있습니다. 이 경우에도 group을 kill하기보다 다른 group 또는 system의 slack에서 allocation을 만족시키는 편이 대체로 낫습니다.

`memory.max`는 이런 spillover를 제한하고 buggy하거나 malicious한 application을 최종적으로 contain합니다.

Upper memory boundary roles
BoundaryPrimary roleOOM behavior
memory.highDirect-reclaim throttle and observable performance controlNever invokes OOM killer by itself
memory.maxLimit spillover and contain buggy or malicious applicationsMay reclaim and OOM to enforce hard ceiling

Adaptive throttle과 ultimate containment를 별도 boundary로 제공합니다.

Original `memory.limit_in_bytes`를 current usage 아래로 설정하면 concurrent charge 때문에 limit-setting이 실패하는 race condition이 있었습니다.

반면 `memory.max`는 먼저 limit을 설정해 new charge를 막고, 새 limit을 만족할 때까지 reclaim과 OOM kill을 수행합니다. 이 과정은 limit이 충족되거나 `memory.max`에 write한 task가 kill될 때 끝납니다.

Hard-limit update ordering
Write lower memory.limit_in_bytes in v1Concurrent charges race with updateLimit setting may fail
Write lower memory.max in v2Install new limit firstPrevent new chargesReclaim and OOM until limit is met or writer dies

V2는 먼저 ceiling을 게시해 concurrent charge race를 닫은 뒤 usage를 낮춥니다.

Combined memory+swap accounting과 limiting은 swap space에 대한 실제 control로 대체되었습니다.

Original design에서 combined facility의 핵심 논리는 global 또는 parental pressure가 child의 신뢰할 수 없는 configuration과 무관하게 anonymous memory 전체를 swap할 수 있어야 한다는 것이었습니다.

그러나 untrusted group은 anonymous memory를 tight loop에서 계속 reference하는 등 다른 방식으로 swapping을 방해할 수 있습니다. 따라서 admin은 untrusted job을 overcommit할 때 완전한 swappability를 가정할 수 없습니다.

Trusted job에 combined counter는 intuitive한 userspace interface가 아니며 cgroup controller가 specific physical resource를 account하고 limit해야 한다는 원칙에도 어긋납니다. Swap space도 system의 다른 resource와 같으므로 unified hierarchy는 이를 별도로 distribute합니다.

Memory and swap accounting rationale
ModelAssumption / problemV2 remedy
Combined memory+swapParental pressure should swap all child anonymous memory, but untrusted jobs can defeat swappingDo not assume full swappability
Separate swap controlSwap is a distinct physical resourceAccount and distribute swap independently in unified hierarchy

Combined counter의 신뢰 가정과 v2의 physical-resource separation을 비교합니다.