xv6, line by line
tour 35
Tours35 Creating and naming files

Tour 35 · File system · about 26 minutes · 17 steps

Creating and naming files

echo hi > newfile creates a file. That sounds like one action, but on the disk it is three: an inode must be found and marked used, a directory entry must be written that names it, and the directory’s own inode is updated. Meanwhile, on two other harts, other processes may be creating files in the same directory, perhaps with the same name.

This tour follows create, called by sys_open with O_CREATE, line by line: how it finds the parent directory, why it holds the parent’s lock from the first lookup to the last write, how ialloc scans the inode blocks for a free inode, and how dirlink adds the name. Then it follows the other naming system calls: sys_link (a second name for the same inode), sys_unlink (removing a name, and why . and .. are refused), and mkdir, whose . and .. make the link count (nlink) of a directory something to think about.

Throughout, watch the order of the locks: parent directory first, then the child, never the reverse. And at the end, watch two harts create the same name at the same moment.

Best after: 31. The log: begin_op, commit and group commit, 33. The life of an inode, 34. Path lookup

Who is running where

The machine has three harts, on a fresh boot (so the next free inode is 24). When the tour starts:

Hart What it is doing
0 Idle in its scheduler
1 Running sh (pid 3), the shell’s child for echo hi > newfile: the process this tour follows
2 Idle, or running another process that creates files in /

The shell (pid 2) waits in kwait. Block numbers come from this build’s mkfs and a traced copy of the kernel: inodes 1–15 live in block 33, 16–31 in block 34; the root directory’s content is block 47; the bitmap is block 46.

Three harts are running. This tour follows one path through the code, but the machine has three CPUs executing at the same time. Watch the locks held display at the top of each step, and read the Meanwhile, on other harts boxes: they show what the other CPUs could be doing at that very moment.
The route
  1. 1The shell asks for a new file user/sh.c
  2. 2One transaction for the whole open kernel/sysfile.c
  3. 3Find the parent, lock it, check it still exists kernel/sysfile.c
  4. 4Is the name already taken? kernel/sysfile.c
  5. 5ialloc scans for a free inode kernel/fs.c
  6. 6Initialize the new inode, parent still locked kernel/sysfile.c
  7. 7dirlink writes the name into the parent kernel/fs.c
  8. 8When dirlink fails, iput cleans up kernel/sysfile.c
  9. 9A slot in the file table kernel/file.c
  10. 10fdalloc, and the file is open kernel/sysfile.c
  11. 11link gives an inode a second name kernel/sysfile.c
  12. 12link, second half: lock the new parent, not both kernel/sysfile.c
  13. 13unlink refuses . and .. before it locks anything else kernel/sysfile.c
  14. 14Remove the name, then maybe the file kernel/sysfile.c
  15. 15mkdir: . and .., and who counts as a link kernel/sysfile.c
  16. 16Two harts, one name kernel/sysfile.c
  17. 17What it costs to name a file kernel/sysfile.c

Keys: ← → step · Home start