Skip to content

104.1 Create partitions and filesystems

Weight: 2

Candidates should be able to configure disk partitions and then create filesystems on media such as hard disks. This includes the handling of swap partitions.

Objectives

  • Manage MBR and GPT partition tables
  • Use various mkfs commands to create various filesystems such as ext2/ext3/ext4, XFS, VFAT, exFAT
  • Basic feature knowledge of Btrfs, including multi-device filesystems, compression and subvolumes.

Terms

fdisk, gdisk, parted, mkfs, mkswap

Block devices

A block device is a nonvolatile mass storage device whose information can be accessed in any order, like hard disks, USB memories, floppy disks and CD-ROMs. We format these devices into fixed sized blocks.

We can check all block devices using the lsblk command. In addition, in a long ls format (-l), block devices are shown with a b in the first column:

nagato@debianamd:~$ ls /dev/ -l | grep "^b"
brw-rw----  1 root disk      8,   0 Feb  3  2023 sda
brw-rw----  1 root disk      8,  16 Feb  3  2023 sdb
brw-rw----  1 root disk      8,  17 Feb  3  2023 sdb1
brw-rw----  1 root disk      8,  18 Feb  3  2023 sdb2
brw-rw----  1 root disk      8,  19 Feb  3  2023 sdb3
brw-rw----+ 1 root cdrom    11,   0 Feb  3  2023 sr0

That b in the first column is the same file type character from 103.3. The grep "^b" filters the listing down to block devices only.

It is possible to create partitions on a block device, splitting it and using it as multiple disks. Systems with old BIOS boot loaders use the Master Boot Record (MBR) method for partitioning, and newer UEFI systems use the GUID Partition Table (GPT) format.

Linux systems use udev to add block devices and their partitions to /dev in the form /dev/sdb1, meaning the second disk (b) and its first partition (1).

   /dev/sdb1
        |||
        ||+--- partition number, 1 = first partition
        |+---- disk letter, b = second disk
        +----- sd = SCSI/SATA disk

The two schemes side by side, which is the heart of this objective:

MBR GPT
Where the table lives first sector, the Boot Sector its own area, with a backup copy
Max disk size 2 TB no practical limit
Max partitions 4 primary 128 in the standard table
Needs extended partitions yes, to get past 4 no
Usual firmware BIOS UEFI
Dates from PC-DOS 2.0, 1983 modern UEFI machines

Editing Partition Tables

fdisk

fdisk is the main command for viewing, changing and creating partitions on MBR systems. The -l switch lists the partitions:

# fdisk -l /dev/sdb
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: QEMU HARDDISK
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: gpt
Disk identifier: 11D48091-5AA7-422A-85F7-A23F476CDFD7

Device        Start      End  Sectors  Size Type
/dev/sdb1      2048  1050623  1048576  512M EFI System
/dev/sdb2   1050624 39942143 38891520 18.5G Linux filesystem
/dev/sdb3  39942144 41940991  1998848  976M Linux swap
  • The Boot flag shows which partition starts the boot on DOS PCs and has no importance for LILO and GRUB
  • Start and End show where this partition is located on the disk.
  • Size shows each partition size.
  • ID indicates the partition format (82 is swap, 83 is linux data, check all with l in interactive mode)

Note Disklabel type: gpt in that output. fdisk reads GPT disks fine on modern versions, even though it is the MBR tool by tradition.

It is also possible to run fdisk in interactive mode. m will show you the help menu:

~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.36.1).
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 disklabel with disk identifier 0xe2dbaded.

Command (m for help): m

Help:

  DOS (MBR)
   a   toggle a bootable flag
   b   edit nested BSD disklabel
   c   toggle the dos compatibility flag

  Generic
   d   delete a partition
   F   list free unpartitioned space
   l   list known partition types
   n   add a new partition
   p   print the partition table
   t   change a partition type
   v   verify the partition table
   i   print information about a partition

  Misc
   m   print this menu
   u   change display/entry units
   x   extra functionality (experts only)

  Script
   I   load disk layout from sfdisk script file
   O   dump disk layout to sfdisk script file

  Save & Exit
   w   write table to disk and exit
   q   quit without saving changes

  Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty DOS partition table
   s   create a new empty Sun partition table

