mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
docs: update Invisible Files documentation
- Explain path loss scenarios (unlinked, virtual files, mount shadowing) - Detail the Ghost File strategy (link count 0) and optimization (fiemap) - Document the Link-Remap strategy (link count > 0) via linkat() - Explain the PID helper (TASK_HELPER) mechanism for virtual files - Clarify handling for NFS Silly Rename and OverlayFS Signed-off-by: Andrei Vagin <avagin@google.com>
This commit is contained in:
parent
48b47d17e7
commit
8b43ce4050
1 changed files with 40 additions and 35 deletions
|
|
@ -1,52 +1,57 @@
|
|||
# Invisible Files
|
||||
# Invisible and Nameless Files
|
||||
|
||||
In Linux, files may be inaccessible via `open()` yet still exist within the system. This page explains how this occurs and how CRIU handles these situations.
|
||||
In Linux, a file can remain accessible to a process even if it no longer has a visible path in the filesystem. This occurs when a file is unlinked (deleted) while still open or when its path becomes inaccessible due to mount shadowing. This document explains how CRIU detects and reconstructs these "invisible" files.
|
||||
|
||||
## How a File Can Lose Its Path
|
||||
|
||||
A common scenario involves a process performing the following:
|
||||
## How Files Lose Their Paths
|
||||
|
||||
### 1. Unlinked while Open
|
||||
The most common case is when an application opens a file and then immediately deletes it:
|
||||
```c
|
||||
int fd = open("/foo/bar", O_RDONLY);
|
||||
unlink("/foo/bar");
|
||||
int fd = open("/tmp/secret", O_RDWR);
|
||||
unlink("/tmp/secret");
|
||||
```
|
||||
The file data persists in the kernel as long as the file descriptor remains open, but it no longer exists in the filesystem directory structure.
|
||||
|
||||
After the `unlink()`, the name `/foo/bar` is removed from the filesystem, but because the process still holds an open file descriptor, the file's data remains on disk.
|
||||
### 2. Virtual Filesystem Deletion
|
||||
On virtual filesystems like `/proc`, if a process dies, its entries (e.g., `/proc/$PID/cmdline`) disappear. However, if another process still has an open file descriptor to one of these entries, the file remains alive but "nameless."
|
||||
|
||||
There are two primary sub-cases. First, if the file has no other hard links, the data is truly "orphaned." Second, if other hard links exist, the file still has a name elsewhere. However, the Linux VFS layer generally does not provide a direct way to find those other names.
|
||||
### 3. Mount Shadowing (Overmounts)
|
||||
If a process opens a file in `/mnt/data` and then a new filesystem is mounted over `/mnt`, the original file becomes inaccessible via its path.
|
||||
|
||||
### Virtual Filesystems
|
||||
## CRIU's Detection and Reconstruction Strategies
|
||||
|
||||
On virtual filesystems like `proc` or `sysfs`, invisible files can appear if the underlying object is removed. For example, if a process opens a file in `/proc/$pid` and that task subsequently dies, the path is removed, but the file descriptor remains open (though subsequent reads will return `ENOENT`).
|
||||
CRIU uses the `/proc/$pid/fd/` and `/proc/$pid/fdinfo/` interfaces to identify open files and their expected paths.
|
||||
|
||||
### Name-less Files
|
||||
### Ghost Files (Link Count = 0)
|
||||
If a file has a link count of zero (`st_nlink == 0`), it is truly deleted.
|
||||
* **Dumping**: CRIU reads the entire content of the file and stores it within the image directory as a "ghost file."
|
||||
* **Restoring**: During restoration, CRIU recreates the file in a temporary location, opens it, and then immediately unlinks it to restore the original unlinked state.
|
||||
* **Optimization**: For large sparse files, CRIU can use the `--ghost-fiemap` option to only capture the data blocks, significantly reducing image size.
|
||||
|
||||
Some files are created without ever having a name. This is discussed in [another article](how-to-open-a-file-without-open-system-call.md).
|
||||
### Link-Remap (Link Count > 0)
|
||||
If a file has a positive link count but its expected path is missing or points to a different file, it means the specific name used to open the file was deleted, but other hard links still exist.
|
||||
* **Strategy**: CRIU uses `linkat()` with the `AT_EMPTY_PATH` flag to create a temporary name for the file on the same filesystem. This allows it to be re-opened via a path during restoration.
|
||||
* **Option**: This behavior is enabled via the `--link-remap` flag.
|
||||
|
||||
### Overmounted Files
|
||||
### Virtual File Remap (The PID Helper)
|
||||
For deleted `/proc` entries, CRIU cannot use ghost files or `linkat()`. Instead:
|
||||
1. It records the PID of the original process that the `/proc` entry referred to.
|
||||
2. During restoration, it creates a temporary **TASK_HELPER** process with that specific PID.
|
||||
3. The restored application opens the `/proc/$PID/...` entry of this helper.
|
||||
4. The helper is terminated once all restoration tasks are complete.
|
||||
|
||||
If a task opens a file and a new mount point is later mounted over any part of its path, the original path may become inaccessible or point to a different file. CRIU currently does not support checkpointing such files and will abort the dump.
|
||||
### Filesystem-Specific Handling
|
||||
|
||||
## How CRIU Handles Invisible Files
|
||||
* **NFS**: CRIU detects "Silly Rename" files (`.nfsXXX`) and handles them via the link-remap mechanism.
|
||||
* **OverlayFS**: Since `linkat()` may fail on OverlayFS if the file resides on a read-only lower layer, CRIU automatically falls back to the ghost file strategy in these cases.
|
||||
* **Devpts**: Files on `devpts` (like PTYs) are managed by the kernel and are restored using specific PTY master/slave allocation logic rather than file-based reconstruction.
|
||||
|
||||
### Detection and Dumping
|
||||
## Technical Details
|
||||
|
||||
Subject to certain [filesystem peculiarities](filesystems-pecularities.md), CRIU detects invisible files as follows:
|
||||
* **--ghost-limit**: By default, CRIU limits ghost files to **1 MB** to prevent excessive disk usage. This can be increased via the `--ghost-limit` option.
|
||||
* **--evasive-devices**: Allows CRIU to proceed even if a character or block device path has changed, provided the device numbers (`st_rdev`) match.
|
||||
|
||||
1. CRIU [retrieves the file descriptors](dumping-files.md) from the target process.
|
||||
2. For each FD, CRIU identifies the file's name by calling `readlink` on `/proc/self/fd/$fd`.
|
||||
3. CRIU then calls `fstat()` on the file descriptor.
|
||||
|
||||
If `st_nlink` is zero, the file has been fully deleted. Since it cannot be reopened by path, CRIU must save the file's contents directly into the image as a **ghost file**. By default, CRIU limits the size of ghost files it can checkpoint to 1 MB, though this can be adjusted with the `--ghost-limit` option.
|
||||
|
||||
If `st_nlink` is non-zero, CRIU verifies if the path retrieved from `proc` still refers to the same file. It calls `stat()` on that path and compares the `st_dev` and `st_inode` fields with those from the `fstat()` call. If they match, the file is still accessible by that name. If they do not match, the name now refers to a different file, and the dump fails (a rare situation that CRIU may support in the future).
|
||||
|
||||
A third possibility is that `stat()` fails with `ENOENT`, meaning the file has other names, but the one used to open it has been removed. In this case, CRIU uses the `linkat` system call to create a temporary name for the file on disk and records this name in the image. This is known as **link-remap**. Because this modifies the filesystem, the `--link-remap` option must be provided. These temporary names are removed after the restoration is complete.
|
||||
|
||||
### Chunked Ghost Files
|
||||
|
||||
When CRIU checkpoints a ghost file larger than 12 MB, it attempts to minimize the image size by identifying holes (sparse areas). This allows CRIU to save only the actual data chunks and record the offsets, skipping empty space. To optimize this process on highly sparse files, CRIU supports the `--ghost-fiemap` option, which uses the `fiemap` ioctl for better performance.
|
||||
|
||||
### Virtual Filesystems
|
||||
|
||||
For the `proc` filesystem, CRIU uses a different technique. If a name in `/proc` is dead, it cannot be linked or saved as a ghost file. Instead, CRIU records the PID of the deceased process. During restoration, CRIU creates a temporary task with that PID, which remains alive until all its openers have been restored.
|
||||
## See also
|
||||
* [Dumping File Descriptors](dumping-files.md)
|
||||
* [Filesystem Peculiarities](filesystems-pecularities.md)
|
||||
* [Mount Points](mount-points.md)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue