Skip to main content

Chapter 06 · Storage Layout & Disk Management

Chapter Overview

Linux’s distinctive storage layout often leaves newcomers scratching their heads. This chapter starts with the on‑disk layout used by Linux, introduces the Filesystem Hierarchy Standard (FHS), explains the kernel’s udev device‑naming rules, and walks through how block devices actually work.

To make the role of a filesystem concrete, we compare the commonly used Ext3, Ext4, and XFS filesystems, then practice the day‑to‑day administration tasks you’ll use most: partitioning, formatting, and mounting disks and partitions. By the end, you’ll be comfortable working with filesystems in real environments.

After you’ve got the fundamentals down, we’ll set up a swap area, configure quota to control disk consumption, and learn to create symbolic (soft) and hard links with ln. The goal is a deep, practical understanding of storage and filesystems on Linux (and how that compares to Windows).

6.1 Everything Starts at “/”

On Linux, everything is a file: directories, character devices, sockets, disks, CD‑ROMs, and printers are all represented as files. If everything is a file, how do we find the one we want?

In Windows, you first choose a drive letter (partition), then the folders within it, and finally the file. Linux has no C:/D:/E: letters. Every path begins at the root directory /, and files are organized beneath it in an inverted‑tree structure defined by the Filesystem Hierarchy Standard (FHS).

Linux is case‑sensitive. root, rOOt, Root, and rooT are all different. Filenames cannot include a forward slash (/). The overall storage layout is shown in Figure 6‑1.

Figure 6‑1 Storage layout on Linux

The FHS distills decades of experience from users and developers. It’s a set of conventions about where things should live (and where you should look to find them). It’s not a police officer—people can and do ignore it—but learning it will save you time. Table 6‑1 lists common top‑level directories and what they’re for.

Table 6‑1 Common directories and what they contain

DirectoryWhat belongs here
/bootBootloader files such as the kernel and boot menu
/devDevice files representing hardware
/etcSystem and service configuration
/rootThe superuser’s home directory
/homeHome directories for regular users
/binCore user commands (available even in single‑user mode)
/sbinAdministrative commands for the superuser
/libShared libraries used by /bin and /sbin
/mediaMount points for removable devices
/optThird‑party application packages
/srvService data for network services
/tmpTemporary files (writable by everyone)
/procVirtual filesystem exposing process and kernel information
/usr/localLocally installed software
/usr/sbinNon‑core admin commands
/usr/shareArchitecture‑independent shared data such as docs and help files
/varVariable data such as logs and spools
/lost+foundRecovered fragments after filesystem repairs

Two path styles matter:

  • Absolute path: starts at / and is valid from anywhere.
  • Relative path: interpreted relative to your current working directory—short to type, but not universal.

If the distinction isn’t crystal clear yet, don’t worry. Practice in the coming pages will make it second nature. For now, keep the FHS roles in mind; they’ll pay off soon.

6.2 How Physical Devices Are Named

If everything is a file, hardware must have filenames too. The kernel’s device manager, udev, creates and maintains device files and names them so you can guess a device’s type and partitioning from its name. udev runs as a daemon and listens to kernel events to manage the entries under /dev. Table 6‑2 shows common device types and their canonical names.

Table 6‑2 Common devices and their names

DeviceName pattern
IDE disks/dev/hd[a-d]
NVMe devices/dev/nvme[0-n]
SCSI/SATA/USB/dev/sd[a-z]
Virtio disks/dev/vd[a-z]
Floppy/dev/fd[0-1]
Parallel printer/dev/lp[0-15]
Optical drive/dev/cdrom
Mouse/dev/mouse
Tape/dev/st0 or /dev/ht0

IDE is rare today, so most disks appear as /dev/sd*. A single host can have many disks, so the kernel uses az to label up to 26 devices of a given class (starting at a). Partition numbering follows these rules:

Primary and extended partitions are numbered 1–4.
Logical partitions start at 5.

Two common misconceptions are worth correcting:

  1. /dev/sda is the device in the first motherboard slot.”
    Not necessarily. The a in /dev/sda reflects detection order, not the physical slot. In practice these often correlate, which fuels the myth, but they’re not the same. For example, an iSCSI disk might show up as /dev/sdb even if the second physical slot is empty—because the kernel’s scan order put it there.

  2. “Partition numbers imply how many partitions exist.”
    They don’t. sda3 means “partition number 3 on sda,” not “the third partition created.” Numbers can be assigned non‑sequentially by the admin.

