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).