1. Overview

Partitioning disks in Linux is generally the first step before installing a system. Before we can create any files, a filesystem must exist. Similarly, we can’t make a filesystem unless there is a partition on the disk.

Partitions are used to divide raw storage space into chunks (slices). This provides the means for organization and hosting of filesystems. Besides that, partitions also help isolate filesystem faults.

In this tutorial, we’ll discuss the tools and the process of partitioning disks in Linux. First, we’ll discuss in brief about disk types and boot modes. Secondly, we’ll go through the partitioning examples, using parted and LVM partitioning. And finally, we’ll conclude with a summary of the discussed topics.

2. Disk Types and Tools

The information about how a disk is partitioned is stored on the disk. This is usually called a partition table. The entries in this table define where partitions on the disk start and end. The format of this table is sometimes regarded as the disk type.

2.1. MBR and GPT

MBR (Master Boot Record) and GPT (GUID Partition Table) are the most widely used partition tables. As compared to GPT, MBR is an old standard and has some limitations.

In the MBR scheme with 32-bit entries, we can only have a maximum disk size of 2 TB. Furthermore, only four primary partitions are allowed. However, we can use an extended partition that is further divided into logical partitions to overcome this limitation.

Besides partition entries, the MBR also contains a boot loader that is written in the initial sectors of the drive.

Whereas, GPT doesn’t contain a boot loader and can have up to 128 partitions (128-bit entries). Thus, most of the modern computers come pre-configured with a GPT disk. Though, GPT does support the MBR section for backward compatibility.

2.2. BIOS and UEFI

BIOS (Basic Input Output System) is low-level software that performs hardware initialization and loads the boot loader from the MBR. Gradually BIOS is being replaced by UEFI (Unified Extensible Firmware Interface). Still, most new systems have support for both.

Instead of loading a boot loader from the MBR, UEFI uses efi images from the EFI System Partition. With UEFI and GPT, we can have large disk support.

In some Linux systems, it is possible to use BIOS boot mode with a GPT disk.

2.3. Partitioning Tools

Historically, to partition MBR disks, the fdisk tool is used. However, in new Linux systems, fdisk can also understand GPT format.

In this article, however, we’ll focus on the parted tool. The parted tool is newer and understands both GPT and MBR layouts. Moreover, it is also considered a better option for partitioning disks in Linux because of its usability in scripting and automation.

3. Using the parted Tool

We’ll use a system with multiple hard drives. Let’s now start a terminal and list available hard drives:

$ lsblk -e7
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda      8:0    0   100G  0 disk 
├─sda1   8:1    0   512M  0 part /boot/efi
├─sda2   8:2    0     1K  0 part 
└─sda5   8:5    0  99,5G  0 part /
sdb      8:16   0 976,6G  0 disk 
sdc      8:32   0   3,8T  0 disk

We’ve used lsblk command with option -e7 to exclude loop devices (device number 7).

In total, we’ve three disks in this system. The sda drive is the Linux system drive with three partitions. But, drives sdb and sdc have no partition table.

3.1. Selecting a Device

Since sda is the system drive, we’ll use sdb and sdc for our partitioning examples.

Let’s now start the parted program and select sdb drive:

# parted 
GNU Parted 3.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)

In interactive mode, all parted commands are issued one at a time, on the (parted) prompt. Notice that parted is using /dev/sda drive by default.

Before committing any partition changes, always check if the correct drive is selected:

(parted) select /dev/sdb                                                  
Using /dev/sdb
(parted)

To change the target device, we use the select command. Additionally, we can also start the parted program with a specific device:

(parted) quit                                                             
# parted /dev/sdb
GNU Parted 3.3
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) q                                                                
#

As we can see that commands can be abbreviated. For instance, q can be used instead of quit.

3.2. Getting Partition Information

We’ll now see, how to list partition information:

# parted /dev/sda
GNU Parted 3.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print                                                            
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sda: 107GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End    Size   Type      File system  Flags
 1      1049kB  538MB  537MB  primary   fat32        boot
 2      539MB   107GB  107GB  extended
 5      539MB   107GB  107GB  logical   ext4

(parted)

Here, we’ve used the print command to show information about the sda drive. We can see that the partition table is MBR (msdos). Furthermore, the disk size (by default) is reported in bytes.

Let’s now try some other units:

