With the group structure in place, FFS needs an allocation policy allocation policy The rules a file system uses to DECIDE where on disk to place inodes and data blocks (as opposed to the data structures that record the result). FFS's mantra: keep related stuff together (a file's data near its inode; files in a directory near each other) and unrelated stuff apart. defined in ch. 41 β open in glossary : rules for where to put inodes and data. The mantra is simple β keep related stuff together (and unrelated stuff apart).
41.4 Policies: Placing Files and Directories
FFS uses a few common-sense heuristics. Directories go in a group with few existing directories (to spread them out) and many free inodes (so its files can be allocated nearby). Files follow two rules: put a fileβs data blocks in the same group as its inode (no more inodeβdata seek), and put files from the same directory in the same group. Watch it against a naive alternative:
1FFS policy: keep a directory's files together
The root / is in Group 0. Directory /a and ALL its files (c, d, e) go in Group 1 β so their inodes and data sit together. Directory /b and its file f go in Group 2. Accessing /a/c then /a/d then /a/e stays within one group: short seeks.
41.5 Measuring Locality
Does directory-based grouping actually match how files are used? The namespace locality namespace locality The tendency for files that are close in the directory tree to be accessed close together in time (e.g. compiling all the files in one directory). FFS exploits it by placing files from the same directory in the same group. Distinct from spatial/temporal locality, which are about addresses/time. defined in ch. 41 β open in glossary in real traces (SEER) says yes: measure the directory-tree distance between consecutive file accesses (0 = same file, 1 = same directory, 2 = shared grandparentβ¦), and about 40% of accesses are at distance 0 or 1 β exactly what FFS optimizes:
| tree distance | frequency (Trace) | meaning | |
|---|---|---|---|
| 0 | 0 | ~7% | the very same file re-opened |
| 0-1 | 0 or 1 | ~40% (cumulative) | same file, or a sibling in the same directory |
| 2 | 2 | +~25% | shared grandparent directory |
| random | Random baseline | much less | randomly ordered accesses β some locality only because all files share the root |
Notably, a big chunk of accesses are at distance 2 (jumping between sibling
directories like src and obj) β locality FFSβs one-level policy does not
capture.
41.6 The Large-File Exception
Thereβs one problem with βkeep a fileβs blocks in its groupβ: a large file would fill an entire group, leaving no room for the related small files that also want to live there. So FFS makes the large-file exception large-file exception FFS's rule that overrides 'keep a file's blocks in one group' for big files: after a chunk (e.g. the 12 direct blocks) fills part of a group, later chunks spill into other groups. This stops one large file from filling a group and destroying locality for related small files β at the cost of extra seeks, amortized by using large enough chunks. defined in ch. 41 β open in glossary :
1Without the exception
File /a is 30 blocks; groups hold 40 data blocks each. Placing all of /a in Group 0 fills it almost entirely β leaving no room for other files related to / (which also wants Group 0).
Spreading a file across groups obviously hurts sequential reads β but amortization rescues it: if each chunk is big enough, you spend most of your time transferring and little time seeking between chunks. With a 40 MB/s disk and 10 ms average positioning, the chunk needed for 50% of peak bandwidth is:
Push for higher bandwidth and the chunk grows fast:
| target bandwidth | chunk size needed | |
|---|---|---|
| 50 | 50% of peak | 409.6 KB |
| 90 | 90% of peak | 3.69 MB |
| 99 | 99% of peak | 40.6 MB |
FFS itself used a simpler rule tied to the inode: the first 12 (direct) blocks go in the inodeβs group, and each indirect blockβs worth of data (1024 blocks = 4 MB) goes in a different group.
Check yourself: FFS policies and the large-file exception
1.What is FFS's core allocation-policy mantra?
2.Under FFS, where do files /a/c, /a/d, and /a/e end up, and why does that help?
3.What did the SEER traces reveal about namespace locality?
4.Why does FFS make an exception for large files?
5.Spreading a large file across groups hurts sequential reads. How does FFS keep performance acceptable?
6.As you target a higher fraction of peak bandwidth, what happens to the required chunk size, and why does this matter over time?