File Systems

Learn how an operating system stores files so they survive power loss and crashes. Use the file and directory system calls, from open and read to fsync, rename, links and permissions. See how a simple file system lays out inodes, bitmaps and data blocks, how the Fast File System keeps related data close together, and how fsck and journaling keep the disk consistent after a crash. Finish with log-structured file systems and with how NFS and AFS share files across a network.

IntermediateLesson 8 of 9 in Operating Systems Course

What you will learn

  1. Use the system calls a program relies on to create, read, write, name, protect and organize files, and predict what each call does to offsets, names and data on disk.
    • Read and write files through file descriptors
      Open files, read and write them through file descriptors, move the file offset, and explain how processes share open files.
    • Make writes durable and updates atomic
      Force data to stable storage when it must survive a crash, and replace a file's contents so that readers see either the old or the new version.
    • Organize names with directories and links
      Create, list and remove directories, and explain how hard links, symbolic links and deleting a file affect names and inodes.
    • Read metadata, control access and mount file systems
      Read a file's metadata with stat, set and interpret permission bits, and explain how separate file systems are joined into one directory tree.
  2. Describe the on-disk structures of a simple Unix-style file system, compute where an inode and a file's blocks live, and trace the disk reads and writes behind opening, reading and writing a file.
    • Lay out a disk in blocks, bitmaps, inodes and directories
      Divide a disk into the superblock, allocation bitmaps, inode table and data region, locate an inode by its number, and describe how directories and free space are stored.
    • Locate a file's data with pointers, indirect blocks and extents
      Explain how an inode's direct pointers, indirect blocks and extents map a file's offsets to disk blocks, and compute the largest file a pointer layout supports.
    • Trace the disk I/O of file operations and the effect of caching
      Count the block reads and writes behind opening, reading, creating and writing a file, and explain how caching and write buffering change that traffic.
  3. Diagnose why early Unix file systems were slow on hard disks, and explain how the Fast File System's groups, placement rules and large-file policy keep related data close together.
    • Explain why early Unix file systems were slow and how groups fix it
      Identify the layout problems that wasted disk bandwidth in the original Unix file system, and describe how cylinder groups and block groups organize the disk.
    • Apply FFS placement rules and size large-file chunks
      Use FFS's placement heuristics for directories and files, apply the large-file exception, compute how large a chunk must be to amortize positioning, and describe FFS's other improvements.
  4. Explain why a crash in the middle of an update can corrupt a file system, and compare repairing it afterwards with fsck, preventing damage with journaling, and other approaches.
    • Explain the crash-consistency problem
      Show why one file operation needs several block writes, list what a crash between them can leave on disk, and classify each outcome.
    • Check and repair a file system with fsck
      Describe what the file system checker examines and repairs after a crash, and explain why scanning the whole disk scales poorly and cannot catch every problem.
    • Protect updates with data journaling and replay the log
      Write an update to a journal before changing the file system in place, explain why the commit block is written last, and recover after a crash by replaying committed transactions.
    • Reduce journaling cost and compare other approaches
      Explain how metadata journaling avoids writing data twice, why ordered journaling writes data before the commit, how revoke records prevent a block-reuse bug, and how other designs keep file systems consistent.
  5. Explain why writing everything sequentially to a log speeds up writes, how the inode map and checkpoint region let the file system find data in that log, and how cleaning and crash recovery work.
    • Write sequentially in segments and find inodes through the inode map
      Explain the motivation for a log-structured file system, size a segment to reach a target bandwidth, and trace how the inode map and checkpoint region locate a file.
    • Reclaim space with the cleaner and recover after a crash
      Explain how LFS finds and compacts live blocks, chooses which segments to clean, recovers after a crash, and how its ideas live on in copy-on-write and flash file systems.
  6. Explain how NFS and AFS let many client machines use files stored on servers, how they handle crashes, and how their caching choices decide when one client sees another's changes.
    • Explain how NFS recovers from failures with stateless requests
      Describe the client/server structure of NFS, how file handles and idempotent requests let a client recover from server crashes by retrying, and why the server must commit writes before replying.
    • Compare NFS and AFS caching and consistency
      Explain how NFS and AFS cache file data on clients, when each makes one client's changes visible to others, and which workloads favor each design.

File Systems study guide

6 chapters

1

Use the file and directory interface

File operations expose several different kinds of state: bytes, names, open positions and permissions. Follow a descriptor through reads and shared offsets, then distinguish a completed call from a durable save. Directories and links explain why deleting a name need not delete the object. Metadata and mounting complete the picture of how a program reaches and uses a file through one directory tree.

1.1 Read and write files through file descriptors

A file is a persistent sequence of bytes. The file system stores those bytes without deciding whether they mean text, an image or machine code. A directory gives the file a readable name; its inode number identifies it within the file system.

Open a file and check the result

open(path, flags, mode) returns a file descriptor, a nonnegative integer used in later calls. An error returns -1 and sets errno. Choose O_RDONLY, O_WRONLY or O_RDWR for access. O_CREAT creates a missing file, O_TRUNC empties an existing file, and O_APPEND places each write at the current end.

For a new file, mode requests permissions and the process's umask removes bits. Without a default directory access control list (ACL), the result is mode & ~umask. Requesting 0666 with umask 0022 gives 0644, or rw-r--r--. This argument does not change the permissions of an already existing file.

Descriptors belong to a process. Normally 0, 1 and 2 are standard input, output and error. open chooses the lowest unused descriptor, often 3. On Linux, strace cat notes.txt exposes the calls: opening the input, reading it, writing to descriptor 1, then closing the input.

Follow the offset, not the requested count

read(fd, buf, n) returns the bytes actually read, up to n. For a nonzero request on a regular file, zero means no bytes remain at or beyond end of file; -1 means an error. write also returns an actual count, which can be short. Check that count before advancing a buffer or deciding the operation is complete.

Suppose log.txt contains 300 bytes. Four requests for 100 bytes return 100, 100, 100 and 0. The offset, the position of the next operation, becomes 100, 200, 300 and 300. End of file is a returned count, not a special byte stored in the file.

lseek(fd, 200, SEEK_SET) sets the offset to 200. Reading 50 bytes then returns bytes 200–249 and leaves offset 250. SEEK_CUR measures from the current offset; SEEK_END measures from the file's end. Seeking changes a number in memory. It does not move a disk head or itself read data. pread and pwrite use an explicit position without changing this offset.

Decide which descriptors share an offset

The process's descriptor table points to entries in the kernel's open file table. Each open entry holds the access mode, offset, inode reference and reference count.

How descriptors ariseOffset behavior
Two separate open callsIndependent offsets, even for the same inode
dup or dup2One shared open entry and offset
Descriptors inherited through forkParent and child share the open entry and offset

If a child seeks a shared descriptor to byte 10, the parent's next read through that entry starts at 10 too. The inode identifies the file, but the open entry holds the offset: two readers can share a file without sharing their position. Shell redirection uses dup2 to make standard output refer to another open entry. close releases one descriptor; the entry disappears after its last reference is released. Closing alone does not force buffered data to stable storage.

Key Takeaways

  • Check the returned byte count from every read and write.
  • An offset belongs to an open file table entry, not to the inode.
  • Separate opens have separate offsets; duplicates and inherited descriptors share one.
  • lseek changes the offset without performing disk I/O.
  • close releases a descriptor; it does not guarantee durability.

1.2 Make writes durable and updates atomic

A successful write and a crash-safe update answer different questions. A write reports that bytes were accepted. Durability asks whether they survive a crash; atomicity asks whether an update can be observed only as a whole.

Force the bytes to stable storage

Operating systems usually buffer writes in memory and send dirty blocks to storage later, often within roughly 5–30 seconds. This combines small writes and lets the program continue quickly. A crash can erase data still waiting in those buffers.

fsync(fd) forces the file's dirty data and metadata to storage and waits for the device to report completion. A program must check its result before reporting a durable save. close releases the descriptor and is not a substitute for this wait.

A file also needs a durable name. The name-to-inode entry is data belonging to its directory, not to the file. After creating a file, synchronizing only the file can leave its bytes durable without guaranteeing that its new name survives. Open the containing directory and synchronize it when the name must persist.

Replace a file without exposing a partial version

Overwriting a document in place creates an interval in which readers can encounter incomplete contents. O_TRUNC first sets its length to zero. If a crash interrupts the later writes, the old complete copy is already gone.

Instead, write the replacement under a temporary name in the same directory. Then use rename to replace the destination. For an existing destination on the same file system, POSIX makes that replacement atomic: the destination name refers to the old file or the replacement, without an intermediate missing name. Readers do not see a mixture of their contents through that name.

For settings.json, the durable replacement sequence is:

  1. Write all new contents to settings.json.tmp, checking for short writes and errors.
  2. Call fsync on the temporary file and check success.
  3. Call rename("settings.json.tmp", "settings.json") and check success.
  4. Call fsync on the containing directory and check success.

The temporary file is complete and durable before the name changes. The final directory synchronization makes that name change durable. A crash during the sequence leaves the destination holding a complete old or complete new version; after the final successful synchronization, the new version is the durable one. Atomic name replacement alone does not promise that an unsynchronized rename survives power loss.

rename across file systems fails with EXDEV. A command that responds by copying and deleting performs several operations, so that fallback has no atomic-replacement guarantee.

Change length without writing every byte

truncate(path, length) and ftruncate(fd, length) set the file's length. Shrinking discards bytes beyond the new end. Extending makes the new region read as zeros. Seeking beyond the end and then writing also creates a zero-reading gap.

A sparse file can represent such a gap without allocating data blocks for it. Starting with an empty file, writing one byte at offset 8192 makes a file 8193 bytes long; the preceding unwritten region reads as zeros. Its logical size can exceed the space physically allocated to it.

Key Takeaways

  • fsync makes file data and metadata durable after successful completion.
  • Synchronize the directory to make a new or replaced name durable.
  • Write, synchronize, rename, then synchronize the directory for a durable replacement.
  • A sparse gap reads as zeros and can occupy no data blocks.

Directories separate the names people use from the objects the file system stores. Each directory has its own inode and data blocks; its entries map names to inode numbers.

Follow paths through the tree

An absolute path starts at /. A relative path starts at the process's current working directory. The entry . names the directory itself and .. names its parent; the root's parent is the root. From /home/lee, the relative path ../shared reaches /home/shared.

An extension such as .txt is part of a name. Programs can use it to choose how to interpret the bytes, but the file system does not require a .txt file to contain text.

mkdir creates a directory containing . and ... To list entries, a program uses opendir, calls readdir until no entries remain, and calls closedir. A readdir result includes a name and inode number. Programs change directory contents through calls such as link, unlink and rename, not ordinary write calls. rmdir removes an empty directory.

Give one file two equal names

link(old, new) creates a hard link: another directory entry pointing to the same inode. Neither name is privileged as the original. The inode's link count records how many names refer to it.

Consider these commands when no process holds the file open:

echo hi > a
ln a b
rm a
cat b
rm b

Creating b raises the link count from 1 to 2. Removing a lowers it to 1; b still reaches the same bytes, so cat b prints "hi". Removing b drops the count to 0, allowing the inode and its blocks to be reclaimed.

An open descriptor adds a second lifetime rule. If the final name is unlinked while a process still has the file open, that process can keep accessing it. Reclamation waits for both zero links and no open references. This explains why deleting a large open log may not immediately release its space.

A hard link cannot cross file systems: the destination's inode number would have no meaning in the other inode table. Most Unix systems also prohibit hard links to directories to preserve a tree without cycles. In classic Unix directory accounting, an empty directory has two links, from its parent entry and its own .. Each subdirectory contributes one more through ..; three subdirectories give a count of 5.

Store a path in a symbolic link

A symbolic link, or soft link, is a separate file whose contents are a target path. ln -s /home/ana/report.txt r creates r with the 20-byte target path as its contents. Following it resolves that path. Symbolic links can cross file systems and point to directories.

Link kindWhat the directory entry reachesEffect of removing the target name
Hard linkThe shared inodeAnother hard link still reaches the file
Symbolic linkA separate link object containing a pathThe link dangles if its stored path no longer resolves

A symbolic link does not increase its target's link count. Keeping the link object therefore does not keep the target alive.

Key Takeaways

  • Directories map names to inode numbers; paths select a sequence of those names.
  • Hard links are equal names for one inode.
  • Unlinking removes a name; reclamation also waits for open references to end.
  • Symbolic links store paths and can dangle.
  • Hard links stay within one file system.

1.4 Read metadata, control access and mount file systems

A file's contents are only part of its state. Metadata records who may use it, its size and type, and when it changed. Mounting makes objects from several file systems reachable through a single tree of names.

Read the metadata correctly

