cgroups(7)

NOM
cgroups – Groupes de contrôle de Linux

DESCRIPTION
Les groupes de contrôle, habituellement appelés cgroups, sont une fonctionnalité du noyau Linux qui permet d'organiser les processus en groupes hiérarchiques afin de limiter et de superviser leur utilisation de types divers de ressource. L’interface cgroup du noyau est fournie à travers un pseudo-système de fichiers appelé cgroupfs. Le regroupement est implémenté dans le code central cgroup du noyau, tandis que le suivi et les limites de ressources sont implémentés dans un ensemble de sous-systèmes de type par ressource (mémoire, CPU, etc.).

  Terminologie
Un cgroup est une collection de processus qui sont liés à un ensemble de limites ou de paramètres définis à l’aide du système de fichiers cgroup.

Un sous-système est un composant du noyau qui modifie le comportement des processus dans un cgroup. Divers sous-systèmes ont été implémentés, rendant possible de faire des choses comme la limitation de temps CPU et de mémoire disponibles pour un cgroup, la comptabilisation du temps CPU utilisé dans un cgroup et le gel ou la reprise de l’exécution des processus dans un cgroup. Les sous-systèmes sont parfois connus comme contrôleurs de ressource (ou simplement, contrôleurs).

Les cgroups pour un contrôleur sont agencés dans une hiérarchie. Celle-ci est définie en créant, supprimant et renommant des sous-répertoires dans le système de fichiers cgroup. À chaque niveau de la hiérarchie, des attributs (par exemple, des limites) peuvent être définis. Les limites, le contrôle et la comptabilisation fournis par les cgroups ont généralement des effets partout dans la sous-hiérarchie du cgroup où les attributs sont définis. Par conséquent, par exemple, les limites placées dans un cgroup d’un niveau supérieur dans la hiérarchie ne peuvent être franchies par des cgroups descendants.

  Cgroups version 1 et version 2
La publication initiale de l’implémentation des cgroups a été faite dans Linux 2.6.24. Au cours du temps, divers contrôleurs de cgroup ont été ajoutés pour permettre la gestion de divers types de ressources. Cependant, le développement de ces contrôleurs n’a pas été coordonné en grande partie avec pour résultat l'apparition de nombreuses incohérences entre les contrôleurs et une complexité accrue de la gestion des hiérarchies de cgroup. Une description plus complète de ces problèmes peut être trouvée dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v2.rst (ou Documentation/cgroup-v2.txt dans Linux version 4.17 et précédentes).

À cause des problèmes avec l’implémentation initiale des cgroups (cgroups version 1), des travaux ont commencé, à partir de Linux 3.10, sur une nouvelle implémentation indépendante pour remédier à ces problèmes. Au départ marquée comme expérimentale, et dissimulée derrière l’option de montage -o __DEVEL__sane_behavior, la nouvelle version (cgroups version 2) est devenue finalement officielle avec la publication de Linux 4.5. Les différences entre les deux versions sont décrites dans le texte qui suit. Le fichier cgroup.sane_behavior, présent dans cgroups version 1, est un vestige de cette option de montage. Le fichier indique toujours « 0 » et n’est conservé que pour la rétrocompatibilité.

Bien que cgroups version 2 soit destiné à remplacer la version 1, l’ancien système continue à exister (et pour des raisons de compatibilité, ne sera vraisemblablement pas supprimé). Actuellement, cgroups version 2 implémente un sous-ensemble de contrôleurs disponibles dans cgroups version 1. Les deux systèmes sont implémentés de façon que les contrôleurs version 1 et 2 puissent être montés sur le même système. Ainsi, par exemple, il est possible d’utiliser les contrôleurs qui sont pris en charge par la version 2, tout en utilisant aussi des contrôleurs version 1 là où la version 2 ne les prend pas encore en charge. La seule restriction ici est qu’un contrôleur ne peut pas être employé simultanément dans une hiérarchie de cgroups version 1 et dans une hiérarchie de cgroups version 2.

CGROUPS VERSION 1
Sous cgroups version 1, chaque contrôleur peut être monté pour un système de fichiers cgroup distinct qui fournit sa propre organisation hiérarchique des processus dans le système. Il est aussi possible de co-monter plusieurs (et même tous) les contrôleurs de cgroups version 1 pour le même système de fichiers cgroup, ce qui signifie que les contrôleurs co-montés gèrent la même organisation hiérarchique des processus.

Pour chaque hiérarchie montée, l’arbre de répertoires reflète la hiérarchie de groupes de contrôle. Chaque groupe de contrôle est représenté par un répertoire, avec chaque cgroup de contrôle enfant représenté par un répertoire enfant. Par exemple, /user/joe/1.session représente le groupe de contrôle 1.session, qui est un enfant du cgroup joe, qui est un enfant de /user. Sous chaque répertoire cgroup existe un ensemble de fichiers qui peuvent être lus ou écrits, reflétant les limites de ressources et quelques propriétés générales du cgroup.

  Tâches (threads) versus processus
Dans cgroups version 1, une distinction est faite entre les processus et les tâches. De ce fait, un processus peut consister en plusieurs tâches (plus couramment appelées threads, du point de vue espace utilisateur, et appelées ainsi dans la suite de cette page de manuel). Dans cgroups version 1, il est possible de manipuler indépendamment l’appartenance de cgroup des threads d’un processus.

La capacité de cgroups version 1 de répartir les threads dans des cgroups différents cause des problèmes dans certains cas. Par exemple, cela n’a aucun sens pour le contrôleur de mémoire, puisque tous les threads d’un processus partagent un même espace d’adressage. À cause de cela, la capacité de manipuler indépendamment l’appartenance de cgroup des threads dans un processus a été retirée dans l’implémentation initiale de cgroups version 2, et ultérieurement restaurée dans une forme plus limitée (voir l’explication sur le « mode threads » ci-après).

  Montage de contrôleurs version 1
L’utilisation de cgroups requiert un noyau construit avec l’option CONFIG_CGROUP. De plus, chaque contrôleur version 1 possède une option de configuration associée qui doit être définie pour utiliser ce contrôleur.

Pour utiliser un contrôleur version 1, il doit être monté pour un système de fichiers de cgroup. L’emplacement habituel de tels montages est sous le système de fichiers tmpfs(5) monté dans /sys/fs/cgroup. Par conséquent, un montage du contrôleur cpu peut être réalisé ainsi :

    mount -t cgroup -o cpu none /sys/fs/cgroup/cpu

Il est possible de co-monter plusieurs contrôleurs pour la même hiérarchie. Ici par exemple, les contrôleurs cpu et cpuacct sont co-montés pour une même hiérarchie :

    mount -t cgroup -o cpu,cpuacct none /sys/fs/cgroup/cpu,cpuacct

Le co-montage de contrôleurs fait qu’un processus est dans le même cgroup pour tous les contrôleurs co-montés. Séparer le montage de contrôleurs permet à un processus d’être dans le cgroup /toto1 pour un contrôleur tout en étant dans /toto2/toto3 pour un autre.

Il est possible de co-monter tous les contrôleurs version 1 pour la même hiérarchie :

    mount -t cgroup -o all cgroup /sys/fs/cgroup

(Le même résultat peut être obtenu en omettant -o all, puisque c’est le comportement par défaut si aucun contrôleur n’est explicitement précisé.)

Il n’est pas possible de monter le même contrôleur pour plusieurs hiérarchies de cgroup. Par exemple, il n’est pas possible de monter à la fois les contrôleurs cpu et cpuacct pour une même hiérarchie et de monter le contrôleur cpu seul pour une autre hiérarchie. Il est possible de créer plusieurs montages avec exactement le même ensemble de contrôleurs co-montés. Dans ce cas cependant, tout cela aboutit à ce que plusieurs points de montage fournissent une vue de la même hiérarchie.

