File Deleted but Space Not Freed: Diagnostics with lsof
How to find an open deleted file using lsof and verify space reclamation. A real test with two file descriptors: why du decreases immediately, but available space reported by df only grows after the last FD is closed.

In this article
Большой журнал удалили, но свободного места почти не прибавилось. В Linux это возможно: имя файла уже исчезло из каталога, а процесс продолжает держать его открытым. До закрытия последней ссылки ядра на такой объект занятые им блоки могут оставаться выделенными.
Подтвердите исходную ситуацию
Эта инструкция относится к Linux с установленной утилитой lsof. Права обычного пользователя могут ограничивать видимость чужих процессов. Если вы администрируете сервер, запускайте проверку с разрешёнными для вашей роли правами; иначе передайте задачу ответственному специалисту.
df -h /var
Запишите файловую систему и доступный объём. Путь /var приведён для примера: нужен именно тот том, на котором находился удалённый файл. Без этой привязки легко принять чужой временный файл за причину заполнения раздела сайта.
Найдите открытые файлы без имени
У lsof есть отбор по числу жёстких ссылок. Значение меньше единицы позволяет найти открытые файлы, удалённые из дерева каталогов:
lsof -nP +L1
Параметры -nP отключают преобразование сетевых адресов и портов в имена. В выводе важны процесс, его идентификатор, дескриптор, устройство и размер. Если список пуст, это может означать отсутствие таких объектов, но также недостаток прав или видимости в текущем пространстве процессов.
Не складывайте каждую строку
Один объект иногда отображается у нескольких процессов или дескрипторов. Простое суммирование всех строк завысит оценку освобождаемого объёма. Сопоставляйте устройство и inode, а также проверяйте, что объект относится к нужной файловой системе.
Надпись об удалении сама по себе не является неисправностью. Приложения могут штатно создавать временные файлы и удалять их имена, оставляя открытые дескрипторы. Важен размер, длительность удержания и связь с наблюдаемым ростом занятого места.
Стендовый пример: один файл и два дескриптора
2 октября 2026 года мы воспроизвели эту ситуацию в отдельной тестовой среде Linux: ядро 6.18.44, lsof 4.95.0, GNU df/du 9.4, файловая система overlay. Python-процесс записал в обычный файл 64 MiB данных, выполнил fsync и сохранил два дескриптора одного файла через dup. Здесь нет клиентских данных и работающего сайта: пример показывает механизм удержания файла, а не результат очистки конкретного сервера.
До удаления имя held.log существовало в каталоге. Затем мы удалили именно это имя, сохранив открытыми оба дескриптора. Для проверки нужного процесса использовали команду ниже. Число 73809 — PID нашего теста; на своём сервере подставляют найденный PID. Параметр -a важен: он объединяет условия отбора через «и», поэтому остаются удалённые открытые файлы выбранного процесса.
lsof -nP -a -p 73809 +L1
COMMAND PID USER FD TYPE DEVICE SIZE NLINK NODE NAME
python3 73809 root 3u REG 0,27 67108864 0 1589490 …/held.log (deleted)
python3 73809 root 4u REG 0,27 67108864 0 1589490 …/held.log (deleted)
В примере сокращён только длинный путь в NAME; остальные значения взяты из реального вывода. FD 3u и 4u — разные дескрипторы, открытые для чтения и записи. REG означает обычный файл, NLINK 0 — отсутствие имён, указывающих на него. Совпадающие DEVICE 0,27 и NODE 1589490 показывают, что обе строки относятся к одному объекту. Смысл полей и отбора +L1 описан в руководстве lsof.
Чтобы проверить объём, мы сравнивали df и du на каждом шаге в байтах: df -B1 --output=source,fstype,size,used,avail,target для файловой системы тестового каталога и du -B1 -s для самого каталога. До создания файла каталог занимал 4096 байт. Это накладные расходы каталога, которые остаются после удаления файла.
Состояние теста | Открытые FD файла | du каталога, байт | Доступно по df, байт |
|---|---|---|---|
Файл существует | 3,4 | 67112960 | 27976044544 |
Имя файла удалено | 3,4 | 4096 | 27976044544 |
Закрыт первый FD | 4 | 4096 | 27976044544 |
Закрыт последний FD | нет | 4096 | 28043153408 |
После удаления имени du перестал учитывать файл, но свободный объём по df не вырос. Закрытие первого дескриптора тоже не изменило df: второй продолжал удерживать тот же объект. После закрытия последнего дескриптора процессом строки исчезли из его вывода lsof, а доступный объём вырос ровно на 67108864 байта, то есть 64 MiB. Именно такую последовательность описывает unlink(2) в документации Linux.
Если сложить два значения SIZE из первоначального вывода, получится 128 MiB. В этом тесте это двойной подсчёт одного файла: его логический размер и выделенные блоки составляли 64 MiB. На другом сервере логический размер не равен гарантированно освобождаемому месту: разреженные файлы, особенности файловой системы и записи других процессов влияют на результат. Оценку подтверждают повторным df на том же томе, а не только столбцом SIZE/OFF.
Границы проверки: мы проверили один обычный файл без отображения в память и закрыли дескрипторы внутри собственного тестового процесса. Это не проверка поведения Nginx, СУБД, NFS, снимков или квот. В среде lsof также предупреждал о недоступной /dev/mqueue; поэтому пустой общий список не считаем доказательством полной проверки сервера. Для нашего файла наличие и исчезновение FD дополнительно проверены через /proc выбранного процесса. На рабочем сервере вывод нужно читать вместе с предупреждениями и правами доступа, а способ освобождения выбирать по документации приложения.
Следующее действие зависит от приложения
Например, веб-сервер может продолжать писать в старый журнал после неправильной ротации. В этом случае нужно проверить штатный механизм переоткрытия логов. У базы данных причина и допустимые действия будут другими. Универсальной команды, безопасно закрывающей любой найденный файл, нет.
Не завершайте процесс только потому, что он стоит в первой строке списка. Он может обслуживать текущие запросы или транзакции. Не обнуляйте файловые дескрипторы через служебные пути: такое вмешательство способно нарушить работу приложения и уничтожить данные. Передайте владельцу сервиса найденный идентификатор, размер и время наблюдения.
Проверка результата
После штатного действия, выбранного администратором, повторите lsof -nP +L1 и замер свободного места на том же разделе. Исчезновение конкретного удерживаемого объекта вместе с ростом свободного объёма подтверждает гипотезу гораздо лучше, чем сам факт перезапуска службы.
Если место не изменилось, вернитесь к другим причинам: снимкам, служебным данным файловой системы или новым записям, появившимся за время проверки. Зафиксируйте результат даже при отрицательном выводе. Это позволит следующему специалисту продолжить диагностику, а не повторять случайные удаления и перезапуски.
A large log file was deleted, but almost no free space was added. This is possible in Linux: the file name has already disappeared from the directory, but the process continues to keep it open. Until the last kernel link to such an object is closed, the blocks occupied by it may remain allocated.
Confirm the initial situation
This instruction applies to Linux with the lsof utility installed. A standard user's permissions may restrict visibility of other processes. If you administer the server, run the check with permissions appropriate for your role; otherwise, delegate the task to the responsible specialist.
df -h /var
Record the file system and available space. The path /var is provided as an example: you need the specific volume where the deleted file was located. Without this binding, it is easy to mistake a stranger's temporary file for the cause of the website section filling up.
Find open files without a name
lsof supports filtering by the number of hard links. A value less than one allows you to find open files that have been deleted from the directory tree:
lsof -nP +L1
The -nP parameters disable the conversion of network addresses and ports into names. The output must include the process, its identifier, the descriptor, the device, and the size. If the list is empty, this may indicate the absence of such objects, but it could also mean insufficient permissions or visibility in the current process space.
Do not simply sum every line
One object may sometimes appear under multiple processes or file descriptors. Simply summing all lines will overestimate the reclaimable volume. Match the device and inode, and verify that the object belongs to the correct file system.
The deletion label itself is not a malfunction. Applications can legitimately create temporary files and remove their names while leaving descriptors open. What matters is the file size, the duration of retention, and the correlation with the observed growth in used space.
Staging example: one file and two descriptors
On October 2, 2026, we reproduced this scenario in a separate Linux test environment: kernel 6.18.44, lsof 4.95.0, GNU df/du 9.4, and an overlay file system. A Python process wrote 64 MiB of data to a regular file, executed fsync, and saved two descriptors of the same file via dup. There is no client data or live site here: the example demonstrates the file hold mechanism, not the result of cleaning a specific server.
Before deletion, the name held.log existed in the directory. We then deleted exactly that name while keeping both descriptors open. To verify the target process, we used the command below. The number 73809 is the PID of our test; substitute the found PID on your own server. The -a parameter is important: it combines selection conditions with AND, so only deleted open files of the selected process remain.
lsof -nP -a -p 73809 +L1
COMMAND PID USER FD TYPE DEVICE SIZE NLINK NODE NAME
python3 73809 root 3u REG 0,27 67108864 0 1589490 …/held.log (deleted)
python3 73809 root 4u REG 0,27 67108864 0 1589490 …/held.log (deleted)
In the example, only the long path in NAME is shortened; other values are taken from real output. FD 3u and 4u are different descriptors, opened for reading and writing. REG indicates a regular file, NLINK 0 means no names pointing to it. Matching DEVICE 0,27 and NODE 1589490 show that both lines refer to the same object. The meaning of the fields and the +L1 selection is described in the lsof guide.
To verify the volume, we compared df and du at each step in bytes: df -B1 --output=source,fstype,size,used,avail,target for the test directory's file system and du -B1 -s for the directory itself. Before the file was created, the directory occupied 4096 bytes. This is directory overhead that remains after the file is deleted.
Test state | Open file descriptors | du for directory, bytes | Available per df, bytes |
|---|---|---|---|
File exists | 3,4 | 67112960 | 27976044544 |
File name removed | 3,4 | 4096 | 27976044544 |
First FD closed | 4 | 4096 | 27976044544 |
Last FD closed | no | 4096 | 28043153408 |
After removing the name, du stopped accounting for the file, but the free space reported by df did not increase. Closing the first descriptor also did not change df: the second descriptor continued to hold the same object. After the last descriptor was closed by the process, the lines disappeared from its lsof output, and the available space increased by exactly 67108864 bytes, or 64 MiB. This exact sequence is described by unlink(2) in the Linux documentation.
Adding the two SIZE values from the initial output yields 128 MiB. In this test, this represents a double count of a single file: its logical size and allocated blocks were both 64 MiB. On another server, the logical size does not necessarily equal the guaranteed reclaimable space: sparse files, filesystem specifics, and records from other processes affect the result. The estimate is confirmed by running df again on the same volume, not just by the SIZE/OFF column.
Test boundaries: we checked a single ordinary file without memory mapping and closed file descriptors within our own test process. This is not a test of Nginx, database, NFS, snapshots, or quotas behavior. The lsof environment also warned about an unavailable /dev/mqueue; therefore, an empty common list is not considered proof of a complete server check. For our file, the presence and disappearance of the FD were additionally verified via /proc for the selected process. On a production server, output must be read together with warnings and access rights, and the release method must be chosen based on the application documentation.
The next step depends on the application
For example, a web server may continue writing to an old log file after an incorrect rotation. In this case, check the standard log reopening mechanism. For a database, the cause and permissible actions will differ. There is no universal command that safely closes any found file.
Do not terminate the process simply because it appears at the top of the list. It may be handling current requests or transactions. Do not zero out file descriptors via utility paths: such interference can disrupt the application and destroy data. Pass the found identifier, size, and observation time to the service owner.
Result verification
After the standard action selected by the administrator, repeat lsof -nP +L1 and measure free space on the same partition. The disappearance of a specific held object together with an increase in free space confirms the hypothesis much better than the mere fact of restarting the service.
If the space has not changed, return to other causes: snapshots, file system metadata, or new records created during the check. Record the result even if the outcome is negative. This allows the next specialist to continue the diagnosis rather than repeating random deletions and restarts.





Discussion 0
Share your experience and ask questions. Comments without links appear after editorial review.
No comments yet. Start the discussion.