В продолжение к предыдущей заметке, где я восстанавливал удалённый файл, который был открыт процессом. Ещё один практический пример на эту тему. Мы теперь знаем, что в Linux сначала удаляется имя файла. Сам же файл удаляется, только после того, как счётчик ссылок станет равен нулю и будут закрыты все файловые дескрипторы, ассоциированные с файлом. Давайте найдём файлы, количество ссылок которых равны нулю.
# lsof +L1
или так:
# lsof | grep '(deleted)'
Вывод этой команды можно ограничить файлами конкретного раздела:
# lsof -s +L1 -a /dev/sda1
Приведу практический пример по этой теме. Создадим большой файл /tmp/tempfile размером в один гибибайт:
# dd if=/dev/zero of=/tmp/tempfile bs=1M count=10241073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.22636 s, 482 MB/s
Находясь в директории /tmp запускаю команду в фоне, которая открывает файл на чтение. Удаляет его и засыпает. Используется оболочка Bash:
# ( : {fd}< ./tempfile && rm -f ./tempfile && sleep 30000 {fd}>&- ) 2> /dev/null &
Если после запуска скрипта посмотреть размер раздела, на котором размещается директория /tmp и сумму всех файлов на этом разделе, то получится разница в этот самый гибибайт. В моём случае это корневой раздел:
# df -h /Filesystem Size Used Avail Use% Mounted on/dev/mapper/debian11--vg-root 19G 2.1G 16G 12% /# du -xhs /1.1G /
Есть процесс, который удалил файл, но продолжает держать открытым файловый дескриптор, поэтому реально файл не удалён и всё ещё занимает место на диске. Если поднять процесс из фона и завершить, то файловый дескриптор будет закрыт и файл перестанет заниматься место на диске.
# fgCTRL+C
На практике я регулярно сталкиваюсь с подобной ситуацией. Чаще всего это касается лог файлов. Кто-то решает удалить распухший лог, но при этом забывает перезапустить сервис. Например некоторые разработчики любят урезать логи docker или nginx с помощью truncate.
В итоге лог вроде как удалён, но файловый дескриптор открыт и служба продолжает писать в него логи. Доходит до того, что всё место на диске занято и непонятно кем. Тут спасёт перезагрузка, или определение с помощью lsof какой файл открыт и какая служба его держит. Перезапускаем и всё становится в порядке с местом.
#terminal