๐Ÿ“š L11: File System Implementations

Lecture Goal

Understand how file systems are implemented at the disk level, including block allocation schemes, free space management, and directory structures.

The Big Picture

A file system bridges the logical view (files and folders) with the physical reality (disk blocks). The key challenge is mapping files to disk blocks efficiently โ€” balancing speed, space utilization, and flexibility. Different allocation schemes (contiguous, linked, FAT, indexed) make different trade-offs, and understanding these is essential for systems programming.


1. Disk Organization

๐Ÿค” The Layered View

A disk is viewed differently at each layer:

flowchart TB
    subgraph User["User View"]
        U["Files & Folders"]
    end

    subgraph OS["OS (File System) View"]
        F["Flat array of logical blocks"]
    end

    subgraph HW["Hardware View"]
        H["Physical sectors on tracks/platters"]
    end

    User -->|"abstraction"| OS
    OS -->|"mapping"| HW

    style User fill:#e1f5fe
    style OS fill:#c8e6c9
    style HW fill:#fff3e0

The disk is organized as a 1-D array of logical blocks, where the block is the smallest accessible unit (typically 512 bytes to 4 KB).

๐Ÿ“€ Disk Layout

flowchart LR
    subgraph Disk["Physical Disk"]
        MBR["MBR<br/>(sector 0)"]
        P1["Partition 1"]
        P2["Partition 2"]
        PN["Partition N"]
    end

    MBR --> P1
    P1 --> P2
    P2 --> PN

    style MBR fill:#ff9999
    style P1 fill:#c8e6c9
    style P2 fill:#c8e6c9
    style PN fill:#c8e6c9

Each partition contains:

flowchart LR
    subgraph Partition["Partition Contents"]
        Boot["OS Boot Block"]
        Details["Partition Details"]
        Dir["Directory Structure"]
        Info["Files Info"]
        Data["File Data"]
    end

    style Boot fill:#fff9c4
    style Details fill:#e1f5fe
    style Dir fill:#e8f5e9
    style Info fill:#e8f5e9
    style Data fill:#e3f2fd
RegionPurpose
MBR (sector 0)Master Boot Record; partition table + boot code
OS Boot BlockInstructions to boot the OS on this partition
Partition DetailsTotal blocks, number/location of free blocks
Directory StructureMaps file names to their information
Files InfoMetadata and block locations for each file
File DataThe actual file contents

๐Ÿ“š Key Terminology

TermDefinition
Logical BlockOS abstraction; smallest addressable unit in the FS
Physical SectorHardware-level storage unit on disk
MBRMaster Boot Record; first sector with partition table
PartitionLogical subdivision of a disk with its own FS

โš ๏ธ Common Pitfalls

Pitfall 1: Confusing logical blocks with physical sectors

Logical blocks are an OS abstraction; physical sectors are hardware reality. The mapping between them is hardware-dependent.

Pitfall 2: MBR is global

The MBR is global to the disk, while each partition has its own independent file system.

Pitfall 3: Internal fragmentation

The last block of a file may be partially filled, wasting space (internal fragmentation).


โ“ Mock Exam Questions

Q1: Logical vs Physical

What is the difference between a logical block and a disk sector?

Answer

Answer: Logical blocks are OS abstractions; disk sectors are hardware units

A logical block is how the OS views storage (e.g., 4 KB blocks). A disk sector is the physical hardware unit (e.g., 512 bytes). Multiple sectors may map to one logical block.

Q2: Partition Contents

What information is stored in the Partition Details region?

Answer

Answer: Total blocks, number and location of free blocks

Partition Details contains metadata about the partition itself, not file contents.


2. File Block Allocation Schemes

๐ŸŽฏ The Core Problem

Since a file is logically a collection of blocks, the OS must decide how to allocate disk blocks to files.

2a. Contiguous Allocation

