Open Operating Systems
Disk Partitioning
& Filesystems
Practical exercises — from loop devices to Arch Linux install
fallocate
losetup
fdisk
mkfs
mount
pacstrap
grub
1
Loop Devices & Partitioning
Create a virtual disk inside a file, partition it — no real hardware needed
2
Creating Filesystems
Format partitions: ext4, vfat, btrfs — what a filesystem actually is
3
Mounting — Visual Guide
What mount really does, loop vs real disk, /etc/fstab
4
Arch Linux Install
Full install from scratch inside a loop file — pacstrap to GRUB
Part 1
Loop Devices & Partitioning
Create a virtual disk inside a file · partition it · no real hardware needed
fallocate / dd
Create a raw file
= our virtual disk
→
losetup
Connect file to
/dev/loop device
→
fdisk / parted
Create partition
table inside file
→
losetup -P
Expose partitions
as /dev/loop0p1…
Part 1
What is a loop device?
A loop device makes the kernel treat a regular file as a block device — exactly like a real disk.
disk.img
Regular file
on disk
(raw bytes)
──
losetup
──▶
/dev/loop0
Block device
Looks exactly like
/dev/sda to kernel
──▶
KERNEL
Sees it as a
normal block device.
Can partition,
format, mount.
Real disk vs. loop device
| Operation | Real disk (/dev/sda) | Loop device (/dev/loop0) |
fdisk | ✓ works | ✓ works identically |
mkfs.ext4 | ✓ works | ✓ works identically |
mount | ✓ works | ✓ works identically |
| Risk | ⚠ data loss possible | ✓ safe — just a file |
Lab 1.1
Create a virtual disk file
Two tools — choose one to create a raw file of a specific size
Method A — fallocate (fast, recommended)
$ fallocate -l 2G disk.img
$ ls -lh disk.img
-rw-r--r-- 1 user 2.0G disk.img
$ file disk.img
disk.img: data
Method B — dd (slower, fills with zeros)
$ dd if=/dev/zero of=disk.img bs=1M count=2048
$ dd if=/dev/zero of=disk.img \
bs=1M count=2048 status=progress
$ ls -lh disk.img
fallocate -l SIZE FILE
-l = length. Supports K, M, G, T. Example: -l 500M
dd if=SRC of=DST
if=input of=output, bs=block size, count=num blocks
Why 2 GB?
Large enough to hold a real OS. Use any size — even 500M for practice.
Lab 1.2
Attach the file to a loop device
Tell the kernel to expose our file as a block device at /dev/loop0
$ sudo losetup --find --show disk.img
/dev/loop0
$ losetup -l
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0 0 0 0 0 /home/user/disk.img
$ lsblk /dev/loop0
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 2G 0 loop
/home/user/disk.imgRegular file
(2 GB of bytes)
→
/dev/loop0Block device
(looks like a disk)
→
fdisk /dev/loop0Now partitionable
like a real disk!
⚠️To detach when done: sudo losetup -d /dev/loop0 — never forget this!
Lab 1.3
Partition with fdisk
fdisk is interactive — follow the menu to create a GPT partition table
$ sudo fdisk /dev/loop0
g
n
Partition: 1 | First: [Enter] | Last: +512M
n
Partition: 2 | First: [Enter] | Last: +1G
n
Partition: 3 | First: [Enter] | Last: [Enter]
p
w
$ sudo losetup -d /dev/loop0
$ sudo losetup -P --find --show disk.img
/dev/loop0
$ ls /dev/loop0*
/dev/loop0 /dev/loop0p1 /dev/loop0p2 /dev/loop0p3
Resulting layout
p1
512M — /boot
EFI System Partition (FAT32)
p2
1G — /
Root filesystem (ext4)
p3
rest — /home
Home partition (ext4)
Key fdisk commands
Lab 1.4
Alternative: parted (non-interactive)
parted can be scripted — useful for automation and install scripts
$ sudo parted -s /dev/loop0 \
mklabel gpt \
mkpart primary 1MiB 513MiB \
mkpart primary 513MiB 1537MiB \
mkpart primary 1537MiB 100%
$ sudo parted /dev/loop0 print
Number Start End Size Name Flags
1 1049kB 538MB 537MB primary
2 538MB 1611MB 1074MB primary
3 1611MB 2147MB 536MB primary
Quick reference — partition tools
fdisk
Interactive TUI. GPT + MBR. Beginner-friendly.
parted
CLI + scriptable. GPT + MBR. More precise.
gdisk
fdisk for GPT only. More GPT features.
cfdisk
Curses TUI. Very visual. Easy for beginners.
Part 2
Creating Filesystems
Format partitions · ext4 · vfat · btrfs · what a filesystem actually is
ext4
Most common Linux FS. Journaling, stable, fast.
vfat
FAT32 — for EFI /boot. Compatible with all operating systems.
btrfs
Modern Copy-on-Write. Snapshots, compression.
xfs
High-performance. Used by RHEL/Fedora.
Part 2
What is a filesystem? (concept)
Before mkfs — raw partition
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
No structure — kernel cannot
read files or directories.
mkfs
.ext4
───▶
After mkfs — structured data
Superblock
Inode table
Block bitmap
Data blocks
Has structure — kernel can
read directories and files.
Key filesystem concepts
Superblock
FS metadata: size, type, block size, free space
Inode
One per file/dir. Stores permissions, timestamps, block locations.
Data block
Where file contents live (typically 4 KB each).
Journal
Log of recent changes — used to recover after crashes.
Lab 2.1
Format partitions with mkfs
Each partition gets its own filesystem. Use the right type for each role.
$ sudo mkfs.vfat -F 32 /dev/loop0p1
mkfs.fat 4.2 (2021-01-31)
$ sudo mkfs.ext4 /dev/loop0p2
Creating filesystem with 262144 4k blocks
Writing superblocks ...: done
$ sudo mkfs.ext4 -L home /dev/loop0p3
$ lsblk -f /dev/loop0
NAME FSTYPE LABEL UUID MOUNTPOINTS
loop0p1 vfat FAT32 xxxx
loop0p2 ext4 1.0 yyyy
loop0p3 ext4 home zzzz
mkfs quick reference
mkfs.ext4 DEV
Format as ext4
mkfs.ext4 -L LABEL
Set volume label
mkfs.vfat -F 32
Format as FAT32
mkfs.btrfs DEV
Format as btrfs
blkid DEV
Show UUID + type
⚠️mkfs DESTROYS all existing data on the partition. No undo. Double-check the device name!
Part 3
Mounting — the visual guide
What mount really does · loop device vs real disk · /etc/fstab
💡The key insight: mount doesn't copy data. It attaches a device socket to a directory. The directory becomes a window into the filesystem.
🔁Physical disk vs loop file: From mount's perspective, they are identical. Both are block devices. mount doesn't care what's behind /dev/loop0 or /dev/sda.
Part 3
What mount does — visually
mount DEVICE DIRECTORY attaches the device's filesystem to that directory in the tree
BEFORE mount /dev/loop0p2 /mnt
/
├── home/
├── etc/
└── mnt/
(empty)
AFTER mount /dev/loop0p2 /mnt
/
├── home/
├── etc/
└── mnt/
├── bin/
├── etc/
└── usr/
↩️umount /mnt → /mnt becomes empty again. The data on the device is NOT affected.
Lab 3.1
Mount loop device partitions
Mount all three partitions and explore their contents
$ mkdir -p /mnt/myroot /mnt/myroot/boot /mnt/myroot/home
$ sudo mount /dev/loop0p2 /mnt/myroot
$ sudo mount /dev/loop0p1 /mnt/myroot/boot
$ sudo mount /dev/loop0p3 /mnt/myroot/home
$ findmnt /mnt/myroot
TARGET SOURCE FSTYPE SIZE
/mnt/myroot /dev/loop0p2 ext4 1.0G
/mnt/myroot/boot /dev/loop0p1 vfat 512M
/mnt/myroot/home /dev/loop0p3 ext4 rest
$ df -h /mnt/myroot /mnt/myroot/boot
mount options
-o rw
Read-write (default)
--bind
Bind mount (mirror dir)
-o remount
Remount with new options
📋Order matters! Mount / before /boot and /home — subdirs must exist before mounting inside them.
Part 3
Physical disk vs. loop file
From mount's perspective: identical. The difference is only in setup.
| Real physical disk | Loop file (disk.img) |
| Device node | /dev/sda, /dev/nvme0n1 | /dev/loop0 |
| How it appears | Hardware detected at boot | losetup --find --show disk.img |
| Partitions | /dev/sda1, /dev/sda2… | /dev/loop0p1, /dev/loop0p2… |
| Partition scan | Automatic | losetup -P or partprobe |
| Format with mkfs | mkfs.ext4 /dev/sda2 | mkfs.ext4 /dev/loop0p2 |
| Mount | mount /dev/sda2 /mnt | mount /dev/loop0p2 /mnt |
| Risk | ⚠ destroys real data | ✓ just a file — safe |
| Portability | Tied to machine | ✓ just copy disk.img |
💡Loop files are perfect for practising Arch installs — start over by deleting disk.img and creating a new one.
Part 3
/etc/fstab — auto-mount at boot
fstab tells the kernel what to mount automatically at startup
UUID=xxxx-yyyy / ext4 defaults 0 1
UUID=aaaa-bbbb /boot vfat defaults 0 2
UUID=cccc-dddd /home ext4 defaults 0 2
tmpfs /tmp tmpfs size=2G 0 0
$ blkid /dev/loop0p2
/dev/loop0p2: UUID="a1b2c3d4" TYPE="ext4"
$ genfstab -U /mnt/myroot
UUID=a1b2... / ext4 rw,relatime 0 1
UUID=e5f6... /boot vfat rw,relatime 0 2
DEVICE
UUID=..., LABEL=...
or /dev/sdaN
MOUNTPOINT
Where to mount:
/, /home, /boot
FSTYPE
ext4, vfat, btrfs
tmpfs, swap
OPTIONS
defaults, ro, noexec
compress=zstd
DUMP
0 = skip backup
(always 0 nowadays)
PASS
fsck order:
0=skip 1=first 2=after
⚠️Always use UUID= not /dev/sdaN — device names change between boots. UUIDs never change.
Part 4
Arch Linux Install from Scratch
loop file · partitions · filesystems · pacstrap · chroot · GRUB
1
Create disk.img
fallocate -l 4G arch.img
2
Partition it
losetup -P + parted mklabel gpt
3
Format partitions
mkfs.vfat -F 32 p1 && mkfs.ext4 p2
4
Mount everything
mount p2 /mnt && mount p1 /mnt/boot
5
pacstrap -K
pacstrap -K /mnt base linux linux-firmware
6
genfstab + chroot
genfstab -U /mnt >> /mnt/etc/fstab && arch-chroot /mnt
7
GRUB bootloader
grub-install + grub-mkconfig
Lab 4.1
Steps 1–3: disk file, partitions, filesystems
STEP 1 — Create the disk file (4 GB)
$ fallocate -l 4G arch.img
STEP 2 — Attach + partition
$ sudo losetup -P --find --show arch.img
/dev/loop0
$ sudo parted -s /dev/loop0 \
mklabel gpt \
mkpart ESP fat32 1MiB 513MiB \
set 1 esp on \
mkpart primary ext4 513MiB 100%
STEP 3 — Format
$ sudo mkfs.vfat -F 32 /dev/loop0p1
$ sudo mkfs.ext4 /dev/loop0p2
$ lsblk -f /dev/loop0
NAME FSTYPE SIZE
loop0p1 vfat 512M
loop0p2 ext4 3.5G
p1
512M — EFI System Partition
FAT32 — required for UEFI boot
p2
3.5G — Root filesystem
ext4 — holds the entire Arch install
Lab 4.2
Step 4: mount partitions at /mnt
Create the directory tree and mount each partition into the right place
$ sudo mount /dev/loop0p2 /mnt
$ sudo mkdir -p /mnt/boot
$ sudo mount /dev/loop0p1 /mnt/boot
$ findmnt /mnt
TARGET SOURCE FSTYPE SIZE
/mnt /dev/loop0p2 ext4 3.5G
/mnt/boot /dev/loop0p1 vfat 512M
$ df -h /mnt /mnt/boot
/dev/loop0p2 3.4G 24K 3.2G 1% /mnt
/dev/loop0p1 511M 0 511M 0% /mnt/boot
Mount tree
/mnt ← loop0p2 (ext4)
├─ boot/ ← loop0p1 (vfat)
├─ bin/
├─ etc/ ↑ created by
├─ usr/ pacstrap
└─ var/
⚠️Mount / (loop0p2) before creating /mnt/boot and mounting loop0p1 inside it!
Lab 4.3
Step 5: pacstrap — install base system
pacstrap downloads and installs Arch Linux packages directly into /mnt
$ sudo pacstrap -K /mnt base linux linux-firmware
:: Synchronizing package databases...
(1/N) installing linux ...
$ sudo pacstrap -K /mnt base linux linux-firmware \
vim nano grub efibootmgr networkmanager
base
Minimal Arch userland — shell, coreutils, pacman
linux
The Linux kernel binary
linux-firmware
Hardware firmware blobs (WiFi, GPU, etc.)
grub + efibootmgr
Bootloader — needed for GRUB install step
Lab 4.4
Steps 6–7: genfstab and arch-chroot
Generate the filesystem table, then chroot into the new system to configure it
Step 6 — Generate /etc/fstab
$ genfstab -U /mnt >> /mnt/etc/fstab
$ cat /mnt/etc/fstab
UUID=aaaa / ext4 rw,relatime 0 1
UUID=bbbb /boot vfat rw,relatime 0 2
Step 7 — chroot into new system
$ sudo arch-chroot /mnt
[root@archiso /]#
Inside chroot — basic config
# ln -sf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime
# hwclock --systohc
# echo 'myhostname' > /etc/hostname
# passwd
# systemctl enable NetworkManager
🔑arch-chroot is smarter than plain chroot — auto-mounts /proc /sys /dev /run inside the new root.
Lab 4.5
Step 8: install GRUB bootloader
GRUB is the first thing that runs after UEFI — it loads the Linux kernel
[root@archiso /]# grub-install \
--target=x86_64-efi \
--efi-directory=/boot \
--bootloader-id=ARCH \
--removable
[root@archiso /]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
done
[root@archiso /]# ls /boot/EFI/BOOT/
BOOTX64.EFI
⚠️--removable is essential for loop device installs — without it GRUB registers with the HOST UEFI and won't be portable.
Lab 4.6
Finish installation and test with QEMU
Final steps inside chroot, then unmount cleanly and boot the image
Still inside arch-chroot
# echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen
# locale-gen
# echo 'LANG=en_US.UTF-8' > /etc/locale.conf
# exit
Back on host — unmount in reverse order!
$ sudo umount /mnt/boot
$ sudo umount /mnt
$ sudo losetup -d /dev/loop0
Test with QEMU (optional)
$ qemu-system-x86_64 \
-drive file=arch.img,format=raw \
-m 2G \
-bios /usr/share/ovmf/OVMF.fd \
-nographic
Or verify without QEMU
$ sudo losetup -P --find --show arch.img
$ sudo mount /dev/loop0p2 /mnt
$ sudo mount /dev/loop0p1 /mnt/boot
$ ls /mnt/boot
vmlinuz-linux initramfs-linux.img EFI/ grub/
$ sudo umount /mnt/boot /mnt
$ sudo losetup -d /dev/loop0
📋Unmount order: reverse of mount. umount /mnt/boot then umount /mnt — never the other way!
Summary
Complete command reference
Loop device
fallocate -l 4G file.imgcreate disk file
losetup -P --find --show fattach + scan
losetup -llist loop devices
losetup -d /dev/loop0detach
Partitioning
fdisk /dev/loop0interactive
parted -s /dev/loop0 mklabel gptscriptable
parted -s ... mkpart primary 1MiB 513MiBadd partition
lsblk /dev/loop0verify
Filesystems
mkfs.vfat -F 32 /dev/loop0p1FAT32 for EFI
mkfs.ext4 /dev/loop0p2ext4
lsblk -fshow FS types
blkid /dev/loop0p2show UUID
Mounting
mount /dev/loop0p2 /mntmount root
mount /dev/loop0p1 /mnt/bootmount EFI
findmnt /mntshow tree
umount /mnt/boot && umount /mntunmount
Arch install pipeline
pacstrap -K /mnt base linux linux-firmware grub efibootmgrinstall base
genfstab -U /mnt >> /mnt/etc/fstabgenerate fstab
arch-chroot /mntenter new system
grub-install --target=x86_64-efi --efi-directory=/boot --removableinstall GRUB
grub-mkconfig -o /boot/grub/grub.cfggenerate GRUB config
Reference
Common errors and fixes
losetup: /dev/loop0 is busy
Run losetup -d /dev/loop0. If that fails, the device is still mounted. Run umount /dev/loop0p1 (and any other partitions) first, then detach.
mount: /dev/loop0p1 does not exist
You forgot -P when attaching. Run losetup -P --find --show disk.img. The -P flag scans the partition table and creates loop0p1, loop0p2… nodes.
mkfs: disk.img contains a filesystem
You're running mkfs on the whole image file instead of a partition. Use the partition device: mkfs.ext4 /dev/loop0p2, not mkfs.ext4 disk.img. You must run fdisk first to create partitions.
grub-install: EFI variables not supported
Add --removable to the grub-install command. Alternatively try modprobe efivars. The --removable flag writes the fallback boot path instead of registering with UEFI firmware.
pacstrap: failed to retrieve files
Check internet connectivity: ping archlinux.org. If you're on Arch, update mirror list with reflector --save /etc/pacman.d/mirrorlist.
umount: target is busy
A process is still using the mount. Kill it with fuser -km /mnt or find it with lsof +D /mnt, then try umount again.