Command (m for help):

Read the greeting again, because it is the most important safety fact about fdisk. Changes stay in memory until you press w. So you can experiment freely and leave with q, and the disk is untouched.

   n, d, t, ...  ---> changes held in memory only
                            |
              +-------------+-------------+
              |                           |
             w                           q
        write to disk               throw away
        (permanent)                 (disk untouched)

That said, do not practise on a disk that matters. Use a spare disk or a USB stick.

To check the current partition list, try the p (print) command:

Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Disk model: QEMU HARDDISK
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: gpt
Disk identifier: 11D48091-5AA7-422A-85F7-A23F476CDFD7

Device        Start      End  Sectors  Size Type
/dev/sdb1      2048  1050623  1048576  512M EFI System
/dev/sdb2   1050624 39942143 38891520 18.5G Linux filesystem
/dev/sdb3  39942144 41940991  1998848  976M Linux swap

You should remember the disk layout concepts from chapter 102.1. So let's create some partitions using fdisk. I will use n for new:

# fdisk /dev/sda

Welcome to fdisk (util-linux 2.36.1).
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 disklabel with disk identifier 0x40bd0f72.

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):
First sector (2048-8388607, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-8388607, default 8388607): +1G

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

Command (m for help): p
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Disk model: QEMU HARDDISK
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: 0x40bd0f72

Device     Boot Start     End Sectors Size Id Type
/dev/sda1        2048 2099199 2097152   1G 83 Linux

Note the +1G for the last sector. You do not have to calculate sector numbers. Giving a size with K, M, G, T or P after a plus sign lets fdisk work it out.

Let's create another Extended partition and add a Linux (83) and a Swap (82) partition there.

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

Created a new partition 2 of type 'Extended' and of size 3 GiB.

Command (m for help): p
Device     Boot   Start     End Sectors Size Id Type
/dev/sda1          2048 2099199 2097152   1G 83 Linux
/dev/sda2       2099200 8388607 6289408   3G  5 Extended

Command (m for help): n
All space for primary partitions is in use.
Adding logical partition 5
First sector (2101248-8388607, default 2101248):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2101248-8388607, default 8388607):

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

Command (m for help): p
Device     Boot   Start     End Sectors Size Id Type
/dev/sda1          2048 2099199 2097152   1G 83 Linux
/dev/sda2       2099200 8388607 6289408   3G  5 Extended
/dev/sda5       2101248 8388607 6287360   3G 83 Linux

Notice the jump from partition 2 to partition 5. On an MBR disk, numbers 1 to 4 are reserved for primary partitions, so logical partitions inside an extended one always start at 5.

   MBR disk
   +----------+--------------------------------+
   | sda1     | sda2  (extended, a container)  |
   | primary  |  +---------+  +---------+      |
   |          |  | sda5    |  | sda6    |      |
   |          |  | logical |  | logical |      |
   |          |  +---------+  +---------+      |
   +----------+--------------------------------+

   numbers 1-4 = primary,  5 and up = logical

Oh, I forgot to allocate space for the swap partition. Let's delete the previous one and add two new ones:

Command (m for help): d
Partition number (1,2,5, default 5): 5

Partition 5 has been deleted.

Command (m for help): n
All space for primary partitions is in use.
Adding logical partition 5
First sector (2101248-8388607, default 2101248):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2101248-8388607, default 8388607): +1G

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

Command (m for help): p
Device     Boot   Start     End Sectors Size Id Type
/dev/sda1          2048 2099199 2097152   1G 83 Linux
/dev/sda2       2099200 8388607 6289408   3G  5 Extended
/dev/sda5       2101248 4198399 2097152   1G 83 Linux

Command (m for help): n
All space for primary partitions is in use.
Adding logical partition 6
First sector (4200448-8388607, default 4200448):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4200448-8388607, default 8388607):

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

And now I have to change the type of partition 6 to swap:

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

