xv6, line by line
user/forphan.c

user/forphan.c

C · 40 lines · annotated 100% · user program / library · upstream

About this file

forphan sets up an orphaned file so that test-xv6.py can check that the kernel cleans it up after a crash. It creates a file, keeps it open, deletes its name, and then sleeps forever. The file now has no name (link count (nlink) 0) but still exists, because an open file keeps its inode alive.

The test script (test-xv6.py:149) waits for the line wait for kill and reclaim N, then kills QEMU, which is like pulling the power plug: the final iput that would have freed the inode on close never runs. On the next boot, fsinit calls ireclaim (kernel/fs.c:48), which finds the inode allocated but with no links and frees it, printing ireclaim: orphaned inode N. The script passes if it sees that line within 30 seconds. Without ireclaim, the inode and its blocks would stay allocated and unreachable forever.

Both this program and ireclaim were added on the same day, 6 August 2025: ireclaim in commit db26774, and this test, with user/dorphan.c, in commit 52efd73 (“Crash tests for reclaiming an orphaned file and directory”). Run by hand in QEMU at this commit, it printed wait for kill and reclaim 24, and the next boot printed ireclaim: orphaned inode 24.

Read before: iput and ireclaim in kernel/fs.c. Read next: user/dorphan.c, the same test with a directory.

6// Create an orphaned file and check if test-xv6.py recovers it.
8#define BUFSZ 500
10char buf[BUFSZ];
12int
13main(int argc, char **argv)
15 int fd = 0;
16 char *s = argv[0];
17 struct stat st;
18 char *ff = "file0";
20 if ((fd = open(ff, O_CREATE | O_WRONLY)) < 0) {
21 printf("%s: open failed\n", s);
22 exit(1);
23 }
24 if (fstat(fd, &st) < 0) {
25 fprintf(2, "%s: cannot stat %s\n", s, "ff");
26 exit(1);
27 }
28 if (unlink(ff) < 0) {
29 printf("%s: unlink failed\n", s);
30 exit(1);
31 }
32 if (open(ff, O_RDONLY) != -1) {
33 printf("%s: open successed\n", s);
34 exit(1);
35 }
36 printf("wait for kill and reclaim %d\n", st.ino);
37 // sit around until killed
38 for (;;)
39 pause(1000);