cgroups(7) | Miscellaneous Information Manual | cgroups(7) |
cgroups – Groupes de contrôle de Linux
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.).
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
Les options suivantes (mount -o) peuvent être spécifiées lors du montage de systèmes de fichiers de groupe 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 :
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.
Chaque cgroup dans une hiérarchie version 2 contient les deux fichiers suivants :
echo '+pids -memory' > x/y/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.
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.
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 :
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.
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 :
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 :
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 :
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é :
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é.
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 :
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 :
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.
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 :
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é.
Parmi les restrictions imposées par cgroups version 2 qui n’étaient pas présentes dans cgroups version 1 :
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 :
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 :
Avec l’ajout du mode threads, cgroups version 2 distingue désormais deux types de contrôleurs de ressource :
Il existe deux manières qui conduisent à la création de sous-arbre threaded. La première manière fonctionne comme ceci :
La second manière de créer un sous-arbre threaded est la suivante :
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.
À 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 :
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.
Un certain nombre de règles s’appliquent lors de l’écriture dans le fichier cgroup.type :
Quelques contraintes doivent aussi être satisfaites pour créer un sous-arbre threaded dont la racine est le cgroup 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.
Selon les chemins décrits ci-dessus, le type d’un cgroup peut changer à domain threaded dans chacun des cas suivants :
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 :
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 :
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.
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é.
Les erreurs suivantes peuvent survenir pour mount(2) :
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.
#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_hiérarchie:liste_contrôleurs:chemin_cgroup
5:cpuacct,cpu,cpuset:/daemons
$ cat /sys/kernel/cgroup/delegate cgroup.procs cgroup.subtree_control cgroup.threads
$ cat /sys/kernel/cgroup/features nsdelegate memory_localevents
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.
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 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.
5 février 2023 | Pages du manuel de Linux 6.03 |