flowchart LR
    subgraph Directory["Directory Entry"]
        Name["file name"]
        Start["start block"]
        Len["length"]
    end

    subgraph Disk["Disk Blocks"]
        B0["Block 0"]
        B1["Block 1"]
        B2["Block 2"]
        B3["Block 3"]
        B4["Block 4"]
    end

    Start --> B0
    Len -->|"2 blocks"| B1

    style B0 fill:#c8e6c9
    style B1 fill:#c8e6c9

Every file occupies consecutive disk blocks. Directory entry stores start block and length.

ProsCons
Simple implementationExternal fragmentation โ€” free space scattered
Fast sequential and random accessFile size must be declared in advance

2b. Linked List Allocation

flowchart LR
    subgraph Dir["Directory Entry"]
        First["first block"]
        Last["last block"]
    end

    subgraph Chain["Block Chain"]
        B9["Block 9<br/>+ptrโ†’16"] --> B16["Block 16<br/>+ptrโ†’1"]
        B16 --> B1["Block 1<br/>+ptrโ†’10"]
        B1 --> B10["Block 10<br/>+ptrโ†’25"]
        B10 --> B25["Block 25<br/>-1 (END)"]
    end

    First --> B9
    Last --> B25

    style B9 fill:#c8e6c9
    style B16 fill:#c8e6c9
    style B1 fill:#c8e6c9
    style B10 fill:#c8e6c9
    style B25 fill:#c8e6c9

Each block stores file data + pointer to next block. Directory stores first and last block numbers.

ProsCons
No external fragmentationSlow random access โ€” must follow N pointers
File can grow dynamicallyPointer wastes part of each block
Single corrupted pointer breaks chain

2c. FAT (File Allocation Table)

flowchart TB
    subgraph Memory["Memory"]
        FAT["FAT Table<br/>All pointers in RAM"]
    end

    subgraph Disk["Disk"]
        B9["Block 9"]
        B16["Block 16"]
        B1["Block 1"]
        B10["Block 10"]
        B25["Block 25"]
    end

    FAT -->|"9โ†’16โ†’1โ†’10โ†’25โ†’-1"| Disk

    style Memory fill:#fff9c4
    style Disk fill:#e1f5fe

All pointers moved to an in-memory table. FAT[i] holds the index of the next block after block i. -1 marks the end.

FAT Example: File "jeep" starts at block 9

FAT index | value (next block)
----------|-------------------
    1     |   10
    9     |   16
   10     |   25
   16     |    1
   25     |   -1   โ† end of file

Block chain: 9 โ†’ 16 โ†’ 1 โ†’ 10 โ†’ 25 โ†’ END

ProsCons
Fast random access (traversal in memory)FAT must track every disk block
No external fragmentationLarge memory consumption for big disks

2d. Indexed Allocation

flowchart LR
    subgraph Dir["Directory Entry"]
        Ptr["โ†’ Index Block"]
    end

    subgraph IndexBlock["Index Block 19"]
        I0["[0]โ†’9"]
        I1["[1]โ†’16"]
        I2["[2]โ†’1"]
        I3["[3]โ†’10"]
        I4["[4]โ†’25"]
        I5["[5]-1"]
    end

    subgraph Data["Data Blocks"]
        D9["Block 9"]
        D16["Block 16"]
        D1["Block 1"]
    end

    Ptr --> IndexBlock
    I0 --> D9
    I1 --> D16
    I2 --> D1

    style IndexBlock fill:#fff9c4
    style Data fill:#c8e6c9

Each file has a dedicated index block storing an array of data block addresses.

ProsCons
Fast direct access: jump to IndexBlock[N]Max file size limited by index block capacity
Only index blocks of open files in memoryIndex block overhead even for small files

2e. Indexed Allocation Variations (Large Files)

flowchart TB
    subgraph Inode["Unix Inode Structure"]
        D["Direct Pointers<br/>(12 entries)"]
        SI["Single Indirect<br/>(1 entry)"]
        DI["Double Indirect<br/>(1 entry)"]
        TI["Triple Indirect<br/>(1 entry)"]
    end

    D -->|"direct"| Data["Data Blocks"]
    SI -->|"index block"| SI_Blocks["Index Blocks"]
    DI -->|"index of indexes"| DI_Blocks["Double Level"]
    TI -->|"3 levels"| TI_Blocks["Triple Level"]

    style D fill:#c8e6c9
    style SI fill:#fff9c4
    style DI fill:#ffccbc
    style TI fill:#ff9999