stat(path, &buf) reads metadata through a path; fstat(fd, &buf) reads it through an open descriptor. The results include the inode number, type, permissions, owner and group IDs, size, allocated blocks and link count. File size counts logical bytes; allocated blocks measure storage actually used, which can be smaller for a sparse file.

Three timestamps describe different events:

FieldMeaningExample event
atimeLast accessReading contents
mtimeLast content modificationWriting bytes
ctimeLast inode status changeWriting, changing permissions or adding a hard link

ctime is not creation time. Updating atime alone does not change ctime. Classic Unix stat has no creation-time field; Linux statx can expose a recorded birth time when the file system supports it.

Decode permission bits

Read, write and execute rights are recorded separately for owner, group and others. Each class is an octal digit: read is 4, write 2 and execute 1. For rw-r-----, the owner gets 4 + 2 = 6, the group gets 4, and others get 0. chmod 640 report.txt sets those bits.

Directory permissions apply to names and traversal. Read allows listing names. Execute allows search, meaning use of the directory in a path. Write together with execute allows creating, deleting and renaming entries. Knowing a name can be enough to open a file in a directory with execute but no read permission, provided the file's own permissions allow access. Listing that directory still fails.

This difference matters for deletion: removing an entry changes its containing directory. A file's write bit controls changing its bytes; it is not the directory's permission to remove its name. Root bypasses most ordinary permission checks. Access control lists (ACLs) can grant rights to named users and groups beyond the three basic classes.

Attach another file system

mkfs initializes a file system on a partition or other device, including its own root directory and metadata. It destroys the device's previous file-system contents, so run it only on a device intended for initialization.

mount attaches that root at an existing directory called the mount point. A drive mounted at /media/usb makes its root contents accessible there. The previous contents of /media/usb are hidden while the mount is active; mounting does not merge them with the mounted tree. Running mount without arguments lists current mounts.

The kernel's virtual file system (VFS) layer gives ext4, XFS, FAT, memory-based and network file systems a common interface. Programs can call open and read through any of them. The combined namespace does not combine their inode tables: equal inode numbers on different file systems can identify unrelated files. Hard links and atomic renames therefore stay within their own file system.

Key Takeaways

  • stat and fstat describe metadata; ctime records status changes.
  • Permission digits add read = 4, write = 2 and execute = 1 for each user class.
  • Directory execute permission allows path traversal; read permission allows listing.
  • Mounting attaches a file system root and hides the previous mount-point contents.
  • The VFS shares an interface across file system types, not one global inode table.
  • Logical file size and allocated space can differ.
2

Explain how a simple file system stores and finds data

A readable path hides a sequence of lookups, allocations and block accesses. Build a small disk layout, calculate an inode address, and map byte offsets through direct pointers, indirect blocks or extents. Then trace the I/O behind common calls. Keeping cache contents explicit lets you explain why the same program can cause many device operations on one run and very few on the next.

2.1 Lay out a disk in blocks, bitmaps, inodes and directories

A file system must remember both where bytes live and which space is available. A simple Unix-style layout makes these jobs visible by separating allocation records, inodes and contents.

Divide the partition into regions

A block is the file system's basic allocation unit. A 4 KiB block contains 4096 bytes, or eight traditional 512-byte sectors. Binary sizes use KiB, MiB and GiB; transfer rates such as MB/s use decimal millions of bytes per second.

The teaching design vsfs, the very simple file system, contains these structures:

StructureInformation stored
SuperblockFile system size, region locations, inode count and identifying magic number
Inode bitmapOne allocation bit per inode
Data bitmapOne allocation bit per data block
Inode tableMetadata and data pointers for every inode slot
Data regionContents of regular files and directories

A bitmap bit of 1 means allocated; 0 means free. The superblock tells the operating system how to interpret the rest of the partition when mounting it. The two bitmaps describe different resources: a file can have an allocated inode before it has any data blocks.

Locate an inode by number

Take a 64-block partition with 4 KiB blocks. Put the superblock at block 0, the inode bitmap at 1, the data bitmap at 2, and the inode table in blocks 3–7. Data occupies blocks 8–63. Five inode-table blocks with 256-byte inodes hold 80 inodes, because each block holds 16. There are 56 data blocks. One 4 KiB bitmap can describe 32768 objects, so much of each bitmap is unused in this tiny layout.

Numbering inode slots from zero, inode 37 starts 37 × 256 = 9472 bytes after the table begins. The table starts at byte 12288, giving absolute byte address 21760. Dividing by 4096 gives disk block 5 with remainder 1280. Dividing by 512 instead gives sector 42 with remainder 256. Read the containing block or sector, then select the inode's bytes within it.

The general method is: table start in bytes plus inode number times inode size. Keep the table's starting address separate from the inode's offset within the table. Omitting that base address locates the wrong disk block.

Separate names, metadata and contents

An inode, or index node, records type, permissions, ownership, size, times, link count, allocated blocks and data locations. It does not contain the filename. The name belongs in a directory entry, allowing several names to share one inode.

A directory has an inode of type directory and data blocks of entries. A simple entry stores an inode number, record length, name length and name. Record length lets traversal skip the whole entry, including reusable space left by deletion. Large directories benefit from indexes: XFS uses B-trees and ext4 uses hashed tree indexes.

Creating a file finds a free inode bitmap bit and sets it. Allocating data similarly changes the data bitmap. An allocator may reserve a run of blocks so the file can grow contiguously. The bitmap says whether a block is free; the inode says which file owns it. These structures must agree.

Key Takeaways

  • The superblock describes the layout; bitmaps track allocation.
  • An inode contains metadata and data locations, while directories contain names.
  • Compute an inode address from the table base, inode number and inode size.
  • Inode allocation and data allocation use separate bitmaps.

2.2 Locate a file's data with pointers, indirect blocks and extents

A program sees consecutive byte offsets, but the corresponding data blocks can be scattered across the disk. The file system needs a mapping from each logical file block to its physical location.

Follow direct and indirect pointers

A direct pointer in an inode names one data block. With 4 KiB blocks, byte offset 10000 lies in logical block 2, because two full blocks use 8192 bytes. The offset within that block is 1808. Logical blocks start at 0, so block 2 uses the third direct pointer.

An indirect pointer names a block containing data-block addresses. A 4096-byte block with 4-byte addresses holds 1024 pointers. A double indirect pointer names a block whose pointers lead to 1024 indirect blocks. Triple indirection adds another level. This multi-level index is deliberately unbalanced: small files use direct pointers without extra pointer-block reads, while large files pay for additional levels.

For an inode with 12 direct pointers and one pointer of each indirect level:

Highest level usedData capacity with 4 KiB blocks
Direct only12 blocks = 48 KiB
Single indirect12 + 1024 blocks = 4144 KiB
Double indirect12 + 1024 + 1024² blocks = 4299210752 bytes
Triple indirectAdds 1024³ blocks = another 4 TiB

These are capacities of this pointer layout. Pointer blocks occupy storage too, but their bytes are not file contents.

Count pointer blocks for a file

A 5 MiB file occupies 1280 data blocks at 4 KiB each. Assign the first 12 to direct pointers. Assign the next 1024 to the single indirect block. That leaves 244 data blocks.

Those 244 need a double indirect root and one indirect block beneath it. In total, the file needs three pointer blocks: the single indirect block, the double indirect root and its one child. Counting only the double indirect root misses the child that actually contains data addresses. Counting all 1024 possible children wastes space: only the required child is allocated.

Compare extents and chains

An extent records a starting disk block and a run length. A contiguous run of 1000 blocks can use one extent instead of 1000 separate pointers. Ext4, XFS and NTFS use extents. Ext4 can hold up to four extents in its inode, with a tree for more. Fragmentation splits runs and increases the number of extent records needed.

Linked allocation follows a chain of blocks. The File Allocation Table (FAT) stores the next-block links in a separate table, usually cached in memory. A directory entry identifies the first block, and reaching a late block requires following the earlier links. FAT does not use Unix inodes and does not support two hard links to one file.

MappingMain strengthMain cost
Direct and indirect pointersDirect access to small files; scalable indexingExtra pointer blocks for large files
ExtentsCompact descriptions of contiguous runsMany records when fragmented
FAT chainsSimple linked allocation with cached linksChain traversal for access near the end

Consecutive offsets never prove physical contiguity. The allocator chooses locations, and the mapping records those choices.

Key Takeaways

  • Divide a byte offset by block size to find its zero-based logical block.
  • An indirect block holds block addresses; each extra level multiplies reach.
  • Count allocated pointer blocks separately from data blocks.
  • Extents describe contiguous runs compactly.
  • FAT follows next-block links instead of a Unix inode index.
  • Logical adjacency does not guarantee physical adjacency.

2.3 Trace the disk I/O of file operations and the effect of caching

One system call can require several disk operations, or none. To trace the work, follow the structures the file system must consult and state which of them are already cached.

Walk a path before reading contents

In the simple uncached model, opening /docs/plan.txt reads five blocks:

  1. The root inode, whose number is known.
  2. Root directory data, to find docs.
  3. The docs inode.
  4. docs directory data, to find plan.txt.
  5. The file's inode.

Each directory fits in one block, and no needed block begins in memory. The file system checks permissions and creates an open file entry. Opening has found the file's metadata; it has not yet read its contents. Root inode number 2 is used in ext2 and ext4.

For a deliberately uncached reading model, each block read then reads the file inode, reads the data, and writes the inode's access time. Two blocks add six I/Os, giving eleven including open. Closing needs no disk I/O in this model. These counts describe the model's explicit rereading and timestamp rules; a real cache changes them.

Account for allocation during creation

Creating /docs/log.txt needs more than finding an existing inode. In the same simple model, it performs four reads for the root and docs inodes and directory data. Reading and writing the inode bitmap adds two I/Os. Updating docs data adds one write. Reading and writing the new inode adds two, and updating the docs inode adds one. Total: ten.

Each newly allocated data block adds five I/Os: read and write the data bitmap, read and write the file inode, and write the data block. Two blocks therefore give twenty I/Os including creation. This trace counts the simple data structures before adding journaling traffic or real cache behavior.

Keeping a ledger helps: list the structure, whether it is read or written, and why. A data write also needs an allocation record and a pointer update. A directory change also changes that directory's metadata.

Let the cache change the trace

A cache hit uses a block already in memory. Linux uses a unified page cache shared with virtual memory, not a permanently separate fixed-size file cache. A repeated open can reuse the directory and inode blocks from the previous traversal. Reading cached contents needs no device read. Linux's usual relatime policy also avoids an atime write on every read.

Write buffering delays sending dirty blocks to disk. Two nearby file creations may update the same inode bitmap in memory and later write it once. The file system can reorder work for better throughput. A short-lived temporary file may be created and removed before its contents ever reach storage.

Buffering improves performance but leaves a durability window. fsync closes that window for a file by waiting for its required writes. Linux O_DIRECT lets suitable programs bypass the page cache when they manage their own buffers; bypassing a cache is not itself the same operation as synchronizing durable storage.

Key Takeaways

  • Trace path traversal separately from reading file data.
  • I/O counts depend on cache contents and timestamp policy.
  • Creating a file updates allocation records, directory entries and inodes.
  • Write buffering combines updates and improves scheduling but delays durability.
  • A system call does not correspond to a fixed number of device operations.
3

Explain how the Fast File System uses locality for speed

A fast interface needs a layout that fits the storage device. Early Unix file systems wasted hard-disk bandwidth on small transfers and distant metadata. FFS groups related objects and balances that locality against the needs of large files. Its placement rules and chunk-size calculation show how a design can improve performance while programs continue to use familiar operations.

3.1 Explain why early Unix file systems were slow and how groups fix it

A hard disk can transfer a long run of bytes quickly once its head reaches them. Small scattered requests waste time seeking and waiting for rotation. The Fast File System changes placement so ordinary file operations use more of the disk's transfer bandwidth.

Diagnose the old Unix layout

The early Unix layout placed all inodes near the start and all file data after them. Reading a file could therefore require a long seek from metadata to contents. A free list gradually scattered allocations as files were created and deleted. Even a sequential file could become many unrelated disk accesses.

Small 512-byte blocks made this worse. Each positioning delay bought only a short transfer before the next request needed another seek or rotation. Historical measurements found the old design delivering as little as 2% of the disk's bandwidth. That figure describes the measured early design, not a fixed limit of Unix interfaces.

The Fast File System (FFS), developed at Berkeley in the early 1980s, kept familiar calls such as open, read and write while changing the layout and allocation policy. Larger blocks, typically 4 KiB, increased the bytes transferred per request. Keeping metadata and contents close reduced the distance between related requests.

Build groups with their own resources

