Temporary files in Linux are ordinary files used for caching, buffering, or holding intermediate data. Examples include storing data while sorting large datasets, temporarily holding the contents of files being zipped or unzipped, or keeping partially-downloaded files until a transfer completes successfully. Many applications rely on temporary files for scratch space, ensuring that incomplete or temporary data stays behind the scenes and never shows up for the user.
There is no special “temporary file” type baked into the virtual filesystem layer (VFS), “temporary” is a convention implemented by software. That said, two mechanisms are commonly used to achieve this:
- tmpfs: a memory-backed filesystem (with optional swap backing) typically mounted at /run or /dev/shm.
- O_TMPFILE: a flag to open(2)/openat(2) that creates an unnamed file on a regular on-disk filesystem (e.g., XFS, ext4). The file starts with no directory entry and exists only by file descriptor, it can later be linked into the namespace atomically.
This article explains each mechanism, details their creation–utilization–deletion lifecycle, and shows how to tell them apart. It also uses XFS filesystem to showcase the O_TMPFILE flag.
tmpfs
tmpfs is a RAM-backed filesystem that allows users to create and use files just like in any traditional directory, but the data is stored in volatile memory rather than on a physical disk. Popular mount points for tmpfs include /dev/shm and /run, depending on how the system is set up. Since tmpfs is managed by the kernel’s VFS layer, working with files and directories in tmpfs is as seamless as anywhere else. Creating, reading, and writing files uses all the familiar commands and APIs.
Setting up a tmpfs mount is straightforward. Many distributions automatically mount /dev/shm, but additional tmpfs partitions can be mounted as needed. For example:
sudo mount -t tmpfs -o size=2G tmpfs /mnt/tmp_fs
This creates a 2GB in-memory filesystem at /mnt/tmp_fs.
Once mounted, files on tmpfs are accessed as usual:
echo "hello world" > /mnt/tmp_fs/hello.txt
dd if=/dev/zero of=/mnt/tmp_fs/bigfile bs=1M count=100
Behind the scenes, writing to tmpfs allocates anonymous memory pages, which live in system RAM. Setting a maximum size with the size mount option ensures the filesystem does not grow beyond the defined limit, which helps with resource management on busy systems. If no limit is specified, tmpfs may use up to half of the total available memory by default, plus swap if enabled. Because tmpfs storage directly consumes memory, writing large files to tmpfs will reduce the amount of free and available memory on the system. This can quickly lead to memory pressure, causing the system to slow down as it resorts to swapping.
It’s worth noting that Linux offers another in-memory filesystem called ramfs. It works in a similar way, keeping files in memory. But unlike tmpfs, ramfs doesn’t let you set size limits or use swap. This means if too much is written to ramfs, it can keep growing and end up using all your system memory. That’s why tmpfs is usually the safer choice for most tasks, it gives you a way to keep memory usage under control.
Since tmpfs is a memory-backed filesystem and not associated with a physical block device, tools like blkid and lsblk do not display tmpfs mounts. Usage and mount details for tmpfs can be checked using the df and mount commands instead.
# mount | grep tmpfs
tmpfs on /mnt/tmp_fs type tmpfs (rw,relatime,seclabel,size=2097152k)
# df -hT /mnt/tmp_fs/
Filesystem Type Size Used Avail Use% Mounted on
tmpfs tmpfs 2.0G 2.3M 2.0G 1% /mnt/tmp_fs
Here is an example showing the memory stats before and after creating a large file on tmpfs.
$ cat /proc/meminfo | grep -E 'Mem|anon'
MemTotal: 16092496 kB
MemFree: 11905188 kB
MemAvailable: 14553688 kB
Active(anon): 899632 kB
Inactive(anon): 15264 kB
After running the command dd if=/dev/zero of=/mnt/tmp_fs/bigfile bs=1M count=1024 we can see the memory consumption details below.
$ cat /proc/meminfo | grep -E 'Mem|anon'
MemTotal: 16092496 kB
MemFree: 10839752 kB
MemAvailable: 13493648 kB
Active(anon): 908424 kB
Inactive(anon): 1063840 kB
As shown in the example, writing large files to tmpfs directly increases the amount of memory used for anonymous pages. Specifically, this is reflected as a rise in Inactive(anon) in /proc/meminfo.
A key property of tmpfs is its volatility. Since data lives in memory, contents disappear when the filesystem is unmounted or the machine is rebooted. Additionally, tmpfs is swap-aware. Under memory pressure, the kernel may move some tmpfs pages to swap, freeing up physical RAM at the cost of slower access. So, there’s no risk of processes monopolizing RAM through tmpfs alone.
Files are removed in tmpfs the same way as on disk: when a file is unlinked (deleted), it is removed from the directory structure, and the memory it used is only freed once no process has it open. Unmounting the tmpfs filesystem erases all of its files immediately, so be sure to copy any important data to persistent storage if required.
In summary, tmpfs is invaluable for scenarios requiring fast,, temporary storage that won’t survive a reboot. Ideal for caches or holding intermediate data. The typical lifecycle of a tmpfs file is:
- Mounts tmpfs (or use a pre-existing mount like /dev/shm).
- Applications create and use files in this space, taking advantage of RAM-speed I/O.
- As system memory fills, tmpfs contents may be swapped.
- Files are deleted when no longer needed, and on unmount or reboot everything is wiped clean.
O_TMPFILE
While tmpfs provides an in-memory, temporary store for files that should disappear upon reboot or unmount, Linux also offers a powerful feature at the filesystem level for managing truly transient files: the O_TMPFILE flag.
Opening a file descriptor with O_TMPFILE instructs the kernel to create an unnamed file that has no visible directory entry. This file physically exists on the filesystem, but remains invisible to all users and processes. The only reference to it is the file descriptor within the process. As a result, even if other processes want to look for it by name, they cannot. Until the file is explicitly made visible, it doesn’t appear anywhere in the filesystem’s directory tree.
The lifecycle of an O_TMPFILE file is closely tied to its file descriptor. As long as at least one file descriptor remains open, the kernel keeps the file alive. If all file descriptors referencing the file are closed and the file has not been linked into the filesystem, the kernel automatically deletes it, making this mechanism perfect for temporary, staging, or scratch files that don’t need persistence or visibility.
The feature truly shines when you want to avoid filename collisions or exposure of incomplete files. For example, application data can be written to an O_TMPFILE file, validate everything, and only then make it visible with an atomic system call like linkat(2). An unlinked file is similar to a file opened with O_TMPFILE, in the sense that both result in a file present on disk with an inode but without an associated directory entry, and both consume space in the filesystem that cannot be found using du tools. However, use tools like lsof to list all files currently open by a process including temporary or unlinked files, even though they do not appear in the filesystem’s directory structure.
Why is O_TMPFILE useful?
- Prevents race conditions and name clashes
- Keeps potentially incomplete or sensitive data invisible until ready.
- Enables atomic publish of the final file. Once
linkat()is called, the file appears under a visible path.
Example
/* LICENSE: GPLv2 */
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
int fd = open("/mnt/xfs", O_TMPFILE | O_RDWR, 0600);
if (fd < 0) {
perror("open(O_TMPFILE)");
return 1;
}
const char *msg = "O_TMPFILE with XFS!\n";
if (write(fd, msg, strlen(msg)) < 0) {
perror("write");
close(fd);
return 1;
}
/*
// Uncomment to link the file
// Link the file into the namespace to make the file visible
if (linkat(fd, "", AT_FDCWD, "/mnt/xfs/published.txt", AT_EMPTY_PATH) < 0) {
perror("linkat");
close(fd);
return 1;
}
*/
close(fd); // If never linked, file is deleted on close
return 0;
}
In the example above, the linkat call with an empty string ("") for the old name and the AT_EMPTY_PATH flag tells the kernel to use the tmp file’s file descriptor as the source. This makes the previously unnamed temporary file visible in the filesystem at /mnt/xfs/published.txt. Without this step, the file would be automatically deleted when closed. For more information about the linkat system call and its flags, see man 2 linkat.
Conclusion
tmpfs is useful when applications need fast, non-persistent storage such as caches or temporary working files that will be lost on unmount or reboot. It stores data in RAM, making file access speedy but temporary.
O_TMPFILE is a feature for securely creating unnamed temporary files on filesystems. It prevents filename clashes and ensures incomplete data remains hidden until explicitly linked. This is helpful for atomic file updates and for keeping scratch files private to a process.
tmpfs is best suited for applications requiring temporary, RAM-backed storage that can be accessed like any normal file. Use O_TMPFILE for transient files that should remain invisible until fully prepared, particularly in scenarios where reliable, race-free file creation and updates are needed.
References
- man open, openat, linkat, lsof