00 Empty            24 NEC DOS          81 Minix / old Lin  bf Solaris
01 FAT12            27 Hidden NTFS Win  82 Linux swap / So  c1 DRDOS/sec (FAT-
02 XENIX root       39 Plan 9           83 Linux            c4 DRDOS/sec (FAT-
03 XENIX usr        3c PartitionMagic   84 OS/2 hidden or   c6 DRDOS/sec (FAT-
04 FAT16 <32M       40 Venix 80286      85 Linux extended   c7 Syrinx
05 Extended         41 PPC PReP Boot    86 NTFS volume set  da Non-FS data
06 FAT16            42 SFS              87 NTFS volume set  db CP/M / CTOS / .
07 HPFS/NTFS/exFAT  4d QNX4.x           88 Linux plaintext  de Dell Utility
08 AIX              4e QNX4.x 2nd part  8e Linux LVM        df BootIt
0b W95 FAT32        51 OnTrack DM6 Aux  a0 IBM Thinkpad hi  ea Linux extended
0c W95 FAT32 (LBA)  52 CP/M             a5 FreeBSD          eb BeOS fs
0e W95 FAT16 (LBA)  53 OnTrack DM6 Aux  a6 OpenBSD          ee GPT
0f W95 Ext'd (LBA)  54 OnTrackDM6       a7 NeXTSTEP         ef EFI (FAT-12/16/
83 Linux            65 Novell Netware   af HFS / HFS+       fd Linux raid auto

Aliases:
   linux          - 83
   swap           - 82
   extended       - 05
   uefi           - EF
   raid           - FD
   lvm            - 8E
   linuxex        - 85
Hex code or alias (type L to list all): swap

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

Command (m for help): p
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Disklabel type: dos
Disk identifier: 0x40bd0f72

Device     Boot   Start     End Sectors Size Id Type
/dev/sda1          2048 2099199 2097152   1G 83 Linux
/dev/sda2       2099200 8388607 6289408   3G  5 Extended
/dev/sda5       2101248 4198399 2097152   1G 83 Linux
/dev/sda6       4200448 8388607 4188160   2G 82 Linux swap / Solaris

The two codes to memorise for the exam are in that list: 83 is Linux and 82 is Linux swap. Modern fdisk also accepts the aliases, so typing swap works as well as 82.

An important warning: do not confuse the partition type with the filesystem on it. They used to line up, but no longer do. A type 83 partition can hold ext4, XFS, Btrfs or anything else. The type code is only a hint to the operating system.

Satisfied! Let's verify and then write the results:

Command (m for help): v
No errors detected.
Remaining 4094 unallocated 512-byte sectors.

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

root@debianamd:~# fdisk -l /dev/sda
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Disk model: QEMU HARDDISK
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: 0x40bd0f72

Device     Boot   Start     End Sectors Size Id Type
/dev/sda1          2048 2099199 2097152   1G 83 Linux
/dev/sda2       2099200 8388607 6289408   3G  5 Extended
/dev/sda5       2101248 4198399 2097152   1G 83 Linux
/dev/sda6       4200448 8388607 4188160   2G 82 Linux swap / Solaris

Two more fdisk details. F shows unallocated space:

Command (m for help): F
Unpartitioned space /dev/sdd: 881 MiB, 923841536 bytes, 1804378 sectors
Units: sectors of 1 * 512 = 512 bytes
  Start End Sectors Size
1050624 2099199 1048576 512M
3147776 3903577 755802 369M

And a trap worth knowing. Those two free blocks add up to 881 MB, but a new 700 MB partition still fails:

Command (m for help): n
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1050624-2099199, default 2099199): +700M
Value out of range.

The reason is that a partition has to be contiguous. The largest single gap is only 512 MB, and a new partition cannot reach over partition 3 to use the space beyond it.

Also, deleting an extended partition deletes every logical partition inside it.

gdisk

As seen in chapter 102.1, we have used gdisk on GPT machines. It is not that different from fdisk. Let's have a look at its main commands:

root@debianamd:~# gdisk /dev/sda
GPT fdisk (gdisk) version 1.0.6  

Warning: Partition table header claims that the size of partition table
entries is 0 bytes, but this program  supports only 128-byte entries.
Adjusting accordingly, but partition table may be garbage.
Partition table scan:
  MBR: MBR only
  BSD: not present
  APM: not present
  GPT: not present

***************************************************************
Found invalid GPT and valid MBR; converting MBR to GPT format
in memory. THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by
typing 'q' if you don't want to convert your MBR partitions
to GPT format!
***************************************************************

Command (? for help): ?
b   back up GPT data to a file
c   change a partition's name
d   delete a partition
i   show detailed information on a partition
l   list known partition types
n   add a new partition
o   create a new empty GUID partition table (GPT)
p   print the partition table
q   quit without saving changes
r   recovery and transformation options (experts only)
s   sort partitions
t   change a partition's type code
v   verify disk
w   write table to disk and exit
x   extra functionality (experts only)
?   print this menu

As you can see, the partition table has to be compatible with your BIOS/UEFI setup.

The commands are deliberately the same as fdisk: p print, n new, d delete, t type, w write, q quit. The help key is ? instead of m.

This is what a GPT partition table looks like from gdisk:

Command (? for help): p
Disk /dev/sdb: 3903578 sectors, 1.9 GiB
Model: DataTraveler 2.0
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): AB41B5AA-A217-4D1E-8200-E062C54285BE
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 3903544
Partitions will be aligned on 2048-sector boundaries
Total free space is 1282071 sectors (626.0 MiB)

Number Start (sector) End (sector) Size Code Name
  1 2048 2099199 1024.0 MiB 8300 Linux filesystem
  2 2623488 3147775 256.0 MiB 8300 Linux filesystem

Three differences from fdisk output stand out:

  • Each disk has a unique GUID, a random 128 bit number. It is used to identify a filesystem at boot time without depending on a device path like /dev/sdb, which can change.
  • It says the table holds up to 128 entries. That is why GPT needs no extended or logical partitions at all.
  • Free space is printed on the last line, so there is no need for the F command.

The type codes differ too. On GPT they are four digits, so 8300 is Linux filesystem and 8200 is Linux swap, matching the MBR 83 and 82.

GPT also allows partitions to be renumbered with s to close gaps. Delete partition 2 out of three, press s, and the old partition 3 becomes partition 2.

Because GPT keeps a backup copy of its header and table, gdisk has a recovery menu under r. From there, b and c rebuild a corrupt main header or table from the backup, d and e rebuild the backup from the main copy, and f and g convert between MBR and GPT.

parted

parted is the GNU tool to edit partitions. Its main advantage is the ability to resize currently defined partitions, but using it is a bit trickier than fdisk and gdisk:

# parted
GNU Parted 3.4
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) help
  align-check TYPE N                       check partition N for TYPE(min|opt) alignment
  help [COMMAND]                           print general help, or help on COMMAND
  mklabel,mktable LABEL-TYPE               create a new disklabel (partition table)
  mkpart PART-TYPE [FS-TYPE] START END     make a partition
  name NUMBER NAME                         name partition NUMBER as NAME
  print [devices|free|list,all|NUMBER]     display the partition table, available devices, free space, all found partitions, or a particular partition
  quit                                     exit program
  rescue START END                         rescue a lost partition near START and END
  resizepart NUMBER END                    resize partition NUMBER
  rm NUMBER                                delete partition NUMBER
  select DEVICE                            choose the device to edit
  disk_set FLAG STATE                      change the FLAG on selected device
  disk_toggle [FLAG]                       toggle the state of FLAG on selected device
  set NUMBER FLAG STATE                    change the FLAG on partition NUMBER
  toggle [NUMBER [FLAG]]                   toggle the state of FLAG on partition NUMBER
  unit UNIT                                set the default unit to UNIT
  version                                  display the version number and copyright information of GNU Parted