A cylinder is the set of tracks at the same radius across a disk's platter surfaces. FFS forms cylinder groups from neighboring cylinders. A file can have its inode and data in the same group, keeping a metadata-to-data seek short.

Each group contains a superblock copy, its own inode and data allocation bitmaps, part of the inode table, and data blocks. The group resembles a small file system, but all groups belong to one file system. A superblock copy also helps recovery if one copy is damaged. Ext4 keeps copies in selected groups instead of every group.

Modern drives hide their physical geometry. Ext2, ext3 and ext4 therefore use block groups, runs of consecutive logical block addresses, to pursue the same locality goal without relying on exact cylinders.

Trace a small file creation

Creating /docs/a.txt needs a free inode, a data block, allocation-map changes, and a new directory entry. FFS tries to place the file in its parent directory's group. The new inode, file data, bitmaps and directory updates can then lie nearby.

The operation still needs several distinct updates. Grouping saves positioning time; it does not collapse all metadata and data into one block. A disk-aware layout improves the cost of reaching those structures without changing the program's file operations.

Storage featureConsequence for placement
Hard-disk seek and rotationNearby blocks avoid repeated long positioning delays
High sequential transfer rateLarger requests move more bytes per delay
SSD without seek or rotationDistance matters much less, but request size and write behavior still matter

Key Takeaways

  • Long seeks, fragmentation and small blocks limited early Unix disk throughput.
  • FFS groups place inodes, allocation maps and data near each other.
  • Modern block groups preserve locality without needing physical disk geometry.
  • FFS improves placement while retaining the existing file interface.

3.2 Apply FFS placement rules and size large-file chunks

FFS uses names as clues about which files a program will access together. It also limits how much space one large file can occupy in a group, balancing locality with room for future allocations.

Place directories and files

A new directory goes into a group with relatively few directories and many free inodes. This spreads different directories while leaving room for their future files. A regular file's inode goes in its parent directory's group, and its data goes near its inode.

For /a/b, /a/c and /a/d, the three files are placed near directory /a. A file /b/f follows its own parent /b, usually into another group. This exploits namespace locality: a compiler working on one project often opens several files in the same directory. The directory relation predicts access patterns; it is not a guarantee about every program.

Make an exception for a large file

One large file could consume its group's free blocks and force all later neighbors elsewhere. FFS keeps the first portion, reached by 12 direct pointers, in the inode's group. With 4 KiB blocks that is 48 KiB. Later chunks, each reached by an indirect block holding 1024 pointers, cover 4 MiB of data and go into other lightly used groups.

This sacrifices some locality within the large file to preserve locality for the directory's other files. The large file pays a positioning delay between chunks, so each chunk must be large enough to make that cost worthwhile.

Derive the chunk size

Let positioning take T seconds and transfer rate be R bytes per second. A chunk C takes C/R seconds to transfer. The fraction of total time spent transferring is:

F=C/RT+C/R.

Solving gives:

C=F1−FRT.

At 100 MB/s with 10 ms positioning, R times T is 1 MB. A 1 MB chunk needs 10 ms transfer plus 10 ms positioning, giving 50% of peak bandwidth. For 90%, multiply 1 MB by 0.9/0.1 to obtain 9 MB. For 99%, the multiplier is 99, giving 99 MB. Convert milliseconds to seconds before multiplying by MB/s. The denominator includes both transfer and positioning time; dividing only by transfer time would hide the overhead.

Transfer rates have improved faster than positioning delays, so achieving the same fraction of peak requires larger chunks as the gap widens.

Fit small files and preserve compatibility

FFS also used 512-byte sub-blocks so small files did not waste a whole 4 KiB block. Growing files were copied into full blocks; the C library buffered writes in 4 KiB pieces to reduce repeated movement. Historical parameterization left rotational gaps between consecutive blocks so a requested next block had not already passed the head. Modern track buffers make that technique unnecessary by fetching a track internally.

Long names, symbolic links and atomic rename were additional FFS capabilities. The layout speedup itself did not require changing existing programs.

Key Takeaways

  • FFS uses a directory as a clue that its files will be accessed together.
  • Directories are spread across groups; their regular files are kept nearby.
  • Large-file chunks spread out to leave space for neighboring files.
  • Include positioning and transfer time when computing effective bandwidth.
  • Sub-blocks reduce small-file space waste; track buffering replaces rotational-gap tuning.
  • FFS added capabilities as well as accelerating existing calls.
4

Keep a file system consistent across crashes

A crash can interrupt one logical file operation between several physical writes. Compare the states left by an unfinished append, then examine how a checker repairs metadata and how a journal makes recovery depend on recorded transactions. Data ordering and block reuse reveal why a valid commit needs more than a marker. Other consistency designs solve the same problem with different costs.

4.1 Explain the crash-consistency problem

One append looks like one action to a program. On disk it changes several structures, and a crash can leave only some of them updated. Crash consistency asks how those partial results can be prevented or repaired.

Track three independent writes

Appending one 4 KiB block to an existing file changes:

  • Db, the new data block containing the appended bytes.
  • I, the inode with a larger size and a pointer to that block.
  • B, the data bitmap marking the block allocated.

All three reaching storage gives the intended consistent update. None reaching storage leaves the old consistent state. The danger lies in the six partial combinations. The device can reorder requests, so issuing them in a particular order without waiting does not establish completion order.

Classify each partial outcome
Writes that surviveResult
Db onlyNew bytes exist, but no pointer reaches them; the old file system state remains consistent
I onlyInode points to old contents and the bitmap still calls the block free
B onlyAn allocated block has no owner: a space leak
I and BMetadata agrees, but the new file region contains old contents
I and DbFile points to valid new data that the bitmap still calls free
B and DbNew bytes are allocated but unreachable: lost data and leaked space

An inconsistency occurs when metadata disagrees, such as an inode claiming a block whose allocation bit is free. The allocator might then give that same block to another file. A space leak reserves storage no file can reach. Garbage data can be harder to detect: I and B agree perfectly even though Db never arrived.

Db alone does not leak allocated space, because the bitmap still permits that block to be reused. Writing bytes to a free location is not the same as allocating it. B alone does leak space, because allocation survived without an owning pointer.

Separate structure from meaning

A checker can compare pointers with bitmaps. It cannot generally tell whether plausible bytes are the bytes a program meant to save. The I-and-B outcome demonstrates this limit: a structurally valid file can have incorrect contents.

The desired transition is atomic across the update: recover to the complete old state or the complete new state. A simple storage model gives atomic writes only for one sector, traditionally 512 bytes. Several file-system blocks exceed that unit, so the file system must construct a stronger protocol. Real device atomic-write guarantees depend on the device and interface; the journal protocol must fit its commit record within the supported atomic unit.

Buffering increases the number of changes that can be lost, but it is not the root cause. Even immediately issuing each write leaves a crash boundary between separate completions. File creation, rename and deletion also change multiple structures. Understanding their failure states begins with the same exercise: identify every block changed and ask what happens when only a subset survives.

Key Takeaways

  • One logical file operation can require several independently completed block writes.
  • Compare data, inode pointers and allocation bits after each possible crash point.
  • Consistent metadata can still point to incorrect file contents.
  • Multi-block atomicity needs a file-system protocol beyond a single atomic device write.

4.2 Check and repair a file system with fsck

A file system checker repairs relationships among stored structures after damage has occurred. Its strength is a broad view of metadata; its weaknesses are the cost of scanning and its lack of knowledge about intended file contents.

Reconstruct the allocation picture

fsck, short for file system check, examines an unclean file system before normal mounting. It checks whether the superblock's size and counts make sense and can use a backup superblock if the main copy is damaged.

It then scans inodes and indirect blocks to determine which data blocks files actually reference. From that ownership information it rebuilds the allocation bitmaps. If an otherwise valid inode points to block 74 while the bitmap calls 74 free, the bitmap must change to allocated. Merely trusting the bitmap could allow a later allocation to overwrite the file's data.

The opposite mismatch is a bitmap bit marked allocated without an owning inode pointer. Reconstructing the map can reclaim that space. Repair chooses a consistent relationship; it cannot reconstruct arbitrary missing application bytes.

Check objects, names and links

Every allocated inode needs a valid type, such as regular file, directory or symbolic link. An inode that cannot be repaired is cleared and the allocation records adjusted.

Walking from the root lets fsck count directory references to each inode. It compares these observed references with recorded link counts and corrects errors. An allocated inode that no directory reaches may be moved into lost+found, giving recovered content a reachable name without knowing its original path.

Other checks include:

  • Duplicate ownership: two inodes claim one data block. A repair can clear one inode or give each file a separate copy.
  • Invalid addresses: pointers outside the file system's valid range must be cleared.
  • Directory structure: . and .. must be valid and occupy the first entries in the simple directory layout, entries must refer to allocated inodes, and directories must not have multiple parents.

These checks interact. Clearing an invalid inode also changes which blocks should be allocated and which directory entries remain valid. A repair therefore needs a coherent view of the metadata, not just a list of suspicious individual bits.

Understand what a clean result establishes

Suppose an append's inode and bitmap reached disk but its data did not. The pointer is in range, the allocation bit is set, and the link structure is valid. fsck has no metadata disagreement to repair. The file can pass checking while holding old bytes in its newly added region.

The running time also depends mainly on the file system's size, not the amount changed before a crash. A crash during one three-block update can still require scanning all metadata. On a large file system this can take minutes to hours, keeping normal access unavailable during the scan.

Journaling reduces normal crash-recovery work by recording recent updates. It does not make a checker obsolete: software bugs or failing hardware can damage structures outside what journal replay can repair. fsck remains a repair tool for those cases.

Key Takeaways

  • fsck reconstructs allocation from inode pointers and corrects metadata relationships.
  • Directory traversal checks link counts and finds unreachable allocated inodes.
  • Checking can repair duplicate ownership and invalid pointers.
  • A clean metadata check cannot establish that application bytes are correct.
  • Full metadata scanning scales with file-system size, even after a small interrupted update.

4.3 Protect updates with data journaling and replay the log

A journal records an update before the file system overwrites its ordinary locations. After a crash, that record tells recovery which complete changes can be redone. This is write-ahead logging. Ext3, ext4, XFS and NTFS use journaling, although their exact log formats differ.

Describe an update as a transaction

For an append, data journaling logs copies of the new inode I, bitmap B and data block Db. A transaction-begin record, TxB, carries an ID and the blocks' final destinations. A transaction-end record, TxE, carries the matching ID and marks commitment.

Logging complete replacement block images is physical logging. Logging an operation description instead is logical logging. Physical redo has a useful property: writing the same image to the same address again has the same effect. Recovery can therefore repeat a checkpoint that partly finished before the crash.

Put commitment after the payload

The basic protocol has four stages:

  1. Journal write: write TxB and I, B and Db to the journal, and wait for durable completion.
  2. Commit: write TxE, and wait. The transaction is now committed.
  3. Checkpoint: copy I, B and Db from the journal to their final locations.
  4. Free: release that transaction's journal space for later reuse.

TxE must not become durable before its payload. If all five blocks were issued without an ordering guarantee, a device could complete TxB and TxE while leaving Db unwritten. Recovery would mistake an incomplete transaction for a valid one. In the basic model, TxE fits within one atomic sector write, so it is either present or absent as a complete commit record.

Device write caches must respect the durability boundary too. Cache flushes or forced writes prevent a volatile device cache from making the protocol believe a payload is safe when power loss could still erase it.

Recover from two crash points

A crash after the payload but before TxE leaves an uncommitted transaction. Recovery ignores it, keeping the old file state.

A crash after TxE but during checkpointing leaves a committed transaction. Recovery writes all its images to their final locations in order. Some writes may repeat work already done, which is harmless for these block images. This is redo recovery. Journal space cannot be reused until the committed images have reached their final locations.

The journal is a circular log. Its superblock tracks the active range, allowing completed space to be reused. Batching several updates into one transaction can log one shared directory block or bitmap once. Ext4's default commit interval is 5 seconds, so commitment is not automatically immediate after every application write.

Separate checksums from durability

A transaction checksum can reveal missing or torn payload blocks even when a commit record is present. A checksum-based protocol can issue journal writes together and accept only transactions whose validation succeeds. Checksums detect incomplete records; cache flushes establish whether acknowledged bytes really survive.

An application's buffered, uncommitted write can still disappear. A program requiring durable completion uses fsync and checks success.

Key Takeaways

  • Write-ahead logging records complete updates before changing their final locations.
  • In the basic protocol, payload durability precedes the commit record.
  • Recovery redoes committed transactions and ignores uncommitted ones.
  • Redo of identical block images is safe after a partial checkpoint.
  • Checkpointing must finish before journal space is reused.
  • Batching reduces metadata traffic, while fsync establishes needed durability.

4.4 Reduce journaling cost and compare other approaches