# parted /dev/sda unit s print unit chs print
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sda: 209715200s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start     End         Size        Type      File system  Flags
 1      2048s     1050623s    1048576s    primary   fat32        boot
 2      1052670s  209713151s  208660482s  extended
 5      1052672s  209713151s  208660480s  logical   ext4

Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sda: 411206,69,1
Sector size (logical/physical): 512B/512B
BIOS cylinder,head,sector geometry: 411206,255,2.  Each cylinder is 261kB.
Partition Table: msdos
Disk Flags: 

Number  Start      End          Type      File system  Flags
 1      4,4,0      2060,11,1    primary   fat32        boot
 2      2064,15,0  411202,65,1  extended
 5      2064,16,0  411202,65,1  logical   ext4

With the unit command, we can change the units that are used to report sizes and start/end marks. For instance, we’ve now used s (sector) and chs (cylinder-head-sector). Additionally, we can chain multiple commands in the command-line mode.

3.3. Creating Partitions

Let’s see now, how to use parted tool for the partitioning of disks:

# parted -s /dev/sdb mklabel gpt
# parted -s /dev/sdb mkpart primary fat32 0% 512MiB
# parted -s /dev/sdb mkpart primary linux-swap 1048576s 16GiB
# parted -s /dev/sdb mkpart primary ext4 16GiB 40%
# parted -s /dev/sdb mkpart primary ext4 40% 60%
# parted -s /dev/sdb mkpart primary ext4 60% 100%
# parted -s /dev/sdb name 1 EFI-Boot
# parted -s /dev/sdb name 2 Swap
# parted -s /dev/sdb name 3 root
# parted -s /dev/sdb name 4 /opt
# parted -s /dev/sdb name 5 /home
# parted -s /dev/sdb set 1 esp on

The mklabel command sets the partition table type. And, the most usual choices are gpt and msdos (MBR). In particular, we must set this before partitioning the disk.

The -s  option is useful in scripts to suppress most warnings from the parted command.

To create partitions on the selected disk, we can use the mkpart command. The syntax requires partition-type, filesystem-type, start, and end parameters.

On a GPT disk, there is no extended partition. Therefore, we can specify all partitions as primary.

Different units are allowed for start and end parameters in the mkpart command. For example, we’ve used percentages, exact sector counts, and sizes as units. Moreover, we can also mix these units in a single command invocation. We’ve also set partition names based on the intended usage.

Additionally, we’ve set the esp (EFI system partition) flag on the first partition. On a GPT disk, the esp flag is an alias to the boot flag. Generally, on a Linux system, this partition is mounted on /boot/efi. We can find more details on how to mount filesystems on Linux.

Let’s verify the changes we’ve made to the sdb drive:

# parted /dev/sdb unit GiB print  
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sdb: 977GiB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start    End      Size     File system  Name      Flags
 1      0,00GiB  0,50GiB  0,50GiB               EFI-Boot  boot, esp
 2      0,50GiB  16,0GiB  15,5GiB               Swap      swap
 3      16,0GiB  391GiB   375GiB                root
 4      391GiB   586GiB   195GiB                /opt
 5      586GiB   977GiB   391GiB                /home

3.4. Modifying Partitions

Let’s go back to the terminal and make some changes in our partition scheme:

# parted -s /dev/sdb rm 5
# parted -s /dev/sdb resizepart 4 70%
# parted -s /dev/sdb mkpart primary ext4 70% 100%
# parted -s /dev/sdb name 5 /home

We want to extend /opt, but this will result in the overlap. Hence, we’ve removed /home to resize /opt partition.

To resize a partition, we can only change the end parameter of a partition. Using the resizepart command, we can extend or shrink a partition.

Let’s again verify our changes:

# parted /dev/sdb unit GiB print
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sdb: 977GiB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start    End      Size     File system  Name      Flags
 1      0,00GiB  0,50GiB  0,50GiB               EFI-Boot  boot, esp
 2      0,50GiB  16,0GiB  15,5GiB               Swap      swap
 3      16,0GiB  391GiB   375GiB                root
 4      391GiB   684GiB   293GiB                /opt
 5      684GiB   977GiB   293GiB                /home

4. Partitioning Using LVM

LVM (Logical Volume Management) is an alternative way for partitioning disks in Linux. LVM provides a higher level of abstraction with the ability to pool physical storage. Consequently, enabling flexibility and dynamic resizing when requirements change.