SchemeHow It Works
Linked index blocksIndex blocks form a linked list
Multilevel indexIndex block points to other index blocks
Combined (Unix inode)Mix of direct, single, double, triple indirect pointers

Unix inode structure:

  • Direct block pointers โ†’ point directly to data blocks (fast for small files)
  • Single indirect โ†’ points to a block of direct pointers
  • Double indirect โ†’ points to a block of single-indirect pointers
  • Triple indirect โ†’ one more level deeper

๐Ÿ“Š Allocation Scheme Comparison

PropertyContiguousLinked ListFATIndexed
Sequential accessโœ… Fastโœ… OKโœ… OKโœ… OK
Random accessโœ… FastโŒ Slowโœ… Fastโœ… Fast
External fragmentationโŒ Yesโœ… Noโœ… Noโœ… No
Memory usageโœ… Lowโœ… LowโŒ Highโœ… Low
File size limitโŒ Fixed upfrontโœ… Flexibleโœ… FlexibleโŒ Limited

๐Ÿ“š Key Terminology

TermDefinition
Contiguous AllocationFile occupies consecutive disk blocks
External FragmentationFree space scattered across disk
FATFile Allocation Table; in-memory table of block pointers
Index BlockBlock storing array of data block addresses
InodeUnix data structure with direct/indirect block pointers

โš ๏ธ Common Pitfalls

Pitfall 1: FAT vs Linked List random access

In linked list, random access to block N requires N disk reads. In FAT, traversal is in memory โ€” only 1 disk read for the final block.

Pitfall 2: Indexed allocation file size limit

Max file size = (block size / pointer size) ร— block size. E.g., 4 KB block with 4-byte pointers = 1024 pointers โ†’ max ~4 MB with single-level index.

Pitfall 3: Unix inode efficiency

The direct blocks in Unix inodes let small files (the common case!) be accessed extremely quickly without traversing indirect pointers.


โ“ Mock Exam Questions

Q1: Random Access Speed

Why is random access slow in plain linked list allocation but faster with FAT?

Answer

Answer: FAT keeps all pointers in memory

In linked list, following pointers requires disk reads. In FAT, the chain is traversed entirely in memory โ€” only the final data block needs a disk read.

Q2: Sentinel Value

What is the purpose of the -1 sentinel value in FAT and indexed allocation?

Answer

Answer: Marks the end of the fileโ€™s block chain

-1 indicates no more blocks follow โ€” the file ends at this block.

Q3: Inode Design

Why does the Unix inode use a combination of direct, single-indirect, double-indirect, and triple-indirect pointers?

Answer

Answer: Optimizes for common case (small files) while supporting large files

Direct pointers give instant access for small files. Indirect pointers scale to handle very large files when needed.


3. Free Space Management

๐ŸŽฏ The Problem

The OS needs to track which disk blocks are free for allocation.

3a. Bitmap (Bit Vector)

flowchart LR
    subgraph Bitmap["Bitmap (32 bits)"]
        B["0 1 0 1 1 1 0 0 1 0 1 1 ..."]
    end

    Occupied["0, 2, 6, 7, 9..."]
    Free["1, 3, 4, 5, 8, 10, 11..."]

    Bitmap -->|"0 = occupied"| Occupied
    Bitmap -->|"1 = free"| Free

    style Bitmap fill:#fff9c4

Every disk block is represented by 1 bit: 1 = free, 0 = occupied.

Size calculation:

ProsCons
Efficient bit operations (AND, OR, scan)Must be kept in memory for performance
Easy to find contiguous free blocksLarge for big disks

3b. Linked List of Free Blocks