Two warnings that matter a great deal here.

First, parted writes changes immediately. There is no w step and no safe q escape. This is the opposite of fdisk and gdisk.

   fdisk / gdisk       parted
   ---------------     --------------------
   change              change  -> written to disk NOW
   change              change  -> written to disk NOW
   w  = commit
   q  = cancel         there is no cancel

Second, running parted with no device name selects the primary disk, usually /dev/sda, automatically. Always name the device.

Getting information. print shows the current disk, print devices lists all disks, print free includes the gaps:

(parted) print
Model: ATA CT120BX500SSD1 (scsi)
Disk /dev/sda: 120GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number Start End Size Type File system Flags
 1 2097kB 116GB 116GB primary ext4
 2 116GB 120GB 4295MB primary linux-swap(v1)
(parted) print free
Number Start End Size Type File system Flags
  32.3kB 2097kB 2065kB Free Space
 1 2097kB 116GB 116GB primary ext4
  116GB 116GB 512B Free Space
 2 116GB 120GB 4295MB primary linux-swap(v1)
  120GB 120GB 2098kB Free Space

Creating a partition table with mklabel. Note that parted calls MBR by its old name, msdos:

(parted) mklabel msdos
(parted) mklabel gpt

Creating a partition with mkpart PARTTYPE FSTYPE START END:

