Linux Disks and Partitions: Complete Storage Guide

 

💽 Linux Disks and Partitions: Complete Storage Guide
How hard disks are physically structured and logically divided
Topic 2 of 9
Disks & Partitions
Tools
fdisk, lsblk
Files
/proc/partitions

Key Terms:

Platter Track Sector Physical Block Partition fdisk Swap Area swapon() /proc/partitions mkswap

How a Hard Disk is Built Physically

A traditional hard disk drive (HDD) is a mechanical device. Data is stored magnetically on spinning platters. Understanding this helps you understand why disk I/O is slow compared to RAM.

📊 Physical Disk Structure
Hard Disk Drive
Platter 1
Magnetic disk
Platter 2
Magnetic disk
Read/Write Head
Moves radially
Spindle Motor
7200 RPM typical
Controller
Talks to OS
On each platter surface:

Tracks (concentric circles)
Sectors (track slices)
Physical Blocks (512 bytes each)

Three Steps to Read Data from Disk:

1️⃣

Seek Time
Head moves to correct track
(~5-10ms)

2️⃣

Rotational Latency
Wait for sector to rotate under head
(~4ms avg)

3️⃣

Transfer Time
Read/write the actual data
(fastest part)

⚠️ Total disk access = ~10-20ms. A modern CPU executes millions of instructions in that time. This is why caching is critical.

🗂️ Disk Partitions

A single physical disk is divided into partitions — each treated by the kernel as a separate device. The partition table (stored at the start of the disk) tells the OS where each partition begins and ends.

Physical Disk (/dev/sda)
Partition Table
/dev/sda
(MBR)
/dev/sda1
ext4 filesystem
(Linux root /)
/dev/sda2
ext4 filesystem
(/home)
/dev/sda3
swap area
(virtual RAM)
/dev/sda4
NTFS
(Windows)

Three Uses for a Partition:

1. File System
Contains regular files and directories. Created with mkfs. Mounted with mount.
2. Raw Data Area
Used directly by databases (e.g., Oracle raw devices) bypassing the OS file system for performance.
3. Swap Area
Used by the kernel as overflow for RAM. Created with mkswap, activated with swapon.

💻 Code Example 1: Read /proc/partitions

/proc/partitions lists all disk partitions the kernel knows about with their major/minor IDs and sizes.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    FILE *fp;
    int major, minor;
    unsigned long blocks;
    char name[64];

    fp = fopen("/proc/partitions", "r");
    if (fp == NULL) {
        perror("fopen /proc/partitions");
        return 1;
    }

    /* Skip header lines */
    char line[256];
    fgets(line, sizeof(line), fp);  /* "major minor  #blocks  name" */
    fgets(line, sizeof(line), fp);  /* blank line */

    printf("%-8s %-8s %-12s %s\n",
           "Major", "Minor", "Blocks(1K)", "Name");
    printf("%-8s %-8s %-12s %s\n",
           "-----", "-----", "----------", "----");

    while (fscanf(fp, "%d %d %lu %63s",
                  &major, &minor, &blocks, name) == 4) {
        printf("%-8d %-8d %-12lu %s\n",
               major, minor, blocks, name);
    }

    fclose(fp);
    return 0;
}

/* Sample output:
Major    Minor    Blocks(1K)   Name
-----    -----    ----------   ----
8        0        976762584    sda
8        1        524288       sda1
8        2        976236544    sda2
*/

💻 Code Example 2: Get Disk Size with ioctl()

Use BLKGETSIZE64 ioctl to get the exact size of a block device in bytes.

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>   /* BLKGETSIZE64 */
#include <stdint.h>

