Disk Structure and Geometry
Imagine a database server that must fetch a customer record. That record sits among a billion rows on spinning magnetic disks. The record might live anywhere on the disk. The physical distance between the read head and the data matters. It can cost the CPU millions of wasted cycles of waiting. Understanding why that wait happens starts with understanding disk geometry. This means understanding platters, tracks, sectors, and cylinders. This geometry is not a historical curiosity. It is the reason operating systems schedule I/O requests. It explains why sequential access is prized over random access. It explains why database designers obsess over data layout. A hard disk drive (HDD) is a mechanical device wearing a digital costume. Underneath the abstraction lies a linear array of numbered blocks. But beneath that lies a spinning stack of magnetic platters. A mechanical arm carries read/write heads across them. Real physical motion takes real physical time. The operating system's storage stack sits atop a single simplifying interface. This stack includes file systems, the I/O scheduler, and the Device Driver layer. The simplifying interface is the logical block address, which hides this geometry. But the performance consequences of that geometry leak through the abstraction constantly. This is why every OS course teaches the mechanics first. Only then does it teach the scheduling policies built on top. This article builds the geometric model of a disk from the platter up. It shows how data is physically arranged into tracks, sectors, and cylinders. It shows how the operating system numbers these locations using logical block addressing (LBA). It shows how a single I/O request decomposes into three additive time components. These are seek time, rotational latency, and transfer time. We derive the classic access-time formula. We show why cylinders (not tracks) are the natural unit of "locality" for scheduling. We reason carefully about one key difference. That is the difference between the drive's physical layout and what the OS is permitted to see. By the end, you will be able to compute the expected service time for a disk request. You will do this from manufacturer specifications. You will explain why seek time dominates on rotating media. You will see precisely why this chapter is a prerequisite for further study. It prepares you for Disk Scheduling Algorithms. It prepares you for understanding why Solid-State Drives (SSDs) eliminate an entire term from the cost equation. It prepares you for reasoning about RAID and Redundant Storage layouts. Such layouts must respect this same physical geometry.
- A hard disk is organized as platters → tracks (concentric rings) → sectors (fixed-size arcs) → cylinders (same track index across all platters).
- The OS addresses disk storage as a flat array of Logical Block Addresses (LBA); the drive controller translates LBA to physical cylinder/head/sector internally.
- Total disk access time = seek time + rotational latency + transfer time, each governed by different physical mechanisms.
- Seek time (arm movement) and rotational latency (waiting for the platter to spin into position) dominate cost for random access; transfer time is comparatively cheap.
- Average rotational latency is exactly half a revolution, a direct consequence of uniform random target-sector position.
- Because seek time is the largest and most variable term, Disk Scheduling Algorithms exist specifically to minimize cumulative arm movement.
A disk's access time is dominated by mechanical motion (seek and rotation), not electronic transfer, so all higher-layer scheduling exists to minimize that motion.
The idea
A hard disk drive stores data on one or more rigid circular platters, each coated with a magnetizable film and spinning on a common spindle at a constant angular velocity, typically 5,400 to 15,000 revolutions per minute (RPM). Data on each platter surface is arranged into concentric rings called tracks. Each track is subdivided into fixed-size arcs called sectors, historically 512 bytes and now commonly 4,096 bytes (the "4Kn" or Advanced Format standard). A cylinder is the set of tracks at the same radial distance across all platter surfaces — moving the read/write head assembly to a given radius accesses one cylinder's worth of tracks simultaneously, one per surface, without further arm movement. The read/write heads are mounted on a single actuator arm assembly, so all heads move together in lockstep; you cannot position the head on platter 1 independently from the head on platter 2. This mechanical coupling is precisely why the cylinder — not the track — is the natural unit of "free" locality: once the arm has paid the cost of a seek to reach a cylinder, the OS can read any track within that cylinder (by switching to a different head electronically) at negligible extra cost, and it can read many sectors around that cylinder as the platters rotate beneath the heads. The operating system and application software never manipulate cylinder/head/sector (CHS) triples directly in modern systems. Instead, the storage stack addresses the disk through Logical Block Addressing (LBA): the entire drive's sectors are numbered sequentially from `0` to `N−1`, and the drive's own firmware (the disk controller) performs the LBA-to-physical translation internally, including remapping around bad sectors transparently. This indirection is a clean instance of the same abstraction principle used throughout the storage stack — the Device Driver issues LBA-based commands over an interface such as SATA or NVMe, and the physical geometry is entirely hidden below that interface. The OS's file system allocates logical blocks, but performance-aware allocation and scheduling policies still reason about the physical consequences of LBA choices, because contiguous LBAs are (usually, though not perfectly, since manufacturers may remap) contiguous in physical space.
How it works
Every disk I/O request — read or write a block at a given LBA — resolves mechanically through three sequential phases, and the total service time is their sum:
Seek time is the time for the actuator arm to move the read/write heads radially from their current cylinder to the target cylinder. It has a fixed component (acceleration/deceleration overhead) and a variable component roughly proportional to the square root of the distance moved (because the arm accelerates, then decelerates, rather than moving at constant speed), though vendors typically publish only an average seek time and a track-to-track seek time as headline numbers.
Rotational latency is the time to wait for the platter to spin until the target sector rotates under the head, once the head is on the correct cylinder. Because the target sector's position relative to the head is effectively uniformly distributed over one revolution for a random access pattern, the average rotational latency is exactly half the time for one full revolution:
Transfer time is the time to actually move the requested bytes across the head-to-controller-to-bus path once the sector is under the head; it depends on the sector size, the number of sectors requested, and the drive's sustained transfer rate. ``` function disk_access_time(request, drive):
# request: target LBA and length; drive: geometry + timing specs current_cyl = drive.head_position_cylinder target_cyl = lba_to_cylinder(request.lba, drive.geometry)
# --- Seek phase --- distance = abs(target_cyl - current_cyl) if distance == 0: seek_time = 0 else: seek_time = drive.seek_overhead + drive.seek_per_cylinder * sqrt(distance)
# sqrt models the accelerate/decelerate motion profile;
# many textbook problems instead use the vendor's flat "average seek time"
# --- Rotational phase --- rotation_time_full = 60000.0 / drive.rpm # ms per full revolution
# Expected wait assuming target sector position is uniformly random: rotational_latency = rotation_time_full / 2.0
# --- Transfer phase --- bytes_per_track = drive.sectors_per_track drive.bytes_per_sector fraction_of_track = request.length_in_bytes / bytes_per_track transfer_time = fraction_of_track rotation_time_full total = seek_time + rotational_latency + transfer_time drive.head_position_cylinder = target_cyl # arm now parked here return total
function lba_to_cylinder(lba, geometry):
# geometry gives sectors_per_track and heads (surfaces) per cylinder sectors_per_cylinder = geometry.sectors_per_track geometry.heads cylinder = lba // sectors_per_cylinder remainder = lba % sectors_per_cylinder head = remainder // geometry.sectors_per_track sector = remainder % geometry.sectors_per_track return cylinder # (head, sector also available if physical CHS is needed) ``` The pseudocode makes explicit an important invariant: <strong>the seek cost of the next* request depends on where the arm currently sits, which is exactly the state that Disk Scheduling Algorithms manipulate by reordering the request queue to minimize cumulative arm travel. The transfer-time computation assumes data is read as a fraction of one track's worth of bytes per revolution — a simplification, but it is the standard first-order model used in every introductory treatment and it is dimensionally and physically sound: transfer rate is bytes-per-track divided by time-per-revolution.
Complexity & correctness
Space: the geometric model itself requires no per-request extra storage; the drive controller maintains a fixed-size translation table (or an algorithmic mapping) from LBA to physical CHS, which is additional state per drive, independent of the number of requests served.
Time per request: a single disk access, under the model above, costs
Seek time's dependence on distance (in cylinders) being rather than follows from basic kinematics: the arm accelerates for roughly the first half of the seek and decelerates for the second half, so for a constant-acceleration motion profile, distance traveled scales as (time)², giving . This is why manufacturers publish both a small "track-to-track" seek time and a much larger "average seek time" (over a random distance uniformly spread across the whole disk) — the relationship is sublinear, not linear, in distance.
Why rotational latency averages exactly half a revolution — the correctness argument: model the target sector's angular offset from the head, at the moment the head arrives at the correct cylinder, as a random variable uniformly distributed on (a reasonable assumption when the workload is not correlated with the disk's rotational phase, which holds for arbitrary/random access patterns). The wait time is where is the time for one full revolution. Then
using for a uniform distribution on . This is not a rough rule of thumb; it is an exact consequence of the uniformity assumption, and it is the reason every textbook average-latency formula divides RPM-derived revolution time by exactly 2.
Honesty about the model's limits. This is a first-order physical model, and real drives deviate from it in several ways worth naming explicitly:
- Zoned bit recording means outer tracks hold more sectors than inner tracks (to keep areal density roughly constant), so "bytes per track" is not a single constant across the disk — sequential transfer rate is higher on outer cylinders.
- The seek model is an idealization; real seek curves include fixed settling time and are often better approximated with a small constant term plus a square-root term, exactly as in the pseudocode above.
- Modern drive firmware performs command queuing (NCQ) and may reorder requests internally, so the OS-visible geometry is a controller-mediated approximation of the true physical layout, not a guarantee.
- LBA-contiguous blocks are usually physically contiguous, but bad-sector remapping and firmware-level wear leveling on hybrid drives can break this assumption silently.
The overall tradeoff this section sets up: because and are mechanical and dominate cost, while is comparatively cheap and scales gently with request size, the single biggest lever the OS has for HDD performance is minimizing seek distance across a batch of pending requests — which is precisely the job of Disk Scheduling Algorithms such as SCAN and C-SCAN.
Worked example
Consider a disk with the following published specifications, typical of a 7,200 RPM consumer HDD:
| Parameter | Value |
|---|---|
| Rotational speed | 7,200 RPM |
| Average seek time | 9 ms |
| Sectors per track | 500 |
| Bytes per sector | 512 |
| Track-to-track (adjacent cylinder) seek | 1 ms |
| Current head position | cylinder 4,000 |
| Request 1 target | LBA corresponding to cylinder 4,050 |
| Request 2 target (immediately after) | cylinder 4,051 |
Step 1 — Rotation time per revolution.
Step 2 — Average rotational latency.
Step 3 — Transfer time for one sector (512 bytes). One track holds bytes, transferred in ms, so:
Step 4 — Request 1: seek from cylinder 4,000 to 4,050 (distance 50). Using the average seek time figure directly (the common introductory simplification, treating any "typical" seek as costing the published average):
Step 5 — Request 2: seek from cylinder 4,050 to 4,051 (distance 1, adjacent cylinder). Here the track-to-track seek time applies instead, since the arm barely moves:
The lesson made concrete: servicing these two requests in this order (as they might arrive from independent processes) costs ms. But notice that request 2's tiny seek distance is only cheap because request 1 already moved the arm to a nearby cylinder. If instead the requests had arrived interleaved with a third request at cylinder 100, naive first-come-first-served order could force the arm to swing back and forth across nearly the whole disk — the exact expensive pattern that motivates Disk Scheduling Algorithms, which reorder the queue (e.g., by nearest-cylinder-first or by sweeping monotonically like an elevator) to keep consecutive seeks small, the way request 2 above was small purely by lucky ordering.
| Quantity | Request 1 (Δcyl = 50) | Request 2 (Δcyl = 1) |
|---|---|---|
| Seek time | 9.00 ms | 1.00 ms |
| Rotational latency (avg) | 4.17 ms | 4.17 ms |
| Transfer time | 0.017 ms | 0.017 ms |
| Total | ≈ 13.19 ms | ≈ 5.19 ms |
Common pitfalls & traps
| Pitfall | Why it's wrong | Fix |
|---|---|---|
| Treating seek time as linear in distance | Real arm motion accelerates/decelerates; cost grows sublinearly (), not proportionally | Use vendor average/track-to-track figures, or the model, not a naive linear scale-up |
| Assuming LBA-adjacent blocks are always physically adjacent | Bad-sector remapping and controller-level indirection can break contiguity | Treat LBA locality as a strong heuristic, not a hard physical guarantee |
| Forgetting zoned bit recording | Assuming a constant "sectors per track" across the whole disk overstates inner-track throughput and understates outer-track throughput | Use per-zone sector counts when precision matters; use average bytes/track only as an estimate |
| Computing rotational latency as zero or as a full revolution | Both ignore the actual physics of a randomly-positioned target sector | Use the expected value: half a revolution, derived from uniform-angle assumption |
| Confusing "track" with "cylinder" when reasoning about seek cost | Switching tracks within the same cylinder costs (almost) nothing — only head switching, not arm movement — while switching cylinders always costs a seek | Reserve "seek" language strictly for cylinder-to-cylinder arm motion |
Pioneers & history
The mechanical disk drive and its geometric model emerged from IBM's storage research, transforming computing from sequential tape-based storage into random-access secondary storage — a shift as consequential to systems design as the stored-program concept was to computer architecture itself.
Origins · 1 minReynold B. Johnson and how this was discovered
Johnson led the team at IBM that built the RAMAC 305, the first computer system with a moving-head magnetic disk drive, introducing the very notion of a mechanically addressed, cylinder-organized random-access storage device that this article describes.
Where this matters
Every operating system's I/O scheduler — the Linux `mq-deadline`, `bfq`, and legacy `cfq` schedulers, Windows' storage stack, and the disk-arm-scheduling algorithms taught immediately after this topic — exists because of the cost structure derived here: seek and rotation dominate, transfer is cheap, so reordering requests to minimize arm travel yields real throughput gains. Database systems exploit this geometry explicitly: B-tree page layout, log-structured merge trees, and write-ahead logging are all designed to convert random I/O into sequential I/O, because sequential access amortizes the fixed seek-plus-rotation cost over far more bytes transferred. File system allocators (e.g., ext4's block groups, NTFS's cluster allocation) try to keep related blocks physically close, directly leveraging the fact that a cylinder's worth of data is nearly free once the arm has already arrived. RAID controllers stripe data across drives with full awareness of per-drive geometry to parallelize seeks across spindles. And this entire chapter of reasoning is precisely what evaporates — and must be re-derived from scratch — when moving to Solid-State Drives (SSDs), which have no platters, no seek arm, and no rotational latency at all, making this geometric model both essential background and a foil for understanding why flash storage is architecturally so different.
Ask the tutor: How would the access-time formula and the cylinder/LBA model need to be rewritten once seek time and rotational latency disappear entirely on an SSD?
Why doesn't the OS just use physical cylinder/head/sector addresses directly?
Early systems did use CHS addressing directly, but it created two serious problems. First, CHS exposes internal geometry that varies drive to drive and even zone to zone within a single drive (due to zoned bit recording), forcing every layer of software to understand a specific disk's physical layout. Second, CHS cannot represent bad-sector remapping transparently: if a sector fails, the controller needs to substitute a spare sector invisibly, which breaks any addressing scheme tied to literal physical geometry. LBA solves both by presenting a flat, sequential address space that the drive's own firmware translates internally, so the entire storage stack above the drive interface — file systems, schedulers, Device Driver code — can be written independently of any particular drive's physical layout.
If seek time dominates, why do transfer rates get advertised so heavily in marketing?
Sustained transfer rate matters most for large, sequential workloads — streaming video, backups, or bulk sequential reads — where the fixed seek-and-rotation cost is paid once and then amortized over megabytes of contiguous transfer. In that regime, transfer rate genuinely becomes the bottleneck, which is why it is a marketable, easily benchmarked number. But for random-access, small-request workloads (databases, virtual memory paging, general-purpose file systems under multi-process load), seek time and rotational latency dominate total cost regardless of the drive's peak transfer rate, and a drive advertised as "fast" on sequential throughput can still perform poorly under a random workload — which is why IOPS (I/O operations per second) is the more relevant marketing number for such workloads.
How does zoned bit recording complicate the simple geometric model?
The simple model assumes every track holds the same number of sectors, but that wastes capacity: outer tracks have larger circumference and could physically fit more sectors at the same bit density. Zoned bit recording (ZBR) groups tracks into zones, with outer zones assigned more sectors per track than inner zones, keeping areal bit density roughly uniform and maximizing total capacity. The consequence is that "bytes per track" and therefore sustained transfer rate are not constant across the disk — outer-zone tracks deliver higher sequential throughput than inner-zone tracks. This is why some performance-sensitive systems deliberately place frequently accessed data on outer cylinders (short-stroking), trading capacity for consistently faster transfer.
Does the LBA-to-cylinder formula in the pseudocode always match the physical layout exactly?
Not exactly, and this is worth being honest about. The formula assumes a simple, uniform mapping — cylinders times heads times sectors-per-track — which was accurate for early CHS-addressed drives but is now only a useful teaching approximation. Modern drives use zoned bit recording (varying sectors per track by radius) and perform bad-sector remapping and firmware-level reordering invisibly, so the true LBA-to-physical mapping is proprietary and non-uniform. The pseudocode's model captures the conceptually important relationship (cylinder = coarse-grained location, head = which surface, sector = position along the track) without claiming to replicate any specific real drive's internal translation table exactly.
Why is the cylinder, rather than the track, treated as the fundamental unit of locality for scheduling?
Because the actuator arm carries all heads together as one rigid assembly, moving to a given radius positions every head over its corresponding track on every platter surface simultaneously, at zero additional arm-movement cost. Switching which surface (head) you read from, within the same cylinder, requires only an electronic head-select operation — dramatically cheaper than a physical seek. Since Disk Scheduling Algorithms exist specifically to minimize costly arm movement, they operate on cylinder numbers as the unit that actually costs something to change, treating same-cylinder track switches as essentially free by comparison.
How does this geometric model change once we move to Solid-State Drives?
It doesn't merely change — it largely disappears. Solid-State Drives (SSDs) have no spinning platters, no actuator arm, and no rotational latency, because they store data in NAND flash cells addressed electronically rather than mechanically. There is no "seek" in the physical sense: any flash page can be accessed in comparable time regardless of its address, though flash has its own asymmetric costs (fast reads, slower writes, and the need for block-level erasure before rewriting). The LBA abstraction survives unchanged as the host-facing interface, but the internal translation is now handled by a Flash Translation Layer rather than a cylinder/head/sector geometry, which is precisely why disk scheduling policies built around minimizing seek distance become largely irrelevant — and sometimes actively counterproductive — on SSDs.
Is average seek time a reliable number to use in performance calculations?
It's a reasonable first-order estimate but a real simplification. "Average seek time" is typically measured by the manufacturer as the mean seek time over a large number of random seeks uniformly distributed across the whole disk surface, so it reflects a workload-independent average distance, not the actual distance for your specific access pattern. If your workload exhibits strong locality (e.g., sequential scans, or repeated access to a small hot region), actual seek costs will be far lower than the advertised average; if it is adversarially scattered, costs could be higher. Introductory calculations use the average-seek figure as a convenient stand-in, but real system designers should reason about the actual distribution of seek distances their workload produces.