Data journaling writes file contents to the journal and then to their final locations. Journaling only metadata reduces that traffic, but the order between data and metadata still determines what recovery can expose.

Keep data ahead of committed pointers

In ordered metadata journaling, Db goes directly to its final location. TxB, I and B go to the journal. These two sets of writes may run in parallel, but both must finish before TxE commits the metadata. After commitment, I and B can be checkpointed and the journal space freed.

The dependency is the key: the block a pointer names must be ready before that pointer becomes recoverable. If I commits first, recovery may install a valid pointer to bytes left by an earlier user of the block. Metadata would agree without holding the intended data.

Ext4 modeWhat enters the journalData-before-commit rule
data=journalData and metadataData is part of the logged transaction
data=orderedMetadataReferenced data reaches its final place before commit
data=writebackMetadataNo such data ordering guarantee

Ordered mode is the default. Metadata journaling alone does not imply ordered mode: writeback mode can recover structurally sound files with stale contents. The data-journal mode illustrates the full protocol but costs a second write of the file data.

Prevent replay from damaging a reused block

Directory contents count as metadata. Suppose a directory block at address 1000 is logged, then the directory is removed and the same address becomes ordinary file data. That new user data is not logged in metadata-only mode. Replaying the old directory image after a crash would overwrite the new file's bytes.

A committed revoke record tells recovery to skip logged copies of that block from transactions up to and including the revoking transaction. It does not forbid every future use of the address. If a later transaction logs that block again, the later image can still be replayed. This time boundary distinguishes revocation from permanently marking a block unusable.

Compare alternatives

Soft updates enforce dependencies between ordinary writes without a journal. Writing initialized data before a pointer prevents reachable garbage, although interrupted operations can leak space for a later background check to reclaim. FreeBSD’s FFS uses this approach. Tracking all dependencies makes implementation difficult.

Copy-on-write (COW) writes changed blocks to unused locations and uses an atomic root-pointer switch to publish the new tree. The old tree remains available until the switch. ZFS, Btrfs and WAFL use related designs; preserving old blocks also enables snapshots.

Backpointer-based research designs record ownership from data back to inodes so incomplete updates leave detectable mismatches. Optimistic crash consistency reduces waiting and uses checksums and other checks to detect incomplete work. Each approach trades write traffic, recovery guarantees and implementation complexity. Ordered metadata journaling keeps recovery short while writing ordinary file data once.

Key Takeaways

  • Ordered journaling sends data to final locations before committing its metadata pointers.
  • Metadata-only journaling and ordered journaling are not synonyms.
  • Revoke records prevent obsolete logged images from overwriting reused blocks.
  • Soft updates order dependencies; copy-on-write publishes a new tree.
  • Less write traffic can require more careful ordering or validation.
5

Explain how a log-structured file system writes and reclaims space

Sequential writes make good use of a disk, but moving every updated block creates new lookup and space-management problems. Follow LFS from buffered segments through the inode map and checkpoint region, then see how the cleaner finds live blocks and restores free segments. Recovery must recover the newest valid mapping without mistaking an interrupted checkpoint for a complete one.

5.1 Write sequentially in segments and find inodes through the inode map

A log-structured file system turns scattered small updates into large sequential writes. This helps a disk whose transfer rate is high but whose seek and rotation delays remain costly.

Gather updates into a segment

Berkeley's LFS, developed by Rosenblum and Ousterhout and published in 1991, started from changing workloads. Larger memories served more reads from cache, making writes a greater share of disk traffic. Sequential bandwidth grew faster than positioning speed. FFS still needed several short metadata and data writes for a small file creation, and small writes also worked poorly with parity RAID.

LFS buffers changed data, inodes and mapping information together in memory. It writes them to an unused disk region as one large segment. Updating a block creates a new version at a new address; the previous version remains physically present until cleaning reclaims its segment.

Segments amortize positioning just as large FFS chunks do. With rate R, positioning time T and desired transfer-time fraction F, the buffered size is:

D=F1−FRT.

At 200 MB/s and 5 ms, 95% requires 19 MB. Transfer takes 95 ms, positioning takes 5 ms, and the effective rate is 19 MB per 0.1 s = 190 MB/s. A high target fraction can require a segment larger than the usual hundreds of kilobytes to several megabytes. The required size follows the device and target, not the word "segment."

Find an inode that keeps moving

The fixed inode-table formula no longer works: every inode update writes a new address. LFS adds an inode map, or imap, mapping each inode number to its newest disk address. Updated imap pieces are written into the log beside the inodes they describe.

A fixed checkpoint region (CR) records where the newest imap pieces are. It is updated periodically, for example every 30 seconds, so the occasional fixed-location write does not dominate traffic.

The lookup chain is:

  1. Read the CR at mount to find the current imap pieces.
  2. Load the imap into memory.
  3. Look up the requested inode number in the imap.
  4. Read that newest inode and follow its data pointers.

Once the imap is cached, ordinary file reads use much the same inode-to-data path as in FFS. The extra mapping makes movement affordable without changing the file's stable identity.

Keep directory entries stable

A directory stores names and inode numbers. If /docs/report.txt is updated, its inode moves but keeps its number. The imap changes; the directory entry need not change merely because of that movement.

Without this indirection, a directory containing physical inode addresses would need rewriting whenever a child inode moved. Its own inode would then move, forcing a change in its parent, continuing toward the root. The imap breaks this recursive update problem.

LFS makes writes sequential, not all reads. A file's unchanged blocks can remain in older segments while later versions of other blocks move elsewhere. Reading that file may still seek between segments; large memory caches are part of the design's motivation.

Key Takeaways

  • LFS writes buffered data and metadata together to unused space in large segments.
  • The imap maps stable inode numbers to moving inode addresses.
  • The fixed checkpoint region locates the newest imap pieces.
  • Directory entries keep inode numbers, avoiding recursive parent rewrites.
  • Segment size must amortize positioning; reads can still be scattered.

5.2 Reclaim space with the cleaner and recover after a crash

Writing new versions to unused locations keeps old bytes physically present. LFS needs to distinguish old unreachable versions from live blocks, reclaim large free regions, and recover a usable mapping after a crash.

Clean whole segments

The cleaner reads partly occupied segments, copies their live blocks into fewer new segments, and frees the old segments. If four equal-size segments each have one quarter live data, their combined live data fills one new segment. Freeing the four old segments after the copy gains three segments of usable capacity.

Cleaning whole segments preserves large contiguous regions for future sequential writes. Copying has a cost: live blocks are read and written again even though no application changed them. A nearly full disk with mostly live segments may require much copying to recover little free space.

Decide whether a block is live

A segment summary identifies each block's owner inode and logical file-block offset. To test a block at address A, use the imap to find that owner's newest inode. Follow its pointer for the recorded logical block. If the pointer still equals A, this is the live version. If it points elsewhere, A is obsolete.

For example, a summary associates address 600 with inode 14, logical block 2. The current inode 14 points logical block 2 to address 920. Block 600 is dead even if its bytes look like valid data. Liveness depends on current reachability, not how recently a block was written or whether its contents look useful.

Version numbers speed up rejection. Deleting a file or truncating it to zero advances its version in the imap. A segment block carrying an older version can be classified dead without reading the inode.

Cleaning policy also considers expected change. Hot segments contain frequently overwritten blocks; waiting can let more of their blocks die without copying. Cold segments change little, so the original LFS policy cleans them sooner. Policy must balance live fraction, age and available space; a segment's temperature alone does not measure the immediate copying cost.

Recover the mapping and recent work

LFS keeps two checkpoint regions at opposite ends of the disk and alternates updates. Each update writes a timestamped header, the body, and a final matching timestamp. Recovery chooses the newest region whose beginning and end match. An interrupted newer update does not displace an older complete checkpoint.

The checkpoint may not include the most recent completed segments. Recovery therefore rolls forward from its recorded log end, finding valid subsequent updates and applying them to rebuild the current mapping. Data that never formed a valid recoverable update cannot be recreated from memory after power loss.

Related copy-on-write systems preserve old blocks to support snapshots; ZFS, Btrfs and WAFL share that broad idea. SSD controllers commonly use log-structured flash translation layers, while F2FS applies log-structured ideas at the file-system level for flash storage. Each still needs a way to reclaim space left by obsolete versions.

Key Takeaways

  • The cleaner copies live blocks into fewer segments and frees the old segments.
  • Liveness follows the newest inode mapping, not a block’s apparent contents.
  • Version mismatches can identify dead blocks quickly.
  • Waiting to clean hot segments can avoid copying blocks that soon become obsolete.
  • Recovery selects a complete checkpoint and rolls forward through valid later updates.
  • Cleaning adds I/O and can become expensive when little free space remains.
6

Compare how distributed file systems share files over a network

Sharing files across machines introduces uncertain replies and cached copies that may disagree. NFS shows how self-contained requests and safe retries simplify one kind of failure recovery. AFS shows how whole-file caching and callbacks reduce server work. Compare their sharing boundaries and failure state to predict when another client sees a change and when concurrent updates can be lost.

6.1 Explain how NFS recovers from failures with stateless requests

A distributed file system keeps files on a server while programs on client machines use familiar file calls. The client translates those calls into network requests. Delays and failures introduce a question local calls usually hide: what should a client do when it cannot tell whether a request completed?

Keep open-file state on the client

Sun's Network File System (NFS) began in the 1980s. NFSv2 made its server stateless with respect to open files. The server stores files but does not remember each client's descriptors or current offsets. Every request carries enough information to execute without an earlier open request.

A file handle identifies the server volume, inode number and inode generation. The generation changes when an inode number is reused, preventing an old handle from accidentally naming a different file in that reused slot.

To open /home/ana/notes.txt, the client starts with a root handle and sends LOOKUP for home, ana and notes.txt. It retains the resulting handle in its own open-file state. Reading the first 4 KiB becomes a READ request containing that handle, offset 0 and count 4096. Closing the local descriptor needs no NFSv2 CLOSE request because the server has no open entry to release.

Retry without repeating an effect

If no reply arrives, the client cannot distinguish a lost request, an unavailable server or a lost reply. It resends the request after a timeout.

An operation is idempotent when repeating it has the same effect as performing it once. READ, LOOKUP and GETATTR do not modify stored contents. An explicit-offset WRITE also safely repeats the same bytes at the same location in this model. Repeating a request that says "append these bytes at the current end" would instead add a second copy; the offset in an NFS WRITE avoids that ambiguity.

Some requests need extra care. Retrying a successful MKDIR after its reply was lost can return "already exists." The directory is present, but the repeated response differs from the original success. Stateless recovery does not turn every operation into a simple repeatable request.

Make acknowledgments trustworthy

NFSv2 must make a WRITE durable before acknowledging success. Otherwise the server could acknowledge a block, lose it from memory during a crash, and then accept later blocks. The client would believe all writes succeeded while the file contained a missing middle update.

Stable replies avoid that failure at a performance cost. NFSv3 added unstable writes followed by COMMIT, allowing several writes to become durable together. The client must distinguish an unstable acknowledgment from durable completion.

Separate versions of the protocol

A stateful protocol needs machinery to recover open and locking state after a server restart and reclaim state from crashed clients. NFSv4 deliberately accepts that complexity: it has OPEN, CLOSE, locks and time-limited leases that clients renew. The Linux client normally tries version 4.2 first, falling back when necessary. Calling NFSv2 stateless therefore does not describe every NFS version.

Key Takeaways

  • NFSv2 keeps descriptors and offsets on clients; each request is self-contained.
  • File handles include a generation to reject stale identities after inode reuse.
  • Explicit offsets make repeating the same WRITE safe in the retry model.
  • NFSv2 acknowledges writes only after stable storage; NFSv3 can defer durability to COMMIT.
  • NFSv4 is stateful and uses recovery machinery and leases.

6.2 Compare NFS and AFS caching and consistency

Client caching saves network trips but creates multiple copies of shared files. The consistency rule determines when another machine must stop using an old copy and fetch the writer's changes.

Validate NFS caches at sharing boundaries

Under NFS close-to-open consistency, closing a modified file flushes buffered writes to the server. A later open on another client checks freshness and sees those changes. GETATTR or related validation compares server attributes with cached attributes, discarding stale cached data when a change is detected.

Checking on every access would burden the server. Linux caches regular-file attributes for default intervals ranging from 3 to 60 seconds. A process that keeps a file open can therefore read stale cached data between checks. Opening is a stronger sharing boundary than an arbitrary read through an already open descriptor. Close-to-open behavior does not promise immediate visibility of every individual write.

Reuse whole files with AFS callbacks

The Andrew File System (AFS) was designed at Carnegie Mellon in the 1980s to support many clients per server. When no valid local copy exists, opening fetches the whole file to local disk. Reads and writes then use that copy, and closing a modified file sends the whole new version to the server. A valid cached copy can be reopened without downloading it again.

