G27
Self-checkedTier 1 15 min reados.file-allocation

File allocation methods and inodes

How the blocks of a file are placed on the disk and found again: contiguous, linked, FAT and indexed allocation with their access costs, the Unix inode with direct and indirect pointers, the maximum file size, the number of disk accesses to read a given block, and the size of a FAT.

Why it exists

A disk offers numbered blocks. A file system must decide which blocks hold which file, and keep enough information to find block number kk of a file quickly. The choice is a trade between three things: fast access (sequential and direct), efficient use of space (no waste, files that can grow), and small bookkeeping. Four classical methods, contiguous, linked (with its table version, the FAT), indexed and the combined Unix inode scheme, embody different trades. GATE asks, over and over, for the maximum file size of an inode scheme and for the number of disk accesses to read a given block, and for the size of a FAT.

Prerequisites

You need files, directories and inodes from file systems.

Precise definitions

Block. The unit of transfer between disk and memory (512 bytes to a few kilobytes). A file occupies a whole number of blocks; its last block is partly empty (internal fragmentation, on average half a block per file).

Contiguous allocation. Each file occupies a set of consecutive blocks. The directory entry holds the start block and the length.

  • Direct access to block kk: start +k+ k, one disk access; sequential access is fastest (the head moves little).
  • Problems: external fragmentation (free space split into runs too small for a new file), the final size must be known when the file is created (or space is over-reserved), and a file that grows may have to be moved. Compaction is expensive.

Linked allocation. Each file is a linked list of blocks that may be anywhere on the disk; each block holds a pointer to the next. The directory entry holds the first (and often the last) block.

  • No external fragmentation, files grow freely.
  • Block kk can be reached only by following kk pointers: k+1k + 1 disk accesses for logical block kk (counting from 0), so direct access is slow.
  • The pointer takes space (a block of BB bytes holds B−pB - p bytes of data); a damaged pointer loses the rest of the file.

File allocation table (FAT). Linked allocation with the pointers stored in a table, with one entry per disk block: the entry of block bb holds the number of the block that follows it in its file (or a special end-of-file value; unused blocks have entry 0). The directory entry holds the first block. The FAT is cached in memory, so following the chain costs no disk accesses: reading logical block kk is one disk access (to the data block), and direct access is fast. Disadvantages: the table (all its entries) must be in memory and is big for a big disk.

FAT size=(number of blocks)×(entry size),entry size≥⌈log⁡2(number of blocks)⌉ bits.\text{FAT size} = (\text{number of blocks}) \times (\text{entry size}), \qquad \text{entry size} \ge \lceil \log_2 (\text{number of blocks}) \rceil \text{ bits}.

Indexed allocation. Each file has an index block that holds the block numbers of all its data blocks; entry ii is the block of logical block ii. The directory entry points to the index block.

  • No external fragmentation; direct access is easy: 2 disk accesses for a block (the index block, then the data block), or 1 if the index block is cached.
  • The index block is overhead even for a tiny file. A file with more blocks than an index block can hold needs more than one index block: linked index blocks (the last entry points to the next index block), a multilevel index (an index of index blocks), or the combined scheme.

Combined scheme: the Unix inode. The inode, kept in memory when the file is open, holds the attributes and:

  • DD direct pointers (usually 12) to data blocks,
  • one single indirect pointer to a block of pointers to data blocks,
  • one double indirect pointer to a block of pointers to blocks of pointers to data blocks,
  • one triple indirect pointer, one level deeper again.

With block size BB and pointer size pp one indirect block holds n=B/pn = B/p pointers. The number of data blocks an inode can address is

D+n+n2+n3,maximum file size=(D+n+n2+n3)⋅BD + n + n^2 + n^3, \qquad \text{maximum file size} = (D + n + n^2 + n^3) \cdot B

(drop the terms of the levels that the inode does not have). Small files use only direct pointers (no extra blocks at all); large files pay for indirect blocks. Disk accesses to read logical block kk (inode in memory, indirect blocks not cached): 11 if k<Dk < D; 22 if in the single range (D≤k<D+nD \le k < D + n); 33 in the double range; 44 in the triple range. (Each level of indirection adds one access.)

Comparison.

MethodDirect access to block kkExternal fragmentationGrowthOverhead
contiguous1 accessyeshardnone
linkedk+1k + 1 accessesnoeasypointer in every block
FAT1 access (table in memory)noeasythe table in memory
indexed2 accesses (1 if cached)noeasy up to the index sizeindex block per file
inode1 to 4 accessesnoeasyindirect blocks for large files