(parted) mkpart primary ext4 1m 100m

The single most confusing thing about parted is that END is not a size. It is the position on the disk where the partition finishes, counted from the start of the disk:

   fdisk:   last sector +1G      means "make it 1 GB big"
   parted:  mkpart ... 1m 100m   means "end at the 100 MB mark"

Also, parted does not create the filesystem. The FSTYPE just sets a flag saying what kind of data to expect.

rm NUMBER deletes a partition. If you delete one by mistake, rescue START END scans that area and offers to put it back:

(parted) rescue 90m 210m
Information: A ext4 primary partition was found at 99.6MB -> 200MB.
Do you want to add it to the partition table?
Yes/No/Cancel? y

rescue only finds partitions that had a filesystem on them. Empty partitions are invisible to it.

Resizing is what parted is really for, with resizepart NUMBER END:

(parted) resizepart 3 350m

But the partition is only half the job. The filesystem inside it also has to be resized, and for ext2/3/4 that is resize2fs:

$ sudo resize2fs /dev/sdb3
resize2fs 1.44.6 (5-Mar-2019)
Resizing the filesystem on /dev/sdb3 to 146212 (1k) blocks.
The filesystem on /dev/sdb3 is now 146212 (1k) blocks long.
$ df -h /dev/sdb3
Filesystem Size Used Avail Use% Mounted on
/dev/sdb3 135M 1.6M 123M 2% /media/carol/part3

The order matters and getting it wrong destroys data:

   GROWING                       SHRINKING
   1. resizepart  (bigger)       1. resize2fs  (smaller)
   2. resize2fs   (bigger)       2. resizepart (smaller)

   the rule: the filesystem must never be
   larger than the partition holding it

The partition must also be unmounted while resizing, and there has to be free space right after it to grow into. resize2fs -M shrinks a filesystem to the smallest size its files allow.

hint? use gparted

The gparted tool is a graphical tool to manage your partitions. It has the ability to resize partitions and is super easy to use. It is not part of the LPIC exam but it is good to know about it, just in case. See gparted.org

Formatting the partition

Filesystems

After you have partitioned your block devices, you have to format them to make them usable to store files and directories. Formatting a file system creates a map which stores the location and name of files and directories, and makes it possible to move files between folders, delete them or rename them. Think of it as the index of a book.

There are several filesystems in the linux world, but these are the most commonly used ones:

Format Description
ext2 second extended filesystem was developed to address shortcomings in the older Unix/Minix filesystem used in early versions of Linux. It has been used extensively on Linux for many years. There is no journaling in ext2, and it has largely been replaced by ext3 and more recently ext4.
ext3 ext2 + journaling, max file size is 2TB and max filesystem size is 16TB
ext4 current version of ext, max file size is 16TB and max filesystem size is 1EB (1000*1000TB)
XFS journaling, caches to RAM, great for uninterruptible power supplies, Max file and filesystem size is 8EB
swap Swap is used when the system needs to use more ram than it has. It is like extra ram on disk
VFAT FAT32, no journaling, good for data exchange with windows, does not understand permissions and symbolic links
exFAT Extended FAT. A newer version of FAT which is used mainly for extended devices which should work on all machines, like USB disks
btrfs A new high performance file system. Max file and filesystem size is 16 EB. Has its own form of RAID and LVM and built-in snapshots and fault tolerance and data compression on the fly.

