Короткий ответ

Одна и та же строка No space left on device бывает и при нуле гигабайт, и при нуле inode. Различие одно: df -h против df -i. Если IUse% = 100%, а Use% = 20%, удаление одного большого ISO не поможет — нужны миллионы мелких файлов. На Ubuntu это часто /var/lib/php/sessions, spool почты, tree lost+found после неудачного rsync, кэш nginx microcache, каталоги CI.

Не форматируйте том «чтобы inode стало больше». Сначала найдите каталог с аномальным find … | wc -l.

Симптомы и как отличить

  • touch /tmp/xNo space left on device;
  • df -h / показывает десятки гигабайт свободно;
  • df -i /IUse% 100%;
  • GUI/мониторинг «диск в порядке», приложения мёртвые.
ПроверкаГигабайтыInode
df -h100%низкий %
df -iнизкий %100%
du -xh большого файладаобычно нет
find | wc -l огромныйне обязательнода

Похожие, но другие проблемы: закончился диск, read-only (там Read-only file system, не ENOSPC).

Возможные причины

  1. PHP/Python сессии без gc: файлы по минуте в /var/lib/php/sessions.
  2. Почтовый spool /var/mail, /var/spool/postfix/deferred при сломанном relay.
  3. cron каждую минуту создаёт уникальный лог в /var/log без ротации — см. cron.
  4. npm/pip кэши, ~/.cache пользователя сервиса.
  5. Массовый touch бэкап-скриптом «маркеров».
  6. ext4 создавался с байтами на inode по умолчанию на крошечных файлах (архив документов).

Диагностика

На host.example:

df -h
df -i
tune2fs -l /dev/vda2 | grep -E 'Inode count|Free inodes|Inode size|Block count'

tune2fs требует размонтирования? Нет, -l только читает суперблок.

Поиск каталогов-лидеров по числу файлов, не по размеру:

sudo du --inodes -xd1 / | sort -n | tail
sudo du --inodes -xd1 /var | sort -n | tail
sudo du --inodes -xd1 /var/lib | sort -n | tail

du --inodes есть в GNU du на Ubuntu 22.04/24.04. Если нет — медленный вариант:

sudo find /var -xdev -printf '%h\n' | sort | uniq -c | sort -n | tail

Примеры точечных счётчиков:

sudo find /var/lib/php/sessions -xdev -type f | wc -l
sudo find /var/spool -xdev -type f | wc -l
sudo find /tmp -xdev -type f | wc -l

Не запускайте find / без -xdev на хосте с NFS — уйдёте в сетевую ФС.

Решение

Сценарий A. Сессии PHP

Подтвердите, что это сессии, а не пользовательские данные:

ls /var/lib/php/sessions | head
sudo find /var/lib/php/sessions -type f -mtime +2 | wc -l

Удаляйте только старые:

sudo find /var/lib/php/sessions -type f -mtime +2 -delete

Включите session.gc_maxlifetime и cron gc, как задумано пакетом php-common.

Сценарий B. Почтовый deferred

sudo find /var/spool/postfix -type f | wc -l
sudo postqueue -p | tail

Разбор очереди — отдельно. Массовое postsuper -d ALL уничтожит легитимную почту. Сначала причина bounce.

Сценарий C. Кэши и CI

Каталоги вроде /var/cache/nginx, /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs считайте du --inodes. Чистка overlay — теми же правилами, что для диска: не rm -rf на живых snapshot.

Сценарий D. Нужно больше inode навсегда

На пустом томе пересоздание ФС с mkfs.ext4 -i 4096 (байт на inode) увеличивает число inode. На живом корне это переустановка. Альтернатива: перенести каталог-потребитель на новый том с мелким -i и bind-mount.

Почему ENOSPC путают с гигабайтами на практике

Ядро возвращает одно и то же ENOSPC (код 28) и для блоков, и для inode. Приложения почти никогда не пишут «inodes exhausted». Поэтому мониторинг только disk used % слеп. На Zabbix/Prometheus нужен node_filesystem_files_free / df -i, иначе PHP начнёт отдавать 500 при «зелёном» диске.

ext4 заранее выделяет таблицу inode при mkfs. Параметр -i bytes-per-inode по умолчанию часто 16384. На томе 20 ГБ это порядка миллиона inode. Каталог сессий PHP легко съедает их за недели, занимая сотни мегабайт. du -sh врёт «каталог маленький», du --inodes показывает правду.

На Ubuntu 24.04 systemd-tmpfiles чистит /tmp по возрасту, но не /var/lib/php/sessions, если gc PHP выключен в пуле. Проверьте:

php -i | grep -E 'session.save_path|session.gc'
ls /etc/php/*/fpm/php.ini

Для mail spool смотрите не только postfix: nullmailer и exim4 кладут очередь в другие пути. find /var/spool -xdev -type f | wc -l покрывает оба.

Если виновник — git-репозиторий с миллионом blob в objects после ошибочного git add каталога node_modules, не git gc на проде без backup: сначала du --inodes по .git.

Как проверить, что проблема устранена

df -i /
touch /tmp/.inode-ok && rm /tmp/.inode-ok
sudo -u admin touch /home/admin/.inode-ok && rm /home/admin/.inode-ok

Повторите создание файла от пользователя приложения (www-data и т.д.). apt-get check не должен падать с ENOSPC.

Если не помогло

  • IUse% падает и сразу растёт: процесс-генератор жив. auditctl/inotifywait на каталог, не reboot как лечение.
  • df -i 100% сразу после fsck: смотрите lost+foundext4 после сбоя.
  • XFS: inode выделяются иначе; смотрите xfs_info и xfs_db. На Ubuntu server чаще ext4 для корня.

Профилактика

  • Алерт df -i > 70%.
  • Отдельный том под сессии/кэш.
  • Не хранить миллионы файлов на корневом LV «пока влезает по гигабайтам».
  • logrotate и tmpfiles.d для /tmp и /var/tmp.

FAQ

Можно ли «добавить inode» без mkfs?

На ext4 нет живого resize inode count. Только новый том или чистка.

Почему мониторинг диска молчал?

Он смотрел %bytes, не %inodes. Два датчика.

rm -rf каталога идёт часами

Миллионы unlink. rsync -a --delete empty/ в пустой каталог иногда быстрее; всё равно это удаление данных — сначала убедитесь, что каталог расходный.

Связано ли это с reserved blocks?

Нет. Reserved blocks — это гигабайты для root, не inode table.

Docker overlay ест inode или байты?

Оба. Слои с кучей мелких файлов бьют именно inode. docker system df не заменяет df -i на /var/lib/docker.