A physical volume (pv) is the lowest level of abstraction in LVM. We can mark a whole physical disk or a partition as a physical volume. And, then, it can be used in pooling.

A volume group (vg) is the next level of abstraction after physical volume. A volume group can pool multiple physical volumes, combining their storage capacity under a single logical unit.

A logical volume (lv) is the highest layer in LVM abstraction. Therefore, users and applications use logical volumes like any standard partition. We can have several logical volumes within a volume group.

4.1. Creating Physical Volumes

We’ll now use some LVM commands to create and monitor volumes. In fact, we’ll use the same partitions from sdb and the whole disk sdc.

Let’s now switch to the terminal and select devices for physical volume preparation:

# lvmdiskscan
  /dev/sdb1 [     511,00 MiB] 
  /dev/sdb2 [      15,50 GiB] 
  /dev/sdb3 [     374,62 GiB] 
  /dev/sdb4 [    <292,97 GiB] 
  /dev/sdb5 [    <292,97 GiB] 
  /dev/sdc  [       3,81 TiB] 
  1 disk
  5 partitions
  0 LVM physical volume whole disks
  0 LVM physical volumes

The lvmdiskscan command can scan for devices, partitions, and physical volumes. Although, beware that the output of this command can be exhaustive and may include other device types. We can control this by the file lvm.conf. For instance, in our system, loop devices and the sda drive is filtered out.

Now we’ve one whole disk and five partitions available that we can mark as LVM physical volume.

Let’s see now, how to mark devices as a physical volume:

# pvcreate /dev/sdc 
  Physical volume "/dev/sdc" successfully created.
# pvcreate /dev/sdb1 
  Physical volume "/dev/sdb1" successfully created.
# pvcreate /dev/sdb2
  Physical volume "/dev/sdb2" successfully created.
# pvcreate /dev/sdb3
  Physical volume "/dev/sdb3" successfully created.

The pvcreate command can mark partitions or whole disks as a physical volume. We do see some warnings because some partitions have a filesystem on them. Beware that this operation may destroy data on these devices.

Let’s now verify the changes we’ve made:

# lvmdiskscan
  /dev/sdb1 [     511,00 MiB] LVM physical volume
  /dev/sdb2 [      15,50 GiB] LVM physical volume
  /dev/sdb3 [     374,62 GiB] LVM physical volume
  /dev/sdb4 [    <292,97 GiB] 
  /dev/sdb5 [    <292,97 GiB] 
  /dev/sdc  [       3,81 TiB] LVM physical volume
  0 disks
  2 partitions
  1 LVM physical volume whole disk
  3 LVM physical volumes
# pvs
  PV         VG Fmt  Attr PSize   PFree  
  /dev/sdb1     lvm2 ---  511,00m 511,00m
  /dev/sdb2     lvm2 ---   15,50g  15,50g
  /dev/sdb3     lvm2 ---  374,62g 374,62g
  /dev/sdc      lvm2 ---    3,81t   3,81t

The lvmdiskscan command now correctly reports the changes we’ve made. Moreover, we can use the pvs command for a summary of all physical volumes including their assignment to volume groups.

4.2. Creating Volume Groups

Let’s now create some volume groups by selecting physical volumes:

# vgcreate VG_Projects /dev/sdb1 /dev/sdb2 
  Volume group "VG_Projects" successfully created
# vgcreate VG_Databases /dev/sdb3 /dev/sdc 
  Volume group "VG_Databases" successfully created

Using the vgcreate command, we’ve created two volume groups. A volume group can include physical volumes from different devices.

Let’s again verify our changes:

# vgs
  VG           #PV #LV #SN Attr   VSize  VFree 
  VG_Databases   2   0   0 wz--n-  4,18t  4,18t
  VG_Projects    2   0   0 wz--n- 15,99g 15,99g
# pvs
  PV         VG           Fmt  Attr PSize   PFree  
  /dev/sdb1  VG_Projects  lvm2 a--  508,00m 508,00m
  /dev/sdb2  VG_Projects  lvm2 a--  <15,50g <15,50g
  /dev/sdb3  VG_Databases lvm2 a--  374,62g 374,62g
  /dev/sdc   VG_Databases lvm2 a--    3,81t   3,81t

Using the vgs command, we can have a summary of all volume groups. Now we can see that volume groups are reported with respective capacities. Furthermore, we can also see that now the pvs command reports the correct physical volume to volume group mapping.

4.3. Creating Logical Volumes

