Allocation Methods for File Storage

Imagine a disk as a long street of numbered houses, each house one block wide. A file is a family that needs several houses to live in. This family can grow, shrink, or move away entirely. The file system's job is to decide which houses each family occupies. It must also find all of a family's houses later. Finally, it must track empty houses for newcomers. This is the allocation problem. Every general-purpose file system — ext4, NTFS, HFS+, FAT — must solve it. The stakes are concrete. A poor allocation strategy wastes disk space. It also forces slow seeks across a fragmented disk. It makes it expensive to grow a file. A good strategy supports fast sequential reads and cheap random access. It also allows graceful growth. All this must happen while keeping metadata overhead small. Rotating disks pay a heavy seek penalty. Even SSDs prefer large sequential transfers. So the physical layout chosen by the allocation method directly affects throughput. This effect is measurable. This article covers the three classical allocation strategies — contiguous, linked, and indexed. It also covers the free-space management structures (bitmaps and free lists). These structures make allocation decisions possible. It builds on Inodes and File Metadata, since every allocation method must ultimately be recorded somewhere in the file's metadata. It also builds on File-System Implementation and Layout, which describes where that metadata lives on disk. By the end, you will be able to trace exactly how a file's blocks are located from its metadata. You will be able to compute the space and time cost of each method. You will be able to explain why modern file systems layer indexing with extents. You will also see how allocation choices set up the crash-consistency and redundancy problems. These problems are tackled in Journaling and Crash Consistency and RAID and Redundant Storage.

Key takeaways
  • Contiguous allocation gives O(1) access but suffers external fragmentation and forces files to guess their final size.
  • Linked allocation eliminates external fragmentation but only supports fast sequential access; random access is O(n).
  • Indexed allocation (index blocks / inodes with pointers) supports O(1) random access to any block via one indirection.
  • Multi-level and extent-based indexing (as in ext4) let a single small metadata structure address huge files efficiently.
  • Free-space is tracked with bitmaps (compact, easy to find contiguous runs) or free lists (simple, but harder to find contiguity).
  • Fragmentation is the central trade-off: external fragmentation plagues contiguous allocation, internal fragmentation plagues fixed-block schemes with rounding.
The core insight

The allocation method is a data structure mapping logical file blocks to physical disk blocks, and every design trades access speed against space efficiency and fragmentation.

The idea

Allocation is the strategy a file system uses to assign disk blocks to a file and to record that assignment so the blocks can be found again. Disks are divided into fixed-size blocks (or clusters), typically 4 KB, the smallest unit the file system manages. A file of logical size LL bytes needs ⌈L/B⌉\lceil L / B \rceil blocks, where BB is the block size; the file system must choose which physical blocks these are and store a mapping from logical block number (0, 1, 2, … within the file) to physical block number on disk. Three classical strategies solve this mapping problem. Contiguous allocation stores a file as one run of consecutive blocks, recording only a starting block and a length. Linked allocation stores a file as a chain of blocks, each holding a pointer to the next, so metadata is just a head pointer. Indexed allocation gathers all of a file's block pointers into one or more dedicated index blocks, so the mapping is an explicit array rather than an implicit run or chain. Real systems (ext4, NTFS) use hybrids — extent-based indexing — that combine the compactness of contiguous runs with the flexibility of indexed pointers. Orthogonal to allocation is free-space management: the file system must always know which blocks are unused so it can satisfy allocation requests. The two dominant structures are the bitmap (one bit per block, 1 = allocated) and the free list (a linked list threading through unused blocks, sometimes cached as a stack of free block numbers in memory). Both must support fast allocation, fast deallocation, and — ideally — fast discovery of runs of contiguous free blocks, since contiguity is what makes sequential I/O fast regardless of which allocation method is layered on top.

How it works

Contiguous allocation

The directory entry (or inode) stores only `(start_block, length)`. To access logical block ii of the file, compute physical block `start_block + i` directly — no traversal needed. ``` function CONTIG_READ(file, logical_block_i): if i >= file.length: error "out of range" physical = file.start_block + i return DISK_READ(physical) function CONTIG_ALLOCATE(size_in_blocks): // Requires finding a contiguous free run of the right size. run = FIND_FREE_RUN(size_in_blocks) // best-fit / first-fit / worst-fit if run == NONE: error "no contiguous space (may need compaction)" MARK_ALLOCATED(run.start, size_in_blocks) return run.start ``` `FIND_FREE_RUN` is the crux: as files are created and deleted, free space fragments into many small runs separated by allocated blocks — external fragmentation. Eventually a request for kk blocks may fail even though the disk has far more than kk free blocks in total, because no single run is long enough. The classic remedy is compaction (copy all files to squeeze free space together), which is correct but expensive — O(n)O(n) in total data moved, and it typically requires taking the file system offline or doing it incrementally. A refinement, extent-based allocation, stores a list of `(start, length)` pairs instead of one — a file is a small number of contiguous runs (extents) rather than one giant run. This keeps most of the sequential-access benefit while tolerating fragmentation gracefully; ext4 and NTFS both use extents.

