Gestion des fichiers ouverts

Dans un système unix ce sont les process qui ouvrent des fichiers, mais le noyaux en garde en sous-main le contrôle pour permettre à des process différents de se partager les ressources ouvertes.

Process

Chaque process doit garder une liste des fichiers qu'il a ouvert et peut donc utiliser.

A chaque fichier ouvert est associé un numéro nommé Un descripteur de fichier (file descriptor). Les différents fichiers ouvert par un process donné sont accessibles via leurs file descriptor dans leurs /proc :

ls -la /proc/$$/fd

Tout process a toujours 3 file descriptors :

Ces fichiers ouverts sont des redirections vers le fichier tty correspondant.

Les fichiers stdin, stdout et stderr présent dans /dev/ sont des liens.

Vers quoi pointent-ils ?

solution

vers les files descriptor de /proc/self/ qui est le process actuellement entrain d'être exécuté (et il change de nombreuses fois par secondes...).

A chaque lecture du fichier /proc/self/, le noyau va donner le process actuellement entrain d'être exécuté, c'est à dire celui qui lit le dossier. Ainsi, si vous exécutez la commande :

ls -l /proc/self

Cela vous affichera le process du ls entrain de lire /proc/self.

De la même manière si vous écrivez :

echo "coucou" >> /dev/stdout

C'est dans le stdout de echo que vous écrivez (et c'est donc identique à écrire echo "coucou").

Ouvrez deux terminaux :

  1. vérifiez que les 3 FD ne pointent pas vers le même tty
  2. écrivez dans le stdout de l'un à partir de l'autre.

Vous pouvez connaître leurs informations dans le dossier fdinfo :

ls -la /proc/$$/fdinfo/1

Fichiers ouverts

Si vous utilisez la commande lsof -p $$ vous verrez que process ouvre plus de fichiers que les fide descriptors numériques (qui sont des entrées/sorties) :

$ lsof -p $$
COMMAND    PID     USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
bash    928549 fbrucker  cwd    DIR   0,24        4 5241736 /proc/928549/fd
bash    928549 fbrucker  rtd    DIR    8,2     4096       2 /
bash    928549 fbrucker  txt    REG    8,2  1415800  655454 /usr/bin/bash
bash    928549 fbrucker  mem    REG    8,2  8321104  662997 /usr/lib/locale/locale-archive
bash    928549 fbrucker  mem    REG    8,2  1641496  663748 /usr/lib/aarch64-linux-gnu/libc.so.6
bash    928549 fbrucker  mem    REG    8,2   195784  658635 /usr/lib/aarch64-linux-gnu/libtinfo.so.6.3
bash    928549 fbrucker  mem    REG    8,2   187776  663741 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
bash    928549 fbrucker  mem    REG    8,2    27004  664116 /usr/lib/aarch64-linux-gnu/gconv/gconv-modules.cache
bash    928549 fbrucker    0u   CHR  136,1      0t0       4 /dev/pts/1
bash    928549 fbrucker    1u   CHR  136,1      0t0       4 /dev/pts/1
bash    928549 fbrucker    2u   CHR  136,1      0t0       4 /dev/pts/1
bash    928549 fbrucker  255u   CHR  136,1      0t0       4 /dev/pts/1

Il y a :

  1. ouvrez un fichier texte avec less
  2. trouver son PID avec ps aux | grep less
  3. voir ses fichiers ouverts

On peut également faire le contraire et regarder quel process ouvre tel fichier en utilisant la commande fuser :

$ fuser -v /usr/bin/bash
                     UTIL.       PID ACCÈS  COMMANDE
/usr/bin/bash:       fbrucker  928549 ...e. bash

Limites

Un process particulier ne peut pas forcément ouvrir autant de fichier. Par défaut, la limite est 1024. Comme annoncée dans le fichier limits du process :

$ cat /proc/$$/limits
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             7422                 7422                 processes 
Max open files            1024                 1048576              files     
Max locked memory         257257472            257257472            bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       7422                 7422                 signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited       

Vous pouvez aussi utiliser la commande : ulimit -a et ses différentes options pour particulariser la limite à chercher. Exemple ulimit -n.

Noyau

Le noyau maintient à jour une table globale contenant tous les fichiers ouverts par tous les process. Cette table, nommé file table contient :

Chaque file descriptor est alors associé à un élément de la file table.

process             noyau
  FD         Table         
              T1  ---------> inode/socket/pipe/...
  23 -        T2 
       \        
        \     Ti  ---
         \            \
  42  ----->  Fj   ------->  Vk

Plusieurs file descriptor (d'un même process ou de process différents) peuvent pointer vers le même élément de la table, et plusieurs élément de la table peuvent ouvrir le même fichier.

La table est initialisée au démarrage et contient toutes les structures, le type de fichier étant libre. Il y a donc un nombre maximum de fichier qui peuvent être ouvert en même temps pour un système.

On peut bien sur connaître le nombre de fichier actuellement ouvert : cat /proc/sys/fs/nr_open et le nombre de fichier maximum cat /proc/sys/fs/file-max. Chez moi cela donne :

$ cat /proc/sys/fs/nr_open
1048576
$ cat /proc/sys/fs/file-max
9223372036854775807

Fork

Lors de la création de nouveaux process, les files descriptors sont dupliqués :

  1. l'enfant à le même nombre de file descriptor que son parent
  2. les file descriptors de l'enfant pointent vers les même élément de la table que son parent