Почему место не освободилось после удаления большого файла в Linux?

Ответ

Это классическая ситуация, которая происходит, когда файл удален (его имя убрано из файловой системы), но один или несколько процессов продолжают держать его открытым. Пока дескриптор файла открыт, ядро не освобождает занимаемые файлом блоки данных на диске.

Диагностика: Первым делом нужно найти процесс, который удерживает удаленный файл.

# Самый распространенный способ
lsof +L1  # Покажет файлы с количеством ссылок <1 (удаленные)
# Или более конкретно:
lsof | grep deleted

# Альтернатива через /proc (полезно в контейнерах, где нет lsof)
for pid in /proc/[0-9]*; do ls -la $pid/fd 2>/dev/null | grep -q "(deleted)" && echo "PID: ${pid##*/}"; done

Вывод покажет PID процесса и номер файлового дескриптора (FD). Часто это лог-файлы, которые продолжает писать приложение (например, Java-процесс, nginx, база данных), после того как лог был удален администратором.

Решение:

  1. Идеальный вариант: Аккуратно перезапустить или остановить зависящий процесс (например, отправив сигнал SIGHUP для реконфигурации или выполни graceful restart сервиса).
  2. Если перезапуск невозможен: Можно вручную очистить содержимое файла через его дескриптор в /proc, что освободит место, но процесс продолжит писать "в ноль".
    # Предположим, PID=1234, FD=5
    > /proc/1234/fd/5  # Очистка файла через перенаправление пустого вывода
    # ИЛИ
    cat /dev/null > /proc/1234/fd/5

    Важно: Это временное решение, основное — переконфигурировать приложение на запись в новый корректный файл.

Для DevOps: Чтобы предотвратить эту проблему, мы настраиваем log rotation (через logrotate) с опцией copytruncate или create и отправляем сигнал приложению для переоткрытия логов. Также важно мониторить использование диска и иметь алерты, которые сработают ДО полного заполнения.

Ответ 18+ 🔞

Да ты посмотри, какая классика жанра! Ситуация, когда файл вроде как удалили, а он на диске сидит, как будто ему там нравится. Просто потому что какой-то процесс за него держится, как за родного. Пока дескриптор не закрыли, ядро эти блоки на диске не отпустит, вот и вся магия. Овердохуища свободного места в мониторинге, а на деле — пизда рулю.

Чё делать, чтобы понять, кто виноват: Первым делом ищем того самого распиздяя, который файл удерживает.

# Самый распространённый способ
lsof +L1  # Покажет файлы, у которых ссылок меньше одной (то есть удалённые)
# Или поконкретнее, если лень:
lsof | grep deleted

# Если lsof нет, как в каком-нибудь урезанном контейнере, лезем в /proc
for pid in /proc/[0-9]*; do ls -la $pid/fd 2>/dev/null | grep -q "(deleted)" && echo "PID: ${pid##*/}"; done

Вывод тебе покажет PID процесса и номер дескриптора (FD). Чаще всего это оказываются лог-файлы от какого-нибудь Java-приложения, nginx или базы данных, которые администратор удалил, а процесс про это нихера не знает и продолжает писать.

Как это починить:

  1. Нормальный путь: Аккуратно перезапустить или остановить этот процесс. Например, отправить SIGHUP, чтобы он перечитал конфиги и открыл лог заново, или сделать graceful restart сервиса. Доверия ебать ноль, что это сработает без последствий, но это правильно.
  2. Если перезапуск — это хитрая жопа и всё упадёт: Можно вручную почистить файл через его дескриптор в /proc. Место освободится, но процесс будет дальше писать в пустоту, как дурак.
    # Допустим, PID=1234, FD=5
    > /proc/1234/fd/5  # Просто засунуть туда пустоту
    # Или так:
    cat /dev/null > /proc/1234/fd/5

    Важно: Это костыль на время, чтобы не лёг сервер. Потом всё равно надо заставить приложение писать в новый, нормальный файл.

Для DevOps, чтобы не было такого пиздеца: Настраиваем нормальный log rotation через logrotate с опциями copytruncate или create и обязательно шлём сигнал приложению, чтобы оно переоткрыло логи. И, конечно, ставим мониторинг на использование диска с алертами, которые сработают до того, как всё накроется медным тазом. А то потом терпения ноль ебать разгребать.