int main(int argc, char *argv[]) {
    int fd;
    uint64_t size_bytes;
    const char *device;

    device = (argc > 1) ? argv[1] : "/dev/sda";

    fd = open(device, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    /* BLKGETSIZE64: fills size_bytes with total bytes on device */
    if (ioctl(fd, BLKGETSIZE64, &size_bytes) == -1) {
        perror("ioctl BLKGETSIZE64");
        close(fd);
        return 1;
    }

    printf("Device: %s\n", device);
    printf("Size (bytes):  %llu\n", (unsigned long long)size_bytes);
    printf("Size (MB):     %.2f\n", size_bytes / (1024.0 * 1024.0));
    printf("Size (GB):     %.2f\n", size_bytes / (1024.0 * 1024.0 * 1024.0));

    /* Calculate number of 512-byte sectors */
    printf("512-byte sectors: %llu\n",
           (unsigned long long)(size_bytes / 512));

    close(fd);
    return 0;
}

/* Run as root: ./disk_size /dev/sda
   Device: /dev/sda
   Size (bytes):  1000204886016
   Size (MB):     953869.39
   Size (GB):     931.51
   512-byte sectors: 1953525168
*/

💻 Code Example 3: Swap Area Management (swapon/swapoff)

The swapon() and swapoff() system calls add/remove swap partitions at runtime. Usually called by the init system at boot.

#include <stdio.h>
#include <unistd.h>

/* These syscall wrappers may not be in all libc versions,
   so we show how to use the shell commands too */

/* Check current swap usage: /proc/swaps */
void read_swap_info(void) {
    FILE *fp;
    char line[256];

    fp = fopen("/proc/swaps", "r");
    if (!fp) { perror("fopen"); return; }

    printf("=== Current Swap Areas (/proc/swaps) ===\n");
    while (fgets(line, sizeof(line), fp))
        printf("%s", line);

    fclose(fp);
}

int main(void) {
    read_swap_info();

    /* Shell equivalent commands:
       To create a swap file:
         dd if=/dev/zero of=/swapfile bs=1M count=1024
         chmod 600 /swapfile
         mkswap /swapfile          -- format as swap
         swapon /swapfile          -- activate swap

       To deactivate:
         swapoff /swapfile

       To see all active swap:
         cat /proc/swaps
         free -h                   -- shows Swap: row
    */

    return 0;
}

/* /proc/swaps sample output:
Filename            Type      Size       Used  Priority
/dev/sda3           partition 4194300    0     -2
/swapfile           file      1048572    0     -3
*/

💻 Code Example 4: Parsing Partition Info Like fdisk
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

/* MBR (Master Boot Record) is 512 bytes at offset 0 of disk.
   Partition table starts at offset 446.
   Each entry is 16 bytes, there are 4 entries. */

typedef struct {
    uint8_t  status;         /* 0x80 = bootable */
    uint8_t  chs_first[3];   /* CHS of first sector */
    uint8_t  type;           /* Partition type code */
    uint8_t  chs_last[3];    /* CHS of last sector */
    uint32_t lba_start;      /* LBA start sector */
    uint32_t sector_count;   /* Number of sectors */
} __attribute__((packed)) PartEntry;

void decode_type(uint8_t type) {
    switch (type) {
        case 0x00: printf("Empty");          break;
        case 0x82: printf("Linux swap");     break;
        case 0x83: printf("Linux ext");      break;
        case 0x07: printf("NTFS/exFAT");     break;
        case 0x0B: printf("FAT32 CHS");      break;
        case 0x0C: printf("FAT32 LBA");      break;
        case 0x05: printf("Extended");       break;
        default:   printf("Unknown(0x%02x)", type); break;
    }
}

int main(int argc, char *argv[]) {
    int fd;
    uint8_t mbr[512];
    PartEntry *pt;
    int i;
    const char *device = (argc > 1) ? argv[1] : "/dev/sda";

    fd = open(device, O_RDONLY);
    if (fd == -1) { perror("open"); return 1; }

    if (read(fd, mbr, 512) != 512) {
        perror("read MBR"); close(fd); return 1;
    }
    close(fd);

    /* Verify MBR signature */
    if (mbr[510] != 0x55 || mbr[511] != 0xAA) {
        printf("No valid MBR found!\n");
        return 1;
    }

    printf("Device: %s\n", device);
    printf("MBR signature: 0x%02x%02x (valid)\n\n",
           mbr[510], mbr[511]);

    printf("%-6s %-12s %-12s %-12s %s\n",
           "Part", "Start(LBA)", "Sectors", "Size(MB)", "Type");

    /* Partition table entries start at offset 446 */
    pt = (PartEntry *)(mbr + 446);
    for (i = 0; i < 4; i++) {
        if (pt[i].type == 0) continue;  /* Skip empty */

        double size_mb = (double)pt[i].sector_count * 512.0
                         / (1024.0 * 1024.0);

        printf("%-6d %-12u %-12u %-12.1f ",
               i + 1,
               pt[i].lba_start,
               pt[i].sector_count,
               size_mb);
        decode_type(pt[i].type);
        if (pt[i].status == 0x80) printf(" [BOOT]");
        printf("\n");
    }

    return 0;
}
/* Run as root: ./read_mbr /dev/sda */

🎯 Interview Questions — Disks and Partitions

Q1. What are the three latency components when reading from a hard disk?

Seek time (head moves to the right track), rotational latency (waiting for the sector to rotate under the head), and transfer time (actual data transfer). Seek + rotational latency dominates and is typically 10–20ms — millions of CPU cycles.

Q2. What is a disk partition? How does the kernel see it?

A partition is a contiguous region of a disk defined in the partition table (MBR or GPT). The kernel treats each partition as an independent block device — e.g., /dev/sda1, /dev/sda2. The fdisk command manages partitions; /proc/partitions lists them.

Q3. What are the three uses of a disk partition in Linux?

1) As a filesystem (containing files/directories, created with mkfs, mounted with mount). 2) As a raw device for direct database access bypassing the OS filesystem. 3) As a swap area (virtual memory extension, created with mkswap, activated with swapon).

Q4. What is the physical block size on a hard disk?

Typically 512 bytes (or 4096 bytes on modern Advanced Format drives). This is the smallest unit the disk hardware can read or write atomically. Above this, the OS filesystem defines its own “logical block” which is a multiple of the physical block size.

Q5. How do you check active swap areas from the command line?

cat /proc/swaps shows all active swap areas with their type (partition or file), size, and usage. The free -h command also shows total swap in a summary. swapon –show is another option.

Q6. What command shows partition information and how does it work internally?

fdisk -l reads the MBR (first 512 bytes) of the disk, validates the 0x55AA signature, and parses the four 16-byte partition table entries at offset 446. Each entry has start LBA, sector count, and partition type byte. Modern tools also handle GPT (GUID Partition Table) for disks over 2TB.

Leave a Reply

Your email address will not be published. Required fields are marked *