SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-22

Pourquoi df est plein alors que du ne trouve rien

Votre VPS affiche un disque plein, mais du ne trouve pas l’espace. Identifiez un fichier supprimé encore ouvert avec lsof, puis vérifiez inodes, montages et blocs réservés.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 15, 2026.

Pourquoi df indique que le disque est plein alors que du affiche autre chose

df indique que le disque est plein, tandis que du ne trouve pas l’espace utilisé, car un processus détient encore un fichier qui a été supprimé. La suppression d’un fichier retire son nom du répertoire. Les blocs de données ne sont libérés que lorsque le dernier descripteur de fichier ouvert qui pointe vers cet inode est fermé. du parcourt les noms de fichiers et ne compte donc rien. df demande au système de fichiers combien de blocs sont alloués. Il compte donc encore le fichier qui n’a plus de nom.

Ce guide reproduit le problème sur un VPS Ubuntu standard avec les outils déjà installés. Il identifie le processus qui détient le fichier avec /proc, puis libère l’espace sans redémarrer le serveur. Les autres causes du même symptôme sont ensuite présentées : une table d’inodes sans entrée libre, des fichiers masqués sous un point de montage et des blocs réservés à root.

Exécutez chaque commande et lisez votre propre sortie. Les valeurs dépendent de votre disque. Comparez donc les résultats avant et après sur votre propre machine, plutôt qu’avec une valeur affichée dans un guide.

Ce que comptent df et du

df (disk free) interroge chaque système de fichiers monté pour obtenir ses propres statistiques : le nombre de blocs existants, alloués et libres. Il n’ouvre aucun répertoire. Le résultat couvre tous les blocs alloués, y compris ceux appartenant à un fichier vers lequel aucune entrée de répertoire ne pointe.

du (disk usage) fait l’inverse. Il part du chemin que vous lui indiquez, lit les répertoires, examine chaque entrée trouvée avec stat, puis additionne les blocs. Un fichier sans nom lui est invisible. Il en va de même pour tout répertoire qu’il n’est pas autorisé à lire, raison pour laquelle un utilisateur ordinaire obtient un total inférieur à celui de root. Exécutez du avec sudo avant de tirer une conclusion de la comparaison.

Deux options sont importantes chaque fois que vous comparez les deux commandes.

  • -x maintient du sur un seul système de fichiers. Sans cette option, du / parcourt tous les systèmes de fichiers montés sous / et produit un total que df / ne mesurait pas.
  • -s affiche une ligne récapitulative par argument au lieu d’une ligne par répertoire.

Vous pouvez ainsi exécuter les deux commandes côte à côte sur le système de fichiers qui vous intéresse.

df -h /
sudo du -xhs / 2>/dev/null

df répond immédiatement. du peut prendre plusieurs minutes sur un grand système de fichiers, car il examine chaque fichier sur son parcours. Lorsque les deux totaux sont très différents et que du a été exécuté en tant que root avec -x, l’espace manquant est alloué à un élément qui n’a pas de nom.

Reproduire volontairement l’écart

Faites-le sur un VPS de test. Tout ce qui suit utilise bash et coreutils, donc rien n’est installé.

Relevez l’état initial du système de fichiers qui contient /var/tmp.

cd /var/tmp
df -h .
df --output=used -B1 .

La deuxième commande affiche les octets utilisés sans arrondi. La vérification finale est donc exacte.

Créez maintenant un fichier. Sa taille est calculée à partir de l’espace libre indiqué par la machine elle-même. La démonstration s’adapte donc à la taille de votre disque.

free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .

$(...) est une substitution de commande : le shell exécute la commande qu’elle contient, puis sa sortie devient la valeur de free. Si cette syntaxe vous est inconnue, la substitution de commande dans bash l’explique correctement. fallocate réserve les blocs réels sans y écrire de données, ce qui explique pourquoi la commande se termine instantanément. Sur un système de fichiers qui ne la prend pas en charge, la commande échoue ; head -c $((free / 10)) /dev/zero > ghost.bin produit alors le même résultat en écrivant les octets.

Comparez ce df -h . avec celui que vous avez relevé. La colonne des blocs utilisés a augmenté et celle de l’espace disponible a diminué.

Maintenez maintenant le fichier ouvert par un autre processus, puis supprimez-le.

sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/null