How it works

All the animations use a disk of 32 blocks (the inode one uses 64), drawn as a grid; each block shows the file and logical position it holds (A3 is the fourth block of file A), and the blocks read in a step are numbered in reading order. The panel at the right shows the directory entry, FAT, index block or inode.

Contiguous. File C starts at block 12; reading logical block 3 is one access (block 15). The animation also shows the problem: file B cannot grow because C follows it, and the free space (19 blocks) is split into runs of 2, 3 and 14 so a 15-block file does not fit.

Contiguous allocation: start

Layout built by script, not typed

Contiguous allocation. Disk of 32 blocks.

0
·
1
·
2
A0
3
A1
4
A2
5
A3
6
·
7
·
8
·
9
B0
10
B1
11
B2
12
C0
13
C1
14
C2
15
C3
16
C4
17
C5
18
·
19
·
20
·
21
·
22
·
23
·
24
·
25
·
26
·
27
·
28
·
29
·
30
·
31
·
blocks read in this step
-
disk accesses so far
0
directory entry of C
start block12
length6

Step 0

Contiguous allocation: each file occupies a run of consecutive blocks, and its directory entry holds just the START block and the LENGTH. Files A, B and C are stored; the free runs are (0, 2), (6, 3), (18, 14) (start, length).

0 / 3
computed by script: the file is stored by the allocation method and read through its on-disk structure. python3 scripts/gen-os-fs-traces.py

Linked. File A is the chain 3, 7, 4, 12, 9; reading logical block 4 means reading all five blocks in order: 5 accesses.

Linked allocation: start

Layout built by script, not typed

Linked allocation. Disk of 32 blocks.

0
·
1
·
2
·
3
A0
→7
4
A2
→12
5
B0
→6
6
B1
→10
7
A1
→4
8
·
9
A4
end
10
B2
end
11
·
12
A3
→9
13
·
14
·
15
·
16
·
17
·
18
·
19
·
20
·
21
·
22
·
23
·
24
·
25
·
26
·
27
·
28
·
29
·
30
·
31
·
blocks read in this step
-
disk accesses so far
0
directory entry of A
first block3
last block9

Step 0

Linked allocation: a file is a chain of blocks that can be ANYWHERE on the disk; each block holds a POINTER to the next (shown as an arrow and a number). The directory entry has only the first and last block of file A. There is no external fragmentation and a file can grow by taking any free block.

0 / 2
computed by script: the file is stored by the allocation method and read through its on-disk structure. python3 scripts/gen-os-fs-traces.py

FAT. The same chain with the pointers in a table in memory: the walk 3, 7, 4, 12, 9 costs nothing, and the single disk read is block 9.

File allocation table: start

Layout built by script, not typed

FAT: linked allocation with the pointers in a table in memory. Disk of 32 blocks.

0
·
1
·
2
·
3
A0
4
A2
5
·
6
·
7
A1
8
·
9
A4
10
·
11
·
12
A3
13
·
14
·
15
·
16
·
17
·
18
·
19
·
20
·
21
·
22
·
23
·
24
·
25
·
26
·
27
·
28
·
29
·
30
·
31
·
blocks read in this step
-
disk accesses so far
0
FAT (one entry per block)
37
74
412
129
9EOF

Step 0

File allocation table (FAT): the linked chain, but the POINTERS are moved out of the data blocks into one table, the FAT, with one entry per disk block (the entry of block b is the number of the block that follows it, or EOF). The FAT is read into MEMORY, so following the chain costs no disk accesses. The data blocks hold only data. The directory entry holds the first block (3).

0 / 1
computed by script: the file is stored by the allocation method and read through its on-disk structure. python3 scripts/gen-os-fs-traces.py

Indexed. File A's index block (20) lists its data blocks; reading logical block 3 reads the index block, then block 11: 2 accesses; the next read, with the index in memory, costs 1.

Indexed allocation: start

Layout built by script, not typed

Indexed allocation (one index block per file). Disk of 32 blocks.

0
·
1
·
2
A1
3
·
4
·
5
A0
6
·
7
·
8
·
9
·
10
·
11
A3
12
·
13
·
14
·
15
·
16
·
17
A2
18
·
19
·
20
idx A
index
21
·
22
·
23
·
24
·
25
·
26
A4
27
·
28
·
29
·
30
·
31
·
blocks read in this step
-
disk accesses so far
0
index block 20 of A
entry 05
entry 12
entry 217
entry 311
entry 426