Remarquez que sur de nombreux systèmes, les contrôleurs version 1 sont automatiquement montés sous /sys/fs/cgroup. En particulier, systemd(1) crée automatiquement de tels montages.

  Démontage des contrôleurs version 1
Un système de fichiers cgroup monté peut être démonté en utilisant la commande umount(8) comme dans l’exemple suivant :

    umount /sys/fs/cgroup/pids

Bien remarquer qu’un système de fichiers de cgroup est démonté seulement s’il n’est pas en cours d’utilisation, c’est-à-dire qu’il n’a pas de cgroups enfants. Si ce n’est pas le cas, le seul effet de umount(8) est de rendre le montage invisible. Par conséquent, pour être sûr que le montage est réellement retiré, les cgroups enfants doivent d’abord être retirés, ce qui à son tour ne peut être fait qu'après que tous les processus membres ont été déplacés de ces cgroups vers le cgroup racine.

  Contrôleurs de cgroups version 1
Chacun de ces contrôleurs de cgroups version 1 est régi par une option de configuration du noyau (liste ci-après). De plus, la disponibilité de la fonctionnalité des cgroups est régie par l’option de configuration CONFIG_CGROUPS du noyau.

cpu (depuis Linux 2.6.24 ; CONFIG_CGROUP_SCHED)
    Un nombre minimal de « partages de CPU » peut être garanti quand un système est actif. Cela ne limite pas l'utilisation de CPU par un cgroup si les CPU ne sont pas actifs. Pour plus d’informations, consultez Documentation/scheduler/sched-design-CFS.rst (ou Documentation/scheduler/sched-design-CFS.txt dans Linux 5.2 et les versions antérieures).

    Dans Linux 3.2, ce contrôleur a été étendu pour fournir un contrôle de la « bande passante » du CPU. Si le noyau est configuré avec CONFIG_CFS_BANDWIDTH, il est possible de définir une limite haute du temps CPU alloué aux processus d’un cgroup à chaque période de planification (définie à l’aide d’un fichier dans le répertoire de cgroup). La limite haute s’applique même s’il n’existe aucune compétition pour le CPU. Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/scheduler/sched-bwc.rst (ou Documentation/scheduler/sched-bwc.txt dans Linux 5.2 et les versions antérieures).

cpuacct (depuis 2.6.24 ; CONFIG_CGROUP_CPUACCT)
    Ce contrôleur fournit la comptabilisation de l’utilisation du CPU par des groupes de processus.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/cpuacct.rst (ou Documentation/cgroup-v1/cpuacct.txt dans Linux 5.2 et les versions antérieures).

cpuset (depuis Linux 2.6.24 ; CONFIG_CPUSETS)
    Ce cgroup peut être utilisé pour lier les processus dans un cgroup à un ensemble spécifié de CPU ou de nœuds NUMA.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/cpusets.rst (ou Documentation/cgroup-v1/cpusets.txt dans Linux 5.2 et les versions précédentes).

memory (depuis Linux 2.6.25 ; CONFIG_MEMCG)
    Le contrôleur de mémoire prend en charge le rapport et la limitation de la mémoire du processus, de la mémoire du noyau et de la partition d’échange utilisées par les cgroups.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/memory.rst (ou Documentation/cgroup-v1/memory.txt dans Linux 5.2 et les versions antérieures).

devices (depuis Linux 2.6.26 ; CONFIG_CGROUP_DEVICE)
    Ce contrôleur prend en charge la définition des processus qui pourront créer (mknod) des périphériques et les ouvrir en lecture ou écriture. Les politiques peuvent être précisées dans des listes d’autorisations ou de refus. La hiérarchie est imposée, aussi des règles nouvelles ne doivent pas violer les règles existantes pour la cible ou pour des cgroups ancêtres.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/devices.rst (ou Documentation/cgroup-v1/devices.txt dans Linux 5.2 et les versions antérieures).

freezer (depuis Linux 2.6.28 ; CONFIG_CGROUP_FREEZER)
    Le cgroup freezer peut suspendre ou restaurer (reprendre) tous les processus d’un cgroup. Geler un cgroup /A fait que ses enfants, par exemple les processus dans /A/B, sont gelés.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/freezer-subsystem.rst (ou Documentation/cgroup-v1/freezer-subsystem.txt dans Linux 5.2 et les versions antérieures).

net_cls (depuis Linux 2.6.29 ; CONFIG_CGROUP_NET_CLASSID)
    Ce contrôleur place un identificateur de classe (classid), précisé pour le cgroup, sur des paquets réseau créés par un cgroup. Ces identificateurs peuvent être utilisés dans des règles de pare-feu, ainsi que pour canaliser le trafic en utilisant tc(8). Cela s’applique aux paquets quittant le cgroup, pas au trafic y arrivant.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/net_cls.rst (ou Documentation/cgroup-v1/net_cls.txt dans Linux 5.2 et les versions antérieures).

