This week we moved on to the next major part of OSTEP: persistence. The lectures covered OSTEP 36, 37, 39, and 40, from I/O devices up to a working file system.
OSTEP 36: I/O Devices
I/O devices are what make computers useful. Keyboards, mice, screens, network adapters, and hard drives are all examples of I/O devices.
There are two main types of I/O devices: block devices and character devices. A block device, like a hard drive, stores data in fixed-size chunks (blocks) with addresses, allowing random access. Character devices, like keyboards, stream data one byte at a time and are not addressable. The type of device determines how the OS and software interact with it.
The CPU talks to devices through a hardware interface, usually a set of registers. There is a status register to check if the device is busy, a command register to tell it what to do, and a data register to exchange information. The main question the lecture raised is: how does the OS use these registers without freezing while waiting?
Three strategies emerged: polling, interrupts, and DMA. Polling means the CPU keeps checking the status register in a loop until the device finishes. It is simple but wasteful because the CPU just spins. Interrupts let the OS issue a request and then do other work; when the device finishes, it signals the CPU to process the result. DMA (Direct Memory Access) lets the device move data into or out of memory without involving the CPU, which is much more efficient for large transfers.
The practical takeaway is that these mechanisms trade off simplicity for efficiency: polling is easiest to reason about, while interrupts and DMA better preserve CPU time for useful work.
OSTEP 37: Hard Drives
Hard drives have a long history in computing and will likely be around for a long time, even as SSDs continue to replace them. This lecture explained the physical mechanisms that make hard drives work.
A hard drive has one or more platters (spinning metal disks), and each platter has two surfaces. Moving arms with heads read or write data as the platter spins. Accessing data on a hard drive requires three steps: seek time (moving the arm to the right track), rotational delay (waiting for the desired sector to spin under the head), and transfer time (actually reading or writing the data).
There are two ways to address a disk block: CHS and LBA. CHS is an older format, which specifies the cylinder (track), head (surface), and sector. Modern drives use Logical Block Addressing (LBA), which is just a single number for each block. The analogy from lecture is that CHS is like a home address (with a number, street, and city), whereas LBA is like if every house had its own serial number.
Because seek time and rotational delay dominate the cost of a disk access, the order in which the OS services requests matters a lot. This is where disk scheduling comes in; a few scheduling algorithms were mentioned in the lecture and OSTEP.
- SSTF (Shortest Seek Time First): always pick the pending request closest to the current head position. Fast on average, but can starve requests that are far away.
- SCAN / C-SCAN (the elevator algorithm): sweep the head across the disk in one direction servicing requests along the way, then reverse. Fairer than SSTF and avoids starvation.
- SPTF (Shortest Positioning Time First): factors in both seek and rotation. Closer to optimal but requires the OS to know detailed disk geometry, so scheduling has largely moved into the drive itself.
The key idea is that the OS works with the hard drive to find the best algorithm, and modern drives increasingly use their own internal scheduling to approach the optimal result.
OSTEP 39: Files and Directories
This lecture introduced files and directories as the key abstractions for organizing data in a file system.
A file is simply a linear array of bytes that is associated with some low-level ID, like an inode number. The inode stores metadata about the file like permissions, size, and timestamps.
A directory is a special kind of file that contains a structured list of (name, inode) pairs. Listing a directory just reads the directory file and looks up the associated inodes.
A hard link is just another name that points to the same inode. This makes it so that a single file can appear to be multiple files. Removing one name does not delete the data as long as another name still points to the inode.
A symbolic link (symlink) points to a path rather than an inode. That difference matters: symlinks can cross file system boundaries, can point to directories, and can dangle (point to something that no longer exists). Hard links can do none of those things because they are tightly bound to the inode they reference on the same file system.
A partition is a raw slice of a physical disk, while a volume is a logical unit where a file system has been created. A logical volume can consist of a single partition or span multiple disks.
A mount attaches a file system into the operating system’s main directory tree, so its contents appear under some existing path.
OSTEP 40: File System Implementation
This chapter was split into two lectures covering the two main parts of a file system: the data structures used to store files, and the access methods used to interact with stored data.
Data structures
We walked through an example file system with 64 blocks to make the idea concrete. The superblock is the first block in the file system and holds some critical information: where inodes are stored, where data blocks start, how many inodes exist, and so on. The file system looks at the superblock first to understand its own layout.
A bitmap tracks which blocks are free and which are in use — one bit per block. To allocate a new block, the file system scans the bitmap, finds a free block, marks it as used, and gives it to the file. A similar bitmap tracks free inodes.
One way to understand a file system is that it is just a data structure laid out on disk. The same kinds of pointers and structures you might see in a memory-based data structure are written to disk blocks and linked together by block numbers instead of memory addresses. The OS reads the superblock to orient itself, then uses inode numbers and block pointers to navigate.
Access methods
The second half of the chapter walked through what actually happens on common syscalls. Three operations made the cost model clear:
- open(“/foo/bar”) is surprisingly expensive. The OS has to traverse the path one component at a time: read the root inode, read the root directory’s data block, find “foo”, read the foo inode, read its data block, find “bar”, read the bar inode. Every component potentially costs an inode read and a data block read.
- read() is cheaper on an already-open file. The OS already has the inode in memory, so it consults the inode’s block pointers, reads the right data block, and updates the file’s offset.
- write() can be the most expensive. If the write extends the file, the OS must consult the data bitmap to find a free block, update the bitmap, update the inode (new size, new block pointer), and then write the actual data: multiple I/Os for a single logical write.
What was most interesting is that every step in path traversal follows the same pattern: get an inode, read its data block, search for the next entry. There is no special logic for subdirectories because directories are just files. That made the whole traversal algorithm feel intuitive.
Reflection
This is the last section of the course, but there is still more to OSTEP that I may revisit to round out the picture. What changed for me is less the volume of facts and more how I think about software and its relationship to hardware.
Before this course, things like “the file system” or “memory” were opaque boxes, but now I’m able to think of them as data structures with access methods. A path lookup is not magic; it is a sequence of inode and block reads. A context switch is not magic; it is a saved set of registers and a scheduling decision.
The core problems that operating systems solve, like virtualization (abstraction), concurrency, and persistence, show up in many technical contexts. Knowing how things work at the OS level will help me to build a better intuitive understanding of these recurring problems, which should serve me well as I continue to develop my technical skillset.