8.11 Code: directory layer
A directory is implemented internally much like a file.
Its inode has type
T_DIR
and its data is a sequence of directory entries.
Each entry is a
struct dirent
(kernel/fs.h:56),
which contains a name and an inode number.
The name is at most
DIRSIZ
(14) characters;
if shorter, it is terminated by a NULL (0) byte.
Directory entries with inode number zero are free.
The function
dirlookup
(kernel/fs.c:552)
searches a directory for an entry with the given name.
If it finds one, it returns a pointer to the corresponding inode, unlocked,
and sets
*poff
to the byte offset of the entry within the directory,
in case the caller wishes to edit it.
If
dirlookup
finds an entry with the right name,
it updates
*poff
and returns an unlocked inode
obtained via
iget
.
dirlookup
is the reason that
iget
returns unlocked inodes.
The caller has locked
dp
,
so if the lookup was for
.
,
an alias for the current directory,
attempting to lock the inode before
returning would try to re-lock
dp
and deadlock.
(There are more complicated deadlock scenarios involving
multiple processes and
..
,
an alias for the parent directory;
.
is not the only problem.)
The caller can unlock
dp
and then lock
ip
,
ensuring that it only holds one lock at a time.
The function
dirlink
(kernel/fs.c:580)
writes a new directory entry with the given name and inode number into the
directory
dp
.
If the name already exists,
dirlink
returns an error
(kernel/fs.c:586-590).
The main loop reads directory entries looking for an unallocated entry.
When it finds one, it stops the loop early
(kernel/fs.c:592-597),
with
off
set to the offset of the available entry.
Otherwise, the loop ends with
off
set to
dp->size
.
Either way,
dirlink
then adds a new entry to the directory
by writing at offset
off
(kernel/fs.c:602-603).