blkio (depuis Linux 2.6.33 ; CONFIG_BLK_CGROUP)
    Le cgroup blkio contrôle et limite l’accès aux périphériques en mode bloc indiqués en appliquant un contrôle d’E/S sous forme de restrictions et de limites d’accès à l’encontre de nœuds feuilles et de nœuds intermédiaires dans la hiérarchie de stockage.

    Deux politiques sont possibles. La première est une division du disque proportionnelle au poids basée sur la durée et implémentée avec CFQ (Completely Fair Queuing — file d'attente complètement équitable). C’est le cas pour les nœuds feuilles utilisant CFQ. La seconde est une politique d’étranglement qui précise les limites supérieures de taux d’E/S sur un périphérique.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/blkio-controller.rst (ou Documentation/cgroup-v1/blkio-controller.txt dans Linux 5.2 et les versions antérieures).

perf_event (depuis Linux 2.6.39 ; CONFIG_CGROUP_PERF)
    Ce contrôleur permet à perf de superviser l’ensemble des processus groupés dans un cgroup.

    Plus d’informations sont disponibles dans le fichier des sources du noyau.

net_prio (depuis Linux 3.3 ; CONFIG_CGROUP_NET_PRIO)
    Ce contrôleur permet de définir des priorités par interface réseau pour les cgroups.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/net_prio.rst (ou Documentation/cgroup-v1/net_prio.txt dans Linux 5.2 et les versions antérieures).

hugetlb (depuis Linux 3.5 ; CONFIG_CGROUP_HUGETLB)
    Ce contrôleur prend en charge la limitation de l’utilisation de très grandes pages par les cgroups.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/hugetlb.rst (ou Documentation/cgroup-v1/hugetlb.txt dans Linux 5.2 et les versions antérieures).

pids (depuis Linux 4.3 ; CONFIG_CGROUP_PIDS)
    Ce contrôleur permet de limiter le nombre de processus pouvant être créés dans un cgroup (et ses descendants).

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/pids.rst (ou Documentation/cgroup-v1/pids.txt dans Linux 5.2 et les versions antérieures).

rdma (depuis Linux 4.11 ; CONFIG_CGROUP_RDMA)
    Le contrôleur RDMA permet de limiter l’utilisation de ressources spécifiques à RDMA/IB.

    Plus d’informations sont disponibles dans le fichier des sources du noyau Documentation/admin-guide/cgroup-v1/rdma.rst (ou Documentation/cgroup-v1/rdma.txt dans Linux 5.2 et les versions antérieures).

  Création de cgroups et déplacement de processus
Un système de fichiers de cgroup contient initialement un seul cgroup racine, « / », auquel tous les processus appartiennent. Un nouveau cgroup est créé en créant un répertoire dans le système de fichiers de cgroup :

    mkdir /sys/fs/cgroup/cpu/cg1

Cette commande crée un nouveau cgroup vide.

Un processus peut être transféré dans ce cgroup en écrivant son PID dans le fichier cgroup.procs du cgroup :

    echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs

Un seul PID à la fois peut être écrit dans ce fichier.

Écrire la valeur 0 dans un fichier cgroup.procs fait que le processus écrivain est transféré dans le cgroup correspondant.

Quand un PID est écrit dans le fichier cgroup.procs, tous les threads du processus sont transférés ensemble dans le nouveau cgroup.

Dans une hiérarchie, un processus peut être membre d'un et un seul cgroup. Écrire un PID de processus dans un fichier cgroup.procs le retire automatiquement du cgroup auquel il appartenait précédemment.

Le fichier cgroup.procs peut être lu pour obtenir une liste des processus qui sont membres d’un cgroup. L'absence de doublons dans la liste renvoyée des PID n’est pas garantie et cette dernière ne sera pas forcément triée. Par exemple, un PID peut être recyclé pendant la lecture de la liste.

Dans cgroups version 1, un thread individuel peut être transféré dans un autre cgroup en écrivant son ID de thread (c’est-à-dire l’ID de thread du noyau renvoyé par clone(2) et gettid(2)) dans le fichier tasks d'un répertoire de cgroup. Ce fichier peut être lu pour découvrir l’ensemble des threads membres du cgroup.

  Suppression de cgroups
Pour supprimer un cgroup, il doit tout d’abord n’avoir aucun cgroup enfant et ne contenir aucun processus (non zombie). Tant que c’est le cas, on peut simplement supprimer le nom de chemin de répertoire correspondant. Remarquez que les fichiers dans le répertoire de cgroup ne peuvent et n’ont pas besoin d’être supprimés.

  Notification de publication de cgroups version 1
Deux fichiers peuvent être utilisés pour déterminer si le noyau fournit des notifications quand un cgroup devient vide. Un cgroup est considéré comme vide quand il ne contient ni cgroup enfant, ni processus membre.

Un fichier spécial dans le répertoire racine de chaque hiérarchie de cgroup, release_agent, peut être utilisé pour enregistrer le nom de chemin d’un programme pouvant être invoqué quand un cgroup dans la hiérarchie devient vide. Le nom de chemin du cgroup nouvellement vide (relatif au point de montage du cgroup) est fourni comme seul argument de ligne de commande quand le programme release_agent est invoqué. Le programme release_agent pourrait supprimer le répertoire du cgroup ou, peut être, le repeupler avec un processus.

Par défaut, le fichier release_agent est vide, signifiant qu’aucun agent de publication n’est invoqué.

Le contenu du fichier release_agent peut être spécifié à l’aide d’une option de montage quand le système de fichiers de cgroup est monté :

    mount -o release_agent=pathname ...

Que le programme release_agent soit invoqué ou pas quand un cgroup particulier devient vide est déterminé par la valeur inscrite dans le fichier notify_on_release dans le répertoire de cgroup correspondant. Si ce fichier contient la valeur 0, alors le programme release_agent n’est pas invoqué. Si cette valeur est 1, le programme release_agent est invoqué. La valeur par défaut inscrite dans ce fichier dans le cgroup racine est 0. Au moment de la création d’un nouveau cgroup, la valeur dans ce fichier est héritée du fichier correspondant dans le cgroup parent.

  Hiérarchies nommées de cgroups version 1
Dans cgroups version 1, il est possible de monter une hiérarchie de cgroup qui n’a pas de contrôleurs attachés.

    mount -t cgroup -o none,name=un_nom none /un/point/de/montage

Plusieurs instances de telles hiérarchies peuvent être montées, chaque hiérarchie devant avoir un nom unique. Le seul but de telles hiérarchies est de suivre les processus (consultez les explications de notification de publication ci-dessous). La hiérarchie de cgroup name=systemd qui est utilisée par systemd(1) pour suivre les services et les sessions d’utilisateur en est un exemple.

Depuis Linux 5.0, l’option d’amorçage cgroup_no_v1 du noyau (décrite ci-après) peut être utilisée pour désactiver les hiérarchies nommées de cgroups version 1, en spécifiant cgroup_no_v1=named.

CGROUPS VERSION 2
Dans cgroups version 2, tous les contrôleurs montés résident dans une seule hiérarchie unifiée. Alors que des contrôleurs (différents) peuvent être montés simultanément dans des hiérarchies version 1 ou 2, il n’est pas possible de monter le même contrôleur simultanément dans les deux hiérarchies version 1 et version 2.

Les nouveaux comportements dans cgroups version 2 sont résumés ici et, dans quelques cas, développés dans les sous-sections suivantes.

-   Les cgroups version 2 fournissent une hiérarchie unifiée pour laquelle tous les contrôleurs sont montés.

-   Les processus « internes » ne sont pas autorisés. À l’exception du cgroup racine, les processus ne peuvent résider que dans les nœuds feuilles (les cgroups qui ne contiennent pas eux-mêmes de cgroups enfants). Les détails sont un peu plus subtils que ça et sont décrits ci-après.

-   Les cgroups actifs doivent être indiqués à l’aide des fichiers cgroup.controllers et cgroup.subtree_control.

-   Le fichier tasks et le fichier cgroup.clone_children qui est utilisé par le contrôleur cpuset ont été supprimés.

-   Un mécanisme amélioré pour la notification de cgroups vides est fourni par le fichier cgroup.events.

Pour plus de détails sur les modifications, consultez le fichier Documentation/admin-guide/cgroup-v2.rst dans les sources du noyau (ou Documentation/cgroup-v2.txt dans Linux 4.17 et les versions antérieures).

Certains de ces nouveaux comportements intègrent une modification avec l’ajout dans Linux 4.14 du « mode thread » (décrit ci-après).

  Hiérarchie unifiée de cgroups version 2
Dans les cgroups version 1, la possibilité de monter différents contrôleurs pour différentes hiérarchies était voulue pour permettre une grande flexibilité dans la conception des applications. En pratique, la flexibilité s’est avérée moins utile qu’espérée et, dans de nombreux de cas, a ajouté de la complexité. Par conséquent, dans cgroups version 2, tous les contrôleurs disponibles sont montés pour une seule hiérarchie. Les contrôleurs disponibles sont automatiquement montés, ce qui signifie qu’il n’est pas nécessaire (ou possible) d’indiquer les contrôleurs lors du montage d’un système de fichiers cgroups version 2 en utilisant une commande telle que la suivante :

    mount -t cgroup2 none /mnt/cgroup2

Un contrôleur cgroups version 2 est disponible seulement s’il n’est pas en cours d’utilisation à l’aide d’un montage pour une hiérarchie de cgroups version 1. Ou, pour dire les choses autrement, il n’est pas possible d’employer le même contrôleur pour les deux hiérarchies version 1 et version 2 unifiée. Cela signifie qu’il peut être nécessaire d’abord de démonter un contrôleur version 1 (comme décrit ci-dessus) avant que ce contrôleur soit disponible en version 2. Puisque systemd(1) utilise abondamment quelques contrôleurs version 1 par défaut, il peut dans certains cas être plus simple d’amorcer le système avec ces contrôleurs version 1 désactivés. Pour ce faire, spécifier l’option cgroup_no_v1=list sur la ligne de commande d’amorçage du noyau. list est une liste de noms séparés par des virgules des contrôleurs à désactiver ou le mot all pour désactiver tous les contrôleurs version 1. Cette situation est gérée correctement par systemd(1), ce qui revient à un amorçage sans ces contrôleurs.

Remarquez que sur de nombreux systèmes modernes, systemd(1) monte automatiquement le système de fichiers cgroup2 dans /sys/fs/cgroup/unified lors du processus d’amorçage.

  Options de montage pour cgroups version 2
Les options suivantes (mount -o) peuvent être spécifiées lors du montage de systèmes de fichiers de groupe version 2 :

nsdelegate (depuis Linux 4.15)
    Traitement des espaces de noms cgroup comme des limites de délégation. Pour plus de détails, voir ci-dessous.

memory_localevents (depuis Linux 5.2)
    memory.events devrait afficher des statistiques seulement pour le cgroup lui-même, pas pour les cgroups descendants. C’était le comportement avant Linux 5.2. Depuis Linux 5.2, le comportement par défaut consiste à inclure des statistiques pour les cgroups descendants dans memory.events et cette option de montage peut être utilisée pour revenir au comportement traditionnel. Cette option s’applique au système entier et peut être définie au moment du montage ou modifiée à travers un remontage seulement à partir de l’espace de noms montage initial. Elle est silencieusement ignorée dans les espaces de noms non initiaux.

  Contrôleurs de cgroups version 2
Les contrôleurs suivants, documentés dans le fichier source du noyau Documentation/admin-guide/cgroup-v2.rst (ou Documentation/cgroup-v2.txt dans Linux 4.17 et les versions antérieures) sont pris en charge dans cgroups version 2 :

cpu (depuis Linux 4.15)
    C’est le successeur des contrôleurs version 1 cpu et cpuacct.

cpuset (depuis Linux 5.0)
    C’est le successeur du contrôleur version 1 cpuset.

freezer (depuis Linux 5.2)
    C’est le successeur du contrôleur version 1 freezer.

hugetlb (depuis Linux 5.6)
    C’est le successeur du contrôleur version 1 hugetlb.

io (depuis Linux 4.5)
    C’est le successeur du contrôleur version 1 blkio.

memory (depuis Linux 4.5)
    C’est le successeur du contrôleur version 1 memory.

perf_event (depuis Linux 4.11)
    Identique au contrôleur version 1 perf_event.

pids (depuis Linux 4.5)
    Identique au contrôleur version 1 pids.

rdma (depuis Linux 4.11)
    Identique au contrôleur version 1 rdma.

Il n’existe pas d’équivalent direct des contrôleurs net_cls et net_prio de cgroups version 1. À la place, une prise en charge a été ajoutée à iptables(8) pour permettre aux filtres eBPF qui s’attachent aux noms de chemin de cgroups version 2 de prendre des décisions à partir du trafic réseau selon le cgroup.

Les contrôleurs version 2 devices ne fournissent pas de fichiers d’interface. À la place, le contrôle de périphérique est sécurisé en attachant un programme eBPF (BPF_CGROUP_DEVICE) à un cgroup version 2.

  Contrôle de sous-arbres de cgroups version 2
Chaque cgroup dans une hiérarchie version 2 contient les deux fichiers suivants :

cgroup.controllers
    Ce fichier en lecture seule contient une liste des contrôleurs qui sont disponibles dans ce cgroup. Le contenu de ce fichier correspond au contenu du fichier cgroup.subtree_control dans le cgroup parent.

cgroup.subtree_control
    Ce fichier contient une liste de contrôleurs qui sont actifs (permis) dans le cgroup. L’ensemble des contrôleurs dans ce fichier est un sous-ensemble de l’ensemble cgroup.controllers de ce cgroup. L’ensemble des contrôleurs actifs est modifié en écrivant des chaînes dans ce fichier contenant des noms de contrôleurs séparés par des espaces, chacun étant précédé par un « + » (pour autoriser le contrôleur) ou un « - » (pour interdire le contrôleur), comme dans l’exemple suivant :

        echo '+pids -memory' > x/y/cgroup.subtree_control

    Un essai pour autoriser un contrôleur qui n’est pas présent dans cgroup.controllers provoque une erreur ENOENT lors d’une écriture dans le fichier cgroup.subtree_control.

Parce que la liste de contrôleurs dans cgroup.subtree_control est un sous-ensemble de ces cgroup.controllers, un contrôleur qui n’est plus autorisé dans un cgroup de la hiérarchie ne peut jamais être réautorisé dans un sous-arbre de ce cgroup.

Un fichier cgroup.subtree_control de cgroup détermine l’ensemble des contrôleurs qui sont activés dans les cgroups enfants. Quand un contrôleur (par exemple, pids) est présent dans le fichier cgroup.subtree_control d’un cgroup parent, les fichiers correspondants interface-contrôleur (par exemple, pids.max) sont automatiquement créés dans l’enfant de ce cgroup et peuvent être utilisés pour exercer le contrôle des ressources dans les cgroups enfants.

  Règle « pas de processus internes » pour cgroups version 2
Cgroups version 2 applique une règle appelée « pas de processus internes ». En gros, cette règle veut dire que, à l’exception du cgroup racine, les processus ne peuvent résider que dans les nœuds feuilles (des cgroups ne contenant pas eux-mêmes de cgroup enfant). Cela évite d'avoir à décider comment partager les ressources entre les processus qui sont membres du cgroup A et les processus dans des cgroups enfants de A.

Par exemple, si le cgroup /cg1/cg2 existe, un processus peut résider dans /cg1/cg2, mais pas dans /cg1. Cela permet d'éviter une ambiguïté dans cgroups version 1 par rapport à la délégation de ressources entre les processus dans /cg1 et les cgroups enfants. L’approche recommandée dans cgroups version 2 consiste à créer un sous-répertoire appelé feuille pour n’importe quel cgroup non feuille qui contiendrait des processus mais pas de cgroup enfant. Ainsi, les processus qui auparavant seraient allés dans /cg1 iraient maintenant dans /cg1/feuille. Cela a l’avantage de rendre explicite la relation entre les processus dans /cg1/feuille et les autres enfants de /cg1.

La règle « pas de processus internes » est en fait plus subtile que ce qui est décrit ci-dessus. Plus précisément, la règle stipule qu’un cgroup (non racine) ne peut pas à la fois avoir des processus membres et distribuer des ressources aux cgroups enfants — c’est-à-dire avoir un fichier cgroup.subtree_control non vide. Par conséquent, il est possible pour un cgroup d’avoir à la fois des processus membres et des cgroups enfants, mais pour que les contrôleurs puissent être autorisés pour ce cgroup, les processus membres doivent être déplacés en dehors du cgroup (par exemple, dans les cgroups enfants).

Avec l’addition dans Linux 4.14 du « mode thread » (décrit ci-après), la règle « pas de processus internes » a été assouplie dans certains cas.

  Fichier cgroup.events de cgroups version 2
Chaque cgroup non racine dans la hiérarchie version 2 contient un fichier en lecture seule, cgroup.events, dont le contenu consiste en paires clé-valeur (délimitées par des caractères de nouvelle ligne, avec les clés et valeurs séparées par des espaces) fournissant des informations d’état sur le cgroup :

    $ cat mygrp/cgroup.events
    populated 1
    frozen 0

Les clés suivantes peuvent apparaître dans ce fichier :

populated
    La valeur de cette clé est soit 1 si ce cgroup ou n’importe lequel de ses descendants a des processus membres, soit 0 dans le cas contraire.

frozen (depuis Linux 5.2)
    La valeur de cette clé est 1 si ce cgroup est actuellement gelé ou 0 s’il ne l’est pas.

Le fichier cgroup.events peut être surveillé dans le but de recevoir des notifications quand la valeur d’une des clés change. Cette surveillance peut être réalisée en utilisant inotify(7), qui notifie les changements tels que les évènements IN_MODIFY ou poll(2) qui notifie les changements en renvoyant les bits POLLPRI et POLLERR dans le champ revents.

  Notification de libération de cgroups version 2
Les cgroups version 2 fournissent un nouveau mécanisme pour recevoir des notifications lorsqu’un cgroup devient vide. Les fichiers cgroups version 1 release_agent et notify_on_release sont supprimés et remplacés par la clé populated dans le fichier cgroup.events. Cette clé a soit la valeur 0, signifiant que le cgroup (et ses descendants) ne contient aucun processus membre (non zombie), ou 1, signifiant que le cgroup (ou un de ses descendants) contient des processus membres.

Le mécanisme de notification de libération de cgroups version 2 offre les avantages suivants par rapport au mécanisme release_agent de cgroups version 1 :

-   IL permet une notification moins coûteuse puisqu’un seul processus peut contrôler plusieurs fichiers cgroup.events (en utilisant les techniques décrites précédemment). En revanche, le mécanisme de cgroups version 1 requiert la charge de créer un processus pour chaque notification.

-   Les notifications pour des sous-hiérarchies différentes de cgroup peuvent être déléguées à des processus différents. En revanche, le mécanisme de cgroups version 1 permet seulement un agent de notification pour la hiérarchie complète.

  Fichier cgroup.stat de cgroups version 2
Chaque cgroup d’une hiérarchie version 2 contient un fichier cgroup.stat en lecture seule (introduit en premier dans Linux 4.14) qui consiste en lignes contenant des paires clé-valeur. Les clés suivantes apparaissent actuellement dans ce fichier :

nr_descendants
    C’est le nombre total de cgroups descendants visibles (c’est-à-dire en vivants) en dessous de ce cgroup.

nr_dying_descendants
    C’est le nombre de cgroups descendants mourants en dessous de ce cgroup. Un cgroup devient mourant après avoir été supprimé. Il reste dans cet état pour une période indéfinie (qui dépend de la charge du système) pendant que les ressources sont libérées avant que le cgroup soit détruit. Remarquez que la présence de quelques cgroups dans l’état mourant est normal et n’indique pas un quelconque problème.

    Un processus ne peut devenir membre d’un cgroup mourant et celui-ci ne peut redevenir actif.

  Limitation du nombre de cgroups descendants
Chaque cgroup dans une hiérarchie version 2 contient les fichiers suivants qui peuvent être utilisés pour afficher et définir les limites du nombre de cgroups descendants dans ce cgroup :

cgroup.max.depth (depuis Linux 4.14)
    Ce fichier définit une limite sur le niveau d’imbrication de cgroups descendants. Une valeur de 0 dans ce fichier signifie qu’aucun cgroup descendant ne peut être créé. Un essai de création dont le niveau d’imbrication excède la limite échouera (mkdir(2) échoue avec l’erreur EAGAIN).

    Écrire la chaîne "max" dans ce fichier signifie qu’aucune limite n’est imposée. La valeur par défaut dans ce fichier est "max".

cgroup.max.descendants (depuis Linux 4.14)
    Ce fichier définit une limite du nombre de cgroups descendants actifs que ce cgroup peut posséder. Un essai de créer plus de descendants qu’autorisés par la limite échoue (mkdir(2) échoue avec l’erreur EAGAIN).

    Écrire la chaîne "max" dans ce fichier signifie qu’aucune limite n’est imposée. La valeur par défaut dans ce fichier est "max".

DÉLÉGATION DE CGROUPS À UN UTILISATEUR AVEC DES PRIVILÈGES MOINDRES
Dans le contexte de cgroups, déléguer signifie transmettre la gestion d'un sous-arbre de la hiérarchie de cgroup à un utilisateur non privilégié. Cgroups version 1 fournit une prise en charge de la délégation basée sur les permissions de fichier dans la hiérarchie de cgroup, mais avec des règles de confinement moins strictes que dans la version 2 (comme signalé ci-dessous). Cgroups version 2 gère la délégation avec confinement selon un modèle explicite. L’explication dans cette section se concentre sur la délégation dans cgroups version 2, avec quelques différences pour cgroups version 1 signalées au fur et à mesure.

Un peu de terminologie est nécessaire pour expliquer la délégation. Un délégant est un utilisateur privilégié (c’est-à-dire le superutilisateur) qui possède un cgroup parent. Un délégué est un utilisateur non privilégié à qui sont accordées les permissions nécessaires pour gérer une sous-hiérarchie sous le cgroup parent, connue comme le sous-arbre délégué.

Pour réaliser la délégation, le délégant autorise l'écriture par le délégué sur certains répertoires et fichiers, typiquement en transférant la propriété des objets à l’ID utilisateur du délégué. En supposant une délégation de hiérarchie de racine (par exemple) /dlgt_grp et qu’il n’y a pas encore de cgroup enfant sous ce cgroup, la propriété de ce qui suit est transférée à l’ID utilisateur du délégué :

/dlgt_grp
    Modifier le propriétaire de la racine d’un sous-arbre signifie que n’importe quel cgroup nouvellement créé dans ce sous-arbre (et les fichiers qu’il contient) sera aussi la propriété du délégué.

/dlgt_grp/cgroup.procs
    Modifier le propriétaire de ce fichier signifie que le délégué peut déplacer les processus dans la racine du sous-arbre délégué.

/dlgt_grp/cgroup.subtree_control (cgroups version 2 seulement)
    Modifier le propriétaire de ce fichier signifie que le délégué peut activer des contrôleurs (qui sont présents dans /dlgt_grp/cgroup.controllers) dans le but d’une redistribution postérieure des ressources à des niveaux inférieurs du sous-arbre. Comme alternative au changement de propriétaire de ce fichier, le délégant pourrait à la place ajouter les contrôleurs sélectionnés dans ce fichier.

/dlgt_grp/cgroup.threads (cgroups version 2 seulement)
    Modifier le propriétaire de ce fichier est nécessaire si un sous-arbre threaded est sous le coup d’une délégation (consultez la description du « mode thread » ci-dessous). Cela permet au délégué d’écrire des ID de thread dans ce fichier. Le propriétaire de ce fichier peut être aussi changé lors de la délégation d’un sous-arbre de domaine, mais actuellement cela ne sert à rien puisque, comme décrit ci-dessous, il n’est pas possible de déplacer un thread entre des cgroups de domaine en inscrivant son ID de thread dans le fichier cgroup.threads.

    Pour les cgroups version 1, le fichier correspondant qui doit être délégué est le fichier tasks.

Le délégant ne doit pas changer le propriétaire de n’importe quel fichier d’interface de contrôleur (par exemple, pids.max, memory.high) dans dlgt_grp. Ces fichiers sont utilisés au niveau juste au-dessus du sous-arbre délégué dans le but de distribuer les ressources dans le sous-arbre, et le délégant ne doit pas avoir la permission de modifier les ressources qui sont distribuées dans le sous-arbre délégué.

Consultez aussi l’explication dans le fichier /sys/kernel/cgroup/delegate dans NOTES pour des informations sur les autres fichiers délégables dans cgroups version 2.

Après que les étapes précitées aient été réalisées, le délégué peut créer des cgroups enfants dans le sous-arbre délégué (les sous-répertoires et les fichiers de cgroup qu’ils contiennent seront la propriété du délégué) et déplacer des processus entre des cgroups dans le sous-arbre. Si quelques contrôleurs sont présents dans dlgt_grp/cgroup.subtree_control, ou si la propriété de ce fichier a été transférée au délégué, celui-ci peut aussi contrôler une prochaine redistribution des ressources correspondantes dans le sous-arbre délégué.

  Délégation de cgroups version 2 : nsdelegate et espace de noms cgroup
Depuis Linux 4.13, une seconde manière existe pour réaliser une délégation de cgroup dans une hiérarchie de cgroups version 2. Cela est fait en montant ou remontant le système de fichiers de cgroups version 2 avec l’option de montage nsdelegate. Par exemple, si un système de fichiers de cgroups version 2 a déjà été monté, il est possible de le remonter avec l’option nsdelegate comme suit :

    mount -t cgroup2 -o remount,nsdelegate \
                     none /sys/fs/cgroup/unified

L’effet de cette option de montage est que l’espace de noms cgroup deviennent automatiquement les limites de délégation. Plus particulièrement, les restrictions suivantes s’appliquent pour les processus à l’intérieur de l’espace de noms cgroup :

-   Inscrire les fichiers des interfaces de contrôleur dans le répertoire racine de l’espace de noms échouera avec l’erreur EPERM. Les processus à l’intérieur de l’espace de noms cgroup peuvent toujours écrire dans les fichiers délégables dans le répertoire racine de l’espace de noms cgroup tels que cgroup.procs et cgroup.subtree_control, et peuvent créer des sous-hiérarchies au-dessous du répertoire racine.

-   Les essais de migrer des processus à travers des limites d’espace de noms sont interdits (avec l’erreur ENOENT). Les processus à l’intérieur d’un espace de noms cgroup peuvent toujours (soumis aux règles de confinement décrites ci-après) déplacer des processus entre cgroups à l’intérieur de la sous-hiérarchie sous l’espace de noms racine.

La possibilité de définir des espaces de noms cgroup comme des limites de délégation rend les espaces de noms cgroup beaucoup plus utiles. Pour en comprendre la raison, supposons qu’il existe déjà une hiérarchie de cgroup qui a été déléguée à un utilisateur non privilégié, cecilia, en utilisant la technique ancienne de délégation décrite ci-dessus. Supposons que plus tard cecilia veuille déléguer une sous-hiérarchie sous la hiérarchie déléguée existante (par exemple, la hiérarchie déléguée peut être associée avec un conteneur non privilégié exécuté par cecilia). Même si un espace de noms cgroup était employé, parce que les deux hiérarchies sont la propriété de l’utilisateur cecilia non privilégié, les actions illégitimes suivantes pourraient être réalisées :

-   Un processus dans la hiérarchie inférieure pourrait modifier les réglages du contrôleur de ressources dans le répertoire racine de cette hiérarchie (ces réglages sont conçus pour permettre le contrôle à exercer à partir du cgroup parent ; un processus dans le cgroup enfant ne devrait pas pouvoir les modifier) ;

-   un processus à l’intérieur de hiérarchie subalterne pourrait déplacer des processus dans ou en dehors de la hiérarchie inférieure si les cgroups dans la hiérarchie supérieure étaient de quelque façon visibles.

L’utilisation de l’option de montage nsdelegate empêche les deux possibilités.

L’option de montage nsdelegate a seulement un effet lorsque elle est utilisée dans l’espace de noms initial montage, dans d’autres espaces de noms montage cette option est ignorée silencieusement.

Remarque : sur certains systèmes, systemd(1) monte automatiquement le système de fichiers de cgroup version 2. Dans le but de tester l’opération nsdelegate, il peut être utile d’amorcer le noyau avec les options de ligne de commande suivantes :

    cgroup_no_v1=all systemd.legacy_systemd_cgroup_controller

Ces options font que le noyau amorce avec les contrôleurs cgroups version 1 désactivés (signifiant que les contrôleurs sont disponibles dans une hiérarchie version 2) et indique à systemd(1) de ne pas monter et utiliser la hiérarchie de cgroup version 2, de façon que la hiérarchie version 2 puisse être montée manuellement avec les options désirées après l’amorçage.

  Règles de confinement de délégation de cgroup
Certaines règles de confinement de délégation assurent que le délégué peut déplacer des processus entre des cgroups à l’intérieur du sous-arbre délégué, mais ne puisse pas déplacer les processus de l’extérieur du sous-arbre délégué dans le sous-arbre ou vice versa. Un processus non privilégié (c’est-à-dire le délégué) peut écrire le PID d’un processus « cible » dans un fichier cgroup.procs seulement si toutes les conditions suivantes sont remplies :

-   l’écrivain a la permission d’écriture dans le fichier cgroup.procs du cgroup de destination ;

-   l’écrivain a la permission d’écrire dans le fichier cgroup.procs dans le plus proche ancêtre commun des cgroups source et de destination. Remarquez que dans certains cas, ce plus proche ancêtre commun peut être le cgroup source ou celui de destination eux-mêmes. Ce besoin n’est pas imposé pour les hiérarchies version 1, avec pour conséquence que le confinement dans la version 1 est moins strict que dans la version 2 (par exemple, dans cgroups version 1 l’utilisateur possédant deux sous-hiérarchies déléguées distinctes peut déplacer un processus entre les hiérarchies) ;

-   si le système de fichiers d’un cgroup version 2 a été monté avec l’option nsdelegate, l’écrivain doit être capable de voir les cgroups source et destination à partir de son espace de noms cgroup ;

-   Dans cgroups version 1, l’UID effectif de l’écrivain (c’est-à-dire le délégué) correspond à l’ID réel utilisateur ou au set-user-ID enregistré du processus cible. Avant Linux 4.11, cette exigence s’appliquait aussi dans cgroups version 2 (c’était une exigence historique héritée de cgroups version 1 qui a été plus tard estimée non nécessaire, puisque les autres règles suffisent pour le confinement dans cgroups version 2).

Remarque : une conséquence des ces règles de confinement de délégation est que le délégué non privilégié ne peut placer le premier processus dans le sous-arbre délégué. À la place, le délégant doit placer le premier processus (un processus possédé par le délégué) dans le sous-arbre délégué.

MODE THREAD DE CGROUPS VERSION 2
Parmi les restrictions imposées par cgroups version 2 qui n’étaient pas présentes dans cgroups version 1 :

-   pas contrôle de granularité au niveau thread : tous les threads d’un processus doivent être dans le même cgroup ;

-   pas de processus internes : un cgroup ne peut à la fois avoir des processus membres et mettre en œuvre des contrôleurs sur des cgroups enfants.

Ces deux restrictions ont été ajoutées parce que l’absence de ces restrictions a causé des problèmes dans cgroups version 1. En particulier, la possibilité de cgroups version 1 de permettre une granularité au niveau threads pour l’appartenance à un cgroup n’avait aucun sens pour certains contrôleurs. Un exemple notable était le contrôleur memory : puisque les threads partagent un espace d’adressage, cela n’avait aucun sens de répartir les threads à travers des cgroups memory différents.

Malgré le fait de la décision initiale de conception de cgroups version 2, des cas d’utilisation existaient pour certains contrôleurs, notablement le contrôleur cpu, pour lesquels la granularité au niveau thread du contrôle était justifiée et utile. Pour tenir compte de tels cas, Linux 4.14 a ajouté le mode thread pour cgroups version 2.

Le mode thread permet les choses suivantes :

-   la création de sous-arbres threaded dans lesquels les threads d’un processus peuvent être répartis à travers des cgroups à l’intérieur de l’arbre (un sous-arbre threaded peut contenir plusieurs processus multithreads) ;

-   le concept de contrôleurs threaded qui peuvent distribuer des ressources à travers les cgroups dans un sous-arbre threaded ;

-   un relâchement de la règle « pas de processus internes », de façon à ce que, à l’intérieur d’un sous-arbre threaded, un cgroup puisse à la fois avoir des processus membres et mettre en œuvre des contrôleurs de ressources de cgroups enfants.

Avec l’ajout du mode thread, chaque cgroup non racine contient désormais un nouveau fichier, cgroup.type, qui expose, et dans certaines circonstances qui peut être utilisé pour modifier, le « type » d’un cgroup. Ce fichier contient une des valeurs de type suivantes :

domain
    C’est un cgroup version 2 normal fournissant un contrôle de niveau de granularité processus. Si un processus est membre de ce cgroup, alors tous les threads de ce processus sont (par définition) dans le même cgroup. C’est le type par défaut de cgroup et il fournit le même comportement qui était fourni pour les cgroups dans l’implémentation initiale de cgroups version 2.

threaded
    Ce cgroup est un membre d’un sous-arbre threaded. Des threads peuvent être ajoutés à ce cgroup et des contrôleurs peuvent être activés pour le cgroup.

domain threaded
    C’est un cgroup domain qui sert de racine à un sous-arbre threaded. Ce type de cgroup est aussi connu comme « threaded root ».

domain invalid
    C’est un cgroup à l’intérieur d’un sous-arbre threaded qui est dans un état « invalid ». Un processus ne peut être ajouté au cgroup et un contrôleur ne peut être activé pour le cgroup. La seule chose qui puisse être faite avec ce cgroup (à part le supprimer) est de le convertir en cgroup threaded en inscrivant la chaine « threaded » dans le fichier cgroup.type.

    La raison de l’existence de ce type « transitoire » lors de la création d’un sous-arbre threaded (plutôt que le noyau ne convertisse simplement immédiatement tous les cgroups sous la racine threaded au type threaded) est de permettre des extensions futures au modèle de mode thread.

  Threaded versus contrôleurs de domaine
Avec l’ajout du mode threads, cgroups version 2 distingue désormais deux types de contrôleurs de ressource :

-   contrôleurs Threaded : ces contrôleurs gèrent la granularité au niveau thread pour le contrôle des ressources et peuvent être activés à l’intérieur de sous-arbres threaded avec pour résultat que les fichiers de l’interface de contrôleur correspondants apparaissent dans les cgroups du sous-arbre threaded. Depuis Linux 4.19, les contrôleurs suivants sont threaded : cpu, perf_event, et pids ;

-   contrôleurs Domain : ces contrôleurs gèrent seulement une granularité au niveau processus pour le contrôle de ressource. Du point de vue contrôleur de domaine, tous les threads d’un processus sont toujours dans le même cgroup. Les contrôleurs de domaine ne peuvent être activés à l’intérieur d’un sous-arbre threaded.

  Création d’un sous-arbre threaded
Il existe deux manières qui conduisent à la création de sous-arbre threaded. La première manière fonctionne comme ceci :

(1) Nous écrivons La chaine « threaded » dans le fichier cgroup.type d’un cgroup y/z ayant actuellement le type domain. Cela a les effets suivants :

    -   le type du cgroup y/z devient threaded ;

    -   le type du cgroup parent, y, devient domain threaded. Le cgroup parent est la racine d’un sous-arbre threaded (aussi connu comme « threaded root » – racine threaded) ;

    -   Tous les autres cgroups sous y qui n’étaient pas déjà de type threaded (parce qu’ils étaient déjà dans des sous-arbres threaded existants sous la nouvelle racine root threaded) sont convertis au type domain invalid. Tout cgroup créé après sous y aura aussi le type domain invalid.

(2) Nous écrivons La chaine « threaded » pour chacun des cgroups domain invalid sous y, dans le but de les convertir au type threaded. Comme conséquence de cette étape, tous les threads sous la racine threaded ont désormais le type threaded et le sous-arbre threaded est désormais pleinement utilisable. Les conditions nécessaires pour écrire « threaded » pour chacun de ces cgroups sont quelque peu laborieuses, mais permettent de futures extensions au modèle de mode thread.

La second manière de créer un sous-arbre threaded est la suivante :

(1) Dans un cgroup existant, z, qui actuellement a le type domain, nous (1.1) activons un ou plusieurs contrôleurs threaded et (1.2) faisons d’un processus un membre de z (ces deux étapes pouvant être réalisées dans n’importe quel ordre). Cela a les conséquences suivantes :

    -   le type de z devient domain threaded ;

    -   tous les cgroups descendants de x qui n’étaient déjà de type threaded sont convertis au type domain invalid.

(2) Comme auparavant, nous rendons le sous-arbre threaded utilisable en écrivant la chaine « threaded » pour chacun des cgroups domain invalid sous y, dans le but de les convertir au type threaded.

Une des conséquences des manières ci-dessus de créer un sous-arbre threaded est qu’un cgroup de racine threaded peut être un parent pour seulement des cgroups threaded (et domain invalid). Le cgroup racine threaded ne peut pas être un parent d’un cgroup domain et un cgroup threaded ne peut avoir de frère qui soit un cgroup domain.

  Utilisation de sous-arbre threaded
À l’intérieur d’un sous-arbre threaded, des contrôleurs threaded peuvent être activés dans chaque sous-groupe dont le type a été changé à threaded. Ce faisant, les fichiers de l’interface de contrôleur correspondants apparaissent dans l’enfant de ce cgroup.

Un processus peut être déplacé dans un sous-arbre threaded en écrivant son PID dans le fichier cgroup.procs dans un des cgroups de l’arbre. Cela a pour effet de rendre tous les threads du processus membres du cgroup correspondant et de faire du processus un membre du sous-arbre threaded. Les threads du processus peuvent être répartis à travers le sous-arbre threaded en écrivant leurs ID de thread (voir gettid(2)) dans les fichiers cgroup.threads dans différents cgroups à l’intérieur du sous-arbre. Les threads d’un processus doivent tous résider dans le même sous-arbre threaded.

Comme pour l’écriture dans cgroup.procs, quelques règles de confinement s’appliquent pour l’écriture dans le fichier cgroup.threads :

-   l’écrivain doit avoir la permission d’écriture dans le fichier cgroup.threads dans le cgroup de destination ;

-   l’écrivain doit avoir la permission d’écriture dans le fichier cgroup.procs dans l’ancêtre commun des cgroups source et destination (dans certains cas, cet ancêtre peut être le cgroup source ou destination eux-mêmes) ;

-   les cgroups source et destination doivent être dans le même sous-arbre threaded (en dehors d’un sous-arbre threaded, un essai de déplacer un thread en écrivant son ID de thread dans le fichier cgroup.threads dans un cgroup domain différent échoue avec l’erreur EOPNOTSUPP).

Le fichier cgroup.threads est présent dans chaque cgroup (incluant les cgroups domain) et peut être lu pour découvrir l’ensemble de threads présents dans le cgroup. L’ensemble d’ID de threads obtenu lors de la lecture de ce fichier n’est pas garanti d’être ordonné ou ne pas avoir de doublons.

Le fichier cgroup.procs dans la racine threaded affiche le PID de tous les processus membres du sous-arbre threaded. Les fichiers cgroup.procs dans les autres cgroups du sous-arbre ne sont pas lisibles.

Les contrôleurs de domaine ne peuvent être activés dans un sous-arbre threaded. Aucun fichier d’interface de contrôleur n’apparait dans les cgroups sous la racine threaded. Du point de vue du contrôleur de domaine, les sous-arbres threaded sont invisibles : un processus multithreaded à l’intérieur d’un sous-arbre threaded apparait pour un contrôleur de domaine comme un processus qui réside dans le cgroup racine threaded.

Dans un sous-arbre threaded, la règle « pas de processus internes » ne s’applique pas : un cgroup peut contenir des processus membres (ou des threads) et utiliser des contrôleurs sur des cgroups enfants.

  Règles pour écrire dans cgroup.type et créer des sous-arbres threaded
Un certain nombre de règles s’appliquent lors de l’écriture dans le fichier cgroup.type :

-   seule la chaine « threaded » peut être écrite. En d’autres mots, la seule transition explicite possible est de convertir un cgroup domain au type threaded ;

-   l’effet d’écrire « threaded » dépend de la valeur en cours dans cgroup.type, comme suit :

    -   domain ou domain threaded : début de la création d’un sous-arbre threaded (dont la racine est le parent de ce cgroup) à l’aide de la première des manières décrites ci-dessus,

    -   domain invalid : conversion de ce cgroup (qui est à l’intérieur d’un sous-arbre threaded) pour être dans un état utilisable (c’est-à-dire threaded),

    -   threaded : aucun effet (une « no-op ») ;

-   il n’est pas possible d’écrire dans un fichier cgroup.type si le type du parent est domain invalid. En d’autres mots, les cgroups d’un sous-arbre threaded doivent être convertis dans l’état threaded d’une manière descendante.

Quelques contraintes doivent aussi être satisfaites pour créer un sous-arbre threaded dont la racine est le cgroup x :

-   il ne peut exister de processus membres dans les cgroups descendants de x (le cgroup_x peut lui avoir des processus membres) ;

-   aucun contrôleur de domaine ne peut être activé dans le fichier cgroup.subtree_control de x.

Si n’importe laquelle des contraintes ci-dessus n’est pas satisfaite, alors un essai d’écrire « threaded » dans un fichier cgroup.type échouera avec l’erreur ENOTSUP.

  Le type « domain threaded » de cgroup
Selon les chemins décrits ci-dessus, le type d’un cgroup peut changer à domain threaded dans chacun des cas suivants :

-   la chaine « threaded » est écrite pour un cgroup enfant ;

-   un contrôleur threaded est activé dans le cgroup et un processus est fait membre du cgroup.

Un cgroup domain threaded, x, peut redevenir du type domain si les conditions ci-dessus ne sont plus vraies, c’est-à-dire si tous les cgroups enfants threaded de x ont été supprimés et si x n’a plus de contrôleurs threaded activés ou n’a plus de processus membres.

Quand un cgroup domain threaded x redevient du type domain :

-   tous les descendants domain invalid de x qui ne sont pas dans des sous-arbres threaded de bas niveau redeviennent du type domain ;

-   les cgroups racines dans n’importe quels sous-arbres threaded de bas niveau redeviennent de type domain threaded.

  Exceptions pour le cgroup racine
Le cgroup racine de la hiérarchie version 2 est traité exceptionnellement : il peut être le parent à la fois de cgroups domain et threaded. Si la chaine « threaded » est écrite dans le fichier cgroup.type d’un des enfants du cgroup racine, alors :

-   le type de ce cgroup devient threaded ;

-   le type de tous les descendants de ce cgroup qui ne fait pas partie de sous-arbres threaded de bas niveau change à domain invalid.

Remarquez que dans ce cas, il n’y a pas de cgroup qui deviennent domain threaded (théoriquement, le cgroup racine peut être considéré comme la racine threaded pour le cgroup dont le type a été changé à threaded).

Le but de ce traitement exceptionnel pour le cgroup racine est de permettre à un cgroup threaded qui emploie le contrôleur cpu d’être placé aussi haut que possible dans la hiérarchie, de façon à minimiser le (faible) coût de parcourir la hiérarchie de cgroup.

  Le contrôleur « cpu » de cgroups version 2 et les threads en temps réel
Depuis Linux 4.19, le contrôleur cpu de cgroups version 2 ne prend pas en charge le contrôle des threads en temps réel (particulièrement les threads ordonnancés sous les politiques SCHED_FIFO, SCHED_RR, SCHED_DEADLINE ; voir sched(7)). Par conséquent, le contrôleur cpu ne peut être activé dans le cgroup racine seulement si tous les threads en temps réel sont dans le cgroup racine (si des threads en temps réel sont dans des cgroups non racines, alors une écriture write(2) de la chaine « +cpu » dans le fichier cgroup.subtree_control échoue avec l’erreur EINVAL).

Dans certains systèmes, systemd(1) place certains threads en temps réel dans des cgroups non racines dans la hiérarchie version 2. Pour de tels systèmes, ces threads doivent d’abord être déplacés dans le cgroup racine avant que le contrôleur cpu ne soit activé.

ERREURS
Les erreurs suivantes peuvent survenir pour mount(2) :

EBUSY
    Un essai de monter un système de fichiers cgroup version 1 n’indiquait ni l’option name= (pour monter une hiérarchie nommée) ni un nom de contrôleur (ou all).

NOTES
Un processus enfant créé à l’aide de fork(2) hérite des appartenances de cgroup de son parent. Les appartenances de cgroup de processus sont préservées à travers execve(2).

Le drapeau CLONE_INTO_CGROUP de clone3(2) peut être utilisé pour créer un processus enfant qui débute son existence dans un cgroup version 2 différent du processus parent.

  Fichiers /proc

/proc/cgroups (depuis Linux 2.6.24)
    Ce fichier contient des informations sur les contrôleurs qui sont compilés dans le noyau. Un exemple du contenu de ce fichier (reformaté pour une meilleure lisibilité) est ce qui suit :

        #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

    Les champs dans ce fichier sont de gauche à droite :

    [1] Le nom du contrôleur.

    [2] L’ID unique de la hiérarchie de cgroup pour laquelle le contrôleur est monté. Si plusieurs contrôleurs de cgroups version 1 sont liés à la même hiérarchie, chacun d'entre eux affichera le même ID de hiérarchie dans ce champ. La valeur dans ce champ sera zéro si :

        -   le contrôleur n’est pas monté pour une hiérarchie de cgroups version 1 ;

        -   le contrôleur est lié à la seule hiérarchie unifiée de cgroups version 2 ;

        -   le contrôleur est désactivé (voir ci-dessous).

    [3] Le nombre de groupes de contrôle dans cette hiérarchie utilisant ce contrôleur.

    [4] Ce champ contient la valeur 1 si le contrôleur est activé ou zéro s’il a été désactivé (à l’aide du paramètre cgroup_disable d’amorçage du noyau dans la ligne de commande).

/proc/pid/cgroup (depuis Linux 2.6.24)
    Ce fichier décrit les groupes de contrôle auxquels le processus ayant le PID correspondant appartient. L’information affichée diffère pour les hiérarchies version 1 et version 2 de cgroups.

    Pour chaque hiérarchie de cgroup dont le processus est membre, il existe une entrée contenant trois champs séparés par des deux-points :

        ID_hiérarchie:liste_contrôleurs:chemin_cgroup

    Par exemple :

        5:cpuacct,cpu,cpuset:/daemons

    De gauche à droite, ces trois champs séparés par des deux-points sont :

    [1] Pour les hiérarchies de cgroups version 1, ce champ contient un numéro d’ID unique de hiérarchie qui peut être comparé avec un ID de hiérarchie dans /proc/cgroups. Pour les hiérarchies de cgroups version 2, ce champ contient la valeur 0.

    [2] Pour les hiérarchies de cgroups version 1, ce champ contient une liste séparée par des virgules de contrôleurs liés à la hiérarchie. Pour les hiérarchies de cgroups version 2, ce champ est vide.

    [3] Ce champ contient le chemin du groupe de contrôle dans la hiérarchie à laquelle le processus appartient. Ce chemin est relatif au point de montage de la hiérarchie.

  Fichiers /sys/kernel/cgroup

/sys/kernel/cgroup/delegate (depuis Linux 4.15)
    Ce fichier exporte une liste de fichiers cgroups version 2 (un par ligne) qui sont délégables (c’est-à-dire dont la propriété peut être changée à l’ID utilisateur du délégué). Dans le futur, l’ensemble des fichiers délégables peut être modifié ou grossir, et ce fichier fournit un moyen pour le noyau d’informer les applications en espace utilisateur quels fichiers doivent être délégués. Depuis Linux 4.15, il est possible de voir ce qui suit lors de l’inspection de ce fichier :

        $ cat /sys/kernel/cgroup/delegate
        cgroup.procs
        cgroup.subtree_control
        cgroup.threads

/sys/kernel/cgroup/features (depuis Linux 4.15)
    Avec le temps, l’ensemble de fonctionnalités de cgroups version 2 fournies par le noyau peut évoluer ou grossir, ou certaines fonctionnalités pourraient ne pas être activées par défaut. Ce fichier fournit un moyen aux applications en espace utilisateur de découvrir quelles fonctionnalités le noyau utilisé gère et a d’activées. Les fonctionnalités sont listées, une par ligne :

        $ cat /sys/kernel/cgroup/features
        nsdelegate
        memory_localevents

    Les entrées pouvant apparaitre dans ce fichier sont :

    memory_localevents (depuis Linux 5.2)
        Le noyau gère l’option de montage memory_localevents.

    nsdelegate (depuis Linux 4.15)
        Le noyau gère l’option de montage nsdelegate.

    memory_recursiveprot (depuis Linux 5.7)
        Le noyau gère l’option de montage memory_recursiveprot.

VOIR AUSSI
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)

Le fichier des sources du noyau Documentation/admin-guide/cgroup-v2.rst.

TRADUCTION
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Jean-Paul Guillonneau <guillonneau.jeanpaul@free.fr>

Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 (https://www.gnu.org/licenses/gpl-3.0.html) concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.