Hole Punching - dev-shm
Core Idea
The target file here is /dev/shm. This is a tmpfs directory which does not store it’s file in disk but rather in page caches. These file in this tmpfs has two separate concepts:
- Logical file size — the range of offsets that belong to the file.
- Physical backing —RAM pages backed by the virtual address space
What is a Hole?
A hole is a range inside a file that exists logically but has no physical storage backing.
Logical file:
0 KB 4 KB 8 KB 12 KB
│----------│----------│----------│
DATA HOLE HOLE DATA
Physical backing:
offset 0 KB → physical block/page
offset 4 KB → NULL (hole)
offset 8 KB → NULL (hole)
offset 12 KB → physical block/page
Reading from a hole returns zeroes, even though no physical blocks/pages are allocated.
What is Hole Punching?
Hole punching removes the physical storage backing a specific range of a file without changing the logical file size.
fallocate(fd,FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,offset,length);
After the operation:
- File size remains the same.
- The specified range no longer consumes physical storage.
- Reads from that range return zeroes.
Why Does Hole Punching Exist?
It allows applications to reclaim storage without rewriting or shrinking the entire file.
Consider a log file that is being written into for months, for instance
10 GB file
[ January ] [ February ] [ March ]
3 GB 3 GB 4 GB
If January and February are no longer needed:
Before:
physical storage = 10 GB
logical size = 10 GB
Punch the first 6 GB:
After:
[ HOLE ][ March ]
physical storage ≈ 4 GB
logical size = 10 GB
March remains at the same logical offset.
Why Not Just Write Zeroes?
Writing zeroes:
[000000000000][DATA]
still consumes physical storage. Slower !!
Hole Punching in tmpfs (/dev/shm)
/dev/shm is usually backed by tmpfs.
For a disk filesystem:
file offset → filesystem mapping → disk block
For tmpfs:
file offset → shmem/tmpfs mapping → RAM page
Therefore, a hole in tmpfs means:
file offset → no physical RAM page
Step 1 — Create the File
ftruncate(fd, 64 * 1024 * 1024);
The logical file size becomes:
64 MB
But physical RAM pages may not yet be allocated.
offset 0 → NULL
offset 4096 → NULL
offset 8192 → NULL
Step 2 — Allocate Backing
fallocate(fd, 0, 0, 64 * MB);
Now the tmpfs file has backing pages.
Step 3 — Punch the Hole
fallocate(fd,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0,
64 * MB);
The backing pages are removed.
offset 0 → NULL
offset 4096 → NULL
offset 8192 → NULL
However, the file still has a logical size of 64 MB.
How to use ?
- Well, I don’t want to reinvent the wheel again. Faith’s blog is already highly detailed about this and how to use it. https://faith2dxy.xyz/2025-11-28/extending_race_window_fallocate/
- For even more detailed walkthrough, read https://starlabs.sg/blog/2023/07-a-new-method-for-container-escape-using-file-based-dirtycred/