Linked allocation

Each block contains data plus a pointer to the next block in the file; the last block's pointer is a sentinel (e.g., −1-1 or null). The directory/inode stores only the address of the first block (and often the last, to support fast appends). ``` function LINKED_READ(file, logical_block_i): ptr = file.head for k = 0 to i - 1: (data, ptr) = DISK_READ(ptr) // follow the chain if ptr == NULL: error "out of range" (data, next) = DISK_READ(ptr) return data function LINKED_APPEND(file, new_data): new_block = FIND_ONE_FREE_BLOCK() WRITE(new_block, new_data, next = NULL) if file.tail != NULL: UPDATE_NEXT_POINTER(file.tail, new_block) else: file.head = new_block file.tail = new_block ``` Free-space management is trivial for allocation itself: any single free block will do, since there is no contiguity requirement — this eliminates external fragmentation entirely (aside from unavoidable internal fragmentation in the last block). But random access to logical block ii costs O(i)O(i) disk reads because every prior block must be traversed to find the next pointer. Reliability is also fragile: a single corrupted pointer breaks the chain for every subsequent block. A well-known optimization, the File Allocation Table (FAT), pulls all the "next" pointers out of the data blocks and into one contiguous table cached in memory, turning traversal into fast in-memory array lookups while keeping data blocks pointer-free. ``` // FAT variant: table[i] = index of block following block i, or EOF function FAT_READ(file, logical_block_i): block = file.first_block for k = 0 to i - 1: block = FAT[block] // in-memory table, O(1) per step if block == EOF: error "out of range" return DISK_READ(block) ``` The FAT table itself, however, must be scanned linearly to find a free entry unless a separate free list or bitmap tracks free blocks — and the whole table typically must reside in memory to be useful, which does not scale to very large volumes.

Indexed allocation

Each file gets one index block holding an array of pointers, one per logical block. The inode stores only the address of the index block. ``` function INDEXED_READ(file, logical_block_i): index_block = DISK_READ(file.index_block_addr) if i >= LENGTH(index_block.pointers): error "out of range" physical = index_block.pointers[i] return DISK_READ(physical) function INDEXED_ALLOCATE_BLOCK(file, logical_block_i, data): p = FIND_ONE_FREE_BLOCK() WRITE(p, data) index_block = DISK_READ(file.index_block_addr) index_block.pointers[i] = p DISK_WRITE(file.index_block_addr, index_block) ``` Random access now costs one indirection (read the index block, typically cached in memory after the first access) plus one data read — O(1)O(1) disk accesses in the worst case, versus O(i)O(i) for pure linked allocation. External fragmentation on data blocks is gone (any free block works), but a single index block has a fixed capacity: with block size BB and pointer size pp bytes, it can address only B/pB/p blocks. For a 4 KB block and 4-byte pointers, that is 1024 blocks — only 4 MB per file, unacceptable for large files. The standard fix is multilevel indexing, exactly as used for Inodes and File Metadata in Unix-style inodes: direct pointers for small files, a single indirect block for medium files, a double indirect block (an index block of index blocks) for large files, and a triple indirect block for very large files. ``` function MULTILEVEL_TRANSLATE(inode, logical_block_i): N = POINTERS_PER_BLOCK // e.g., 1024 if i < NUM_DIRECT: return inode.direct[i] i -= NUM_DIRECT if i < N: // single indirect L1 = DISK_READ(inode.single_indirect) return L1.pointers[i] i -= N if i < N N: // double indirect L1 = DISK_READ(inode.double_indirect) L2 = DISK_READ(L1.pointers[i / N]) return L2.pointers[i % N] i -= N N if i < N N N: // triple indirect L1 = DISK_READ(inode.triple_indirect) L2 = DISK_READ(L1.pointers[i / (N*N)]) L3 = DISK_READ(L2.pointers[(i / N) % N]) return L3.pointers[i % N] error "file exceeds maximum addressable size" ``` Access time is bounded by the number of indirection levels touched — a small constant (at most 4 disk reads for the triple-indirect case, often fewer with caching), independent of file size, so it remains O(1)O(1) in the number of blocks the file occupies.

