Test yourself · category 18 of 20
Inodes, directories and path lookup The inode table, ref versus nlink, iget/ilock/iput, directories as arrays of dirents, namex’s one-lock-at-a-time walk, and create, link and unlink.
All Not yet answered Got wrong Reset this category
A struct inode in memory has both ref and nlink. What does each one count?
kernel/file.h
16 // in-memory copy of an inode
20 int ref ; // Reference count
22 int valid ; // inode has been read from disk?
24 short type ; // copy of disk inode
Check Try again
How many on-disk inodes (dinode ) fit in one disk block in this file system
(the value of IPB)?
kernel/fs.h
31 // On-disk inode structure
34 short major ; // Major device number (T_DEVICE only)
35 short minor ; // Minor device number (T_DEVICE only)
36 short nlink ; // Number of links to inode in file system
44 // Block containing inode i
Check Try again
What does the content of a directory (its data blocks) consist of in this file
system?
kernel/fs.h
53 // Directory is a file containing a sequence of dirent structures.
56 // The name field may have DIRSIZ characters and not end in a NUL
Check Try again
4 warm-up True or false, and why True or false: when rm removes the only name of a file that another process still
has open, the file’s data blocks are freed immediately.
Check Try again
iget returns an inode table entry with valid = 0 and does not read the inode
from disk; ilock does that later. Why not read it in iget?
kernel/fs.c
245 // Find the inode with number inum on device dev
246 // and return the in-memory copy. Does not lock
247 // the inode and does not read it from disk.
255 // Is the inode already in the table?
267 // Recycle an inode entry.
Check Try again
Match each function with its job.
igetchoose… scan the on-disk inodes for one with type 0 and mark it allocated take the inode’s sleep-lock and load the dinode from disk if the entry is not valid copy the in-memory inode’s fields into its disk block and log_write that block drop a reference, and truncate and free the inode if it was the last reference and nlink is 0 find or claim an inode-table entry for (dev, inum) and take a reference, without reading the disk ilockchoose… scan the on-disk inodes for one with type 0 and mark it allocated take the inode’s sleep-lock and load the dinode from disk if the entry is not valid copy the in-memory inode’s fields into its disk block and log_write that block drop a reference, and truncate and free the inode if it was the last reference and nlink is 0 find or claim an inode-table entry for (dev, inum) and take a reference, without reading the disk iupdatechoose… scan the on-disk inodes for one with type 0 and mark it allocated take the inode’s sleep-lock and load the dinode from disk if the entry is not valid copy the in-memory inode’s fields into its disk block and log_write that block drop a reference, and truncate and free the inode if it was the last reference and nlink is 0 find or claim an inode-table entry for (dev, inum) and take a reference, without reading the disk iputchoose… scan the on-disk inodes for one with type 0 and mark it allocated take the inode’s sleep-lock and load the dinode from disk if the entry is not valid copy the in-memory inode’s fields into its disk block and log_write that block drop a reference, and truncate and free the inode if it was the last reference and nlink is 0 find or claim an inode-table entry for (dev, inum) and take a reference, without reading the disk iallocchoose… scan the on-disk inodes for one with type 0 and mark it allocated take the inode’s sleep-lock and load the dinode from disk if the entry is not valid copy the in-memory inode’s fields into its disk block and log_write that block drop a reference, and truncate and free the inode if it was the last reference and nlink is 0 find or claim an inode-table entry for (dev, inum) and take a reference, without reading the disk Check Try again
In namex , click the line that gives up the current directory (its lock and its
reference) after finding the next element, before the loop locks that element.
kernel/fs.c
712 // Stop one level early.
Your pick: none yet (click a line in the code)
Check Try again
What is the largest number of data blocks one file can have in this file system
(MAXFILE )?
Check Try again
In this image the superblock says inodestart = 33. Which disk block holds inode 24?
kernel/fs.h
44 // Block containing inode i
Check Try again
Why does namex unlock the current directory before it locks the next path
element, instead of locking the child first and then letting go of the parent?
kernel/fs.c
712 // Stop one level early.
Check Try again
open("newfile", O_CREATE|O_WRONLY) calls create for a name that does not exist
yet. Put the steps of create in order.
kernel/sysfile.c
274 // a new directory's ".." would push dp->nlink past its maximum
301 // No ip->nlink++ for ".": avoid cyclic ref count.
310 // now that success is guaranteed:
iunlockput(dp) and return the new inode, still locked↑ ↓ ialloc claims a free dinode and gives it type T_FILE↑ ↓ dirlink writes the entry (name, inum) into the parent↑ ↓ dirlookup finds no entry with that name↑ ↓ nameiparent returns the parent directory, referenced but unlocked, and the last name↑ ↓ ilock(dp), then check that dp->nlink is not 0↑ ↓ ilock(ip), set nlink = 1, iupdate↑ ↓ Check Try again
12 solid Choose all that apply Which of these code paths hold two inode sleep-locks at the same time?
Check Try again
Starting from nothing, a user runs mkdir /d, mkdir /d/x, mkdir /d/y and
echo hi > /d/f. What is the nlink of directory d afterwards?
Check Try again
sys_unlink refuses the names . and .. (line 221) before it calls
dirlookup and ilock(ip). Apart from keeping the tree intact, what would go
wrong with the locks if unlink("d/.") were allowed through?
kernel/sysfile.c
220 // Cannot unlink "." or "..".
Check Try again
A program creates abcdefghijklmnop (16 characters) and then calls
open("abcdefghijklmnXY", O_RDONLY) in the same directory. What happens?
Check Try again
iput is dropping the last reference to an inode whose nlink is 0. Put its steps
in order.
kernel/fs.c
354 // Last reference of an unlinked inode? Capture dev/inum before ref--,
355 // since once ref hits 0, ip may be recycled by a concurrent iget()
356 // for a different inum.
361 // ip->ref == 1 means no other process can have ip locked.
365 itrunc ( ip ); // free the data blocks (type stays nonzero on disk)
acquire itable.lock; compute last and copy dev and inum into locals ↑ ↓ itrunc : free the data blocks, set size 0, iupdate↑ ↓ acquiresleep(&ip->lock) while still holding itable.lock↑ ↓ ifree(dev, inum): write type 0 on disk↑ ↓ release itable.lock ↑ ↓ re-acquire itable.lock, ref-- (to 0), release it ↑ ↓ valid = 0, then release the sleep-lock↑ ↓ Check Try again
fileclose wraps the iput of an inode in begin_op and end_op , even though
closing a file usually writes nothing. Why?
kernel/file.c
58 // Close file f. (Decrement ref count, close when reaches 0.)
Check Try again
gdb shows the first 12 bytes of inode 24’s dinode (little-endian: type, major,
minor, nlink as 2-byte shorts, then size as a 4-byte uint):
01 00 00 00 00 00 03 00 40 00 00 00. Decode it.
Value: 0100 0000 0000 0300 40000000
typechoose… T_DIR (1) T_FILE (2) T_DEVICE (3) free (0) nlinkchoose… 3 0 768 1 How many subdirectories does it have? choose… 2 3 1 cannot be zero for a directory How many 16-byte entries does its content hold (size / 16)? choose… 4 64 3 2 If its ref dropped to 0 now, would iput free it? choose… no yes
Check Try again
19 deep Choose all that apply rm /x removes a regular file /x that has 3 data blocks, nlink 1, and is not open
anywhere. Which blocks does this one transaction log (pass to log_write )?
Check Try again
In iput , click the line after which ialloc on another hart may hand this
inode’s number to a brand-new file.
kernel/fs.c
354 // Last reference of an unlinked inode? Capture dev/inum before ref--,
355 // since once ref hits 0, ip may be recycled by a concurrent iget()
356 // for a different inum.
361 // ip->ref == 1 means no other process can have ip locked.
365 itrunc ( ip ); // free the data blocks (type stays nonzero on disk)
Your pick: none yet (click a line in the code)
Check Try again
21 deep Fill in the machine state cat calls close(3) on a file that rm already unlinked. Inside fileclose →
iput , line 362’s acquiresleep has just returned and line 363 has not run yet.
What is the state of the hart running cat?
kernel/fs.c
354 // Last reference of an unlinked inode? Capture dev/inum before ref--,
355 // since once ref hits 0, ip may be recycled by a concurrent iget()
356 // for a different inum.
361 // ip->ref == 1 means no other process can have ip locked.
365 itrunc ( ip ); // free the data blocks (type stays nonzero on disk)
Privilege mode choose… M (machine) S (supervisor) U (user) Active stack choose… user stack the process's kernel stack scheduler stack (stack0) boot stack (stack0) no usable stack Page table (satp) choose… paging off kernel page table user page table Interrupts (sstatus.SIE) choose… on off noff choose… 0 1 2 3 4 intena choose… 0 1 — (noff is 0)
Check Try again
iput copies ip->dev and ip->inum into the locals dev and inum (line 358),
and line 377 calls ifree(dev, inum) rather than ifree(ip->dev, ip->inum). Why?
kernel/fs.c
354 // Last reference of an unlinked inode? Capture dev/inum before ref--,
355 // since once ref hits 0, ip may be recycled by a concurrent iget()
356 // for a different inum.
361 // ip->ref == 1 means no other process can have ip locked.
365 itrunc ( ip ); // free the data blocks (type stays nonzero on disk)
Check Try again
On a fresh disk a user runs mkdir /a, mkdir /a/b, cd /a/b, /rm /a/b, /rm /a,
and then /ls ... What happens in this kernel, and which check is responsible?
kernel/fs.c
712 // Stop one level early.
Check Try again
24 deep Choose all that apply Two processes on two harts call open("same", O_CREATE|O_WRONLY) in / at nearly the
same moment; same does not exist yet. Which statements are true afterwards?
kernel/sysfile.c
274 // a new directory's ".." would push dp->nlink past its maximum
Check Try again
sys_link increments the file’s nlink, then unlocks the file (line 153)
before calling nameiparent and locking the target directory. Why not keep the
file locked until the new entry is written?
kernel/sysfile.c
122 // Create the path new as a link to the same inode as old.
158 // dp may have been unlinked while we resolved it; linking into an
159 // orphaned directory leaks ip (itrunc discards the record without
160 // dropping ip->nlink). create() has the same guard.
Check Try again
← Logging and crash recovery All categories Files, pipes, the console and the UART →