The word journaling appears three times in that table and is the key idea. A journal is a log the filesystem writes before it makes a change. If the power fails halfway through, the system reads the journal on the next boot and finishes or undoes the change, instead of leaving the disk in a broken state. That is the main reason ext3 replaced ext2.

Several details per filesystem:

  • XFS was made by Silicon Graphics in 1993 for IRIX, and is common on servers needing high, guaranteed throughput. Red Hat Enterprise Linux 7 uses it by default. Its journal, called the log section, normally sits inside the data section but can be put on a separate disk for speed.
  • VFAT is FAT16 extended to support long file names up to 255 characters. FAT16 tops out at a 4 GB volume and a 2 GB file, FAT32 at a 2 PB volume and a 4 GB file. Both are handled by mkfs.fat, with mkfs.vfat as an alias.
  • exFAT was made by Microsoft in 2006 to fix that file size limit, reaching 16 EB per file and 128 PB per disk. Windows, Linux and macOS all support it, which is why the SD Association picked it as the default for SDXC cards over 32 GB.
  • Btrfs has been developed since 2007 by Oracle and others. It is copy-on-write: when you change part of a file, the new data is written to free space first, the metadata is then pointed at the new data, and only then is the old data released. Nothing is overwritten in place, so a crash mid-write cannot corrupt the file.

Creating filesystems

You can format your partitions with the mkfs command, and mkswap for swap. This is a front end to commands like mkfs.ext3 for ext3, mkfs.ext4 for ext4 and mkfs.reiserfs for ReiserFS. The full list installed on your system is here:

# ls /sbin/mk*
/sbin/mkdosfs  /sbin/mkexfatfs  /sbin/mkfs.bfs     /sbin/mkfs.exfat  /sbin/mkfs.ext3  /sbin/mkfs.fat    /sbin/mkfs.msdos  /sbin/mkfs.vfat     /sbin/mkinitramfs   /sbin/mkntfs
/sbin/mke2fs   /sbin/mkfs   /sbin/mkfs.cramfs  /sbin/mkfs.ext2   /sbin/mkfs.ext4  /sbin/mkfs.minix  /sbin/mkfs.ntfs   /sbin/mkhomedir_helper  /sbin/mklost+found  /sbin/mkswap

If using mkfs, the main switch is -type (or -t) to specify the format:

# mkfs -t ext4 /dev/sda1
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: 63625ecd-857a-419f-a300-12395aaad89f
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

root@debianamd:~# mkfs.exfat /dev/sda5
mkexfatfs 1.3.0
Creating... done.
Flushing... done.
File system created successfully.

Read the mkfs -t ext4 output line by line, since it names the parts of an ext filesystem:

  • 262144 4k blocks and 65536 inodes = the space is divided into 4 KB blocks, and there are 65536 inodes, one per file or directory the filesystem can hold.
  • Filesystem UUID: ... = the unique identifier just created for this filesystem.
  • Superblock backups stored on blocks: = copies of the superblock, the master record of the filesystem, kept at several places so a damaged one can be repaired. This comes back in 104.2.
  • Creating journal (8192 blocks) = ext4 is a journaling filesystem, so a journal was made.

An important detail about the ext tools: mkfs.ext2, mkfs.ext3 and mkfs.ext4 are all symbolic links to one program, mke2fs, which changes its defaults based on which name it was called by. So these two lines do the same thing:

# mkfs.ext4 /dev/sdb1
# mke2fs -t ext4 /dev/sdb1