AFSv1 checked validity on every open and left path traversal to the server. AFSv2 shifted traversal to clients, which cache directories, and introduced callbacks. The server promises to notify a client when a cached object changes. Until that promise is broken, the client reuses its copy without repeated checks. Its file identifier includes a volume, a file identifier and a uniquifier.

Follow two overlapping sessions

Suppose clients A and B both open a file. A changes its local copy and closes, sending the new version to the server. The server breaks other clients' callbacks. A later open on B fetches the new version, but B's already open session keeps its existing copy until close and reopen.

If both machines modify their copies, the last one to close replaces the server's whole file. Blocks from the two copies are not merged. Two edits to different offsets can still lose one client's changes because last closer wins chooses a complete version. Processes on one client machine see each other's writes immediately.

Callbacks are server state. After a client restart, cached files are suspect because notifications may have been missed. After a server restart, clients must detect the lost callback promises, through heartbeats or a server notice, and revalidate.

Match caching to the workload
Workload or issueNFSAFS
Small part of a large fileTransfers requested blocksWhole-file transfer can waste work
Repeated large-file reads beyond memory capacityDepends on available cached blocksLocal disk copy avoids more network downloads
Freshness trackingAttribute checksServer callbacks
Concurrent sharingNeeds coordinationNeeds coordination; last closer can overwrite another version

AFS also offered a global namespace, access control lists and administrator-managed volumes. AFSv2 historically increased server scale to about 50 clients from roughly 20 for AFSv1. Neither design's cache rule replaces explicit coordination, such as file locks, when programs need safe shared updates.

Key Takeaways

  • NFS uses close-to-open validation while attribute caching can leave open readers stale.
  • AFS reuses a whole-file disk cache while a callback remains valid.
  • AFS publishes on close; an already open remote session keeps its old copy.
  • Concurrent AFS writers replace whole versions, so the last closer wins.
  • Callback state requires revalidation after failures.
  • Transfer granularity determines which workloads benefit from each cache design.

File Systems examples

6 Walkthroughs

1

Follow a File from Open to Durable Replacement

19 steps
Trace descriptors, names, permissions and a save that survives a crash.
  1. 1
    IntroductionFollow four kinds of state

    A file operation can change bytes, an open position, a directory name or a permission record. Follow a small program through these layers, then build a durable replacement. Keeping the layers separate explains two initially surprising results: a file can remain usable after its last name is removed, and closing a file does not by itself make a save durable.

  2. 2
    ExampleOpen and read a byte range

    A 260-byte file is opened for reading. Suppose open returns descriptor 3 and the first read(3, buf, 80) returns 80. The descriptor identifies this process’s open reference; the offset now equals 80. The returned count tells you how far to advance. The requested count is only an upper bound, so the program must inspect the return value.

  3. 3
    ChallengeFind the next offset

    The next request asks for 100 bytes but returns 60. At what offset will the following ordinary read begin?

    ---reveal---

    It begins at byte 140: the previous offset 80 advances by the 60 bytes actually read. Advancing by the requested 100 would incorrectly skip bytes. A read returning 0 at end of file would leave the offset unchanged.

  4. 4
    AnalogyShare a bookmark

    An open file entry is like a shared bookmark in one copy of a book. dup gives another way to reach that same bookmark; two separate open calls create two bookmarks. The analogy tracks position only: both opens still reach the same underlying file. Editing its bytes can affect both readers even though their offsets are independent.

  5. 5
    ExampleTrace a duplicated descriptor

    The program calls other = dup(3), then lseek(other, 20, SEEK_SET). Descriptor 3 now also uses offset 20 because both descriptors reach one open file entry. A 15-byte read through descriptor 3 leaves their shared offset at 35. The seek itself changes memory state; it does not read a block or move a physical disk head.

  6. 6
    TipChoose the right position operation

    Use pread when a read should name an explicit byte position without changing the open entry’s offset. This matters when descriptors share that entry after dup or fork. Ordinary read advances the shared offset; pread does not. Check either call’s returned count and errors before assuming the requested bytes were obtained.

  7. 7
    ExplanationMake accepted bytes durable

    A successful write usually places new bytes in memory buffers. A later crash can erase them before storage receives them. fsync waits for the file’s dirty data and metadata to reach storage as reported by the device. Closing a descriptor releases an open reference; it does not perform the same durability operation.

  8. 8
    ExamplePrepare a complete replacement

    An editor wants to replace settings.json. It first writes all replacement contents into settings.json.tmp in the same directory, checking write counts and errors. The old destination remains intact during this work. It then successfully synchronizes the temporary file, ensuring the complete replacement bytes are durable before changing the destination name.

  9. 9
    ExamplePublish and persist the new name

    Next the editor renames the temporary file over settings.json. The same-file-system replacement is atomic: the name reaches the old or the new file, without a missing-name interval. Finally it synchronizes the containing directory. That last step persists the name change, because the directory entry belongs to the directory rather than to the file.

  10. 10
    ChallengeFind the missing durability step

    A program writes and synchronizes a new file, renames it over the destination, and immediately reports a durable save. What operation is still needed?

    ---reveal---

    Synchronize the containing directory and check success. File synchronization protects the replacement’s contents, while directory synchronization protects the changed name. Atomic rename alone does not establish that the rename survives a crash.

  11. 11
    ExampleAdd a second name

    The command ln draft saved creates a hard link. Both names refer to one inode and the regular file’s link count becomes 2. Removing draft leaves saved usable with count 1. Nothing copied the contents: the operation added a directory entry. A symbolic link would instead be its own object storing a path to follow.

  12. 12
    ChallengeRemove every name from an open file

    A process has saved open. Another process removes its final hard link. Can the first process still read it, and when can storage be reclaimed?

    ---reveal---

    The open descriptor remains usable. Reclamation waits until there are no names and no open references. The link count records names, so reaching zero does not by itself end an existing open reference.

  13. 13
    Key InsightA path is not an object reference

    A symbolic link keeps a target path, so deleting or renaming the target can leave it dangling. A hard link directly names the inode and survives removal of its other names. Symbolic links can cross file systems because paths can cross mount points; hard links cannot, because inode numbers have meaning within one file system.

  14. 14
    ExampleDecode access rights

    The permission string rw-r----- divides into owner rw-, group r-- and other ---. With read = 4, write = 2 and execute = 1, the digits are 6, 4 and 0. Thus chmod 640 report sets owner read/write, group read and no rights for others. The three digits describe separate user classes, not one shared sum.

  15. 15
    ChallengeReach a known filename

    A user has execute but no read permission on /srv/data, and the file’s permissions allow reading /srv/data/plan. Can the user open the known path and list the directory?

    ---reveal---

    The user can open the known path because execute permits directory search. Listing needs directory read permission, so listing fails. File permissions are checked as well; directory search alone does not grant access to every file inside.

  16. 16
    TipRead ctime correctly

    After chmod, ctime changes because the inode’s status changed. It is not a creation timestamp. mtime records changes to file contents; atime records access, often with delayed updates. Keeping these meanings distinct helps you interpret stat output without concluding that a permission change created a new file or rewrote its bytes.

  17. 17
    ConnectionJoin trees without joining identities

    Mounting attaches another file system’s root at a directory such as /media/usb, hiding that directory’s previous contents while mounted. The virtual file system layer gives both trees common calls. It does not merge their inode tables: inode 25 on one file system can be unrelated to inode 25 on the other.

  18. 18
    ChallengeReplace a File Through a Second Name

    A program keeps the old file open through hard link backup. An editor publishes a complete new file by renaming a temporary file over current, then synchronizes the directory. Which contents does the old descriptor reach, and which does a new open of current reach?

    ---reveal---

    The descriptor and backup still reach the old inode. A new open of current reaches the replacement inode. Rename changes a directory entry without retargeting existing open references; synchronization persists that name switch.

  19. 19
    RecapUse the correct state model

    Track ordinary read positions through open file entries, and names through directories and inodes. For durable replacement, finish the temporary file, synchronize it, rename it, then synchronize the directory. When diagnosing access or deletion, examine the relevant directory rights and open references as well as the file’s own metadata.

2

Find Bytes on Disk and Count the Work

17 steps
Locate inodes and data blocks, then trace an uncached path and its cached counterpart.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionTranslate names into blocks
  2. 2
    ExampleBuild the partition layout
  3. 3
    ChallengeCount inode slots
  4. 4
    ExampleCompute an absolute inode address
  5. 5
    ExampleSelect bytes within the containing block
  6. 6
    Key InsightKeep the filename out of the inode
  7. 7
    ExampleLocate a logical data block
  8. 8
    ExplanationExpand the pointer tree
  9. 9
    ExampleAllocate the first part of a large file
  10. 10
    ChallengeFinish the pointer-block count
  11. 11
    ConnectionDescribe a run instead of every address
  12. 12
    ExampleWalk an uncached path
  13. 13
    ChallengeApply the reading model
  14. 14
    TipCount each changed structure
  15. 15
    Key InsightLet memory remove device work
  16. 16
    ChallengeRepeat a Lookup After Caching It
  17. 17
    RecapSeparate three translations
3

Place Related Files and Size Their Transfers

13 steps
Use FFS locality rules and derive the chunk size needed for a bandwidth target.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionSpend time transferring useful bytes
  2. 2
    ExplanationDiagnose distant metadata and small transfers
  3. 3
    AnalogyKeep a working set together
  4. 4
    ExamplePut local resources in each group
  5. 5
    ChallengeExplain what grouping changes
  6. 6
    ExamplePlace a directory’s files
  7. 7
    Key InsightLeave room for neighboring files
  8. 8
    ExampleMeasure the overhead
  9. 9
    ExampleSolve for a 90% target
  10. 10
    ChallengePredict a faster drive’s chunk size
  11. 11
    TipMatch allocation to small files too
  12. 12
    ChallengeKeep Room for Files Created Together
  13. 13
    RecapBalance locality, space and transfer size
4

Follow an Append Through a Crash and Recovery

18 steps
Compare partial writes, checker repair, journal commitment and ordered metadata recovery.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionRecover one complete update
  2. 2
    ExampleName the three changed blocks
  3. 3
    ChallengeClassify an allocation without a pointer
  4. 4
    ExampleFind hidden garbage
  5. 5
    Key InsightSeparate three failure types
  6. 6
    ExplanationReconstruct ownership with fsck
  7. 7
    ChallengeJudge a clean check
  8. 8
    ConnectionRepair names without inventing them
  9. 9
    ExampleWrite the redo payload first
  10. 10
    ExampleCommit the complete transaction
  11. 11
    ChallengeRecover after a partial checkpoint
  12. 12
    TipCheck commitment and durability separately
  13. 13
    ExampleAvoid journaling the data twice
  14. 14
    ChallengeSpot the missing ordering rule
  15. 15
    ExampleProtect a reused block from old replay
  16. 16
    ConnectionPublish a new tree instead
  17. 17
    ChallengeRecover Structure Without Recovering Intent
  18. 18
    RecapAsk what recovery can prove
5

Write, Find and Clean a Moving Log

15 steps
Trace an LFS update through its mapping, liveness check and crash recovery.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionKeep identity stable while locations move
  2. 2
    ConnectionTurn many short updates into one transfer
  3. 3
    ExampleWrite a new version
  4. 4
    ExplanationUpdate the inode map
  5. 5
    ChallengeCheck the parent directory
  6. 6
    ExampleFind the map after mounting
  7. 7
    ExampleSize a sequential segment
  8. 8
    Key InsightDo not infer sequential reads
  9. 9
    ExampleTest the old block’s liveness
  10. 10
    ChallengeCompute the space recovered
  11. 11
    TipAvoid copying data that will soon die
  12. 12
    ExampleChoose a complete checkpoint
  13. 13
    ChallengeRecover work after the checkpoint
  14. 14
    ChallengeRecover the Map Before Testing Liveness
  15. 15
    RecapPay for sequential updates with mapping and cleaning
6

Retry Requests and Predict Shared-File Visibility

16 steps
Compare NFS failure recovery with NFS and AFS cache-sharing timelines.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionHandle uncertainty across machines
  2. 2
    ExampleBuild a self-contained read
  3. 3
    Key InsightStateless does not mean storage-free
  4. 4
    ChallengeRetry a lost WRITE reply
  5. 5
    TipRecognize a retry that changes the response
  6. 6
    ExampleMake the acknowledgment durable
  7. 7
    ConnectionKeep protocol versions distinct
  8. 8
    ExampleShare at an NFS open boundary
  9. 9
    ChallengeExplain an old cached read
  10. 10
    AnalogyReplace repeated checks with a promise
  11. 11
    ExampleKeep an existing AFS session’s copy
  12. 12
    ChallengePredict two writers’ result
  13. 13
    Key InsightAccount for callbacks after a crash
  14. 14
    ConnectionChoose transfer granularity for the workload
  15. 15
    ChallengeSeparate a Safe Retry from a Safe Shared Edit
  16. 16
    RecapAsk two separate network questions