Let’s decode /dev/sda5 (Figure 6‑2):

Figure 6‑2 Decoding a device filename

  • Entries under /dev denote hardware.
  • sd denotes a SCSI/SATA/USB storage device.
  • a is the first detected device of that class.
  • 5 indicates a logical partition.

NVMe is increasingly common in servers. It fully exploits SSD performance and outpaces SATA/SCSI. NVMe device names differ from SATA/SCSI; Figure 6‑3 illustrates the mapping.

Figure 6‑3 NVMe naming versus SATA/SCSI

A quick primer on partitioning: Disks are composed of sectors (traditionally 512 bytes). The first sector is special; it contains the Master Boot Record (MBR) and the partition table. In the classic MBR layout, the boot code uses 446 bytes, the partition table 64 bytes, and the signature 2 bytes. Each partition table entry consumes 16 bytes, so at most four entries fit—hence the limit of four primary partitions. Figure 6‑4 shows the first sector layout.

Figure 6‑4 Contents of the first sector

But four partitions are rarely enough. The solution is the extended partition: one of the four table entries points to additional partition records elsewhere on disk. The extended partition is just a pointer, not a place to store data. You then create multiple logical partitions inside it. Figure 6‑5 shows a typical plan.

Tips:
The extended partition forms a one‑way linked list of records. Because it’s a container, not a data area, you store data in the logical partitions it links to—not in the extended partition itself.

Figure 6‑5 Planning out primary, extended, and logical partitions

What does /dev/hdc8 mean? It’s the third IDE disk’s logical partition number 8 (IDE is mostly historical now).

You’ll also see devices like /dev/vda and /dev/vdb on RHCE exams or cloud VMs. Those are Virtio devices—the paravirtualized disks used by hypervisors such as KVM or Xen.

6.3 Filesystems and Your Data

Try writing a few lines on a blank sheet of A4 paper held sideways. Your lines soon drift up or down. Now switch to lined paper—everything becomes neat and easy to read. The lesson: without structure, content drifts. On storage, that structure is provided by a filesystem. It decides how to lay out and organize data, tracks metadata, and makes space use efficient.

Linux supports dozens of filesystems. The most common are:

Ext2 — The first commercial‑grade Linux filesystem (1993), modeled on classic UNIX designs. It lacks journaling, so crashes make recovery difficult and risky. Avoid it unless you truly need it (e.g., on small SD cards or certain USB sticks).

Ext3 — Adds a journal: before writing data, it records the intent. After a crash, the system replays the journal to bring the filesystem back to a consistent state. On very large volumes, recovery can still take a long time, and, as with any journaling FS, there’s no absolute guarantee of zero data loss.

Ext4 — An improved Ext3 and the default on RHEL 6. It supports volumes up to 1 EB (1,073,741,824 GB) and vast directory counts. Extent‑based allocation boosts throughput by allocating blocks in contiguous chunks. Many mainstream servers still default to Ext4.

XFS — A high‑performance journaled filesystem and the default on RHEL 7 and later. It recovers quickly after crashes and its journal overhead is low. XFS supports volumes up to 18 EB, effectively eliminating size limits for most real‑world needs.

A note on performance: RHEL 10 adopts XFS as its primary filesystem. While the official line touts big gains, real‑world read performance depends on many variables (file sizes and counts, CPU and memory pressure, controller/SSD models, etc.). In testing, XFS beats Ext4 in several cases but not overwhelmingly. XFS’s most impressive headline feature is its 18‑EB maximum size.

To visualize 18 EB: that’s 18,874,368 TB. With 100‑TB drives you’d need roughly 190,000 of them. At this scale, the limit is usually your budget, not the technology. A classic joke in the field: “If you must move 18 EB of data from Shanghai to Beijing as fast as possible, what’s the best transport?” Answer: the high‑speed rail—put the disks on a train.

When you unbox a new disk, the workflow is:

  1. Partition it (optional in some cases),
  2. Format the partition(s) with a filesystem, then
  3. Mount the filesystem at a directory.

Tips:
It’s like working with a large sheet of paper: first cut it into sizes you want (partition), then draw lines so writing stays neat (format), then start writing (mount).

