Inode Exhaustion: Disk Full with Space Available
Diagnose and fix inode exhaustion when df shows space but you can't create files
What Are Inodes?
An inode is a data structure that stores metadata about every file and directory on your filesystem (name, size, owner, permissions, etc.). Even if you have gigabytes of free disk space, if you run out of inodes, you cannot create new files.
This is different from disk space, you can have 50% disk usage but 100% inode usage, and still get "No space left on device" errors.
Identify the Problem
The Symptom
touch /tmp/testfile
# touch: cannot touch '/tmp/testfile': No space left on deviceBut checking disk space shows plenty available:
df -h
# Filesystem Size Used Avail Use% Mounted on
# /dev/vda1 50G 20G 25G 44% /Check Inode Usage
df -i
# Filesystem Inodes IUsed IFree IUse% Mounted on
# /dev/vda1 3200000 3197432 2568 100% /If IUse% is 100% (or very high like 99%), you've exhausted inodes.
This is a different problem from running out of disk space. You can have plenty of gigabytes free but still be unable to create files if inodes are exhausted.
Find What's Consuming Inodes
The most reliable method to find directories with the most files:
find / -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -rn | head -20This command:
- Searches from root without crossing filesystem boundaries (
-xdev) - Counts files by parent directory
- Shows top 20 directories
Common Inode Culprits
1. PHP Session Files
Location: /var/lib/php/sessions
Check:
ls -la /var/lib/php/sessions | wc -l
find /var/lib/php/sessions -type f | wc -lClean old sessions (older than 7 days):
find /var/lib/php/sessions -type f -mtime +7 -deleteEnable automatic cleanup in PHP config:
Edit /etc/php/8.1/fpm/pool.d/www.conf (or your pool):
php_admin_value[session.save_path] = "/var/lib/php/sessions"Or set cron job to clean daily:
0 2 * * * find /var/lib/php/sessions -type f -mtime +7 -delete2. Mail Spool
Locations: /var/mail, /var/spool/mail, /var/spool/postfix
Check Postfix queue:
postqueue -pClear old messages:
postsuper -d ALLCheck mail spool:
du -sh /var/spool/postfix/*
ls -lh /var/mail/3. Log Files and Rotations Gone Wrong
du -sh /var/log
ls -lhS /var/log | head -20If log rotation is broken, old logs accumulate. Compress or delete:
gzip /var/log/apache2/access.log
# or delete entirely
rm /var/log/apache2/access.log.1 /var/log/apache2/access.log.2 /var/log/apache2/access.log.34. Temp Files and Cache
# /tmp cleanup
find /tmp -type f -atime +30 -delete
# /var/tmp cleanup
find /var/tmp -type f -atime +30 -delete
# Application cache (if applicable)
rm -rf /var/www/myapp/cache/*5. Uploaded Files or User Content
If you host file upload services, check:
find /var/www -type f | wc -l
du -sh /var/wwwLook for:
- Unused or orphaned files
- Failed upload directories
- Temporary upload directories
Advanced: Truncate Large Open Files
If a log file is still open (being written to), deleting it won't free inodes immediately. You need to truncate it:
# Find large files in use
lsof +L1 2>/dev/null | head -20
# Truncate without closing the file
truncate -s 0 /var/log/largefile.logThe difference:
rmdeletes the inode, but the space isn't freed if the file is still opentruncate -s 0empties the file while keeping it open, freeing space immediately
Permanent Solutions
1. Increase Inode Count (For New Filesystems)
When formatting a new partition:
mkfs.ext4 -i 4096 /dev/vda1
# or
mkfs.ext4 -N 4000000 /dev/vda1The -i flag sets the ratio of bytes per inode. Lower value = more inodes.
2. Implement Automatic Cleanup
Create a cron job to regularly clean old files:
# /etc/cron.d/cleanup-inodes
0 2 * * * root find /var/lib/php/sessions -type f -mtime +7 -delete
0 3 * * * root find /tmp -type f -atime +30 -delete
0 4 * * * root find /var/tmp -type f -atime +30 -delete3. Monitor Inode Usage
Add to your monitoring/alerting:
# Alert if inode usage > 85%
df -i | awk 'NR==2 {if ($5+0 > 85) print "Warning: Inode usage at " $5}'Quick Diagnostic Checklist
- Confirm the problem:
df -ishows 100% usage - Find culprits:
find / -xdev -printf '%h\n' | sort | uniq -c | sort -rn | head -20 - Check PHP sessions:
ls /var/lib/php/sessions | wc -l - Check mail spool:
postqueue -p,du -sh /var/mail - Clean old sessions:
find /var/lib/php/sessions -type f -mtime +7 -delete - Clean /tmp:
find /tmp -type f -atime +30 -delete - Verify recovery:
df -i(should show lower usage) - Set up automatic cleanup via cron