Free-space management

Bitmap. One bit per block: `bit[i] = 1` means block ii is allocated. Finding a free block is a linear scan for a 0 bit; finding kk contiguous free blocks is a scan for kk consecutive 0 bits, which the bitmap supports naturally because adjacency in the bitmap mirrors adjacency on disk. ``` function BITMAP_FIND_FREE_RUN(bitmap, k): run_start = -1 run_len = 0 for i = 0 to LENGTH(bitmap) - 1: if bitmap[i] == 0: if run_len == 0: run_start = i run_len += 1 if run_len == k: return run_start else: run_len = 0 return NONE ``` A bitmap for a 1 TB disk with 4 KB blocks needs 2302^{30} bits ≈\approx 128 MB — small enough to hold largely in memory, and word-at-a-time scanning (checking 64 bits per comparison) makes the common case fast in practice despite the O(n)O(n) worst case.

Free list. Each free block stores a pointer to the next free block, forming a linked list threaded through unused space; the file system keeps only a head pointer (and sometimes a count). Allocating one block is O(1)O(1): pop the head. But finding kk contiguous free blocks is not naturally supported — the list order need not reflect physical adjacency — so contiguous allocation on top of a pure free list typically requires an auxiliary structure (e.g., grouping the list by extent, or falling back to a bitmap-like scan). A common optimization caches a large array of free block numbers in memory (a "free list cache" or the FAT itself doubles as one) to avoid disk I/O for every allocation. ``` function FREELIST_ALLOCATE_ONE(): if free_list.head == NULL: error "disk full" b = free_list.head free_list.head = DISK_READ(b).next_free // O(1) return b function FREELIST_DEALLOCATE(b): DISK_WRITE(b, next_free = free_list.head) // O(1) free_list.head = b ```

Figure
Three allocation methods for the same logical file of four blocks
Contiguous 01 23 start=0, len=4 Linked blk 7 blk 2 blk 9 blk 4 → NULL head = 7 (only metadata stored) Indexed index block [0]→7 [1]→2 [2]→9 [3]→4 7 2 9 4 any block i: 1 lookup + 1 read

Complexity & correctness

Contiguous allocation. Sequential read of the whole file: O(n)O(n) blocks with no seek overhead between blocks (best possible for sequential I/O). Random access to block ii: O(1)O(1) — direct arithmetic on `start + i`. Allocation of a new file: O(D)O(D) in the worst case, where DD is the number of free-space fragments, since the allocator must scan for a run of the requested size using strategies like first-fit or best-fit. Correctness relies on the invariant that `(start, length)` always denotes a set of blocks currently marked allocated in the free-space structure and owned by exactly one file; any allocator that maintains this invariant (never returns overlapping runs) is correct by construction. The persistent weakness is space efficiency: even with Θ(n)\Theta(n) live data, the disk can become unusable because free space is not "usable" free space — this is the textbook definition of external fragmentation, and no local fix removes it without global compaction.

Linked allocation. Sequential read: O(n)O(n) blocks, but each block may be scattered anywhere on disk, so real wall-clock time picks up a seek between almost every block on a rotating disk — asymptotically O(n)O(n) but with a much worse constant than contiguous. Random access to block ii: O(i)O(i), since the chain must be walked from the head; worst case O(n)O(n) for the last block. Space overhead: one pointer per block (small, e.g., 4–8 bytes out of 4096), giving negligible internal fragmentation from the pointer itself. Correctness invariant: following `next` pointers from `head` visits exactly the blocks of the file, in logical order, terminating at a sentinel — true as long as no pointer is corrupted and no block is shared between two chains, which the allocator must guarantee by only ever allocating from the free set.

