An operator removes a transcription worker’s old log pathname, yet the filesystem remains nearly full. A directory scan cannot see the file. Its open descriptor still points to the underlying file object.
The Linux unlink(2) manual describes the precise lifetime: removing a name makes the file’s space reusable only when that was the last link and no process has it open. If the last name disappears while a descriptor remains open, the file persists until the last referring descriptor closes. Another hard link can also retain the file.
Follow the space, then the descriptor
df reports usage for a filesystem; du walks the files it can reach through directory names. Their scopes differ, as the GNU df manual and GNU du manual describe. Compare the same mount, preferably with consistent units and a du scan confined to that filesystem. A large gap after a pathname was removed is a clue that warrants descriptor inspection. Mount layout and permission limits can also affect the comparison.
On Linux, a read-only next step is lsof +L1. The lsof manual says this selects open files with a link count below one. Inspect the command, process ID, file descriptor, device, inode, and link count. A zero link count identifies an unlinked object; the device and inode help tie the row to the filesystem and avoid relying on a stale pathname alone. Check the owning service and whether it is still writing before changing anything.
The /proc/PID/fd documentation gives a second view: each entry represents one descriptor of that process. For a known PID and descriptor, readlink /proc/PID/fd/FD is a read-only inspection. Access can be restricted, so an empty or denied view does not establish that no process holds the file.
For a hypothetical 100 GiB mount, suppose df reports 96 GiB used while a complete, same-filesystem du scan accounts for 55 GiB. That 41 GiB gap does not identify a culprit. If lsof +L1 points to PID 2400, descriptor 7 and an inode on that mount, inspect that object directly:
stat -L -c 'device=%d inode=%i links=%h blocks=%b blockbytes=%B' /proc/2400/fd/7
GNU stat documents these fields. Match device and inode, confirm zero links, then multiply allocated blocks by block bytes. A hypothetical 40 GiB allocation would explain most of the gap. Logical file length alone cannot establish that allocation, especially for sparse files. The process can close or replace the descriptor during inspection, so repeat the identity check before acting.
A planned application log reopen or controlled service restart may release the descriptor, provided the service can safely tolerate it. There may be several holders or descriptors, so confirm the file is gone from the open-file view and recheck filesystem usage afterward. Decide on the process action from its operational impact; deleting more pathnames cannot close an existing descriptor.

The Campfire
No commentsNobody has pulled up a log by this one yet. Be the first to say what you make of it.
Held for the desk. It appears after a look.