Step 0

Indexed allocation: ALL the pointers of a file are gathered in one INDEX BLOCK (block 20); entry i is the block number of logical block i. The directory entry points to the index block. Data blocks can be anywhere, there is no external fragmentation, and direct access is easy. The cost is the index block itself (a file of one block still needs an index block).

0 / 2
computed by script: the file is stored by the allocation method and read through its on-disk structure. python3 scripts/gen-os-fs-traces.py

Unix inode (toy sizes). Blocks of 32 bytes and 4-byte pointers give 8 pointers per indirect block; the inode has 4 direct pointers, a single and a double indirect pointer. Reading logical block 2 costs 1 access, block 7 costs 2, and block 25 costs 3.

Unix inode allocation: start

Layout built by script, not typed

Combined (Unix inode) allocation: direct, single and double indirect pointers. Disk of 64 blocks.

0
·
1
F0
2
F1
3
F2
4
F3
5
·
6
F:S
indirect
7
F4
8
F5
9
F6
10
·
11
F7
12
F8
13
F9
14
F10
15
·
16
F11
17
F:D
double
18
F:D0
indirect
19
F12
20
·
21
F13
22
F14
23
F15
24
F16
25
·
26
F17
27
F18
28
F19
29
F:D1
indirect
30
·
31
F20
32
F21
33
F22
34
F23
35
·
36
F24
37
F25
38
F26
39
F27
40
·
41
F:D2
indirect
42
F28
43
F29
44
·
45
·
46
·
47
·
48
·
49
·
50
·
51
·
52
·
53
·
54
·
55
·
56
·
57
·
58
·
59
·
60
·
61
·
62
·
63
·
blocks read in this step
-
disk accesses so far
0
inode of F (in memory)
direct[0]1
direct[1]2
direct[2]3
direct[3]4
single indirect6
double indirect17

Step 0

Unix inode allocation (toy sizes): a block is 32 bytes and a pointer 4 bytes, so an indirect block holds 8 pointers. The inode, kept in memory while the file is open, has 4 DIRECT pointers, one SINGLE indirect pointer and one DOUBLE indirect pointer. Small files need no index block at all; larger ones add one or two levels. The file F has 30 blocks: logical blocks 0 to 3 are direct, 4 to 11 go through the single indirect block, and the rest through the double indirect block.

0 / 3
computed by script: the file is stored by the allocation method and read through its on-disk structure. python3 scripts/gen-os-fs-traces.py

Worked examples

EX 1Maximum file size and access counts, by program

Easy

Block size 1 KB, 4-byte pointers (256 pointers per block), an inode with 12 direct pointers and single, double and triple indirect pointers.

#include <stdio.h>
 
/* blocks addressable by an inode with `direct` direct pointers and one single, double and triple indirect pointer */
static unsigned long long max_blocks(unsigned direct, unsigned per_block) {
    unsigned long long n = direct, p = 1;
    for (int level = 1; level <= 3; level++) { p *= per_block; n += p; }
    return n;
}
 
/* disk blocks read to fetch logical block k, with the inode in memory */
static int accesses(unsigned long long k, unsigned direct, unsigned per_block) {
    if (k < direct) return 1;
    k -= direct;
    unsigned long long p = 1;
    for (int level = 1; level <= 3; level++) {
        p *= per_block;
        if (k < p) return 1 + level;
        k -= p;
    }
    return -1;
}
 