File Systems practice questions

60 Practice Questions in 6 sets

Set 1: Diagnose File-System Designs10 Practice Questions

Question 1 of 10

A utility successfully copies a file to another file system and then deletes its source. Does that provide the same atomic replacement guarantee as a same-file-system rename?
  1. No, because copying and deletion are separate
  2. Yes, because deletion makes the copy durable
  3. Yes, because both files have the same bytes
  4. No, because hard links are required for all moves
Show answerHide answer
Answer: A
The copy-and-delete sequence has intermediate states and cannot make the two operations one atomic name replacement. Cross-file-system rename itself fails with EXDEV, prompting such fallbacks. Equal contents at the end do not remove the intermediate failure boundaries, and deletion does not establish the copy’s durability.

Question 2 of 10

one and two are hard links to a file, and shortcut is a symbolic link containing the path one. A process opens two, then all three names are unlinked. Before that process closes its descriptor, what remains?
  1. No data, because every link object is gone
  2. An unnamed open file with link count zero
  3. The file with one hard link from the descriptor
  4. A live shortcut keeping the target reachable
Show answerHide answer
Answer: B
Removing the two hard names drops the target’s link count to zero, while the symbolic link never counted as a target hard link. The existing descriptor still keeps the unnamed target usable until it closes. Counting that descriptor as a hard link confuses open references with directory names.

Question 3 of 10

An inode has 8 direct pointers, a single indirect pointer and a double indirect pointer. Blocks are 2 KiB and addresses are 8 bytes. A non-sparse file is 550 KiB long. How many total blocks hold its data and external pointer structures?
  1. 277 blocks
  2. 279 blocks
  3. 275 blocks
  4. 278 blocks
Show answerHide answer
Answer: D
The file needs 275 data blocks, while each pointer block holds 256 addresses. Eight direct and 256 single-indirect blocks leave eleven data blocks requiring a double root and one child. Three pointer blocks bring the total to 278; 277 misses one of the double-indirection levels.

Question 4 of 10

A 4 MB chunk achieves 80 MB/s on a disk whose peak rate is 100 MB/s. With unchanged positioning cost, what chunk size achieves 95% of peak?
  1. 7.6 MB
  2. 19 MB
  3. 9.5 MB
  4. 76 MB
Show answerHide answer
Answer: B
The observed request takes 50 ms, including 40 ms transfer, leaving 10 ms positioning. At 95% of peak, transfer must last nineteen times that delay: 190 ms, or 19 MB. Scaling the original size only by the percentage ratio would miss the fixed positioning overhead in the denominator.

Question 5 of 10

In basic data journaling, what record marks a transaction committed after its payload is durable?
  1. The allocation bitmap alone
  2. The next directory entry
  3. The new inode number
  4. The matching TxE record
Show answerHide answer
Answer: D
The matching TxE record supplies the commit decision for the transaction whose payload is already durable. An inode or bitmap image is part of the update but cannot independently authorize replay. Payload presence without a valid commit record still leaves the basic transaction uncommitted.

Question 6 of 10

T20 logs block 44 as directory metadata. T21 deletes that directory, reuses block 44 for user data and commits a revoke for 44. T22 logs a different metadata image for 44 but never commits. A crash leaves all three journal payloads readable. What may recovery replay to block 44?
  1. T22’s image, the newest one
  2. T20’s image, the last committed
  3. T20’s image, then T22’s image
  4. Neither T20’s nor T22’s image
Show answerHide answer
Answer: D
T21’s committed revoke suppresses T20’s obsolete image through the revoking transaction. T22 is later, but its missing commit makes it ineligible for redo. Replaying the newest readable payload would ignore commitment, while replaying T20 would overwrite reused storage with revoked directory contents.

Question 7 of 10

A three-segment LFS cleaning candidate contains one segment-equivalent of live data. Another contains two live equivalents across three segments. With equal segment sizes and metadata overhead ignored, which yields more free capacity per live segment written?
  1. Both: 1 gained per 1 written
  2. The second: 2 gained per 1 written
  3. The first: 2 gained per 1 written
  4. The first: 3 gained per 1 written
Show answerHide answer
Answer: C
The first candidate copies one live segment and frees three old ones, gaining two per one written. The second copies two and frees three, gaining one per two written. Counting every released segment as net gain ignores the destination capacity and would overstate both candidates’ cleaning benefit.

Question 8 of 10

An NFSv2 redesign acknowledges a middle block write from volatile memory, then crashes. The client already received success for that write, so it retries only a later unacknowledged explicit-offset write. What weakness remains?
  1. The acknowledged middle update can stay missing
  2. The inode generation must equal the last offset
  3. The later retry must duplicate the middle block
  4. Client offsets must be reconstructed on the server
Show answerHide answer
Answer: A
The retry repairs only the later requested range; it does not recover a middle update the client believes was already safely completed. Idempotency makes repetition safe but does not make an earlier acknowledgment durable. Stable-before-reply is needed to prevent that acknowledged gap after server memory is lost.

Question 9 of 10

A client repeatedly rereads a file larger than memory. A valid AFS disk-cached copy remains available. What avoids repeated network downloads?
  1. Immediate global visibility of every write
  2. Converting every read into a server OPEN
  3. Reusing the whole-file local disk copy
  4. Disabling the server’s callback mechanism
Show answerHide answer
Answer: C
AFS retains a whole-file copy on local disk and can reuse it while valid even when the file no longer fits in memory. Callbacks provide freshness information without requiring repeated downloads. This cache benefit does not imply that every remote write becomes visible immediately to an already open session.

Question 10 of 10

An AFS server publishes A’s changed file and invalidates B’s callback. B still has an older read session open. The server then restarts and loses callback lists. What should B’s existing session and later cache reuse do?
  1. Keep the open copy; detect restart and revalidate for reuse
  2. Keep the open copy; trust callbacks after a server restart
  3. Replace the open session immediately; trust all old callbacks
  4. Replace the open session; fetch only after client reboot
Show answerHide answer
Answer: A
B’s already open remote session keeps its existing copy until close and reopen. Separately, server restart destroys callback state, so clients must detect it and revalidate before trusting cached copies for reuse. Callback loss does not splice new bytes into the current session or make old promises trustworthy after restart.
Set 2: Map Inodes, Data Blocks and Device Work10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

In a cold-cache model with one-block directories, how many inode-or-directory block reads locate /lab/raw/data before reading its contents?
  1. 7 reads
  2. 5 reads
  3. 8 reads
  4. 6 reads
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A file system allocates an inode for an empty regular file. What bitmap records that allocation?
  1. The inode bitmap
  2. The data bitmap
  3. The extent bitmap
  4. The directory bitmap
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

An inode table begins at disk block 4. Blocks are 4 KiB and inodes are 256 bytes, numbered from zero. At what absolute byte address does inode 23 begin?
  1. 22272
  2. 5888
  3. 16384
  4. 22528
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A partition has 100 blocks. Its superblock uses 1, its two bitmaps use 2, and its inode table uses 8. How many blocks remain in its data region?
  1. 97 blocks
  2. 89 blocks
  3. 92 blocks
  4. 91 blocks
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A 4 KiB indirect block stores 8-byte addresses. How many addresses fit?
  1. 2048 addresses
  2. 512 addresses
  3. 4096 addresses
  4. 1024 addresses
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

With 2 KiB blocks, where is byte offset 6500 within the file’s logical block mapping?
  1. Block 3, byte offset 1500
  2. Block 2, byte offset 2404
  3. Block 4, byte offset 356
  4. Block 3, byte offset 356
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

An inode has 6 direct pointers, one single indirect pointer and one double indirect pointer. Blocks are 1 KiB and pointers are 4 bytes. A non-sparse file occupies 400 data blocks. How many pointer blocks are needed outside the inode?
  1. 2 pointer blocks
  2. 5 pointer blocks
  3. 3 pointer blocks
  4. 4 pointer blocks
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A file consists of three separate contiguous runs of 40, 15 and 25 blocks. What minimum number of extent records describes those runs?
  1. 80 records
  2. 1 record
  3. 3 records
  4. 2 records
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A file uses only direct data pointers. In a simple cold-cache model, each directory occupies one block. After opening /lab/raw/data, the program reads three data blocks; each block access rereads the inode and writes atime. Closing has no I/O. What is the total?
  1. 13 I/Os
  2. 19 I/Os
  3. 10 I/Os
  4. 16 I/Os
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Two file creations change the same inode-bitmap block before it is flushed. How can buffering reduce traffic for that block?
  1. It avoids reserving either inode on disk
  2. It replaces allocation bits with inode pointers
  3. It combines both changes into one later write
  4. It stores the bitmap inside both new files
Show answerHide answer

Save this lesson to see this answer.

Set 3: Descriptors, Names and Durable Saves10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A regular-file read requests 120 bytes and returns 45. Starting at offset 30, where does the next ordinary read begin?
  1. Offset 75
  2. Offset 120
  3. Offset 150
  4. Offset 45
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A process separately opens the same file as a and b, then reads 24 bytes through a. What is the offset of b before its first read?
  1. 24, because the inode is shared
  2. 0, because the first read resets both entries
  3. 24, because all descriptors share offsets
  4. 0, because the opens have separate entries
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A file has at least 200 bytes. A process opens it as a, creates b = dup(a), and separately opens it as c. After fork, the child seeks b to 70. The parent reads 12 bytes through a, then calls pread(c, buf, 9, 100). What are the final offsets for a, b and c?
  1. 82, 82, 0
  2. 82, 82, 109
  3. 12, 70, 0
  4. 82, 70, 109
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A program has successfully written a complete existing file. What call directly waits for that file’s dirty data and metadata to reach storage?
  1. close(fd)
  2. fstat(fd, &buf)
  3. lseek(fd, 0, SEEK_SET)
  4. fsync(fd)
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

An editor writes a complete temporary replacement in the destination’s directory and successfully synchronizes it. What sequence completes a durable replacement?
  1. Close the temporary file, then rename it
  2. Rename it, then synchronize the directory
  3. Truncate the destination, then rename it
  4. Synchronize the directory, then rename it
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A new empty file is sought to offset 12288 and one byte is written there. What are its logical size and the contents of the preceding gap?
  1. 1 byte; the gap is outside the file
  2. 12289 bytes; the gap contains old disk bytes
  3. 12289 bytes; the gap reads as zeros
  4. 12288 bytes; the gap reads as zeros
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Two names, red and blue, are hard links to one closed regular file. After red is unlinked, what happens to blue?
  1. It remains usable with link count 2
  2. It remains usable with link count 1
  3. It disappears with the shared inode
  4. It becomes a dangling symbolic link
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A regular file has one name and an open descriptor. Another process unlinks the name. When can the file system reclaim its inode and data?
  1. When the process next seeks the descriptor
  2. After the remaining open references end
  3. After a later directory listing completes
  4. Immediately when the last name disappears
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A user can traverse /srv/team but cannot list its names. The user knows /srv/team/brief, and that file’s permissions permit reading. What access is possible?
  1. Both listing and opening succeed
  2. Listing succeeds, but opening fails
  3. Opening succeeds, but listing fails
  4. Both listing and opening fail
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A drive is mounted on a directory that already contains files. What happens to those previous files while the mount is active?
  1. They are copied into the mounted file system
  2. They are removed as part of mounting
  3. They are merged into the mounted root
  4. They are hidden by the mounted root
Show answerHide answer

Save this lesson to see this answer.

Set 4: Locality, Throughput and Partial Updates10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

What disk overhead does placing a file’s inode close to its data primarily reduce?
  1. Directory link counts
  2. Pointer storage space
  3. Seek and rotational delay
  4. File permission checks
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A hard disk has a high sequential transfer rate, but a file system issues tiny reads scattered across it. Why can throughput remain low?
  1. Scattered blocks need larger file offsets
  2. Directory depth sets every data-block seek
  3. Small reads lower the drive’s peak bandwidth
  4. Positioning dominates the short transfers
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A directory’s group has ample space. Where does FFS normally place a newly created regular file’s inode and data?
  1. Together in the least-used distant group
  2. Together in the parent directory’s group
  3. In separate groups to spread all traffic
  4. With the inode in a global table only
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Why does FFS use sub-blocks for small files?
  1. To avoid all metadata writes
  2. To remove the inode’s data pointers
  3. To make each file span groups
  4. To reduce unused space in large blocks
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A disk peaks at 120 MB/s. A 3 MB chunk takes 35 ms including positioning and transfer. What chunk size would reach 90% of peak if positioning time stays fixed?
  1. 3.78 MB
  2. 10.8 MB
  3. 12 MB
  4. 37.8 MB
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