La redirection est l’élément essentiel. sleep infinity < ghost.bin & démarre un processus en arrière-plan dont l’entrée standard correspond à ce fichier. Le shell ouvre donc le fichier et transmet le descripteur à sleep, qui le maintient ouvert. $! contient l’identifiant du processus de cette tâche en arrière-plan. rm supprime ensuite le nom alors que le descripteur est toujours ouvert.

Lisez la sortie. ls ne trouve pas le fichier, car son nom a disparu. du est revenu près de sa valeur initiale, car il parcourt les noms. df n’a pas changé, car les blocs sont toujours alloués. Le système de fichiers et l’arborescence des répertoires ne correspondent désormais plus. L’écart entre eux correspond au fichier que vous venez de supprimer.

Trouver le processus qui détient le fichier supprimé

Chaque descripteur de fichier ouvert apparaît sous /proc/<pid>/fd/ sous la forme d’un lien symbolique vers le fichier auquel il fait référence. Lorsque le fichier a été désindexé, le noyau marque la cible de ce lien comme supprimée. Il faut donc trouver un lien dont la cible porte cette indication.

sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

-lname recherche la cible d’un lien symbolique plutôt que son nom, %p affiche le chemin du descripteur et %l affiche sa cible. Le PID est le deuxième élément du chemin affiché. Exécutez la commande avec sudo, car sans cette option, vous ne pouvez lire que /proc/<pid>/fd pour vos propres processus. La redirection de stderr supprime les messages des processus qui se terminent pendant que find parcourt l’arborescence.

Un serveur actif détient plusieurs fichiers supprimés à tout moment. La plupart sont petits et sans conséquence. Triez-les par taille pour placer les fichiers intéressants en tête.

sudo bash -c 'for fd in /proc/[0-9]*/fd/*; do
  target=$(readlink "$fd" 2>/dev/null) || continue
  case "$target" in
    *"(deleted)") echo "$(stat -Lc %s "$fd" 2>/dev/null) $fd $target" ;;
  esac
done' | sort -rn | head

stat -L suit le lien jusqu’à l’inode lui-même. %s indique donc la taille du fichier qui n’a plus de nom. Le tri sur ce nombre place le plus volumineux en premier.

Identifiez ensuite le processus associé au descripteur en tête de liste. Le chemin affiché en première position contient les deux nombres nécessaires. Placez-les d’abord dans des variables, en remplaçant PID et N par les valeurs affichées sur votre système.

pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"

ps indique le nom du programme et depuis combien de temps il fonctionne. stat -L affiche la taille et le nombre de blocs alloués de l’inode supprimé. Ces informations répondent à la question essentielle : quel service maintient ce fichier ouvert.

Si la machine dispose déjà de lsof, sudo lsof +L1 liste les fichiers ouverts dont le nombre de liens est tombé à zéro et affiche leur taille dans un même tableau. Cet outil n’est pas présent sur une image Ubuntu minimale. Installer un paquet sur un système de fichiers sans espace libre peut également échouer. Le parcours avec /proc est donc la méthode qui fonctionne toujours.

Libérer l’espace sans redémarrer

Un redémarrage règle effectivement le problème, mais ce n’est pas la première mesure à prendre : il interrompt le service et détruit les éléments utiles au diagnostic. Quatre options moins perturbatrices existent, dans l’ordre où les essayer.

Commencez par copier les données ailleurs si vous souhaitez les conserver. La lecture du chemin du descripteur lit l’inode actif.

sudo cp /proc/<pid>/fd/<n> /root/recovered.log

C’est le seul cas où un fichier supprimé est facile à récupérer. C’est pourquoi récupérer des fichiers supprimés avec rm -rf commence par vérifier si un processus tient encore le fichier ouvert. Une fois le dernier descripteur fermé, cette possibilité disparaît.

Deuxièmement, videz le fichier via le descripteur. Le chemin /proc mène au même inode. Le tronquer libère donc les blocs tout en laissant le processus s’exécuter.

sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /

Cela fonctionne correctement lorsque le processus d’écriture a ouvert le fichier en mode append, car chaque écriture est alors effectuée à la fin actuelle du fichier. Sinon, le processus conserve son ancien offset d’écriture. Sa prochaine écriture se fait donc très loin dans le fichier et le recrée avec un trou au début. Un trou n’est pas alloué, les blocs restent donc libres et df conserve l’espace qu’il vient de libérer. Seule la taille réapparaît : exécutez de nouveau sudo stat -L "/proc/$pid/fd/$n" après l’écriture du processus. La commande indique alors l’ancienne taille à côté d’un nombre de blocs qui ne lui correspond plus. Redémarrez le processus lorsque vous voulez également que la taille reparte de zéro.