int main(void) {
    unsigned block = 1024, ptr = 4, per = block / ptr;
    unsigned long long n = max_blocks(12, per);
    printf("block %u bytes, pointer %u bytes: %u pointers per block\n", block, ptr, per);
    printf("12 direct + single + double + triple: %llu blocks, %.2f GB\n", n, (double)n * block / (1024.0 * 1024 * 1024));
    printf("direct only: %u KB; with the single indirect block: %u KB\n", 12 * block / 1024, (12 + per) * block / 1024);
    unsigned long long ks[7] = {0, 11, 12, 267, 268, 65803, 65804};
    printf("disk accesses for logical blocks:");
    for (int i = 0; i < 7; i++) printf(" %llu->%d", ks[i], accesses(ks[i], 12, per));
    printf("\n");
    /* 512-byte blocks, 4-byte pointers, 10 direct, single and double indirect only */
    unsigned long long m = 10 + 128 + 128ull * 128;
    printf("10 direct + single + double with 512-byte blocks: %llu blocks, %llu KB\n", m, m * 512 / 1024);
    /* FAT: a 16 GB disk with 4 KB blocks */
    unsigned long long blocks = (16ull << 30) / 4096;
    int bits = 0;
    while ((1ull << bits) < blocks) bits++;
    printf("FAT for a 16 GB disk with 4 KB blocks: %llu entries of %d bits (stored in 4 bytes): %llu MB\n", blocks, bits, blocks * 4 / (1024 * 1024));
    printf("linked allocation: %d data bytes in a 512-byte block, %d in a 4096-byte block\n", 512 - 4, 4096 - 4);
    return 0;
}
block 1024 bytes, pointer 4 bytes: 256 pointers per block
12 direct + single + double + triple: 16843020 blocks, 16.06 GB
direct only: 12 KB; with the single indirect block: 268 KB
disk accesses for logical blocks: 0->1 11->1 12->2 267->2 268->3 65803->3 65804->4
10 direct + single + double with 512-byte blocks: 16522 blocks, 8261 KB
FAT for a 16 GB disk with 4 KB blocks: 4194304 entries of 22 bits (stored in 4 bytes): 16 MB
linked allocation: 508 data bytes in a 512-byte block, 4092 in a 4096-byte block

Reading it. The inode addresses 12+256+65536+16 777 216=16 843 02012 + 256 + 65536 + 16\,777\,216 = 16\,843\,020 blocks, 16.06 GB at 1 KB per block. The ranges of logical blocks and their costs: 0 to 11 direct (1 access), 12 to 267 single indirect (2), 268 to 65803 double (3), 65804 on triple (4). The second case (512-byte blocks, no triple indirect pointer) has 128 pointers per block and 10+128+1282=1652210 + 128 + 128^2 = 16522 blocks, about 8.07 MB. The FAT for the big disk takes 16 MB of memory, which is why a FAT is used on small disks and for removable media.

EX 2Reading the toy inode

Medium

Blocks of 32 bytes, pointers of 4 bytes: 8 pointers per indirect block; 4 direct pointers, one single and one double indirect. Logical blocks 0 to 3 are direct. Logical block 7: after the 4 direct blocks, 7−4=37 - 4 = 3 is entry 3 of the single indirect block: read the indirect block, then the data block: 2 accesses. Logical block 25: 25−4=2125 - 4 = 21; the single indirect range holds 8, so 21−8=1321 - 8 = 13 is in the double range; 13=1×8+513 = 1 \times 8 + 5: entry 1 of the double indirect block names an inner indirect block, whose entry 5 names the data block: 3 accesses (double, inner, data). The largest file here has 4+8+64=764 + 8 + 64 = 76 blocks. A search over every logical block of several toy inode shapes confirmed that each maps to a distinct pointer path and that their number equals D+n+n2D + n + n^2.

EX 3Which method suits which need?

Medium

A file that is written once and read in order (a video, a backup): contiguous allocation (fast sequential reading) if the size is known. A file that grows by appending (a log): linked, FAT, indexed or inode (no relocation). Fast random access to any block of a big file: indexed, FAT or inode, not plain linked (it needs k+1k + 1 accesses). No external fragmentation: all but contiguous. The disk must be usable by a small system with very little memory: not the FAT (its table must be in memory). Mostly small files: the inode (no index block at all for the first 12 blocks).

EX 4Maximum size with 4 KB blocks

GATE level

Blocks of 4 KB, 4-byte pointers: n=1024n = 1024 pointers per block. An inode with 12 direct pointers, one single and one double indirect pointer addresses 12+1024+10242=1 049 61212 + 1024 + 1024^2 = 1\,049\,612 blocks, which is 1 049 612×4096=4 299 210 7521\,049\,612 \times 4096 = 4\,299\,210\,752 bytes, a little over 4 GB (4 GB ++ 4 MB ++ 48 KB). With only direct and single indirect pointers the maximum would be (12+1024)×4(12 + 1024) \times 4 KB =4144= 4144 KB. A change of pointer size changes nn: with 8-byte pointers and 4 KB blocks, n=512n = 512. The disk size can limit it too: a pointer of pp bytes can number at most 28p2^{8p} blocks, so with 4-byte pointers the disk addressable is at most 2322^{32} blocks. Questions often ask the maximum file size and then ask for the number of disk accesses to read the last block of that maximum file: with the triple indirect pointer in use, 4.