What happens during formatting? Linux maintains a “map” called the superblock, which tracks filesystem‑wide information. File metadata (permissions, owner, size, timestamps, etc.) lives in fixed‑size records called inodes (128 bytes by default in classic Ext filesystems). The data itself lives in blocks (typically 1 KB, 2 KB, or 4 KB). An inode stores pointers to data blocks. If one inode’s pointers aren’t enough, the filesystem allocates extra blocks just to hold more pointers, chaining everything together so the kernel can read the entire file.

Two common space‑usage scenarios (assuming 4‑KB blocks):

  • A 1‑KB file still consumes one full 4‑KB block → ~3 KB wasted (internal fragmentation).
  • A 5‑KB file uses two blocks (one full 4‑KB block + one additional block for the remaining 1 KB).

This “last block can’t be fully filled” reality exists on every filesystem. Check any file’s size on disk vs. logical size and you’ll see they differ (Figure 6‑6).

Figure 6‑6 Logical size vs. space on disk

Inodes + blocks enable read/write operations but feel abstract. Figure 6‑7 makes their relationship concrete.

Figure 6‑7 How inodes reference blocks

To insulate user‑space tools from the quirks of each filesystem, the kernel provides VFS (Virtual File System). VFS is a translation layer that exposes a uniform API. Your tools interact with VFS (Figure 6‑8), and VFS translates those calls to the specific filesystem implementation below.

Figure 6‑8 The VFS architecture

Tips:
VFS is so reliable and transparent that many admins use it for years without realizing it’s there.

6.4 Mounting Storage

If you’re used to Windows, you probably plug in a USB drive and start using it without thinking about the steps involved. On Linux we’ll make the process explicit: mounting and unmounting devices so you understand how the OS wires a device into the directory tree.

Mounting associates a device (or partition) with an existing directory—called a mount point. After mounting, the device’s contents become visible inside that directory.

The mount command’s basic form is:

mount [filesystem] [mountpoint]

Modern Linux usually auto‑detects the filesystem type, so -t is rarely needed. The -a option tells mount to attempt mounting everything declared in /etc/fstab.

Table 6‑3 Common mount options

OptionMeaning
-aMount everything defined in /etc/fstab
-tSpecify filesystem type explicitly

Example: mount /dev/sdb2 on /backup:

root@linuxprobe:~# mount /dev/sdb2 /backup

For network storage, device names can change. Use UUIDs (Universally Unique IDentifiers), which are stable and unique per filesystem. Find them with blkid:

root@linuxprobe:~# blkid
/dev/sdb1: UUID="1ff63c74-090c-4fa9-a3fb-cfb029572819" TYPE="xfs"
/dev/sdb2: UUID="53f01fa2-2a23-4979-8add-8fe0df5b8947" TYPE="ext4"
… [output truncated] …

Mount by UUID:

root@linuxprobe:~# mount UUID=53f01fa2-2a23-4979-8add-8fe0df5b8947 /backup

Ad‑hoc mounts disappear on reboot. To make a mount persist across boots, add an entry to /etc/fstab using this six‑field format: device mountpoint fstype options dump fsck. Table 6‑4 explains the fields.

Table 6‑4 Fields in /etc/fstab

FieldMeaning
DeviceDevice path (e.g., /dev/sdb2) or UUID=…
MountpointDirectory to attach to (create it first)
FstypeFilesystem type (e.g., Ext3, Ext4, XFS, SWAP, iso9660 for CD/DVD)
Optionsdefaults expands to rw,suid,dev,exec,auto,nouser,async
Dump1 to enable dump backups at boot, else 0
Fsck1 to enable filesystem checks at boot, else 0

Example: auto‑mount an Ext4 filesystem at /backup with defaults and no fsck:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults 0 0

Optical media use the iso9660 filesystem. To pre‑declare a CD/DVD mount at /media/cdrom:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0

After editing /etc/fstab, activate pending mounts with:

root@linuxprobe:~# mount -a

Use df -h to see mounted filesystems and their space usage (“disk free”). The -h option renders sizes in human‑friendly units (KB/MB/GB), so 10240K prints as 10M:

root@linuxprobe:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 3.7G 13G 23% /
devtmpfs 4.0M 0 4.0M 0% /dev
tmpfs 1.9G 84K 1.9G 1% /dev/shm
efivarfs 256K 56K 196K 23% /sys/firmware/efi/efivars
tmpfs 776M 9.7M 767M 2% /run
tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service
/dev/sr0 6.5G 6.5G 0 100% /media/cdrom
/dev/sda2 960M 272M 689M 29% /boot
/dev/sda1 599M 8.3M 591M 2% /boot/efi
/dev/sdb2 480M 20M 460M 4% /backup