Troisièmement, demandez au service de rouvrir ses journaux. Un daemon dont le fichier journal a été supprimé alors qu’il était encore ouvert est le cas réel le plus courant de ce problème. De nombreux daemons rouvrent leurs fichiers journaux à la réception d’un signal : nginx utilise SIGUSR1 et rsyslog utilise SIGHUP. Consultez la documentation du daemon concerné au lieu de deviner, car l’envoi du mauvais signal au mauvais daemon l’arrête.

sudo systemctl kill -s USR1 nginx

Cette commande envoie le signal au processus que systemd enregistre comme processus principal de l’unité. Une unité qui déclare la mauvaise valeur de Type= par rapport au démarrage réel de son daemon peut donc transmettre votre signal à un processus qui n’a jamais détenu le fichier supprimé. L’espace reste alors occupé.

Quatrièmement, redémarrez l’unité. sudo systemctl restart <unit> ferme tous les descripteurs détenus par l’ancien processus. Les blocs sont donc libérés avec certitude. Dans la démonstration précédente, le détenteur est un sleep que vous avez lancé vous-même. Il suffit donc de l’arrêter.

kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

Comparez les octets utilisés avec la valeur relevée avant la création du fichier. Les valeurs correspondent de nouveau et find n’indique plus votre descripteur. Vérifier le résultat avec la même commande que celle ayant détecté le problème est une bonne habitude à conserver.

Suivre l’évolution de cette valeur est plus simple que d’exécuter df manuellement à répétition. watch répète une commande à intervalle fixe et réaffiche la sortie au même endroit. Ainsi, watch df -h / affiche l’évolution de la colonne utilisée lorsque l’espace est libéré.

Lorsque les totaux concordent alors que le disque est toujours plein

Si df et un du -x exécutés avec root concordent, aucun fichier supprimé n’est en cause. Les causes restantes sont d’une autre nature et chacune nécessite sa propre vérification.

À court d’inodes, mais pas de blocs

Un inode contient les métadonnées d’un fichier. ext4 crée un nombre fixe d’inodes lors de la création du système de fichiers. Un système de fichiers peut donc manquer d’inodes alors qu’il dispose encore de blocs libres. La création de nouveaux fichiers échoue alors, même si df -h indique qu’il reste de l’espace.

df -h /
df -i /

La première commande compte les blocs et la seconde compte les inodes. Comparez la colonne d’utilisation de chacune. Une faible utilisation des blocs et une utilisation des inodes à la limite indiquent la présence d’un très grand nombre de fichiers très petits.

df refuse -i et --output dans le même appel. Pour obtenir les compteurs bruts, les lire ou les transmettre à une autre commande, sélectionnez les champs d’inodes par leur nom et n’utilisez pas -i.

df --output=itotal,iused,iavail,ipcent /

Ces colonnes contiennent les mêmes informations de comptabilisation que celles affichées par df -i, dans un format que vous pouvez analyser.

Trouvez les fichiers en comptant les entrées plutôt que les octets.

sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | head

Répétez la même commande un niveau plus bas dans le répertoire arrivé en tête, jusqu’à atteindre l’arborescence qui crée les fichiers. Si votre du ne prend pas en charge --inodes, sudo find /var -xdev -type f | wc -l compte un sous-arbre plus lentement.

La solution consiste à supprimer ou à déplacer ces fichiers. Vous ne pouvez pas ajouter d’inodes à un système de fichiers ext4 existant, car leur nombre est fixé au moment de mkfs. L’augmenter implique donc de recréer le système de fichiers et de restaurer une sauvegarde. XFS alloue les inodes selon les besoins et n’est donc pas soumis à la même limite fixe. Une machine qui exécute des conteneurs atteint les deux limites plus rapidement que la plupart des autres, car les couches d’image contiennent de nombreux petits fichiers. Sur cette machine, réduire l’utilisation disque de Docker sur un VPS est la solution adaptée. Cette opération libère beaucoup plus d’espace qu’un nettoyage général du système de fichiers.

Espace masqué sous un point de montage

Un répertoire peut contenir des fichiers avant qu’un système de fichiers y soit monté. Montez un système de fichiers sur ce répertoire : les fichiers sous-jacents restent exactement à leur emplacement. Ils sont toujours alloués, toujours comptabilisés par df, mais ne sont plus accessibles par leur nom. du ne peut pas les voir, car le montage les masque.

Utilisez tmpfs pour le démontrer. Aucun disque disponible supplémentaire n’est nécessaire. Cette partie nécessite une machine sur laquelle vous avez le droit d’effectuer des montages. Elle fonctionne donc sur un VPS KVM.

sudo mkdir -p /srv/covered
sudo cp /etc/services /srv/covered/
ls /srv/covered
sudo mount -t tmpfs tmpfs /srv/covered
ls /srv/covered
sudo umount /srv/covered
ls /srv/covered

Le ls du milieu affiche un répertoire vide. La copie n’a pas disparu : elle se trouve toujours sur le système de fichiers racine et réapparaît dès que vous démontez le système de fichiers. Imaginez maintenant un service qui a écrit dans ce chemin pendant un mois avant qu’une personne y monte un volume.

Pour trouver les fichiers réels sur un serveur en fonctionnement, montez une seconde fois le système de fichiers racine à un autre emplacement. Un bind mount affiche un système de fichiers sans les systèmes de fichiers montés à l’intérieur.

sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheck

Tout élément présent dans cette liste, mais absent du chemin habituel, est masqué sous un point de montage. Démontez le bind mount lorsque vous avez terminé. Sinon, un du ultérieur sans -x comptabilisera les mêmes fichiers deux fois.

Blocs réservés à root

ext4 réserve une partie de ses blocs à l’utilisateur root. Ainsi, un disque plein n’empêche pas root de se connecter et de réparer la machine. Un processus exécuté par un utilisateur ordinaire atteint cette limite en premier, tandis que df affiche encore un peu d’espace libre. Consultez le réglage de votre propre système de fichiers au lieu de supposer la valeur par défaut.

dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'

Cette commande affiche le nombre total de blocs et le nombre de blocs réservés dans les mêmes unités. Leur rapport est donc direct. df indique, dans la colonne disponible, l’espace qu’un utilisateur normal peut encore utiliser. C’est pourquoi la somme de l’espace utilisé et de l’espace disponible est inférieure à la taille totale. L’écart correspond à la réserve.

Modifiez ce réglage avec sudo tune2fs -m <percent> "$dev". La modification s’applique immédiatement et ne nécessite aucun remontage. Réduire la réserve sur un système de fichiers de données distinct est raisonnable. Sur le système de fichiers racine, conservez une réserve suffisante pour que root puisse encore écrire. Un système de fichiers racine totalement dépourvu d’espace libre est beaucoup plus difficile à réparer. Cette réserve vous évite également d’être bloqué hors du système : une clé ajoutée à authorized_keys sur un système de fichiers sans espace libre peut être écrite partiellement, voire pas du tout. La connexion suivante répond alors Permission denied (publickey) pour une raison qui n’a rien à voir avec la clé elle-même. tune2fs fonctionne avec ext2, ext3 et ext4. XFS ne propose pas de réglage équivalent.

Quand du vous induit en erreur utilisé seul

Quatre comportements de du produisent des totaux qui semblent incorrects.

  • Liens physiques : du ne compte un inode qu’une seule fois, même lorsque plusieurs noms pointent vers lui. Une arborescence remplie de liens physiques affiche donc un total inférieur à la somme de ses fichiers.
  • Fichiers creux : du indique les blocs réellement alloués, tandis que ls -l indique la taille apparente. Ajoutez --apparent-size pour afficher l’autre valeur.
  • Permissions : exécuté par un utilisateur ordinaire, du ignore ce qu’il ne peut pas lire et sous-estime le total. Les erreurs qu’il affiche sont celles que l’on redirige vers /dev/null avant de ne plus les consulter.
  • Limites des systèmes de fichiers : sans -x, du / compte tous les systèmes de fichiers montés sous /. Son total peut donc dépasser celui indiqué par df /.

