Skip to content

Commit 51c6bb7

Browse files
fsnotify: Add safeguards and ZDTM test for overlayfs fix
- Increase scan depth limit from 32 to 64 for larger container filesystem trees - Add entry count tracking with a warning after 10,000 entries to flag potentially slow scans - Add inotify_overlayfs ZDTM test that: * Mounts an overlayfs with a test file in the lower layer * Creates an inotify watch on the file through the overlay * Checkpoints and restores * Verifies the watch still delivers events after restore Signed-off-by: Ankit Mahajan <ankimaha-sys@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e5b067a commit 51c6bb7

4 files changed

Lines changed: 132 additions & 1 deletion

File tree

criu/fsnotify.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static char *scan_dir_for_inode(int mntns_root, const char *base_path,
119119
unsigned int s_dev, unsigned long i_ino,
120120
int depth)
121121
{
122+
static int entries_scanned;
122123
int fd;
123124
DIR *dir;
124125
struct dirent *de;
@@ -153,6 +154,10 @@ static char *scan_dir_for_inode(int mntns_root, const char *base_path,
153154
if (fstatat(mntns_root, child_path, &st, AT_SYMLINK_NOFOLLOW))
154155
continue;
155156

157+
entries_scanned++;
158+
if (entries_scanned == 10000)
159+
pr_warn("Overlayfs inode scan: checked over 10000 entries\n");
160+
156161
if (st.st_dev != s_dev)
157162
continue;
158163

@@ -173,7 +178,7 @@ static char *scan_dir_for_inode(int mntns_root, const char *base_path,
173178
return result;
174179
}
175180

176-
#define OVERLAYFS_SCAN_MAX_DEPTH 32
181+
#define OVERLAYFS_SCAN_MAX_DEPTH 64
177182

178183
static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle)
179184
{

test/zdtm/static/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ TST_DIR = \
418418
inotify01 \
419419
inotify02 \
420420
inotify04 \
421+
inotify_overlayfs \
421422
cgroup00 \
422423
rmdir_open \
423424
cgroup01 \
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#include <unistd.h>
2+
#include <limits.h>
3+
#include <sys/types.h>
4+
#include <sys/stat.h>
5+
#include <sys/mount.h>
6+
#include <fcntl.h>
7+
#include <string.h>
8+
#include <stdio.h>
9+
#include <errno.h>
10+
#include <sys/inotify.h>
11+
#include <stdlib.h>
12+
13+
#include "zdtmtst.h"
14+
15+
const char *test_doc = "Check inotify C/R on overlayfs mounts";
16+
const char *test_author = "Ankit Mahajan <ankimaha-sys@users.noreply.github.com>";
17+
18+
char *dirname;
19+
TEST_OPTION(dirname, string, "directory name", 1);
20+
21+
#define BUFF_SIZE ((sizeof(struct inotify_event) + PATH_MAX))
22+
23+
#define LOWER "lower"
24+
#define UPPER "upper"
25+
#define WORK "work"
26+
#define MERGED "merged"
27+
28+
int main(int argc, char *argv[])
29+
{
30+
char lower[PATH_MAX], upper[PATH_MAX], work[PATH_MAX], merged[PATH_MAX];
31+
char test_file[PATH_MAX];
32+
char buf[BUFF_SIZE];
33+
char opts[PATH_MAX * 3];
34+
int fd, wd, len, real_fd;
35+
36+
test_init(argc, argv);
37+
38+
snprintf(lower, sizeof(lower), "%s/%s", dirname, LOWER);
39+
snprintf(upper, sizeof(upper), "%s/%s", dirname, UPPER);
40+
snprintf(work, sizeof(work), "%s/%s", dirname, WORK);
41+
snprintf(merged, sizeof(merged), "%s/%s", dirname, MERGED);
42+
43+
if (mkdir(dirname, 0755) && errno != EEXIST) {
44+
pr_perror("Can't create %s", dirname);
45+
return 1;
46+
}
47+
if (mkdir(lower, 0755)) {
48+
pr_perror("Can't create %s", lower);
49+
return 1;
50+
}
51+
if (mkdir(upper, 0755)) {
52+
pr_perror("Can't create %s", upper);
53+
return 1;
54+
}
55+
if (mkdir(work, 0755)) {
56+
pr_perror("Can't create %s", work);
57+
return 1;
58+
}
59+
if (mkdir(merged, 0755)) {
60+
pr_perror("Can't create %s", merged);
61+
return 1;
62+
}
63+
64+
/* Create a test file in the lower layer */
65+
snprintf(test_file, sizeof(test_file), "%s/testfile", lower);
66+
real_fd = open(test_file, O_CREAT | O_WRONLY, 0644);
67+
if (real_fd < 0) {
68+
pr_perror("Can't create %s", test_file);
69+
return 1;
70+
}
71+
close(real_fd);
72+
73+
/* Mount overlayfs */
74+
snprintf(opts, sizeof(opts), "lowerdir=%s,upperdir=%s,workdir=%s",
75+
lower, upper, work);
76+
if (mount("overlay", merged, "overlay", 0, opts)) {
77+
pr_perror("Can't mount overlayfs");
78+
return 1;
79+
}
80+
81+
/* Set up inotify watch on file inside the overlay */
82+
snprintf(test_file, sizeof(test_file), "%s/testfile", merged);
83+
84+
fd = inotify_init1(IN_NONBLOCK);
85+
if (fd < 0) {
86+
pr_perror("inotify_init1 failed");
87+
goto umount;
88+
}
89+
90+
wd = inotify_add_watch(fd, test_file, IN_MODIFY | IN_ACCESS);
91+
if (wd < 0) {
92+
pr_perror("inotify_add_watch failed on %s", test_file);
93+
goto umount;
94+
}
95+
96+
test_msg("Added inotify watch (wd=%d) on %s\n", wd, test_file);
97+
98+
test_daemon();
99+
test_waitsig();
100+
101+
/*
102+
* After restore, verify the watch still works by triggering
103+
* an event and reading it.
104+
*/
105+
real_fd = open(test_file, O_RDONLY);
106+
if (real_fd < 0) {
107+
fail("Can't open %s after restore", test_file);
108+
goto umount;
109+
}
110+
close(real_fd);
111+
112+
len = read(fd, buf, sizeof(buf));
113+
if (len <= 0) {
114+
fail("No inotify events after restore (len=%d)", len);
115+
goto umount;
116+
}
117+
118+
pass();
119+
120+
umount:
121+
close(fd);
122+
umount2(merged, MNT_DETACH);
123+
return 0;
124+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{'flags': 'suid', 'feature': 'overlayfs'}

0 commit comments

Comments
 (0)