The mke2fs options worth knowing, all of which work with mkfs.ext2/3/4 too:

  • -b SIZE block size, 1024, 2048 or 4096 bytes
  • -c check for bad blocks first, and -c -c for a slower thorough check
  • -d DIRECTORY pre-populate the new filesystem with the contents of a directory
  • -F force, ignoring warnings. -F -F will even format a mounted device, which is a very bad idea
  • -L LABEL set a volume label, at most 16 characters
  • -n a trial run, showing what would happen without doing it
  • -q quiet, for use in scripts
  • -U ID set the UUID, or use clear, random or time
  • -V verbose

The -n option is the one to remember for safety. It lets you check a mkfs command before running it for real.

The other filesystems have their own options:

XFS, with mkfs.xfs: -b size=VALUE block size, default 4096; -m crc=1 metadata checksums, on by default; -m uuid=VALUE set the UUID; -f force; -l logdev=DEVICE put the journal on another disk; -l size=10m limit the journal size; -L LABEL label, max 12 characters; -N trial run.

FAT/VFAT, with mkfs.fat: -c check bad blocks; -C FILENAME BLOCK_COUNT create a disk image file rather than formatting a device; -F SIZE pick 12, 16 or 32 for FAT12, FAT16 or FAT32; -n NAME label, max 11 characters; -v verbose. Note that mkfs.fat cannot create a bootable filesystem.

exFAT, with mkfs.exfat: -i VOL_ID volume ID; -n NAME label, max 15 characters; -p SECTOR first sector; -s SECTORS sectors per cluster, must be a power of two.

Btrfs, with mkfs.btrfs, has features the others do not. It takes more than one device at once, spanning the filesystem across them:

# mkfs.btrfs /dev/sdb1
# mkfs.btrfs /dev/sdb1 -L "New Disk"
# mkfs.btrfs -d single -m single /dev/sdb /dev/sdc

-m sets how metadata is spread across the devices, accepting raid0, raid1, raid5, raid6, raid10, single and dup. Btrfs labels can be up to 256 characters. Spanning several disks with single means one disk failing loses all the data, and the risk grows with each disk added.

Subvolumes are filesystems inside a filesystem. Unlike partitions they do not reserve fixed space, they share the free space of the parent and grow as needed:

# btrfs subvolume create /mnt/disk/BKP
$ ls -lh /mnt/disk/
total 0
drwxr-xr-x 1 root root 0 jul 13 17:35 BKP
drwxrwxr-x 1 carol carol 988 jul 13 17:30 Images

A subvolume looks like an ordinary directory but can be mounted on its own:

# mount -t btrfs -o subvol=BKP /dev/sdb1 /mnt/bkp

Snapshots are subvolumes pre-filled with the contents of the volume they came from. They take almost no space at first, because they copy the filesystem tree while still pointing at the same data:

# btrfs subvolume snapshot /mnt/disk /mnt/disk/snap

From that point the two diverge. Deleting files from the original leaves them intact inside the snapshot:

$ rm LG-G8S-ThinQ-*
$ ls -lh
-rw-rw-r-- 1 carol carol 109K jul 10 16:22 Galaxy_Note_10.png
-rw-rw-r-- 1 carol carol 484K jul 5 15:01 geminoid2.jpg
drwx------ 1 carol carol 366 jul 13 17:56 snap
$ ls -lh snap/
-rw-rw-r-- 1 carol carol 109K jul 10 16:22 Galaxy_Note_10.png
-rw-rw-r-- 1 carol carol 484K jul 5 15:01 geminoid2.jpg
-rw-rw-r-- 1 carol carol 467K jul 2 11:48 LG-G8S-ThinQ-Mirror-White.jpg
-rw-rw-r-- 1 carol carol 654K jul 2 11:39 LG-G8S-ThinQ-Range.jpg

The two deleted files are still in snap/ and can be restored. Adding -r makes a read-only snapshot, frozen in time.

Compression on Btrfs is transparent and per file, switched on by mounting with -o compress. The default algorithm is ZLIB, with LZO (faster, compresses less) and ZSTD (faster than ZLIB, similar ratio) also available. It detects files that will not compress and leaves them alone, so one directory can hold a mix of compressed and uncompressed files.