flowchart LR
    subgraph Memory["Memory"]
        Head["Head Pointer โ†’ Block 5"]
    end

    subgraph Disk["Disk Free Blocks"]
        B5["Block 5<br/>[8,12,19,22]<br/>โ†’ Block 30"]
        B30["Block 30<br/>[35,40...]<br/>โ†’ Block 50"]
        B50["Block 50<br/>..."]
    end

    Head --> B5
    B5 --> B30
    B30 --> B50

    style Memory fill:#fff9c4

Free blocks are chained. Each free block stores several free block numbers + pointer to next group.

ProsCons
Only head pointer needs to be in memoryHigh overhead if many free block lookups needed
Easy to allocate (take from head)Fetching next group requires disk I/O

๐Ÿ“š Key Terminology

TermDefinition
BitmapArray of bits, one per disk block, tracking free/used status
Free Block ListLinked structure tracking free disk blocks

โš ๏ธ Common Pitfalls

Pitfall 1: Forgetting to update free space

When a file is deleted, you must add its blocks to the free space structure. Skipping this causes leaked (permanently lost) disk blocks.

Pitfall 2: Bitmap persistence

The bitmap must be written back to disk periodically. A crash before this causes free space inconsistency.

Pitfall 3: Linked list I/O cost

Only the first group is in memory. Fetching the next group requires a disk read โ€” which is slow.


โ“ Mock Exam Questions

Q1: Bitmap Size

A 1 TB disk uses 4 KB blocks. How large is the bitmap?

Answer

Answer: 32 MB

Total blocks = blocks. Bitmap size = bytes = 32 MB.

Q2: Free Space Update

What operation does the OS perform on the free space list when a file is deleted?

Answer

Answer: Add the fileโ€™s blocks to the free space structure

All blocks previously used by the file are marked as free in the bitmap or added to the free list.


4. Directory Structure Implementation

๐ŸŽฏ Directory Purpose

A directory has two jobs:

  1. Track the files it contains (with metadata)
  2. Map file names to their file information

4a. Linear List

flowchart LR
    subgraph Dir["Directory (Linear List)"]
        E1["file1.txt โ†’ info"]
        E2["file2.txt โ†’ info"]
        E3["..."]
        E4["fileN.txt โ†’ info"]
    end

    Search["Lookup: O(N)"] --> Dir

    style Dir fill:#e1f5fe

Directory stored as sequential list. Search requires linear scan โ€” O(N).

ProsCons
Simple implementationSlow for large directories

4b. Hash Table

flowchart TB
    subgraph Hash["Hash Table Directory"]
        S0["Slot 0"]
        S1["Slot 1 โ†’ fileA, fileX (chain)"]
        S2["Slot 2 โ†’ fileB"]
        S3["Slot 3"]
    end

    Lookup["Hash(filename) โ†’ index"] --> Hash

    style Hash fill:#c8e6c9

Hash the file name โ†’ index K. Check HashTable[K] for matching entry.

ProsCons
O(1) average lookupFixed maximum size
Depends on hash function quality

4c. Storing File Information

ApproachWhatโ€™s in the Entry
All-in-oneFile name + all metadata + disk block info
Pointer-basedFile name + pointer to separate structure (e.g., inode)

Pointer-based (Unix) is more flexible โ€” multiple directory entries can point to the same inode (hard links).


๐Ÿ“š Key Terminology

TermDefinition
Linear List DirectorySequential list of directory entries
Hash Table DirectoryHash-indexed directory for O(1) lookup

โš ๏ธ Common Pitfalls

Pitfall 1: Directory doesn't contain file data

A directory stores metadata and pointers, not actual file contents.

Pitfall 2: Name duplicate check

When creating a file, the OS must first check for name duplicates in the parent directory.

Pitfall 3: Hash collisions

Two filenames may hash to the same slot. Chaining (linked list at each slot) handles this.


โ“ Mock Exam Questions

Q1: Hash vs Linear

Why is a hash table preferred over a linear list for large directories?

Answer

Answer: O(1) average lookup vs O(N) scan

Hash tables provide constant-time lookup regardless of directory size, while linear lists require scanning all entries.

Q2: Pointer-based Entries

What is the advantage of storing only a pointer to file information in the directory entry?

Answer

Answer: Enables hard links and flexible metadata management