Indexed allocation (single index block). Random access: O(1)O(1) disk operations (one index-block read, cached after first touch, plus one data read). Space overhead: one pointer per file block, held in the index block(s) rather than inline, so data blocks carry zero overhead, but a whole block is spent per file just for the index even for a 1-block file — a form of internal fragmentation for small files. Maximum file size with one index block of B/pB/p pointers is B⋅(B/p)B \cdot (B/p) bytes. Multilevel indexing extends the addressable range multiplicatively at each level while keeping access time bounded: with LL levels beyond direct pointers, worst-case disk accesses to reach a data block is L+1L + 1 — a small constant independent of nn, because the branching factor N=B/pN = B/p (commonly 512–1024) makes even two levels of indirection address gigabytes of data, and three levels reach terabytes. This is the same complexity argument used to justify BB-tree-like fan-out elsewhere: constant depth for enormous capacity because depth grows as log⁡N(size)\log_N(\text{size}), and with N≈1000N \approx 1000, that log is effectively bounded by 3–4 for any realistic file size.

Free-space bitmap. Space: n/8n/8 bytes for nn blocks (1 bit each) — for a 1 TB disk at 4 KB blocks, about 128 MB, feasible to cache in RAM. Finding one free block: O(n)O(n) worst case (all allocated blocks scanned before a 0 bit is found), but with word-parallel scanning (test 64 bits at once) the practical constant shrinks by roughly 64×, and maintaining a "next free hint" pointer makes the amortized case close to O(1)O(1) under typical allocation/deallocation patterns. Finding a contiguous run of kk blocks: O(n)O(n) worst case, unavoidable in the worst case since contiguity is a global property, but bitmaps are the natural structure for this because bit adjacency mirrors block adjacency.

Free list. Space: one pointer per free block, stored in the free blocks themselves — effectively zero extra space beyond the head pointer, better asymptotically than a bitmap for space when free space is small, though bitmaps win when free space is large (a free list of mm free blocks needs mm pointer-writes; a bitmap is always n/8n/8 regardless of how many blocks are free). Allocate/deallocate one block: O(1)O(1) — pop/push the head. Finding contiguous runs: not supported without auxiliary structure, since list order is not tied to physical order; this is the chief reason many systems prefer bitmaps or grouped/extent-based free lists despite the free list's simplicity.

Worked example

Consider a small file system with 16 blocks (0–15), block size 4 KB, and a file `report.txt` that needs 4 blocks. Suppose blocks 2, 4, 7, and 9 are currently free among otherwise allocated blocks 0, 1, 3, 5, 6, 8, 10–15.

StepContiguousLinkedIndexed
Free blocks available2, 4, 7, 9 (no run of 4!)2, 4, 7, 92, 4, 7, 9
Can allocate 4-block file now?No — largest free run is length 1Yes — any 4 free blocksYes — any 4 free blocks + 1 index block
Blocks used for data— (must wait/compact)2, 4, 7, 9needs a 5th free block, say block 11, for the index
Metadata stored—head = 2index_block = 11
Chain / index contents—2→4, 4→7, 7→9, 9→NULLindex[0]=2, index[1]=4, index[2]=7, index[3]=9
Read logical block 3 (0-indexed)—follow 2→4→7→9: 3 disk reads then the data read = 4 totalread block 11 (index), read index[3]=9: 2 reads
Fragmentation exhibitedExternal — 4 free blocks exist but no contiguous run of 4None (any free block usable)None on data; 1 extra block (11) spent purely on metadata

This trace makes the trade-off concrete: contiguous allocation fails outright here despite 4 free blocks existing in total, because none of the strategies can conjure contiguity that does not exist — the request must wait for deletions to coalesce free space, or the system must compact. Linked allocation succeeds immediately but costs 3 extra disk reads to reach the last block (block 9) versus indexed allocation's fixed 2 reads regardless of which block is requested. Indexed allocation pays a one-block metadata tax (block 11) that neither of the other schemes pays directly, though contiguous allocation pays an implicit tax in its `(start, length)` inode fields and linked allocation pays it in per-block pointer overhead spread across all four data blocks. Now suppose the file grows to 1200 blocks with a 4-byte pointer and 4 KB blocks (N=1024N = 1024 pointers per index block), and the inode has 12 direct pointers. Using the multilevel scheme:

1200−12=1188 blocks addressed via indirection.1200 - 12 = 1188 \text{ blocks addressed via indirection}.

Since 1188<10241188 < 1024, a single indirect block is not enough (it only reaches 12+1024=103612 + 1024 = 1036 blocks); block 1200 falls into the double indirect range, which starts at logical block 10361036 and can address up to 12+1024+10242≈1,049,61212 + 1024 + 1024^2 \approx 1{,}049{,}612 blocks. Reaching logical block 1199 (0-indexed 1188th indirect block) costs: 1 read for the double-indirect block, 1 read for the appropriate first-level index block within it, 1 read for the data block — 3 disk operations total, regardless of whether the target were block 1199 or block 1,000,000. That constancy is exactly the O(1)O(1)-in-file-size claim made above.