An FFS-like allocator must leave room near a project directory for small sibling files while storing a large streaming file. Other groups have ample space. The disk peaks at 160 MB/s and positioning takes 5 ms. How should later large-file chunks be placed and sized to reach 90% of peak?
  1. Use 7.2 MB chunks only in the home group
  2. Use 0.8 MB chunks only in the home group
  3. Use 7.2 MB chunks in other groups
  4. Use 0.8 MB chunks in other groups
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

After an append, the new data and inode reach disk, but the allocation bitmap does not. What is the main structural risk?
  1. The same block may be allocated again
  2. The block is reserved without any owner
  3. The inode has lost all directory names
  4. The new data is unreachable from the file
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Only the new data block of an append reaches disk. Neither the inode nor the bitmap update survives. How is the resulting state classified?
  1. Inconsistent, with two block owners
  2. Committed, with an outdated file length
  3. Leaked, with an allocated orphan block
  4. Consistent, with the append absent
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A crash leaves a block marked allocated but unreferenced. A second file’s inode points to a different block still marked free. After repair, which allocation-bit changes reconcile these two cases?
  1. Clear the first bit and set the second
  2. Set both bits and preserve all pointers
  3. Clear both bits and preserve all pointers
  4. Set the first bit and clear the second
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

An append’s inode and bitmap updates survive, but its data does not. Why can the file pass structural checking while containing wrong bytes?
  1. Bitmaps reconstruct the missing bytes
  2. The inode no longer describes its data
  3. Ownership agrees even though contents are stale
  4. Checking compares file names only
Show answerHide answer

Save this lesson to see this answer.

Set 5: Check, Commit and Replay Safely10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A valid inode claims block 85, but the bitmap marks block 85 free. What bitmap repair matches ownership?
  1. Keep the mismatch for now
  2. Clear the inode’s pointer
  3. Mark block 85 allocated
  4. Free block 85 at checkpoint
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

An allocated inode contains valid pointers and data but no name reachable from root. How can fsck preserve access to it?
  1. Create a reachable entry in lost+found
  2. Leave it unlinked and change its link count
  3. Preserve it only by restoring a backup copy
  4. Free its allocated blocks without adding a name
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A basic data-journal payload is fully durable, but its TxE commit record never reached storage. What does crash recovery do with the transaction?
  1. Install only its inode and bitmap images
  2. Replay it because its payload looks complete
  3. Ignore it because commitment is absent
  4. Treat its payload as already checkpointed
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A transaction is committed, and half its images reached final locations before a crash. Why can recovery replay every image?
  1. It first discards all already written data
  2. Identical block replacement is repeatable
  3. Commitment makes final writes unnecessary
  4. Checkpointing changes only directory names
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A file initially has two data blocks. Data-journal transaction T1 appends blocks 80 and 81 and commits. T2 appends block 82 in its journal payload but has no commit record. A crash occurs after only T1’s inode image was checkpointed. After recovery, what are the file length and allocation states of blocks 80–82?
  1. Five blocks long; 80, 81 and 82 allocated
  2. Four blocks long; 80, 81 and 82 allocated
  3. Two blocks long; 80, 81 and 82 free
  4. Four blocks long; 80 and 81 allocated, 82 free
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A journal wraps around while a committed transaction is only partly checkpointed. The proposed implementation reuses that transaction’s space immediately because TxE is durable. What failure can this cause?
  1. The transaction becomes uncommitted despite TxE
  2. Recovery adds every logged change a second time
  3. Recovery must checkpoint the whole file system
  4. A crash can erase the only copies needed to finish
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

In ordered metadata journaling, data writes and journal metadata writes run in parallel. What must finish before TxE is made durable?
  1. Both data and journal metadata writes
  2. Only the data’s final-location write
  3. The metadata checkpoint at final locations
  4. Only the journal metadata payload
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Committed T10 logs block 70 as directory metadata. Committed T11 revokes block 70 after deletion. Committed T12 later logs a new metadata image for block 70. What happens to those block images during recovery?
  1. Replay T10 and skip T12
  2. Skip both T10 and T12
  3. Skip T10 and replay T12
  4. Replay both T10 and T12
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

An ext4 file recovers with consistent metadata but stale contents because its metadata committed before associated data reached its final location. What data mode permits this ordering?
  1. data=writeback
  2. data=ordered
  3. All three modes equally
  4. data=journal
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A soft-updates design writes initialized data first, then crashes before publishing its pointer. A repair later reclaims unused allocation. What trade-off does this illustrate?
  1. Published pointers can safely name unwritten data
  2. Safe references can coexist with a space leak
  3. Every application write was already durable
  4. All metadata scans become unnecessary
Show answerHide answer

Save this lesson to see this answer.

Set 6: Moving Logs and Network Caches10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

An LFS inode moves to a new disk address after an update. What structure maps its stable number to that newest address?
  1. The inode map
  2. The directory
  3. The inode table
  4. The data bitmap
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

Why does storing stable inode numbers in LFS directories avoid recursive parent updates when a file’s inode moves?
  1. Only the imap needs the changed address
  2. Directory entries hold whole inode images
  3. Old and new inode addresses stay current
  4. All directories stay pinned in memory
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A segment write of 6 MB takes 40 ms on a disk peaking at 200 MB/s. With the same positioning delay, how large must a segment be to reach 95% of peak?
  1. 114 MB
  2. 38 MB
  3. 19 MB
  4. 8 MB
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A segment summary assigns address 450 to inode 9, logical block 3. The imap’s newest inode 9 points block 3 to address 880. Is the old block at 450 live?
  1. Yes, because inode 9 still exists
  2. Yes, because the summary names its owner
  3. No, because the current pointer differs
  4. No, because all checkpointed blocks are dead
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A cleaner reads six equal-size segments, each 50% live, and packs their live data into new segments. Ignoring metadata overhead, how many segments of free capacity are gained and how many segment-equivalents of live data are written?
  1. 3 gained; 6 written
  2. 6 gained; 6 written
  3. 6 gained; 3 written
  4. 3 gained; 3 written
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Checkpoint A has matching timestamp 52. Checkpoint B has header 53 and ending timestamp 51. Valid segments follow the log end recorded in A. What recovery plan preserves the latest recoverable work?
  1. Use A, then roll forward through valid later segments
  2. Use A, then discard every segment not in its map
  3. Use B, then ignore segments older than its header
  4. Use B, then rebuild directories from inode-table slots
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A client retains an NFS handle for a deleted file. Its inode number is reused for another file on the same volume. What handle field prevents access to the replacement?
  1. The client’s descriptor offset
  2. The inode generation number
  3. The directory’s link count
  4. The server’s open-file position
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A client sends an NFSv2 WRITE at an explicit offset. The server durably completes it, crashes before replying, then restarts. What makes resending that request sufficient in the basic recovery model?
  1. The server restores the client’s old open offset
  2. The retry appends bytes after the stored result
  3. The client infers that the first request never ran
  4. The stable result survives and repeating it is safe
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Client A closes a modified NFS file before client B opens it under close-to-open consistency. What should B’s new open observe?
  1. Only changes made before A originally opened
  2. Its old copy until all attribute timers expire
  3. A’s changes after freshness validation
  4. Its old copy until the server reboots
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

AFS clients A and B open the same version. A changes region X and closes. B changes region Y in its still-open copy, closes last, then C opens. What version does C receive?
  1. The original file until both clients reopen
  2. A’s file until B’s callback expires
  3. B’s whole version, possibly losing A’s edit
  4. A merged file containing both clients’ edits
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

96 Key Terms, each with its definition

A

Absolute path
An absolute path identifies an object by starting from the root directory, shown by an initial slash in Unix paths.
The path /srv/reports/today starts at root even when the process’s current directory is /home/lee.
Access control list
An access control list adds permission rules for named users or groups beyond the owner, group and other permission classes.
An ACL can grant a particular project member access without granting the same rights to every other user.
Allocation bitmap
An allocation bitmap uses one bit per tracked object to record whether that inode or data block is allocated or free.
Allocating a new data block sets its data-bitmap bit, while a new file also needs an inode-bitmap bit.
Amortization
Amortization spreads a fixed cost across enough useful work that the cost becomes a smaller fraction of the total time.
A 9 MB transfer at 100 MB/s spends much less of its total time on a 10 ms seek than a 1 MB transfer.
Andrew File System
The Andrew File System, or AFS, is a distributed design using whole-file client caching and server callbacks to reduce repeated work.
A valid AFS disk-cached copy can be reopened without a new download, while an invalidated copy needs refreshing.
Append mode
Append mode is an open-file mode that places each write at the file’s current end, selected with O_APPEND.
A logging process uses O_APPEND so each new message is placed after the file’s existing contents.
atime
atime is a file’s last-access timestamp, recording content access under the file system’s timestamp-update policy.
A read can update atime, although Linux’s usual relatime policy avoids writing it after every access.
Atomic replacement
An atomic replacement switches a destination name from an old file to a new file without exposing an intermediate missing name.
A same-file-system rename replaces config while readers reach either the old or the new complete file.
Atomic write unit
An atomic write unit is the amount a storage interface guarantees to write completely or leave unchanged when interrupted.
A journal commit record must fit the device’s supported atomic unit for the basic all-or-nothing marker protocol.
Attribute cache
An attribute cache retains file metadata temporarily so a client can avoid asking the server to validate it on every access.
Default Linux regular-file attribute timers range from 3 to 60 seconds, allowing stale reads between checks.

B

Bad pointer
A bad pointer is a stored block address outside the file system’s valid address range and therefore unable to identify valid owned data.
If an inode points beyond the partition’s end, fsck clears that invalid pointer during repair.
Block group
A block group is a consecutive range of logical disk blocks with local allocation structures, inodes and data space.
Ext4 uses block groups to pursue locality even though the drive does not expose its true geometry.

C

Cache hit
A cache hit occurs when requested information is already present in the cache and can be used without fetching it from storage.
Opening a neighboring file can reuse directory blocks retained from the previous path traversal.
Callback
An AFS callback is a server promise to notify a client when a cached object changes, allowing reuse without repeated checks.
Publishing a changed file causes the server to break other clients’ callbacks so later opens refresh their copies.
Checkpoint region
The checkpoint region is a fixed LFS location recording addresses of the latest imap pieces so the moving log can be located.
At mount, the system reads the checkpoint region before loading the inode map and locating file inodes.
Checkpointing
Checkpointing in journaling copies a committed transaction’s logged blocks to their ordinary final file-system locations.
Journal space remains needed until checkpointing has placed every required image safely at its destination.
Circular log
A circular log reuses a bounded storage region by wrapping around and reclaiming records whose recovery work is finished.
When a transaction is checkpointed, its journal space can become available for a later transaction.
Cleaner
The cleaner is the LFS component that copies live blocks out of partly used segments and frees the old segments for reuse.
Compacting four quarter-live segments into one gains three segments of capacity while costing copy I/O.
Close-to-open consistency
Close-to-open consistency makes a writer’s flushed changes visible to a later opener while permitting weaker visibility during open sessions.
After client A closes a modified NFS file, client B opens it and validates its cache before reading the changes.
Commit record
A commit record marks a transaction as complete and recoverable after its required journal contents have reached durable storage.
Payload blocks without a valid matching commit record are ignored by the basic redo recovery protocol.
Copy-on-write
Copy-on-write places modified blocks at new addresses and publishes a new root, keeping the old version intact until the switch.
A crash before publication leaves the old tree reachable instead of exposing a mixture of in-place updates.
Crash consistency
Crash consistency is the requirement that stored file-system structures can recover to an agreed valid state after interrupted updates.
An append must not leave an inode owning a block that the allocator still regards as available to another file.
ctime
ctime is the inode status-change timestamp, updated by content writes and changes such as permissions, ownership or links.
Running chmod changes ctime even though the bytes and therefore the content modification time stay unchanged.
Cylinder group
A cylinder group is an FFS region of neighboring disk cylinders that keeps its inodes, bitmaps and data physically close.
Placing a small file in its directory’s cylinder group shortens seeks among the structures being updated.

D

