JeffTP

Squandering a perfectly good opportunity to shut up and listen.

Manual Partitioning

Published: 2024-08-25 • Reading time: 6 min

#linux #nixos #disko #sysadmin

The deeper I get into NixOS, the more I question the choices of the NixOS community. When I wrote about partitioning disks in NixOS using Disko I provided an example of a basic linux partitioning scheme using ext4 partitions. Disko does the trick of partitioning the disk from a mostly straightforward Nix file. But what's the point of using Disko when it requires downloading nearly 200 MB of additional helpers to get the job done? Worse, you can't edit the disko.nix file later and hope to magically reconfigure or resize partitions.

I really like the concept of write everything in Nix, except I find the Nix language itself difficult to understand and impossible to troubleshoot because the available development tooling is pretty thin for Nix.

Review Disko Configuration File

Let's review the Disko configuration for my simple partitioning scheme. As a reminder, my partition scheme:

  • /dev/sda1 -- /boot, 1 GB, FAT32
  • /dev/sda2 -- (LVM vg1), the rest, LVM
    • /dev/vg1/swap -- (swap), 8G, swap
    • /dev/vg1/nix -- /nix, 50G, ext4
    • /dev/vg1/root -- /, the rest, ext4

Here's the Disko configuration file written in nix:

{
  disko.devices = {
    disk.sda = {
      type = "disk";
      device = "/dev/sda";
      content = {
        type = "gpt"; # Initialize the disk with a GPT partition table
        partitions = {
          ESP = { # Setup the EFI System Partition
            type = "EF00"; # Set the partition type
            size = "1000M"; # Make the partition a gig
            content = {
              type = "filesystem";
              format = "vfat"; # Format it as a FAT32 filesystem
              mountpoint = "/boot"; # Mount it to /boot
            };
          };
          primary = { # Setup the LVM partition
            size = "100%"; # Fill up the rest of the drive with it
            content = {
              type = "lvm_pv"; # pvcreate
              vg = "vg1";
            };
          };
        };
      };
    };
    lvm_vg = { # vgcreate
      vg1 = { # /dev/vg1
        type = "lvm_vg";
        lvs = { # lvcreate
          swap = { # Logical Volume = "swap", /dev/vg1/swap
            size = "8G";
            content = {
              type = "swap";
            };
          };
          nix = { # Logical Volume = "nix", /dev/vg1/nix
            size = "50G";
            content = {
              type = "filesystem";
              format = "ext4";
              mountpoint = "/nix";
              mountOptions = [
                "noatime" # Reduce writes--we don't care about access times
              ];
            };
          };
          root = { # Logical Volume = "root", /dev/vg1/root
            size = "100%FREE"; # Use the remaining space in the Volume Group
            content = {
              type = "filesystem";
              format = "ext4";
              mountpoint = "/";
              mountOptions = [
                "defaults"
              ];
            };
          };
        };
      };
    };
  };
}

I admit, it's nice to have the fstab options (namely noatime for /nix) defined along with the rest of the disk configuration. But let's compare this configuration to a shell script that does the same thing as Disko:

# Create the partitions
parted /dev/sda -- mklabel gpt
parted /dev/sda -- mkpart ESP fat32 1MiB 1GiB
parted /dev/sda -- set 1 esp on
parted /dev/sda -- mkpart vg1 1GiB 100%
parted /dev/sda -- set 2 lvm on

# Setup LVM
pvcreate /dev/sda2
vgcreate vg1 /dev/sda2
lvcreate --name swap --size 8G vg1
lvcreate --name nix --size 50G vg1
lvcreate --name root --extents 100%FREE vg1

# Format the filesystems
mkfs.fat -F 32 /dev/sda1
mkswap /dev/vg1/swap
mkfs.ext4 /dev/vg1/nix
mkfs.ext4 /dev/vg1/root

# Mount partitions for NixOS install
swapon /dev/vg1/swap
mount /dev/vg1/root /mnt
mkdir -p /mnt/nix
mount /dev/vg1/nix /mnt/nix
mkdir -p /mnt/boot
mount /dev/sda1 /mnt/boot

Normally I would use fdisk to partition disks, but I find scripting fdisk or guiding someone through fdisk to be a terrible end-user experience. Because I wanted a readable partition configuration, I decided to get more familiar with parted and walked away pleasantly surprised at how clear it comes across.

How to Successfully use mkpart with parted

There's a great deal of confusion spread across the blogs and wikis of the Linux world from the days of MSDOS partition tables. If your mkpart command includes the keyword primary, you're reading out of data or incorrect instructions. Or worse, you're using an MSDOS partition table.

In most cases, you should not be using MSDOS partition tables. First, an MSDOS partition table is limited to 2 TB disks or smaller. So it's met the end of it's useful life. Second, with UEFI systems, a GPT partition table is required. There may be UEFI systems that will work with MSDOS partition tables, but they're doing something outside the UEFI specification.

If you've built your partition table with mklabel gpt, then the mkpart command takes these commands:

mkpart [partition-label] [filesystem-type] <start> <end>

The partition-label and filesystem-type options are... optional. The partition-label will set a text label on the partition of your choosing. You want to name your partition Cheesy Poofs, go ahead. That's weird, but maybe that's your kind of labeling scheme. The filesystem-type can be BTRFS, EXT2, EXT3, EXT4, FAT16, FAT32, linux-swap, NTFS, XFS, etc. It's notable that parted doesn't offer LVM or ZFS as available types; or maybe it's just notable to me.

The start and end are both from the start of the drive. In my example above the boot partition starts at 1 MiB and ends at 1 GiB both measured from the start of the disk. The LVM partition starts at 1 GiB (where the boot partition ends) and the end is specified as 100% of the distance from the start of the disk, which is should be the end of the disk.

Partition Labels with Spaces

In my testing I was running into problems with specifying partition labels with spaces. For example, when manually typing in the command below using "EFI System Partition" as the partition label I would get an error that parted didn't understand System as a valid filetype.

parted /dev/sda -- mkpart "EFI System Partition" fat32 1MiB 1GiB

The problem is bash is eating my quotation marks and I had to add single quote marks around the double quote marks:

parted /dev/sda -- mkpart '"EFI System Partition"' fat32 1MiB 1GiB

Comparing Disko and Manual Partitioning

When compared to Disko this manual/scripted method of getting the disks setup is so much more clear as to what's going on. I understand it, or can at least look up each command and get answers to questions about what is going on. Manual partitioning also doesn't require downloading 200 MB of additional material to execute. And this is my biggest problem with Disko. It's a really great idea, but it's too easy to replace with two dozen lines of a shell script that I can manually type in.

Maybe if Disko did more than one-shot partitioning, I could recommend it. I can see the desire to move everything to Nix, except that I don't particularly like the Nix language and I do not like how much of Disko feels like magic incantation rather than system administration.