For network filesystems declared in fstab, add the _netdev option so the system waits for networking to come up before attempting the mount (handy with iSCSI in Chapter 17):

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/sdb2 /backup ext4 defaults,_netdev 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0

To unmount, specify either the device or the mount point:

root@linuxprobe:~# umount /dev/sdb2

If the target is busy (e.g., your shell is cd’d into the mount point), leave that directory and try again:

root@linuxprobe:~# cd /media/cdrom
root@linuxprobe:/media/cdrom# umount /dev/cdrom
umount: /media/cdrom: target is busy.
root@linuxprobe:/media/cdrom# cd ~
root@linuxprobe:~# umount /dev/cdrom
root@linuxprobe:~#

Tips:
Mounting is like registering a marriage—both parties (device and directory) must be present. Once recorded, you can’t “remarry” the same device to another directory without first unmounting it.

When there are lots of disks and partitions, it’s easy to forget what’s where. Use lsblk to see a tree of block devices, partitions, and LVM volumes:

root@linuxprobe:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 600M 0 part /boot/efi
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 18.4G 0 part
├─rhel-root 253:0 0 16.4G 0 lvm /
└─rhel-swap 253:1 0 2G 0 lvm [SWAP]
sdb 8:16 0 20G 0 disk
├─sdb1 8:17 0 1G 0 part
└─sdb2 8:18 0 500M 0 part
sr0 11:0 1 6.5G 0 rom

6.5 Adding a New Disk

Here’s the workflow we’ll practice:

  1. add a new virtual disk,
  2. partition it,
  3. make a filesystem and mount it, and
  4. verify mounts and actually use the space.

Using a VM saves buying real hardware and is ideal for learning. Steps:

  1. Shut down the VM and return to the hypervisor’s main window. Click Edit virtual machine settings, then Add to add hardware (Figure 6‑9).

Figure 6‑9 Add hardware in your VM

  1. Choose Hard Disk, click Next (Figure 6‑10).

Figure 6‑10 Choose the device type

  1. Select SATA as the virtual disk type (Figure 6‑11). The device will appear as /dev/sdb in Linux.

Figure 6‑11 Choose SATA for the new disk

  1. Pick Create a new virtual disk (Figure 6‑12).

Figure 6‑12 Create a brand‑new virtual disk

  1. Set Maximum disk size to 20 GB. This caps usage; it doesn’t pre‑allocate the space (Figure 6‑13).

Figure 6‑13 Cap the virtual disk at 20 GB

  1. Accept the default filename and location, click Finish (Figure 6‑14).

Figure 6‑14 Disk file name and location

  1. Review the new device in the VM’s hardware list and boot the VM (Figure 6‑15).

Figure 6‑15 Review hardware, then boot

Back in Linux, the new disk should appear as /dev/sdb. Let’s carve out a 2‑GB partition.

fdisk manages MBR‑style partition tables: create, delete, change type, list, and write. It’s interactive; type a letter at the prompt to invoke a function (Table 6‑5).

Table 6‑5 fdisk commands

KeyAction
mList all available commands
nAdd a new partition
dDelete a partition
lList known partition types
tChange a partition’s type
pPrint the partition table
wWrite changes and exit
qQuit without saving

Start fdisk and print the empty table:

root@linuxprobe:~# fdisk /dev/sdb

Welcome to fdisk (util-linux 2.40.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS (MBR) disklabel with disk identifier 0x186f3f5e.

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

Create a primary partition (np) of 2 GB. Accept the default first sector and specify +2G for the last sector:

Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p

Partition number (1-4, default 1): 1
First sector (2048-41943039, default 2048): [press Enter]
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-41943039, default 41943039): +2G
Created a new partition 1 of type 'Linux' and of size 2 GiB.

Print the table and write it with w:

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 4196351 4194304 2G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Partition type IDs are short codes describing a partition’s intended use. List them with l. We’ll change one later to 82 (Linux swap) in Section 6.6:

Command (m for help): l
[output abbreviated]
Aliases:
linux - 83
swap - 82
extended - 05
uefi - EF
raid - FD
lvm - 8E
linuxex - 85