Data block
A data block is an allocation unit holding file contents or directory entries, reached through the object’s stored mapping.
A directory’s data block contains names and inode numbers, while a regular file’s block contains its bytes.
Direct pointer
A direct pointer is an address stored in an inode that points straight to one data block without a separate pointer block.
The third direct pointer locates logical file block 2 because block numbering starts at zero.
Directory entry
A directory entry associates a name with an inode number, allowing a directory lookup to identify the named object.
Adding a hard link creates another directory entry for an existing inode without copying file contents.
Dirty buffer
A dirty buffer is an in-memory copy of data or metadata that has changed and still needs to be written to storage.
Several edits can update one dirty block before the file system sends its final contents to the device.
Distributed file system
A distributed file system lets client machines use files stored on servers over a network through familiar file operations.
The client translates a program’s read into a request identifying a server file and the desired byte range.
Double indirect pointer
A double indirect pointer reaches a block of pointers to indirect blocks, adding a second level of addresses before the data.
A file exceeding direct and single-indirect capacity allocates a double root and enough indirect children.
Duplicate pointer
A duplicate pointer is a block reference that gives conflicting ownership when two inodes claim the same data block.
A repair may give each file its own copy so changing one file cannot silently change the other file’s data.
Durability
Durability is the property that an acknowledged stored update remains available after a crash or loss of power.
An editor waits for successful fsync before reporting that a document’s new contents are durably saved.

E

Extent
An extent is a starting disk address and a run length that together describe a contiguous sequence of a file’s blocks.
A contiguous 1000-block file can use one extent instead of storing 1000 individual block addresses.

F

File Allocation Table
The File Allocation Table, or FAT, stores next-block links for files in a separate table, forming a chain from each first block.
Finding a file’s twentieth block requires following its chain even when the table itself is cached.
File descriptor
A file descriptor is a process-local nonnegative integer that refers to a kernel entry for an open file.
After open returns 4, the program passes 4 to read, write and close for that open reference.
File handle
A file handle identifies a remote object, using information such as its server volume, inode number and generation.
A client includes the handle in READ so the server knows the object without relying on a prior OPEN request.
File offset
A file offset is the byte position in an open file entry at which the next ordinary read or write begins.
Reading 32 bytes from offset 80 leaves the offset at 112 when the read returns the full count.
Fragmentation
Fragmentation is the scattering of free space or a file’s blocks into separated regions, increasing the work needed for access.
A file can have sequential byte offsets but require repeated seeks because its allocated blocks are scattered.
fsck
fsck is a file-system checker that scans metadata and repairs allocation, pointer, inode and directory relationships after corruption.
The checker can set a bitmap bit when a valid inode owns the block but the map incorrectly says it is free.

G

Garbage data
Garbage data is unintended old or invalid content exposed through a file even when its pointers and allocation records agree.
If a new block pointer commits before that block’s new bytes arrive, a valid-looking file can expose the block’s previous contents.
Generation number
A generation number distinguishes successive objects assigned the same inode number, protecting clients from stale identities.
Reusing inode 31 with a newer generation prevents an old handle for deleted inode 31 from naming its replacement.

H

Hard link
A hard link is a directory name that refers directly to an existing inode and has equal standing with its other names.
After ln draft copy, removing draft leaves copy pointing to the same file and its existing bytes.
Hot segment
A hot segment contains blocks that are frequently replaced, so waiting can let additional blocks become dead before cleaning.
Delaying a hot segment may save copying data that another application write will soon make obsolete.

I

Idempotency
Idempotency means repeating an operation has the same effect as performing it once, enabling safe retries of suitable requests.
Repeating an explicit-offset WRITE stores identical bytes at the same location instead of adding them again.
Indirect block
An indirect block stores an array of block addresses, expanding the data reachable through a single pointer in the inode.
A 4 KiB indirect block with 4-byte addresses can identify 1024 separate data blocks.
Inode
An inode is a Unix-style file-system record that stores an object’s metadata and data locations but does not store its filename.
Two directory names can share inode 28, so changing the file through either name updates the same object.
Inode map
The inode map, or imap, translates each stable inode number into the disk address of its newest version in an LFS log.
A directory can keep inode number 14 even when the latest inode moves from address 300 to address 900.
Inode table
An inode table is a region containing fixed-size inode records whose positions can be computed from their inode numbers.
A table beginning at byte 16384 places inode 20 of size 256 bytes at absolute byte address 21504.

J

Journal
A journal is a reserved on-disk log holding update records so committed changes can be recovered after interrupted writes.
A crash during checkpointing can be repaired from the journal without scanning every inode in the file system.

L

Large-file exception
The large-file exception spreads later parts of a large FFS file across groups so it cannot consume its directory’s whole group.
The first direct-pointer blocks remain local, while later indirect chunks move to other lightly used groups.
Last-closer-wins consistency
Last-closer-wins consistency resolves concurrent AFS writes by letting the final closing client replace the server’s whole file version.
Two clients editing different regions can still lose one edit because closing publishes a complete local copy.
Lease
A lease is time-limited server-managed state or a promise that a client must renew to retain, allowing expiration after failure.
An NFSv4 server can reclaim a crashed client’s state when its lease expires without renewal.
Link count
A link count records how many directory names refer to an inode, with special dot-entry accounting for classic Unix directories.
Two hard links to one regular file produce a link count of 2, regardless of how many descriptors are open.
Live block
A live block is a stored block still referenced by the newest valid mapping for its owning file and logical position.
A summary names inode 14 and block 2, but the old address is dead if the newest inode points elsewhere.
Log-structured file system
A log-structured file system writes buffered data and metadata sequentially to unused space, replacing old versions through new mappings.
Updating one file block writes a new block and inode instead of overwriting their previous disk locations.
Logical file block
A logical file block is a block-sized portion of a file identified by its position within that file, independently of disk location.
Logical blocks 0 and 1 can be stored far apart even though their byte ranges are consecutive.
Logical logging
Logical logging records a description of an update operation instead of storing complete replacement images of every changed block.
A compact operation record describes a change, while a physical journal contains the new block bytes themselves.

M

Metadata
Metadata is information describing a file, such as its type, size, ownership, permissions, timestamps and data locations.
fstat reads metadata through a descriptor without treating the file’s contents as a metadata record.
Metadata journaling
Metadata journaling logs changes to file-system structures while ordinary file data is written directly to its final locations.
Both ordered and writeback modes journal metadata, but only ordered mode enforces data-before-commit ordering.
Mount point
A mount point is an existing directory path where another file system’s root is attached to the visible directory tree.
Mounting a drive at /media/usb hides that directory’s previous contents while the mount remains active.
mtime
mtime is a file’s last-content-modification timestamp, distinguishing changes to stored bytes from other inode status changes.
Changing permissions updates ctime, while writing the file’s contents updates mtime as well as ctime.

N

Namespace locality
Namespace locality is the tendency for files close in the directory tree, especially within one directory, to be accessed together.
A compiler opening several source files in one project benefits when their inodes and contents lie nearby.
Network File System
The Network File System, or NFS, is a family of protocols for accessing server files, with stateless v2 and stateful v4 designs.
A Linux client normally tries NFS version 4.2 first, so the older stateless model does not describe every mount.

O

Open file table entry
An open file table entry is a kernel record holding an open file’s offset, access mode, inode reference and reference count.
Descriptors created by dup point to one open entry, so a seek through either changes their shared position.
Ordered journaling
Ordered journaling is metadata journaling that makes referenced data durable at its final location before committing the metadata.
A new data block and journal metadata can be written in parallel, but both must finish before the commit record.

P

Page cache
The page cache is memory used to retain file data and related blocks so later access can avoid storage-device operations.
A second read of an unchanged cached block can copy bytes to the program without issuing another disk read.
Path traversal
Path traversal resolves a path component by component, using directory contents to find each next inode until it reaches the target.
Opening /team/result first finds team in root, then finds result in the team directory.
Permission bits
Permission bits encode read, write and execute rights separately for a file’s owner, its group and other users.
Mode 750 gives the owner all three rights, the group read and execute, and others no rights.
Physical logging
Physical logging records complete replacement block images, letting recovery redo an update by writing those images to fixed addresses.
Replaying an inode image repeats the same stored bytes even if that image was checkpointed before the crash.
Positioning cost
Positioning cost is the seek and rotational delay a hard disk pays before it can begin transferring the requested data.
Two distant 4 KiB reads can spend far more time positioning than transferring their small contents.

R

Recursive update problem
The recursive update problem occurs when moving one object forces rewrites of parent pointers, which move and force further rewrites.
Stable inode numbers plus the imap stop a moved file inode from forcing updates all the way to the root.
Relative path
A relative path identifies an object starting from the process’s current working directory instead of the root.
From /srv/reports, the path ../logs reaches /srv/logs by first following the parent entry.
Revoke record
A revoke record tells recovery not to replay a block’s obsolete logged images from transactions through the revoking transaction.
Revocation stops an old directory image from overwriting user data after the same disk block has been reused.
Roll-forward recovery
Roll-forward recovery scans valid log updates after a checkpoint and applies them to reconstruct state newer than that checkpoint.
A segment written after the last checkpoint can still be recovered when its update is valid and complete.

S

Segment
A segment is a large sequential unit of LFS output containing buffered data and metadata written together to unused space.
Combining many small changes in one segment spreads a disk’s positioning cost across a longer transfer.
Segment summary
A segment summary records ownership information such as inode number and logical offset for blocks stored in an LFS segment.
The cleaner uses the summary to find which current inode pointer it must compare with a block’s address.
Short write
A short write is a successful write call that reports fewer bytes written than the program requested.
If write returns 200 for a 500-byte request, the program still needs to handle the remaining 300 bytes.
Snapshot
A snapshot preserves a view of an earlier file-system state by retaining the older blocks and mappings that define that version.
Copy-on-write can keep the old tree available while changed blocks are written for the current version.
Soft updates
Soft updates order dependent metadata and data writes to prevent unsafe references without recording updates in a journal.
Writing initialized data before the pointer can leave a leak after a crash while avoiding a reachable invalid block.
Space leak
A space leak is allocated storage that no reachable owning object uses, making capacity unavailable without preserving useful contents.
A bitmap update without its new inode pointer can reserve a block that no file can reach after recovery.
Sparse file
A sparse file contains logical zero-filled regions that the file system can represent without allocating data blocks.
Writing one byte far beyond the end can create a large logical file with little allocated storage.
Stale cache
A stale cache contains an older copy of an object that no longer matches the version currently published by its server.
A client with an already open file can read old cached bytes after another client has closed a modified version.
Stateless server
A stateless server executes self-contained requests without retaining per-client open-file state such as descriptors and offsets.
An NFSv2 server can resume serving requests after restart without rebuilding every client’s open-file table.
Sub-block
A sub-block is a smaller allocation piece used by FFS to store short files without wasting an entire large file-system block.
A short file can occupy a 512-byte piece before growth requires copying its contents into a full block.
Superblock
A superblock stores the counts, layout information and identifying values needed to interpret and mount a file system.
The operating system reads the superblock to locate the inode table before looking up individual files.
Symbolic link
A symbolic link is a separate file whose contents specify a target path that the system follows during path resolution.
A link to /media/archive can reach a different file system, but fails if its target path disappears.

T

Track buffer
A track buffer is drive memory that retains data read from a track, reducing the need for software-controlled rotational spacing.
The drive can return the next requested block from its track buffer even after it has passed under the head.
Transaction
A transaction groups related updates under one commit decision so recovery accepts a complete change or ignores it.
An append transaction can contain a new inode image, an allocation bitmap image and the new data block.
Transaction checksum
A transaction checksum summarizes logged contents so recovery can detect an incomplete or damaged transaction payload.
A matching-looking commit marker is insufficient when validation shows that part of its payload is missing.
Truncation
Truncation changes a file’s logical length; shrinking discards trailing bytes, while extension creates bytes that read as zeros.
Opening an existing file with O_TRUNC empties it before the program writes any replacement contents.

U

Umask
A umask is a process setting that removes selected permission bits from the permissions requested for a new file.
Without a default ACL, umask 0022 changes a request for 0666 into permissions 0644.
Unreachable inode
An unreachable inode is an allocated inode that cannot be reached through the directory tree from the file system’s root.
After directory damage, fsck can place an otherwise valid unreachable inode in lost+found for inspection.

V

Virtual file system
The virtual file system is a kernel layer that presents common file operations across different underlying file system types.
A program can use read on an ext4 file and an NFS file while their implementations handle different storage.

W

Whole-file caching
Whole-file caching retains a complete file on the client, serving local reads and writes while that cached version remains usable.
AFS can reopen a valid disk-cached file without downloading it again even after it no longer fits in memory.
Write buffering
Write buffering keeps changed blocks in memory temporarily so the system can combine, schedule or sometimes eliminate writes.
Creating two files close together can update one bitmap in memory and later write that bitmap only once.
Writeback journaling mode
Writeback journaling mode journals metadata without requiring associated data blocks to reach final storage before commitment.
After recovery in data=writeback, metadata can be consistent even when a recently written file contains stale bytes.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started