df a également un comportement à connaître. Il indique chaque système de fichiers séparément. Exécutez-le donc sur le chemin exact ciblé par l’écriture qui échoue. Un autre /boot se remplit selon son propre calendrier à mesure que les paquets du kernel s’accumulent, et supprimer les anciens kernels sur Ubuntu est une opération différente de la libération d’espace sur /.

Une méthode d’intervention pour un incident réel

  1. Exécutez df -h <path> et df -i <path> sur le système de fichiers qui devait recevoir l’écriture échouée, et non systématiquement sur /.
  2. Exécutez sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -h, puis descendez dans le répertoire le plus volumineux.
  3. Si du ne permet pas d’expliquer l’espace utilisé indiqué par df, recherchez dans /proc les fichiers supprimés qui sont toujours ouverts.
  4. Si les deux commandes concordent, montez le système de fichiers ailleurs avec un bind mount et recherchez les fichiers situés sous un point de montage.
  5. Si la limite concerne l’utilisation des inodes, comptez les fichiers plutôt que les octets.

Chaque étape repose sur une commande dont vous pouvez lire la sortie. C’est ce qui permet de corriger le problème au lieu de procéder par suppositions.

FAQ

Pourquoi df indique-t-il que le disque est plein alors que du trouve beaucoup moins d’espace utilisé ?

La cause habituelle est un fichier supprimé alors qu’un processus l’avait encore ouvert. La suppression retire l’entrée du répertoire. du ne trouve donc plus de nom à parcourir et cesse de le comptabiliser. L’inode et ses blocs restent alloués jusqu’à la fermeture du dernier descripteur, tandis que df comptabilise les blocs alloués. Recherchez dans /proc/<pid>/fd les liens symboliques dont la cible est marquée comme supprimée : vous trouverez ainsi le fichier et le processus qui le conserve ouvert. Avant de faire confiance à la comparaison, vérifiez que vous avez exécuté du en tant que root et avec -x, car un utilisateur ordinaire ignore silencieusement les répertoires qu’il ne peut pas lire.

Comment trouver un fichier supprimé qui est encore ouvert sans utiliser lsof ?

Utilisez l’inventaire des descripteurs ouverts tenu par le kernel. sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null liste chaque descripteur pointant vers un fichier sans nom. L’identifiant du processus apparaît dans le chemin affiché. sudo stat -Lc %s sur l’un de ces chemins de descripteur indique sa taille. Vous pouvez donc les trier et sélectionner celui qui vous intéresse. Aucun package n’est nécessaire. C’est important, car l’installation d’un package sur un filesystem sans espace libre peut échouer.

Puis-je libérer l’espace sans arrêter le processus ?

Parfois. sudo truncate -s 0 /proc/<pid>/fd/<n> atteint le même inode via le descripteur et libère ses blocs sans arrêter le processus. Cette méthode est la plus propre lorsque le processus a ouvert le fichier en mode append, car ses écritures vont toujours à la fin actuelle du fichier. Sinon, la position d’écriture reste celle où elle se trouvait. L’écriture suivante recrée alors le fichier avec un trou au début. La taille indiquée augmente de nouveau, tandis que les blocs correspondant au trou restent libres. Redémarrer l’unité ou lui envoyer le signal prévu par sa documentation pour rouvrir ses journaux est la solution qui ne laisse aucun fichier sparse.

df indique de l’espace libre, mais les écritures échouent toujours. Quelle peut être la cause ?

Vérifiez les inodes avec df -i sur le même chemin. Un filesystem qui dispose encore de blocs libres mais d’aucun inode disponible refuse la création de nouveaux fichiers. Vérifiez si l’écriture est effectuée par un utilisateur non-root sur un filesystem ext4 où seuls les blocs réservés restent disponibles. sudo tune2fs -l sur le device l’indiquera. Vérifiez aussi que vous consultez bien le filesystem réellement ciblé par l’écriture, car un /boot ou un /var distinct peut être plein indépendamment de /.

Pourquoi du indique-t-il un total supérieur à df ?

du sans -x traverse tous les filesystems montés sous le chemin fourni. Il additionne donc plusieurs filesystems, tandis que df décrit un seul filesystem. Les bind mounts aggravent le problème, car les mêmes fichiers sont comptabilisés une fois pour chaque chemin sous lequel ils apparaissent. Ajoutez -x pour maintenir du sur un seul filesystem, et fournissez le même chemin à df afin que les deux commandes décrivent la même chose.