After partitioning, the kernel should expose /dev/sdb1. If it doesn’t appear immediately, use partprobe to nudge the kernel (run it twice if needed). As a last resort, reboot.

root@linuxprobe:~# file /dev/sdb1
/dev/sdb1: cannot open `/dev/sdb1' (No such file or directory)
root@linuxprobe:~# partprobe
root@linuxprobe:~# partprobe
root@linuxprobe:~# file /dev/sdb1
/dev/sdb1: block special (8/17)

Format the partition. Typing mkfs and pressing Tab twice shows formatters for various filesystems:

root@linuxprobe:~# mkfs
mkfs mkfs.exfat mkfs.ext3 mkfs.fat mkfs.msdos mkfs.xfs
mkfs.cramfs mkfs.ext2 mkfs.ext4 mkfs.minix mkfs.vfat

Use the appropriate tool, e.g., mkfs.xfs /dev/sdb1:

root@linuxprobe:~# mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=131072 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=1
= reflink=1 bigtime=1 inobtcount=1 nrext64=1
data = bsize=4096 blocks=524288, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=16384, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

Mount and confirm:

root@linuxprobe:~# mkdir /newFS
root@linuxprobe:~# mount /dev/sdb1 /newFS
root@linuxprobe:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 17G 3.7G 13G 23% /
devtmpfs 4.0M 0 4.0M 0% /dev
tmpfs 1.9G 84K 1.9G 1% /dev/shm
efivarfs 256K 56K 196K 23% /sys/firmware/efi/efivars
tmpfs 776M 9.7M 767M 2% /run
tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service
/dev/sda2 960M 272M 689M 29% /boot
/dev/sr0 6.5G 6.5G 0 100% /media/cdrom
/dev/sda1 599M 8.3M 591M 2% /boot/efi
tmpfs 388M 120K 388M 1% /run/user/0
/dev/sdb1 2.0G 71M 1.9G 4% /newFS

du (disk usage) reports space consumed by directories or files. To find which top‑level directory is hogging space:

root@linuxprobe:~# du -sh /*
0 /afs
0 /bin
229M /boot
84K /dev
29M /etc
12K /home
0 /lib
0 /lib64
6.5G /media
0 /mnt
0 /newFS
0 /opt
0 /proc
4.2M /root
9.8M /run
0 /sbin
0 /srv
0 /sys
20K /tmp
3.2G /usr
69M /var

Copy some files over and check consumption:

root@linuxprobe:~# cp -rf /etc/* /newFS
root@linuxprobe:~# ls /newFS
adjtime gshadow profile
aliases gshadow- profile.d
alsa gss protocols
alternatives host.conf pulse
anacrontab hostname qemu-ga
asound.conf hosts ras
… [output truncated] …
root@linuxprobe:~# du -sh /newFS
29M /newFS/

To make the new mount persistent, add it to fstab:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0

6.6 Adding Swap

SWAP

Swap is disk space used as an overflow for RAM: when physical memory is tight, the kernel pushes less‑active pages to disk to free RAM for active tasks. Because disks are far slower than RAM, swap is used only when necessary.

The workflow mirrors adding a filesystem. Before we begin on /dev/sdb, a sizing guideline: in production, swap is often 1.5–2× RAM. To make the effect obvious, we’ll carve out a 5‑GB swap partition.

Create the partition with fdisk and then change its type ID to 82 (Linux swap):

root@linuxprobe:~# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.40.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): [press Enter]
First sector (4196352-41943039, default 4196352): [press Enter]
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4196352-41943039, default 41943039): +5G

Created a new partition 2 of type 'Linux' and of size 5 GiB.

Command (m for help): t
Partition number (1,2, default 2): 2
Hex code or alias (type L to list all): 82

Changed type of partition 'Linux' to 'Linux swap / Solaris'.

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x186f3f5e

Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 4196351 4194304 2G 83 Linux
/dev/sdb2 4196352 14682111 10485760 5G 82 Linux swap / Solaris

Command (m for help): w
The partition table has been altered.
Syncing disks.

Format the swap area and enable it:

root@linuxprobe:~# mkswap /dev/sdb2
Setting up swapspace version 1, size = 5 GiB (5368705024 bytes)
no label, UUID=cd6c8f9d-0af2-4020-96bc-02509c118b5c

root@linuxprobe:~# free -m
total used free shared buff/cache available
Mem: 3879 1535 1563 14 1125 2344
Swap: 2047 0 2047

root@linuxprobe:~# swapon /dev/sdb2
root@linuxprobe:~# free -m
total used free shared buff/cache available
Mem: 3879 1540 1558 14 1126 2339
Swap: 7167 0 7167

To persist swap across reboots, add it to fstab:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0

6.7 Disk Quotas

Linux was designed as a multi‑user, multi‑tasking OS, and disk space is finite. To prevent a single user from filling a filesystem with giant videos or a blizzard of tiny files, the superuser can impose quotas—limits on the total space or total file count a user (or group) may consume on a given mount point. Quotas have two thresholds:

Soft limit — crossing it triggers warnings but still allows operation for a grace period.
Hard limit — cannot be exceeded; operations are immediately denied.

RHEL 10 ships with the quota tools installed, but filesystems don’t enable quota by default. Edit /etc/fstab and enable user quotas on /boot, then reboot so XFS initializes quota accounting:

root@linuxprobe:~# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Mar 12 19:35:26 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=408f4a3d-a4d3-4a44-bb23-6988cdbd10bf / xfs defaults 0 0
UUID=4cf8ecae-bcb6-4b1e-8001-968b33643a8a /boot xfs defaults,uquota 0 0
UUID=1FB8-9199 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=d936c726-45a7-4ca2-8932-c54f84a3d787 none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
/dev/sdb1 /newFS xfs defaults 0 0
/dev/sdb2 swap swap defaults 0 0
root@linuxprobe:~# reboot

Tips:
In some versions of VMware Workstation, the guest can confuse devices on reboot and fail to boot. If that happens, remove the /dev/sdb2 entry from fstab (or switch to UUID‑based entries) and reboot again.

If you used very old distributions (RHEL 5/6 era), note the option name change: older systems used usrquota; modern XFS uses uquota for user quotas.

After reboot, confirm quotas are active:

root@linuxprobe:~# mount | grep boot
/dev/sda2 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,usrquota)

Create a test user and grant write access to /boot so the user can exercise the quota:

root@linuxprobe:~# useradd tom
root@linuxprobe:~# chmod -R o+w /boot

Use xfs_quota to manage quotas on XFS. The -c flag passes subcommands; -x enables expert mode for advanced operations.

Set user tom to have bsoft=3m and bhard=6m (block‑based soft/hard limits) and isoft=3 and ihard=6 (inode‑based soft/hard limits). Then report the quota:

root@linuxprobe:~# xfs_quota -x -c 'limit bsoft=3m bhard=6m isoft=3 ihard=6 tom' /boot
root@linuxprobe:~# xfs_quota -x -c report /boot
User quota on /boot (/dev/sda2)
Blocks
User ID Used Soft Hard Warn/Grace
---------- --------------------------------------------------
root 225552 0 0 00 [--------]
tom 0 3072 6144 00 [--------]

There are two groups of limits: i‑soft/i‑hard and b‑soft/b‑hard. As discussed in Section 6.3, each file consumes one inode to store its metadata, so i‑limits cap file counts. b‑limits cap total space consumed, measured in blocks.

“Soft” means the system only logs that the limit was crossed; “hard” means the operation is blocked immediately.

Switch to the test user and try creating a 5‑MB file, then an 8‑MB file. The second attempt should be denied by the quota:

root@linuxprobe:~# su - tom
tom@linuxprobe:~$ cd /boot
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=5M count=1
1+0 records in
1+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.00163334 s, 3.2 GB/s
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=8M count=1
dd: error writing '/boot/tom': Disk quota exceeded
1+0 records in
0+0 records out
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.00370067 s, 1.1 GB/s

To adjust limits later, use edquota. It edits quota settings in your default editor. -u targets a user; -g targets a group; other flags copy policies or edit grace periods.

Table 6‑6 edquota options

OptionMeaning
-uEdit a user’s limits
-gEdit a group’s limits
-pCopy one user’s/ group’s limits
-tEdit grace periods

Example: raise tom’s hard block limit to 8 MB and verify:

tom@linuxprobe:/boot$ exit
root@linuxprobe:~# edquota -u tom
Disk quotas for user tom (uid 1001):
Filesystem blocks soft hard inodes soft hard
/dev/sda2 4096 3072 8192 1 3 6
root@linuxprobe:~# su - tom
tom@linuxprobe:~$ cd /boot
tom@linuxprobe:/boot$ dd if=/dev/zero of=/boot/tom bs=8M count=1
1+0 records in
1+0 records out
8388608 bytes (8.4 MB, 8.0 MiB) copied, 0.00644861 s, 1.3 GB/s
tom@linuxprobe:~$ exit

With disk management under your belt, let’s introduce Linux’s equivalent of a “shortcut.” Windows shortcuts are small files that point to another file; if you move or delete the original, the shortcut breaks. Linux offers two flavors of links, and the details matter.

  • Symbolic (soft) link — a reference that stores the target’s pathname. If the target is moved or deleted, the symlink breaks. Symlinks can point to files or directories and can cross filesystem boundaries. This is the closest match to Windows shortcuts. See Figure 6‑16.

Figure 6‑16 How a symbolic link points to its target

  • Hard link — an additional directory entry that points to the same inode as the original file. Hard links are valid only within the same filesystem and cannot target directories. Because multiple names point at the same inode, the link continues to work even if one name is removed.

Create a test file and a symbolic link to it:

root@linuxprobe:~# echo "Welcome to linuxprobe.com" > old.txt 
root@linuxprobe:~# ln -s old.txt new.txt
root@linuxprobe:~# ls -l
total 8
-rw-r--r--. 1 root root 26 Mar 16 23:18 old.txt
lrwxrwxrwx. 1 root root 7 Mar 16 23:18 new.txt -> old.txt
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com

Rename the original file. The symlink breaks because it only stores the old path name:

root@linuxprobe:~# mv old.txt newold.txt
root@linuxprobe:~# ls -l
total 8
lrwxrwxrwx. 1 root root 7 Mar 16 23:18 new.txt -> old.txt
-rw-r--r--. 1 root root 26 Mar 16 23:18 newold.txt
root@linuxprobe:~# cat new.txt
cat: new.txt: No such file or directory

Create a hard link instead:

root@linuxprobe:~# echo "Welcome to linuxprobe.com" > old.txt 
root@linuxprobe:~# ln old.txt new.txt
root@linuxprobe:~# ls -l
total 12
-rw-r--r--. 2 root root 26 Mar 16 23:18 new.txt
-rw-r--r--. 2 root root 26 Mar 16 23:18 old.txt
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com
root@linuxprobe:~# ls -l old.txt
-rw-r--r--. 2 root root 26 Mar 16 23:18 old.txt

Notice the second column now shows 2 (the link count)—the number of directory entries pointing at the same inode. Delete one name and the other still works because the inode (and data) remain until the link count reaches zero:

root@linuxprobe:~# rm -f old.txt 
root@linuxprobe:~# cat new.txt
Welcome to linuxprobe.com

You cannot create hard links to directories, and hard links cannot cross filesystem boundaries. Their effect is illustrated below.

Figure 6‑17 How a hard link points to the same inode

Tips:
Think of the table of contents in a book: each entry is a label that leads you to the real page. A link is the same idea — a name that resolves to the actual data.

Table 6‑7 ln options and what they do

OptionMeaning
-sCreate a symbolic link (without -s, ln creates a hard link)
-fForce creation (overwrite existing destination)
-iPrompt before overwriting
-vVerbose: print actions taken

That wraps up the fundamentals. For production environments you’ll also want RAID (combine multiple disks into arrays) and LVM (resize logical volumes on the fly). On to Chapter 7!

Review Questions

  1. What’s similar and different between files under /home and /root?

  2. How does Linux determine names like /dev/sda1 and /dev/sdb2?

  3. What are primary, extended, and logical partitions? Why is there a limit of four primary partitions?

  4. In the MBR’s first sector, what’s stored where?

  5. Which commands format filesystems and which mount them?

  6. How can you view mounted filesystems and space usage?

  7. You try to unmount a filesystem and get “device is busy.” What does that usually mean, and how do you proceed?
    Answer: Your current directory (or another process) is using the mount point. Change to another directory (e.g., cd ~) or stop the process, then try again.

  8. In quota configuration, must the soft limit be lower than the hard limit?
    Answer: Not necessarily; soft can be ≤ hard.

  9. If the original file is renamed, will a symbolic link still reach it?
    Answer: No.

  10. If the original file is deleted, will a hard link still reach it?
    Answer: Yes—until the link count drops to zero.