Finally, we can create some logical volumes within volume groups:

# lvcreate -L 8G -n ProjectA VG_Projects
  Logical volume "ProjectA" created.
# lvcreate -l 100%FREE -n ProjectB VG_Projects
  Logical volume "ProjectB" created.
# lvcreate -l 30%VG -n DatabaseA VG_Databases
  Logical volume "DatabaseA" created.
# lvcreate -l 50%FREE -n DatabaseB VG_Databases
  Logical volume "DatabaseB" created.

Using the lvcreate command, we’ve created four logical volumes. A fixed-size can be used with -L option. However, with -l option, we can specify the size in percentages.

For instance, 30%VG will use 30 percent of volume group capacity, and 50%FREE will use 50 percent of the remaining space on the volume group.

Let’s get back to the terminal and verify the changes:

# lvs
  LV        VG           Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  DatabaseA VG_Databases -wi-a----- 1,25t                                                    
  DatabaseB VG_Databases -wi-a----- 1,46t                                                    
  ProjectA  VG_Projects  -wi-a----- 8,00g                                                    
  ProjectB  VG_Projects  -wi-a----- 7,99g   

With the lvs command, we can see the logical volumes that we’ve created.

4.4. Modifying Logical Volumes and Volume Groups

A logical volume can be accessed either as /dev/VolumeGroup/LogicalVolume or as /dev/mapper/VolumeGroup-LogicalVolume.

To extend/reduce a volume group, we can use vgextend/vgreduce commands. Likewise, to extend/reduce a logical volume, we can use lvextend/lvreduce commands.

Let’s now make some modifications:

# vgreduce VG_Databases /dev/sdb3 
  Removed "/dev/sdb3" from volume group "VG_Databases"
root@LinBox:~# vgs
  VG           #PV #LV #SN Attr   VSize  VFree 
  VG_Databases   1   2   0 wz--n-  3,81t <1,10t
  VG_Projects    2   2   0 wz--n- 15,99g     0 
root@LinBox:~# vgextend VG_Projects /dev/sdb3
  Volume group "VG_Projects" successfully extended
root@LinBox:~# vgs
  VG           #PV #LV #SN Attr   VSize   VFree  
  VG_Databases   1   2   0 wz--n-   3,81t  <1,10t
  VG_Projects    3   2   0 wz--n- 390,61g 374,62g
root@LinBox:~# lvextend -L +5G /dev/VG_Projects/ProjectA
  Size of logical volume VG_Projects/ProjectA changed from 8,00 GiB (2048 extents) to 13,00 GiB (3328 extents).
  Logical volume VG_Projects/ProjectA successfully resized.
root@LinBox:~# lvreduce -L -2G /dev/VG_Projects/ProjectB
  WARNING: Reducing active and open logical volume to 5,99 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce VG_Projects/ProjectB? [y/n]: y
  Size of logical volume VG_Projects/ProjectB changed from 7,99 GiB (2046 extents) to 5,99 GiB (1534 extents).
  Logical volume VG_Projects/ProjectB successfully resized.
root@LinBox:~# lvs
  LV        VG           Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  DatabaseA VG_Databases -wi-ao----  1,25t                                                    
  DatabaseB VG_Databases -wi-ao----  1,46t                                                    
  ProjectA  VG_Projects  -wi-ao---- 13,00g                                                    
  ProjectB  VG_Projects  -wi-ao----  5,99g             

Now we’ve reduced VG_Databases by removing /dev/sdb3 and added this to VG_Projects. Additionally, we extended ProjectA and reduced ProjectB.

We should take special care if reducing logical volumes will result in data loss. However, In this example, all modifications were done while filesystems are live, and no data was lost.

5. Conclusion

In this article, we discussed some ways of partitioning disks in Linux. Firstly, we discussed some background on MBR/GPT partitioning schemes, BIOS/UEFI boot modes, and their support in new systems. And Later on, we discussed partitioning with the parted tool and the LVM.

The GPT format has more benefits over the older MBR scheme. However, to support legacy systems, we can still see the MBR format being used in production.

Although we can resize standard partitions, this isn’t flexible in case of overlaps. Moreover, after resizing with parted, the filesystem needs to be extended. We need to be cautious when using parted for resizing a partition.

The LVM partitioning does provide a more flexible and robust solution than standard partitioning. That is specifically useful in administrative tasks like resizing or moving volumes without data loss.