Multiple directory entries can point to the same file structure (inode), allowing hard links.


5. File System in Action

๐Ÿ”„ Runtime Data Structures

flowchart TB
    subgraph Process["Process P"]
        FD["File Descriptor Table<br/>(per-process)"]
    end

    subgraph OS["OS Kernel"]
        Open["System-Wide Open File Table"]
        Cache["Directory Cache"]
        Buffer["Disk Block Buffer Cache"]
    end

    subgraph Disk["Disk"]
        DirData["Directory Data"]
        FileData["File Data"]
    end

    FD -->|"fd โ†’ entry"| Open
    Open -->|"file info"| FileData
    Cache --> DirData
    Buffer --> FileData

    style Process fill:#e1f5fe
    style OS fill:#c8e6c9
    style Disk fill:#fff3e0
StructureScopePurpose
Per-process FD tablePer processMaps fd numbers to open file table entries
System-wide open file tableGlobalStores file info, offset, for all open files
Directory cacheGlobalCaches recently accessed directory entries
Buffer cacheGlobalCaches recently read/written disk blocks

5a. File Create

flowchart TD
    Start["create(/path/to/parent/F)"] --> Traverse["Traverse path to parent"]
    Traverse --> Check["Search parent for F"]
    Check -->|"Found"| Error["Error: duplicate name"]
    Check -->|"Not found"| FindFree["Find free disk blocks"]
    FindFree --> AddEntry["Add entry to parent directory"]
    AddEntry --> Done["File created"]

    style Error fill:#ff9999
    style Done fill:#c8e6c9

5b. File Open

flowchart TD
    Start["open(/path/to/F)"] --> Traverse["Traverse path to locate F"]
    Traverse -->|"Not found"| Error["Error"]
    Traverse -->|"Found"| Load["Load F's info into open file table"]
    Load --> AddFD["Add entry to process FD table"]
    AddFD --> Return["Return fd to process"]

    style Error fill:#ff9999
    style Return fill:#c8e6c9

๐Ÿ“š Key Terminology

TermDefinition
File Descriptor TablePer-process table mapping fd numbers to open files
Open File TableSystem-wide table tracking all open files
Buffer CacheIn-memory cache of disk blocks

โš ๏ธ Common Pitfalls

Pitfall 1: FD numbers are per-process

Different processes can have the same fd number pointing to different files. FD is just an index into the processโ€™s own table.

Pitfall 2: Open file table is global

Two processes opening the same file get separate entries (independent offsets), unless sharing via fork().

Pitfall 3: Disk vs Memory structures

Inode is on disk. Itโ€™s read into the open file table at open() time. Donโ€™t confuse the two.


โ“ Mock Exam Questions

Q1: Independent Opens

Two processes both open the same file independently. Do they share a file offset?

Answer

Answer: No โ€” each has independent offset

Independent open() calls create separate entries in the system-wide open file table with separate offsets.

Q2: FD Scope

What does a file descriptor number refer to?

Answer

Answer: Index into the processโ€™s own file descriptor table

FD numbers are meaningful only within a process. Different processes can have the same FD number for different files.


6. Disk I/O Scheduling

โฑ๏ธ Disk Access Time

StageDescriptionTypical Range
Seek timeMove head to correct track2โ€“10 ms
Rotational latencyWait for sector under head2โ€“6.25 ms
Transfer timeRead/write dataVery fast (ยตs)

Seek and rotational latency dominate โ€” the OS schedules requests to minimize head movement.


6a. FCFS (First Come First Served)

Requests served in arrival order. Simple but can cause large head movements.

FCFS Example

Requests: [13, 14, 2, 18, 17, 21, 15], starting at track 13 Path: 13โ†’14โ†’2โ†’18โ†’17โ†’21โ†’15 Total movement = 1+12+16+1+4+6 = 40 tracks


6b. SSF (Shortest Seek First)

Always serve the request closest to current head position.

SSF Example

Requests: [13, 14, 2, 18, 17, 21, 15], starting at track 13 Order: 13โ†’14โ†’15โ†’17โ†’18โ†’21โ†’2 Total movement = 1+1+2+1+3+19 = 27 tracks

