Β§40.1–40.3vsfs: On-Disk Organization and the Inode

Part III OSTEP pp. 493–500 Β· ~9 min read

  • block
  • superblock
  • inode table
  • bitmap
  • data block
  • direct pointer
  • indirect pointer
  • multi-level index
  • extent

We know how to use a file system (ch39). Now we build one: vsfs, the Very Simple File System β€” a stripped-down UNIX-style FS. A file system is pure software, so the design space is enormous (AFS to ZFS); we learn by case study, starting simple.

The Crux: How To Implement A Simple File System

What on-disk structures does a file system need? What do they track? And how are they accessed during opens, reads, and writes?

40.1 The Way To Think

Understand two things and you understand a file system:

  • Data structures β€” what on-disk structures organize its data and metadata (vsfs uses simple arrays of blocks; fancier systems use trees).
  • Access methods β€” how it maps open(), read(), write() onto reads and writes of those structures.

The rest of this chapter develops both. Build your mental model: what’s on disk, and what gets touched on each call.

40.2 Overall Organization

Start by dividing the disk into fixed-size blocks β€” 4 KB each (distinct from the drive’s 512-byte sectors). On a tiny 64-block partition, we assemble the layout region by region:

Building the vsfs on-disk layout on a tiny 64-block (4 KB each) partition. Violet = superblock, gold = bitmaps, brown = inodes (dark) and data (light).
012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 blocks of 4 KB, addressed 0…63

1Divide the disk into blocks

A simple file system uses one block size β€” here 4 KB. Our tiny partition is 64 blocks, addressed 0…63. Everything the FS stores must fit in these blocks.

step 1 / 5

The final layout: block 0 is the superblock (S), blocks 1–2 are the inode and data bitmaps (i, d), blocks 3–7 are the inode table (I), and blocks 8–63 are the data blocks (D). A bitmap is dead simple β€” one bit per object, 0 = free, 1 = in-use β€” one bitmap for inodes, one for data.

40.3 File Organization: The Inode

The inode (β€œindex node”) is the key structure. Each is named by its i-number, and β€” because inodes are fixed-size and packed in an array β€” the FS computes an inode’s disk location directly from that number:

blk=inumberΓ—sizeof(inode)blockSize\text{blk} = \frac{\text{inumber} \times \text{sizeof(inode)}}{\text{blockSize}} sector=(blkΓ—blockSize)+inodeStartAddrsectorSize\text{sector} = \frac{(\text{blk} \times \text{blockSize}) + \text{inodeStartAddr}}{\text{sectorSize}}

For inode 32 (256 B inodes, inode table starting at 12 KB): the byte offset is 32 Γ— 256 = 8192, so the block sits at 12 KB + 8 KB = 20 KB, i.e. disk sector 20 KB / 512 = 40. Inside the inode is the file’s metadata plus its block pointers:

A simplified ext2 inode (Fig 40.1): metadata plus the block pointers. Sizes in bytes.
sizefieldpurpose
mode2moderead/write/execute permissions
uid/gid2+2uid / gidowner user and group
size4sizefile length in bytes
times4Γ—4time / ctime / mtime / dtimeaccess / create / modify / delete times
links_count2links_countnumber of hard links
blocks4blocksnumber of blocks allocated
block60block15 disk pointers (12 direct + single/double/triple indirect)
Dotted-underlined cells have explanations β€” click one.

The multi-level index

How does the inode record where the data blocks are? A few direct pointers (disk addresses) live right in the inode β€” enough for small files. For bigger files, an indirect pointer points to an indirect block filled with 1024 more pointers; a double indirect pointer adds a level (1024 Γ— 1024 blocks), and a triple adds another. This imbalanced tree is the multi-level index :

inodedirect Γ— 12indirectdouble indir.data Γ— 12indirect blk1024 ptrsdata Γ— 10242Γ— indirdata Γ— 1024Β² (β‰ˆ4 GB)

With 12 direct + single + double indirect pointers, 4 KB blocks and 4-byte addresses, a file can reach:

(12+1024+10242)Γ—4 KBβ‰ˆ4 GB(12 + 1024 + 1024^2) \times 4\,\text{KB} \approx 4\,\text{GB}

Why this lopsided design? Because of a truth that holds across the decades β€” most files are small β€” so it’s worth making the common case (a handful of direct pointers) cheap, and paying the indirect-block cost only for the rare big file:

Figure 40.2: file-system truths that hold across the decades β€” and why the inode optimizes for small files.
findingdetail
smallMost files are small~2 KB is the most common size
growingAverage file size is growingalmost 200 KB on average
bytesMost bytes are in large filesa few big files use most of the space
manyFile systems hold lots of files~100K on average
halfFile systems are ~half fullstays ~50% full even as disks grow
dirsDirectories are smallmost have 20 or fewer entries
Dotted-underlined cells have explanations β€” click one.

Tip: Consider Extent-Based Approaches

Instead of a pointer per block, an extent is a disk pointer plus a length (in blocks) β€” one extent describes a whole contiguous run. Extent-based file systems (XFS, ext4) allow several extents per file. They’re less flexible than pointers but far more compact, and work well when files can be laid out contiguously β€” which allocation policy aims for anyway.

Check yourself: vsfs layout and the inode

1.What two aspects should you understand to grasp any file system?

2.In the vsfs layout (S i d I I I I I D…D), what is the superblock (S) for?

3.Why can the file system compute an inode's disk location directly from its i-number?

4.How does a bitmap track allocation, and when is it consulted?

5.How do direct and indirect pointers differ in the multi-level index?

6.Why is the multi-level index an imbalanced tree (a few direct pointers, then indirect levels)?

6 questions