EX 5Contiguous against linked

GATE level

A file of 100 blocks. Reading block 60 (counting from 0): contiguous 1 access; linked 60+1=6160 + 1 = 61 accesses; FAT 1; indexed 2 (or 1 if the index is cached). Reading the whole file sequentially: contiguous 100 accesses with very short head movements; linked 100 accesses, but the blocks may be scattered, so each access needs a seek. Appending 10 blocks: linked just takes 10 free blocks and fixes pointers; contiguous may need to move the whole file if the next blocks are used. The external fragmentation example in the first animation: 19 free blocks in runs of 2, 3 and 14 cannot hold a file of 15 blocks.

Cheat box

Cheat box

  • Contiguous: start and length; 1 access; external fragmentation; hard to grow. Linked: pointer in each block; k+1k + 1 accesses; no fragmentation; pointer overhead pp per block.
  • FAT: table with one entry per BLOCK in memory; 1 disk access; size == blocks ×\times entry size, entry ≥⌈log⁡2blocks⌉\ge \lceil \log_2 \text{blocks} \rceil bits.
  • Indexed: index block; 2 accesses (1 if cached). Pointers per block n=B/pn = B/p.
  • Inode: DD direct, single, double, triple. Max blocks =D+n+n2+n3= D + n + n^2 + n^3; max size == blocks ×B\times B.
  • Accesses to block kk (inode in memory): 1 direct, 2 single, 3 double, 4 triple.
  • Internal fragmentation: half a block per file on average.

Traps and GATE patterns

Connections

Each method rests on the files and inodes of file systems. Contiguous allocation has the external fragmentation of contiguous memory allocation, and the inode's levels of pointers are the same idea as a multilevel page table: the number of levels adds one access each. Where the blocks lie decides how far the head must move, which is the subject of disk scheduling.

PYQs