ProsCons
Minimizes total head movementCan starve far-away requests

๐Ÿ“š Key Terminology

TermDefinition
Seek TimeTime to move disk head to correct track
Rotational LatencyTime for correct sector to rotate under head
FCFSFirst Come First Served scheduling
SSFShortest Seek First scheduling

โš ๏ธ Common Pitfalls

Pitfall 1: FCFS fairness

FCFS is fair but inefficient โ€” requests served in order regardless of head position.

Pitfall 2: SSF starvation

SSF can starve requests far from the busy area if nearby requests keep arriving.

Pitfall 3: Transfer time

Transfer time is negligible compared to seek + latency for small reads. Donโ€™t overweight it.


โ“ Mock Exam Questions

Q1: Seek vs Transfer

Why does seek time dominate transfer time in magnetic disk performance?

Answer

Answer: Mechanical movement is slow; electronic transfer is fast

Moving the disk head (mechanical) takes milliseconds. Transferring data (electronic) takes microseconds โ€” 1000ร— faster.

Q2: SSF Disadvantage

What is the main disadvantage of SSF compared to FCFS?

Answer

Answer: Starvation of far-away requests

If requests near the current head position keep arriving, far-away requests may never be served.


7. Practice Problems

๐Ÿ“ Problem 1: Indexed Allocation

A disk uses indexed allocation with 512-byte blocks and 4-byte block addresses.

(a) How many pointers fit in one index block?

(b) What is the maximum file size with single-level index?

(c) What is the maximum file size with double-indirect pointer?

Solution

(a) Pointers per index block:

(b) Max file size (single-level):

(c) Max file size (double-indirect):

  • First level: 128 index blocks
  • Each second-level: 128 data blocks

๐Ÿ“ Problem 2: FAT Traversal

File โ€œalphaโ€ starts at block 3. The FAT contains:

IndexValue
37
712
1220
20-1

(a) List all blocks belonging to โ€œalphaโ€ in order.

(b) How many disk reads to access the 3rd block with plain linked list?

(c) How many disk reads with FAT (FAT in memory)?

Solution

(a) Block chain: 3 โ†’ 7 โ†’ 12 โ†’ 20

(b) Plain linked list: Must read blocks 3, 7, then 12. Answer: 3 disk reads

(c) FAT in memory: Chain traversal is free. Only need to read block 12. Answer: 1 disk read


๐Ÿ“ Problem 3: Disk Scheduling

Disk head at track 10. Requests: [3, 20, 5, 18, 8, 25, 12]

(a) Calculate total head movement using FCFS.

(b) Calculate total head movement using SSF.

Solution

(a) FCFS: Serve in arrival order.

10 โ†’ 3 โ†’ 20 โ†’ 5 โ†’ 18 โ†’ 8 โ†’ 25 โ†’ 12
    7  + 17 + 15 + 13 + 10 + 17 + 13 = 92 tracks

Answer: 92 tracks

(b) SSF: Always pick closest.

10 โ†’ 12 (2) โ†’ 8 (4) โ†’ 5 (3) โ†’ 3 (2) โ†’ 18 (15) โ†’ 20 (2) โ†’ 25 (5)
Total: 2+4+3+2+15+2+5 = 33 tracks

Answer: 33 tracks

SSF is better: 33 vs 92 tracks.


๐Ÿ”— Connections

๐Ÿ“š Lecture๐Ÿ”— Connection
L10File system implementation builds on file concepts from L10
L9Virtual memory paging concepts apply to file buffer cache
L7Memory allocation concepts parallel disk block allocation

The Key Insight

A file system is all about mapping โ€” mapping logical files to physical blocks, mapping names to metadata, mapping free blocks to allocation requests. The genius of different allocation schemes is in their trade-offs: contiguous for speed, linked for flexibility, indexed for balance. The Unix inodeโ€™s multi-level design is particularly elegant โ€” optimizing for the common case (small files) while scaling to handle the uncommon case (huge files). ๐Ÿ’พ