If you need to assign a label to the partition, you have to use the -L label_name option. Note that on recent systems people use UUIDs instead of labels. The UUID of a disk can be viewed with:

# blkid /dev/sda1
/dev/sda1: UUID="63625ecd-857a-419f-a300-12395aaad89f" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="40bd0f72-01"

That UUID is the same one mkfs printed when it created the filesystem. UUIDs matter because device names can move. If you add a disk, today's /dev/sdb1 might be tomorrow's /dev/sdc1, but the UUID never changes. This is why /etc/fstab uses UUIDs, which comes up in 104.3.

And as the last task, let's create a swap on /dev/sda6:

# mkswap /dev/sda6
Setting up swapspace version 1, size = 2 GiB (2144333824 bytes)
no label, UUID=6a59cf20-8fd6-4d86-b044-89f7bc67993b

and then

# swapon /dev/sda6

In chapter 104.3 we will see how we can mount and unmount these filesystems.

The three steps for swap, in order:

   1. make the partition, type 82 on MBR or 8200 on GPT
   2. mkswap /dev/sda6      prepare it as swap space
   3. swapon /dev/sda6      start using it

swapoff with the device name stops using it again.

Linux can also use a swap file instead of a partition. You make an empty file with dd, then treat it exactly like a partition:

$ dd if=/dev/zero of=myswap bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 7.49254 s, 143 MB/s
# mkswap myswap
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=49c53bc4-c4b1-4a8b-a613-8f42cb275b2b
# swapon myswap

That dd line is the one from 103.3: if= input, of= output, bs=1M one megabyte blocks, count=1024 of them, giving 1 GB of zeros. The swap file should be owned by root with permissions 0600, or both mkswap and swapon will complain. A swap file set up this way lasts only until reboot unless it is added to /etc/fstab.

Real world use for a swap file: a running server has too little swap and no free partition to spare. A swap file can be created, enabled and removed without touching the partition table at all.

Summary

I have a Linux system where a disk has to be partitioned before it can hold anything, and the partition table comes in two forms. MBR is the old scheme, stored in the first sector, limited to 2 TB disks and four primary partitions, which is why extra partitions have to live inside an extended container and get numbered from 5 upward. GPT is the modern scheme used with UEFI, with no practical size limit, room for 128 partitions, a unique GUID per disk and a backup copy of its own table.

I edit MBR tables with fdisk and GPT tables with gdisk, and the two share almost the same keys: p to print, n to add, d to delete, t to change the type, v to verify, w to write and q to leave. Both keep my changes in memory until I press w, so I can back out safely. parted is the third tool and behaves differently in two ways I have to remember: it writes every change immediately with no undo, and its mkpart takes an ending position rather than a size. What parted gives me in return is resizepart, and resizing means resizing the filesystem too, growing the partition first and the filesystem second, but shrinking the filesystem first and the partition second.

Once a partition exists it still needs a filesystem, which I create with mkfs -t TYPE or one of the named forms like mkfs.ext4, mkfs.xfs, mkfs.fat or mkfs.exfat. The ext family are all one program, mke2fs, reached under different names. I pick ext4 for normal Linux use, XFS for servers wanting throughput, VFAT or exFAT when a Windows or macOS machine has to read the disk too, and Btrfs when I want subvolumes, snapshots and transparent compression. Journaling is what separates ext3 and later from ext2, and copy-on-write is what makes Btrfs resilient. Useful options across the tools are -L for a label and -n or -N for a trial run that shows what would happen without touching anything.

Swap is a partition of type 82 on MBR or 8200 on GPT, prepared with mkswap and switched on with swapon, and off again with swapoff. If I have no spare partition I can make a swap file instead, using dd to create an empty file and then treating it exactly like a partition, as long as it is owned by root with permissions 0600. Whether I use a partition or a file, it only survives a reboot once it is listed in /etc/fstab. Finally, every filesystem gets a UUID when it is made, which I can read back with blkid. That UUID is worth using in place of a device path, because /dev/sdb1 can become /dev/sdc1 the moment I add another disk, while the UUID never changes.