Common pitfalls & traps

PitfallWhy it happensFix
Assuming linked allocation gives O(1) random accessConfusing "no external fragmentation" with "fast access"; students conflate the two independent axesRemember: fragmentation and access speed are separate metrics — trace the chain explicitly
Forgetting the last block's internal fragmentationFixed block size means a file of size not a multiple of BB wastes part of its last block, in every methodAlways account for ⌈L/B⌉⋅B−L\lceil L/B\rceil \cdot B - L wasted bytes regardless of allocation strategy
Treating bitmap scans as always O(n)O(n) in practiceIgnoring word-parallel bit tricks and free-hint pointers that make the common case much fasterState worst case honestly, but note amortized/practical behavior separately
Believing indexed allocation has zero overheadThe index block(s) themselves consume space and must be read, so tiny files pay a disproportionate metadata costCompare index-block overhead against file size explicitly, especially for 1-block files
Losing a pointer in a linked list on crashA single corrupted `next` pointer strands every subsequent block, with no way to detect it in isolationUse FAT-style external tables or checksummed/doubly-linked structures; motivates Journaling and Crash Consistency
Assuming compaction is "free" because it fixes fragmentationCompaction moves O(n)O(n) data and typically requires quiescing the file systemWeigh compaction cost against simply over-provisioning free space or using extents

Pioneers & history

Origins · 1 minDennis M. Ritchie and how this was discovered
DM
Dennis M. Ritchie
1941–2011 · Bell Labs, co-creator of Unix and the C language

Ritchie, with Ken Thompson, designed the Unix file system whose inode-based indexed allocation — direct, single, double, and triple indirect blocks — became the template that this article's multilevel indexing scheme describes almost verbatim, and that shaped Inodes and File Metadata design for decades afterward.

History
1969
— Unix file system introduces inode-based indexed allocation with direct and indirect blocks.
1977
— Microsoft's FAT file system popularizes table-based linked allocation for floppy disks and early PCs.
1984
— 4.2BSD Fast File System introduces block groups and better free-space locality to reduce fragmentation.
1993
— NTFS introduces the Master File Table and extent-based allocation for large, reliable volumes.
2008
— ext4 adds extent-based allocation to the Linux ext family, replacing pure indirect-block indexing for large files.

Where this matters

Every mainstream file system is a variant or hybrid of these three ideas. FAT12/16/32 and exFAT use table-based linked allocation, still found on USB drives, SD cards, and camera storage because of its simplicity and universal compatibility. ext2/ext3 used classic Unix indexed allocation with direct/indirect/double-indirect/triple-indirect pointers; ext4 and XFS moved to extent-based allocation, representing large contiguous runs compactly to reduce both metadata size and fragmentation for large files (video, databases, virtual machine disk images). NTFS stores file layout as a run list of extents inside the Master File Table, blending contiguous runs with indexed flexibility. Database systems and virtual machine hypervisors often bypass the general-purpose file system entirely and manage raw block allocation themselves, using the same bitmap/free-list trade-offs to control fragmentation for performance-critical workloads. SSD-aware file systems and log-structured file systems (e.g., F2FS) lean toward append-only, sequential allocation patterns precisely because random writes interact badly with flash translation layers, echoing the sequential-access advantage of contiguous allocation. The layout decisions made here directly determine what must be logged or checksummed to survive a crash, which is the subject of Journaling and Crash Consistency, and how blocks are striped or mirrored across disks for durability and throughput, the subject of RAID and Redundant Storage.

Ask the tutor: How does extent-based allocation in ext4 combine the benefits of contiguous and indexed allocation while avoiding their respective weaknesses?

Why don't modern file systems just use pure contiguous allocation, since it's the fastest?

Contiguous allocation is fastest for sequential access and gives O(1) random access via simple arithmetic, but it suffers badly from external fragmentation: as files are created, resized, and deleted, free space breaks into many small runs, and eventually a request for a large contiguous block can fail even though total free space is ample. It also requires knowing (or guessing) a file's final size at creation time, which is impractical for files that grow unpredictably, like logs or databases. Modern systems instead use extent-based allocation, a compromise that stores a list of contiguous runs per file, getting most of the sequential-access benefit while tolerating fragmentation and dynamic growth. Pure contiguous allocation survives mainly in specialized contexts like CD-ROM/ISO9660 file systems, where the file set is fixed and known in advance, eliminating the fragmentation problem entirely.