8 previous year questions from your book. I re-solved each one myself (6 by running or simulating, 2 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2025 · MCQQ7 · page 341 of the book
A disk of size 512M bytes is divided into blocks of
64K bytes. A file is stored in the disk using linked
allocation. In linked allocation, each data block
reserves 4 bytes to store the pointer to the next data
block. The link part of the last data block contains
a NULL pointer (also of 4 bytes). Suppose a file of
1M bytes needs to be stored in the disk. Assume,
1K = 210 and 1M = 220. The amount of space in
bytes that will be wasted due to internal
fragmentation is ______. (Answer in integer)
GATE 2025 · NATQ3 · page 357 of the book
A disk of size 512 M bytes is divided into blocks of
64 K bytes. A file is stored in the disk using linked
allocation. In linked allocation, each data block
reserves 4 bytes to store the pointer to the next data
block. The link part of the last data block contains a
NULL pointer (also of 4 bytes). Suppose a file of 1 M
bytes needs to be stored in the disk. Assume, 1 K =
210and 1 M = 220. The amount of space in bytes that
will be wasted due to internal fragmentation is
______
GATE 2022 · NAT · 2 marksQ7 · page 358 of the book
Consider two files systems A and B, that use
contiguous allocation and linked allocation,
respectively. A file of size 100 blocks is already
stored in A and also in B. Now, consider inserting
a new block in the middle of the file
(between 50th and 51st block), whose data is
already available in the memory. Assume that there
are enough free blocks at the end of the file and that
the file control blocks are already in memory. Let
the number of disk accesses required to insert a
block
in
the
middle
of
the
file
in A and B are  nA and nB, respectively, then the
value of nA+nB is__________________.
GATE 2019 · NATQ10 · page 358 of the book
The index node (inode) of a Unix-like file system has
12 direct, one single-indirect and one double-indirect
pointers. The disk block size is 4 kB, and the disk
block address is 32-bits long. The maximum possible
file size is (rounded off to 1 decimal place) ______
GB.
GATE 2017 · Set 2 · MCQ · 1 markQ12 · page 359 of the book
In a file allocation system, which of the following
allocation scheme(s) can be used if no external
fragmentation is allowed?
1. Contiguous
2. Linked
3. Indexed
  • (a)1 and 3 only
  • (b)2 only
  • (c)3 only
  • (d)2 and 3 only
year not read yetQ18 · page 359 of the book
A FAT (file allocation table) based file system is
being used and the total overhead of each entry in the
FAT is 4 bytes in size. Given a 100 × 106 bytes disk
on which the file system is stored and data block size
is 103 bytes, the maximum size of a file that can be
stored on this disk in units of 106 bytes is
____________.

OPERATING SYSTEMS
GATE 2012 · MCQ · 2 marksQ21 · page 360 of the book
A file system with 300 Gbyte disk uses a file
descriptor with 8 direct block addresses, 1 indirect
block address and 1 doubly indirect block address.
The size of each disk block is 128 Bytes and the
size of each disk block address is 8 Bytes. The
maximum possible file size in this file system is
  • (a)3 KBytes
  • (b)35 KBytes
  • (c)280 Kbytes
  • (d)dependent on the size of the disk
GATE 2008 · MCQ · 1 markQ26 · page 361 of the book
The data blocks of a very large file in the Unix file
system are allocated using
  • (a)contiguous allocation
  • (b)linked allocation
  • (c)indexed allocation
  • (d)an extension of indexed allocation

Self-check

Question 1

Blocks of 512 bytes, 4-byte pointers, an inode with 10 direct pointers and one single indirect pointer. Maximum file size?

Show answer

n=512/4=128n = 512/4 = 128. Blocks =10+128=138= 10 + 128 = 138; size =138×512=70656= 138 \times 512 = 70656 bytes (69 KB).

Question 2

Same inode (with also a double indirect pointer). How many disk accesses to read logical block 200 (counting from 0)?

Show answer

Direct 0 to 9, single 10 to 137; 200>137200 > 137, so it is in the double range: 3 accesses.

Question 3

A FAT disk has 2 million blocks. How many bits must each entry have at least, and how big is the table with 4-byte entries?

Show answer

⌈log⁡2(2×106)⌉=21\lceil \log_2 (2 \times 10^6) \rceil = 21 bits (since 221=2 097 152≥2 000 0002^{21} = 2\,097\,152 \ge 2\,000\,000). With 4-byte entries: 8 000 0008\,000\,000 bytes, about 7.6 MB.

Question 4

Which allocation method needs no extra disk access to find block kk of a file once the file is open, and does not suffer external fragmentation?

Show answer

The FAT (the chain is followed in memory, one access reads the data); an inode with only direct pointers also qualifies for small files.

Revision card

One-screen revision

  • Contiguous: start, length, 1 access, external fragmentation. Linked: k+1k + 1. FAT: table of blocks in memory, 1 access. Indexed: index block, 2 accesses.
  • Inode: n=B/pn = B/p; blocks D+n+n2+n3D + n + n^2 + n^3; accesses 1, 2, 3, 4 by range.
  • FAT size == blocks ×\times entry size; entry ≥⌈log⁡2blocks⌉\ge \lceil \log_2 \text{blocks} \rceil bits.

References

  • ·Silberschatz, Galvin, Gagne, Operating System Concepts, Chapter 14 File-System Implementation (allocation methods)
  • ·Tanenbaum and Bos, Modern Operating Systems, Chapter 4 File Systems (implementing files, i-nodes)
  • ·Stallings, Operating Systems: Internals and Design Principles, Chapter 12 File Management (file allocation)

Verification

Each layout is built by a script (scripts/gen-os-fs-traces.py) and the blocks read for a logical block are computed by following the on-disk structure (the chain, the FAT, the index block, the inode pointers); tests/os-fs-traces.test.ts rebuilds each path from the cells' own labels and notes and rechecks the read order and the access counts, and scripts/enum-checks/os_fs.py checks by brute force that a toy inode (several sizes) maps every logical block to a distinct pointer path and that their number equals the formula. The size and access-count figures (16843020 blocks = 16.06 GB for 12 direct + 256 + 256^2 + 256^3 blocks of 1 KB; 16522 blocks for the 512-byte-block case; a 16 MB FAT for a 16 GB disk with 4 KB blocks) are exact arithmetic checked in Python and by the C program on this page (npm run verify:c). Conventions that change answers: the inode is in memory when the file is open; the index or indirect blocks are not cached; a pointer is 4 bytes unless stated; the FAT is in memory. Textbook chapter titles are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand. No defect found. Status raised to self-checked; verified needs a textbook or human check.

last verified: never