CGROUPS(7) | Руководство программиста Linux | CGROUPS(7) |
cgroups - управляемые группы в Linux
Управляемые cgroup-ы, обычно называемые cgroups, это свойство ядра Linux, которое позволяет объединять процессы в иерархические группы, и в этих группах отслеживать и ограничивать разные типы ресурсов. Ядро предоставляет интерфейс работы с cgroup-ами через псевдо-файловую систему, называемую cgroupfs. Группировка реализована в базовой части ядра cgroup, а слежение за ресурсами и ограничениями — в подсистемах самих ресурсов (память, ЦП и т. п.).
cgroup — это набор процессов, которые связаны с набором ограничений или параметров, определяемых через файловую систему cgroup.
subsystem — компонент ядра, который изменяет поведение процессов в cgroup-у. Реализованы различные подсистемы, они позволяют делать разные вещи, например ограничивать количество времени ЦП и память доступную для cgroup-ы, подсчитывать время ЦП, используемое группой и останавливать и возобновлять выполнение процессов в cgroup-е. Подсистемы иногда также называют контроллерами ресурсов (или просто, контроллерами).
Для контроллера cgroup-ы упорядочены в иерархию. Иерархия определяется посредством создания, удаления и переименования подкаталогов в файловой системе cgroup. На каждом уровне иерархии можно задать атрибуты (например, ограничения). Если атрибуты назначены, то ограничение, контроль и учёт, предоставляемый cgroup-ами, обычно, распространяется в иерархии по всем нижестоящим элементам. То есть, например, ограничение, заданное на cgroup на высшем уровне иерархии не может быть превышено в дочерних cgroup-ах.
Впервые реализация cgroup появилась в Linux 2.6.24. Постепенно добавлялись различные контроллеры cgroup, позволяющие управлять различными типами ресурсов. Однако, разработка этих контроллеров была, по большей части, не скоординированной, что привело к несогласованности между контроллерами, и управление иерархиями cgroup стало очень сложным (расширенное описание проблем можно найти в файле исходного кода ядра Documentation/cgroup-v2.txt).
Вследствие проблем в первой реализации cgroup (cgroups версии 1), начиная с Linux 3.10 началась работа на новой независимой реализацией, учитывающей возникшие ошибки. Сначала помеченная как экспериментальная и скрытая параметром монтирования -o __DEVEL__sane_behavior новая версия (cgroups версии 2) в конце концов была добавлена в Linux 4.5. Различия между версиями описаны далее.
Хотя cgroups v2 создавалась как замена cgroups v1, старая система всё ещё существует (и для обеспечения совместимости её не хотелось бы удалять). В настоящее время, в cgroups v2 реализованы не все контроллеры, доступные в cgroups v1. Эти две системы реализованы таким образом, что контроллеры v1 и v2 можно монтировать одновременно. То есть, например, можно не только использовать контроллеры, поддерживаемые версией 2, но и использовать контроллеры версии 1, которые пока не поддерживаются версией 2. Единственным ограничением является то, что один и тот же контроллер не может быть запущен одновременно в иерархии cgroups v1 и cgroups v2.
В cgroups v1 каждый контроллер можно смонтировать в отдельную файловую систему cgroup, которая представляет собой собственную иерархию процессов в системе. Также возможно совместное монтирование нескольких (или даже всех) контроллеров cgroups v1 в единую файловую систему cgroup, при этом совместно смонтированные контроллеры управляют одной иерархией процессов.
Для каждой смонтированной иерархии дерево каталогов отражает иерархию управляемой группы. Каждая управляемая группа представляется каталогом, каждый её потомок управляемой cgroups представляется дочерним каталогом. Например, /user/joe/1.session представляет управляемую группу 1.session, которая является потомком cgroup joe, которая является потомком /user. В каждом каталоге cgroup есть набор файлов, доступных на чтение и запись, через которые доступны ограничения ресурсов и другие общие свойства cgroup.
В cgroups v1 процессы и задачи различаются. Процесс может состоять из нескольких задач (чаще всего называемых нитями, если смотреть из пользовательского пространства, и так они будут называться далее в этой справочной странице). В cgroups v1 возможно независимо управлять членством cgroup для нитей процесса.
В некоторых случаях способность cgroups v1 разделять нити по разным cgroups вызывает проблемы. Например, это не имеет смысла для контроллера memory, так как все нити процесса находятся в одном адресном пространстве. Из-за таких проблем способность независимого управления членством cgroup для нитей процесса была удалена в первой реализации cgroups v2, но позже восстановлена в более ограниченном виде (смотрите описание «режим нитей» ниже).
Для использования cgroups требуется собрать ядро с параметром CONFIG_CGROUP. Также с каждым контроллером v1 связан параметр настройки, который должен быть задан, если нужно работать с этим контроллером.
Чтобы использовать контроллер a v1, его нужно смонтировать в файловую систему cgroup. Обычно для этого используют файловую систему tmpfs(5), смонтированную в /sys/fs/cgroup. Таким образом, можно смонтировать контроллер cpu следующим образом:
mount -t cgroup -o cpu none /sys/fs/cgroup/cpu
Можно смонтировать несколько контроллеров вместе в одной иерархии. Например, так контроллеры cpu и cpuacct одновременно монтируются в одной иерархии:
mount -t cgroup -o cpu,cpuacct none /sys/fs/cgroup/cpu,cpuacct
Для одновременно смонтированных контроллеров процесс находится в одной cgroup всех одновременно смонтированных контроллеров. Отдельно смонтированные контроллеры позволяют процессу находиться в cgroup /foo1 одного контроллера и в /foo2/foo3 другого.
Можно смонтировать все контроллеры v1 вместе в одной иерархии:
mount -t cgroup -o all cgroup /sys/fs/cgroup
(Параметр -o all можно опустить, так как по умолчанию монтируются все контроллеры, если ни один не указан явно)
Невозможно смонтировать один и тот же контроллер в несколько иерархий cgroup. Например, невозможно смонтировать контроллеры cpu и cpuacct в одну иерархию и смонтировать только контроллер cpu в другую. Возможно создать несколько точек монтирования с полностью одинаковым набором одновременно смонтированных контроллеров. Однако в этом случае получается только несколько точек монтирования, представляющих одну иерархию.
Заметим, что на многих системах контроллеры v1 автоматически монтируется в /sys/fs/cgroup; в частности, такие точки монтирования автоматически создаёт systemd(1).
Смонтированная файловая система cgroup может быть размонтирована с помощью команды umount(8) как показано в этом примере:
umount /sys/fs/cgroup/pids
Но заметим: файловая система cgroup размонтируется только, если она не занята, то есть не имеет дочерних cgroup. Если это не этот случай, то действием umount(8) будет только сокрытие монтирования. То есть, чтобы действительно удалить точку монтирования, сначала нужно удалить все дочерние cgroup, что, в свою очередь, можно выполнить только после перемещения всех процессов-членов из этих cgroup в корневую cgroup.
Все контроллеры cgroups версии 1 управляются параметрами настройки ядра (список далее). Также, включение свойства cgroups управляется параметром настройки ядра CONFIG_CGROUPS.
Первоначально, в файловой системе cgroup содержится только корневая cgroup, «/», которой принадлежат все процессы. Новая cgroup создаётся посредством создания каталога в файловой системе cgroup:
mkdir /sys/fs/cgroup/cpu/cg1
Данная команда создаёт новую пустую cgroup.
Помещение процесса в эту cgroup выполняется с помощью записи его PID в файл cgroup cgroup.procs:
echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs
В этот файл единовременно должен записываться только один PID.
Запись в файл cgroup.procs значения 0 приводит к помещению в соответствующую cgroup записывающего процесса.
При записи PID в cgroup.procs в новую cgroup одновременно перемещаются все нити процесса.
Внутри иерархии процесс может быть членом только одной cgroup. Запись PID процесса в файл cgroup.procs автоматически удаляет его из cgroup, в которой он числился до этого.
Для получения списка процессов, числящихся в cgroup, можно прочитать файл cgroup.procs. Возвращаемый список PID не обязательно упорядочен. Также PID могут повторяться (например, во время чтения списка PID может использоваться повторно).
В cgroups v1 отдельные нити могут перемещаться в другую cgroup посредством записи ID нити (т. е., ядерный ID нити, возвращаемый clone(2) и gettid(2)) в файл tasks из каталога cgroup. Этот файл можно прочитать, чтобы получить набор нитей, принадлежащих cgroup.
Удаляемая cgroup не должна содержать дочерних cgroups и процессов (не зомби). Если это соблюдается, то можно просто удалить соответствующий каталог. Заметим, что файлы в каталоге cgroup невозможно и ненужно удалять.
Для определения того, как ядро выполняет уведомления об опустевших cgroup, можно использовать два файла. Cgroup считается пустой, если не содержит дочерних cgroup и процессов.
Специальный файл в корневом каталоге каждой иерархии cgroup, release_agent, можно использовать для регистрации программы, которая будет вызываться всякий раз, когда cgroup в иерархии становится пустой. При вызове программы release_agent в единственной аргументе командной строки передаётся путь (относительно точки монтирования cgroup) только что опустевшей cgroup. Программа release_agent может удалить удалить каталог cgroup или, возможно, повторно добавить в него процесс.
По умолчанию файл release_agent пуст, то есть агент освобождения не вызывается.
Содержимое файла release_agent также можно задать в параметре монтирования при монтировании файловой системы cgroup:
mount -o release_agent=файл …
Будет ли программа release_agent вызываться для определённой ставшей пустой cgroup, задаётся значением файла notify_on_release в каталоге, соответствующем cgroup. Если этот файл содержит значение 0, то программа release_agent не вызывается. Если он содержит 1, то программа release_agent вызывается. По умолчанию в этом файле содержится 0 для корневой cgroup. В момент, когда создаётся новая cgroup, значение в этом файле наследуется из соответствующего файла родительской cgroup.
В cgroups v1 возможно монтирование иерархии cgroup, у которой нет присоединённых контроллеров:
mount -t cgroup -o none,name=какое-то_имя none /some/mount/point
Можно смонтировать несколько экземпляров таких иерархий; каждая иерархия должна иметь уникальное имя. Единственной целью таких иерархий является слежение за процессами (смотрите описание о выдаче уведомлений ниже). В пример можно привести иерархию cgroup name=systemd, которая используется systemd(1) для слежения за службами и пользовательскими сеансами.
Начиная с Linux 5.0, параметром ядра cgroup_no_v1 (описан ниже) можно выключить иерархию cgroup v1 с определённым именем: cgroup_no_v1=named.
В cgroup v2 все смонтированные контроллеры располагаются в единой унифицированной иерархии. Хотя (различные) контроллеры могут одновременно монтироваться в иерархиях v1 и v2, невозможно одновременное монтирование одного контроллера в обеих иерархиях v1 и v2.
Далее приведено краткое описание новых правил поведения cgroups v2, и в некоторых случаях, расширено в последующих подразделах.
Дополнительную информацию смотрите в файле исходного кода ядра Documentation/cgroup-v2.txt.
Некоторые новые упомянутые выше функциональные возможности появились с добавлением в Linux 4.14 «режима нитей» (смотрите далее).
В cgroups v1, способность монтировать различные контроллеры в разные иерархии предназначалась для повышения гибкости при разработки приложения. Однако на практике выяснилось, что гибкость не так полезна как ожидалось, и во многих случаях добавляет сложности. Поэтому в cgroups v2, все доступные контроллеры монтируются в одну иерархию. Доступные контроллеры монтируются автоматически, то есть не нужно (но можно) указывать контроллеры при монтировании файловой системы cgroup v2 с помощью команды вида:
mount -t cgroup2 none /mnt/cgroup2
Контроллер cgroup v2 доступен только, если он уже не смонтирован в иерархии cgroup v1. Или, иначе говоря, невозможно использовать тот же контроллер одновременно в иерархии v1 и унифицированной иерархии v2. Это означает, что сначала может потребоваться размонтировать контроллер v1 (как описано выше), чтобы он стал доступен в v2. Так как systemd(1) по умолчанию интенсивно использует некоторые контроллеры v1, в некоторых случаях проще загрузить систему с отключёнными контроллерами v1. Для этого укажите параметр cgroup_no_v1=список в командной строке загрузки ядра; в списке через запятую перечисляются имена отключаемых контроллеров или указывается слово all для выключения всех контроллеров v1 (этот вариант корректно отрабатывается systemd(1) и она начинает работать без указанных контроллеров).
Заметим, что во многих современных системах systemd(1) автоматически монтирует файловую систему cgroup2 в каталог /sys/fs/cgroup/unified при запуске системы.
Следующие контроллеры, описанные в файле исходного кода ядра Documentation/cgroup-v2.txt, поддерживаются в cgroups версии 2:
Каждая cgroup в иерархии v2 содержит следующие два файла:
echo '+pids -memory' > x/y/cgroup.subtree_control
Так как список контроллеров в cgroup.subtree_control является поднабором из cgroup.controllers, то контроллер, отключённый в иерархии cgroup, невозможно включить в поддереве ниже этой cgroup.
Файл cgroup cgroup.subtree_control определяет набор контроллеров, которые выполняются в дочерних cgroup. Когда контроллер (например pids), есть в файле cgroup.subtree_control родительской cgroup, то соответствующие файлы интерфейса контроллера (например pids.max) автоматически создаются в дочерних cgroup и могут использоваться для влияния на управление ресурсами в дочерних cgroup.
Cgroups v2 вводит так называемое правило «нет внутренним процессам». Грубо говоря, это правило означает, что за исключением корневой cgroup, процессы могут располагаться только в краевых узлах (cgroup, которая не содержит дочерних cgroup). Это позволяет не решать как делить ресурсы между процессами, которые являются членами cgroup A и процессами в дочерних cgroup-ах A.
Например, если существует cgroup /cg1/cg2, то процесс может располагаться в /cg1/cg2, но не в /cg1. Это решает проблему с неясностью в cgroups v1 в плане разделения ресурсов между процессами в /cg1 и её дочерних cgroup-ах. Рекомендуемый подход в cgroups v2 — создать подкаталог leaf для всех конечных cgroup, в котором будут содержаться только процессы и отсутствовать дочерние cgroup-ы. То есть процессы, которые раньше находились в /cg1 теперь должны помещаться в /cg1/leaf. Преимуществом этого является явное указание родства между процессами в /cg1/leaf и в других потомках /cg1.
На самом деле, правило «нет внутренним процессам» не столь категорично как утверждалось выше. Более точно, правило состоит в том, что (не корневая) cgroup не может одновременно (1) иметь процессы-члены и (2) распределять ресурсы в дочерних cgroup, то есть иметь непустой файл cgroup.subtree_control. Таким образом, cgroup может иметь процессы-члены и дочерние cgroup, но перед тем как в этой группе можно будет включить контроллеры, члены-процессы нужно вывести из cgroup (например, в дочерние cgroup).
С добавлением в Linux 4.14 «режима нитей» (смотрите далее) для некоторых случаев применение правила «не внутренних процессов» было ослаблено.
В cgroups v2 появился новый механизм получения уведомления при появлении пустой cgroup. Файлы cgroups v1 release_agent и notify_on_release удалены и заменены новым, более общим файлом cgroup.events. В этом доступном только для чтения файле содержится пара ключ-значение (пары разделяются символом новой строки, ключ и значение разделяется пробелами), которые определяют события или состояние cgroup. В настоящее время доступен только один ключ, populated, который имеет значение 0, означающее, что эта cgroup (и её потомки) не содержат процессов (не зомби), или 1, означающее, что cgroup содержит процессы.
За файлом cgroup.events можно установить наблюдение и получить уведомление, когда cgroup изменяет состояние с пустой на непустую и наоборот. При наблюдении за файлом с помощью inotify(7) во время перехода генерируются события IN_MODIFY, а при наблюдении с помощью poll(2) во время перехода в возвращаемом поле revents устанавливаются биты POLLPRI и POLLERR.
Механизм уведомлений cgroups v2, предоставляемый полем populated в файле cgroup.events имеет, по крайней мере, два преимущества над механизмом cgroups v1 release_agent. Во-первых, уведомление менее требовательно, так как один процесс может следить за несколькими файлами cgroup.events. Для сравнения, механизм cgroups v1 требует создания процесса для каждого уведомления. Во-вторых, уведомление может бы поручено процессу, который находится внутри контейнера, связанного с только что созданной пустой cgroup.
Каждая cgroup в иерархии v2 содержит файл cgroup.stat, доступный только для чтения (появился в Linux 4.14), который состоит из строк с парами ключ-значение. В этом файле появляются следующие ключи:
Каждая cgroup в иерархии v2 содержит следующие файлы, которые можно использовать для просмотра и изменения количества дочерних cgroup в cgroup:
В контексте cgroups, делегирование означает передачу управления частью поддерева иерархии cgroup непривилегированному пользователю. Cgroups v1 предоставляют поддержку делегирования на основе файловых прав доступа в иерархии cgroup, но эти правила менее ограничительны по сравнению с v2 (смотрите далее). Поддержка делегирования в cgroups v2 планировалась изначально. В основном, этот раздел описывает делегирование для cgroups v2, попутно указывая различия с cgroups v1.
Для описания делегирования необходима некоторая терминология. Делегирующий это привилегированный пользователь (т.е., корневой объект), которому принадлежит родительская группа cgroup. Делегат это непривилегированный пользователь, которому будут предоставлены права, необходимые для управления некоторой субиерархией в родительской группе cgroup, также называемой делегированным поддеревом.
Для делегирования, делегирующий создает определённые каталоги и файлы, доступные на запись делегату, обычно, назначая владельцем объектов идентификатором пользователя-делегата. Предполагая, что нужно делегировать иерархию с корнем (например) /dlgt_grp и что пока нет каких-либо дочерних cgroups в cgroup, меняем владельца на идентификатор пользователя-делегата у следующего:
Делегирующий не должен изменять владельцев файлов интерфейса контроллера (например, pids.max, memory.high) в dlgt_grp. Эти файлы используются со следующего уровня над делегируемым поддеревом, чтобы распределить ресурсы в поддерево, и делегат не должен иметь права изменять ресурсы, распределённые в делегируемое поддерево.
Информацию о других делегируемых файлах cgroups v2 смотрите описание файла /sys/kernel/cgroup/delegate в ЗАМЕЧАНИЯХ.
После выполнения вышеуказанных шагов делегат может создавать подгруппы cgroups в рамках делегированного поддерева (подкаталоги cgroup и файлы в них будут принадлежать делегату) и перемещать процессы между группами cgroup в поддереве. Если в dlgt_grp/cgroup.subtree_control есть контроллеры, или право владения этим файлом перешло к делегату, то делегат также может управлять дальнейшим распределением соответствующих ресурсов в делегированном ему поддереве.
Начиная с Linux 4.13 появился второй способ делегирования cgroup в иерархии cgroups v2. Этого можно достичь монтированием или перемонтированием файловой системы cgroup v2 с параметром монтирования nsdelegate. Например, если файловая система cgroup v2 уже смонтирована, то её можно перемонтировать с параметром nsdelegate следующим образом:
mount -t cgroup2 -o remount,nsdelegate \ none /sys/fs/cgroup/unified
Данный параметр монтирования заставляет пространства имён cgroup автоматически устанавливать границы делегирования. При этом на процессы внутри пространства имён cgroup накладываются следующие ограничения:
Возможность определения пространств имён cgroup для границ делегирования делает пространства имён cgroup ещё более полезными. Чтобы понять почему, предположим, что у нас уже есть одна иерархия cgroup, которая была делегирована непривилегированному пользователю, cecilia, посредством старого способа делегирования, описанного выше. Также предположим, что cecilia тоже хочет делегировать одну иерархий из имеющихся в делегированной иерархии (например, делегированная иерархия может быть связана с непривилегированным контейнером, запущенным cecilia). Даже, если пространство имён cgroup namespace было передано, так как обе иерархии принадлежат непривилегированному пользователю cecilia, могут быть выполнены следующие неправомерные действия:
Использование параметра монтирования nsdelegate предотвращает обе эти возможности.
Параметр монтирования nsdelegate действует только, когда применяется к начальному пространству имён монтирования; для других пространств имён монтирования он игнорируется.
Замечание: в некоторых системах systemd(1) автоматически монтирует файловую систему cgroup v2. Чтобы попробовать работу с nsdelegate , может быть полезно загрузить ядро с следующими параметрами командной строки:
cgroup_no_v1=all systemd.legacy_systemd_cgroup_controller
Эти параметры заставляют ядро загружаться с выключенными контроллерами cgroups v1 (т. е., контроллеры доступны из иерархии v2) и указывают systemd(1) не монтировать и использовать иерархию cgroup v2, таким образом позволяя вручную смонтировать иерархию v2 с желаемыми параметрами после загрузки.
Некоторые сдерживающие правила делегирования обеспечивает то, что делегат может перемещать процессы в рамках делегированного поддерева, но не сможет перемещать процессы извне делегированного поддерева в поддерево и наоборот. Непривилегированный процесс (т. е., делегат) может записать PID «целевого» процесса в файл cgroup.procs только, если всё следующее верно:
Замечание: одним из следствий этих сдерживающих правил является то, что непривилегированный делегат не может поместить первый процесс в делегированное поддерево; вместо этого делегирующему необходимо поместить первый процесс (процесс, принадлежащей делегату) в делегированное поддерево.
Ограничения, налагаемые cgroups v2, но отсутствующие в cgroups v1:
Эти ограничения добавлены из-за того, что их отсутствие вызывало проблемы в cgroups v1. В частности, возможность понитевого контроля членства в cgroups v1 приводило к бессмысленности некоторых контроллеров (особенно это касалось контроллера memory: так как нити используют одно адресное пространство, нет смысла разделять нити по разным memory cgroup).
В первоначальном решении проекта cgroups v2 не учитывалось, что для некоторых контроллеров, таких как cpu, было бы важным и полезным задействовать понитевое управление. Чтобы приспособиться под такие случаи, в Linux 4.14 для cgroups v2 добавлен режим нитей.
Режим нитей позволяет следующее:
Также, в режиме нитей каждая не корневая cgroup теперь содержит новый файл, cgroup.type, который отражает и, в некоторых случаях, может использоваться для изменения «типа» cgroup. Этот файл содержит одно из следующих значений типа:
С добавлением режима нитей теперь в cgroups v2 различают два типа контроллеров ресурсов:
Существует два способа создания поддерева нитей. Первый:
Второй способ создания поддерева нитей:
Следствием одного из этих путей создания поддерева нитей является то, что cgroup корня нитей может быть родителем только cgroup с типом threaded (и domain invalid). cgroup корня нитей не может быть родителем cgroup с типом domain и cgroup с типом threaded не может быть на одном уровне с cgroup с типом domain.
В поддереве нитей можно включать контроллеры нитей для каждой подгруппы, чей тип был изменён на threaded; после того, как это сделано, файлы интерфейса соответствующего контроллера появятся в дочерних cgroup.
Процесс можно перемещать в поддерево нитей посредством записи его PID в файл cgroup.procs одной из cgroup внутри дерева. В результате все нити процесса становятся членами соответствующей cgroup,а процесс — членом поддерева нитей. После этого нити процесса можно размещать по поддереву нитей посредством записи ID нитей (смотрите gettid(2)) в файлы cgroup.threads различных cgroup внутри поддерева. Все нити процесса должны быть расположены в одном поддереве нитей.
Как и при записи в cgroup.procs, при записи в файл cgroup.threads накладываются некоторые сдерживающие правила:
Файл cgroup.threads существует в каждой cgroup (включая cgroup c типом domain) и может быть прочитан для нахождения набора нитей, представленных в группе. Для набора ID нитей, получаемых при чтении этого файла, не гарантируется порядок и отсутствие повторов.
Файл cgroup.procs в корне нитей отражает PID всех процессов, являющихся членами поддерева нитей. Файлы cgroup.procs других cgroup в поддереве недоступны для чтения.
Доменные контроллеры невозможно включить в поддереве нитей; в cgroup ниже корня нитей отсутствуют интерфейсные файлы контроллера. С точки зрения доменного контроллера поддеревья нитей невидимы: многонитевые процессы внутри поддерева нитей видятся доменным контроллером как процесс, расположенный в cgroup корня нитей.
В поддереве нитей правило «нет внутренних процессов» не применяется: cgroup может иметь одновременно процессы-члены (или нить) и выполняемые контроллеры в дочерних cgroup.
При записи в файл cgroup.type накладывается несколько правил:
Также для создания поддерева нитей с корнем cgroup x требуется выполнить несколько условий:
Если какое-либо из этих ограничений нарушено, то попытка записи "threaded" в файл cgroup.type завершится ошибкой ENOTSUP.
Согласно способам, описанным выше, тип cgroup можно измениться на domain threaded в следующих случаях:
Cgroup с типом domain threaded, x, может снова стать domain, если перечисленные выше условия не соблюдаются — то есть, если удалены все потомки cgroup x с типом threaded, у x выключены все контроллеры нитей или больше нет процессов-членов.
Когда cgroup x с типом domain threaded возвращается к типу domain:
Корневая cgroup иерархии v2 рассматривается отдельно: она может быть родителем cgroup сразу обоих типов: domain и threaded. Если строка "threaded" записывается в файл cgroup.type одного из потомков корневой cgroup, то
Заметим, что в этом случае нет cgroup, чей тип стал domain threaded (в принципе, корневая cgroup может рассматриваться как корень нитей для cgroup, чей тип был изменён на threaded).
Данное исключение для корневой cgroup позволяет cgroup нитей, запускающей контроллер cpu, быть помещённой выше всех насколько возможно в иерархии, для того, чтобы минимизировать ущерб (маленький) от обхода иерархии cgroup.
Начиная с Linux 4.19, контроллер cgroups v2 cpu не поддерживает управление нитями реального времени(нити, запланированные к выполнению планировщиками SCHED_FIFO, SCHED_RR, SCHED_DEADLINE; смотрите sched(7)). Поэтому контроллер cpu можно включить в корневую cgroup только, если все нити реального времени находятся в корневой cgroup (если есть нити реального времени вне корневой cgroups, то запись (write(2)) строки "+cpu" в файл cgroup.subtree_control завершится ошибкой EINVAL).
В некоторых системах systemd(1) помещает определённые нити реального времени в некорневую cgroups иерархии v2. В таких системах такие нити должны помещаться раньше в корневую cgroup, до включения контроллера cpu.
Следующие ошибки могут возникать при mount(2):
Дочерний процесс, созданный fork(2), наследует членство родителя в cgroup. Членство в cgroup сохраняется при execve(2).
#subsys_name hierarchy num_cgroups enabled cpuset 4 1 1 cpu 8 1 1 cpuacct 8 1 1 blkio 6 1 1 memory 3 1 1 devices 10 84 1 freezer 7 1 1 net_cls 9 1 1 perf_event 5 1 1 net_prio 9 1 1 hugetlb 0 1 0 pids 2 1 1
ID иерархии:список контроллеров:путь cgroup
5:cpuacct,cpu,cpuset:/daemons
$ cat /sys/kernel/cgroup/delegate cgroup.procs cgroup.subtree_control cgroup.threads
$ cat /sys/kernel/cgroup/features nsdelegate
prlimit(1), systemd(1), systemd-cgls(1), systemd-cgtop(1), clone(2), ioprio_set(2), perf_event_open(2), setrlimit(2), cgroup_namespaces(7), cpuset(7), namespaces(7), sched(7), user_namespaces(7)
2019-03-06 | Linux |