How does FAT differ from a general linked-list allocation scheme?

Plain linked allocation stores each block's "next" pointer inside the data block itself, so following the chain requires a disk read at every single step, and random access to block i costs O(i) disk reads. FAT (File Allocation Table) pulls all of those pointers out of the data blocks and collects them into one contiguous table, which is typically small enough to cache entirely in memory. Traversing the chain then becomes O(i) memory accesses instead of disk accesses, which is far faster in practice even though the asymptotic complexity for full traversal from the head is unchanged. The trade-off is that the FAT table itself must be scanned (or separately indexed) to find free entries, and very large volumes make the table large enough that fully caching it becomes impractical, which motivated the move to inode-based indexed allocation in Unix and its descendants.

Why do inodes use direct pointers plus indirect blocks instead of one flat index for every file?

A single flat index block can only address as many blocks as fit in one block divided by the pointer size — for 4 KB blocks and 4-byte pointers, about 1024 blocks, or 4 MB, far too small for modern files. Multilevel indexing solves this by using a small number of direct pointers for the common case of small files (avoiding any indirection overhead for the majority of files, which are small), while reserving single, double, and even triple indirect pointers for progressively larger files. Because the branching factor per index block is large (roughly 1000), even two or three levels of indirection can address terabytes of data while keeping worst-case access time to a small constant number of disk reads. This design directly parallels why shallow, high-fan-out trees like B-trees are preferred over deep binary trees for on-disk structures.

Bitmap or free list: which should a new file system use?

It depends on the expected ratio of free to allocated space and the importance of contiguous allocation. Bitmaps cost a fixed n/8 bytes regardless of how much space is actually free, but they make it easy and natural to search for runs of k contiguous free blocks because adjacent bits represent adjacent blocks — valuable for extent-based or contiguous allocators trying to minimize fragmentation. Free lists cost essentially nothing extra when free space is small (pointers are stored inside the free blocks themselves) and support O(1) single-block allocation and deallocation, but they do not naturally expose contiguity information, since list order need not match physical order. Most production systems favor bitmaps or bitmap-like structures (sometimes grouped per block-group, as in ext-family file systems) specifically because they support the contiguous-run queries that extent-based allocation needs.

Does SSD storage make allocation method choice less important?

Somewhat, but not entirely. SSDs eliminate the mechanical seek penalty that makes scattered blocks catastrophically slow on rotating disks, so linked allocation's poor locality is less punishing than it once was. However, SSDs still strongly prefer large sequential writes over many small random writes because of how the flash translation layer, garbage collection, and wear leveling work internally, so contiguous or extent-based allocation still improves throughput and reduces write amplification. Metadata compactness still matters too, since indirect-block chasing still costs real I/O operations even if each one is fast, and fewer, larger index structures reduce the total operation count. Log-structured file systems, which lean toward purely sequential, append-only allocation, are popular specifically on flash for this reason.

What happens when an indexed-allocation file system's index block itself gets corrupted?

Losing or corrupting the index block is catastrophic for that file because every data-block pointer lives in one place: without it, none of the file's blocks can be located even though the data blocks themselves may be perfectly intact on disk. This single-point-of-failure risk is one reason production file systems replicate or checksum critical metadata blocks, and it is precisely the class of problem that motivates Journaling and Crash Consistency — by logging metadata updates before committing them, a system can recover a consistent index block after a crash rather than losing the mapping entirely. Some systems also maintain redundant copies of critical index structures (superblocks, inode tables) specifically to survive localized corruption.

How does allocation method interact with RAID?

Allocation methods determine the logical block-to-physical-block mapping within a single logical volume, while RAID and Redundant Storage determines how logical blocks are further spread across multiple physical disks for redundancy and throughput. A file system using extent-based or contiguous allocation tends to generate large, sequential write patterns that map efficiently onto RAID stripes, maximizing parallel throughput across disks in schemes like RAID-0 or RAID-5. Conversely, a fragmented, linked-list-style layout can scatter a single file's blocks across many different stripes unnecessarily, undermining RAID's ability to batch large sequential transfers. In this sense, allocation strategy and RAID striping strategy are complementary layers: good allocation reduces logical fragmentation, and good RAID design turns that contiguity into parallel physical bandwidth.

Before this

Where this leads