Klaus on Tilde Town

Resizing an encrypted swap partition in Linux

If I had to enumerate the scariest computer things that I've had to do over my career with Linux, what I went through just this afternoon would probably rank on the top 5, if not 3. At first, it sounded straightforward enough - resizing a swap partition to get more space. But there was an aggravation factor: the disk where it resided was LUKS encrypted.

Why did I want to do that? Simple - to hibernate properly. For some reason that I don't know modern installers are quite stingy in terms of allocation of swap space in the disk, with my latest installs always defaulting to just under 1GB of space (963 MB or so). This is not nearly enough to save a work session from a laptop into the disk. I'd need a few GB more to be comfortable, and in this case a swap file simply didn't work.

Usually, the procedure I follow for these cases is simple enough: boot a live USB, run GParted, resize the partitions graphically and commit the changes. However, because the partition was encrypted, I ran into a few problems. For starters, GParted wasn't able to read the encrypted partitions because a few extra packages were missing to handle LUKS. But even after I installed them, it would still not be able to do anything with the partitions within the encrypted volume, which were exactly the things I wanted to resize.

This was when the fear hit: I no longer could use the safety of the graphical program to change my partitions. I was left, again, with only the command-line to complete the mission. After searching for a how-to on performing this very specific task, I found an answer on Stackoverflow describing the exact situation. It turns out that it isn't much of GParted's fault: you really can't resize things freely within the volume, but rather, you must instead shrink a certain part of the volume to make space for the other one you want to expand. Here's the summary:

The procedure

First, boot into a live medium that contains GParted (my portable distro of choice Alpine Linux is great for this!) and find out the order and IDs of the disk partitions in the machine:

$ lsblk
NAME         MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda            8:0    0 223.6G  0 disk  
├─sda1         8:1    0   512M  0 part  
├─sda2         8:2    0   488M  0 part  
└─sda3         8:3    0 222.6G  0 part
...

In this example, /dev/sda3 is the root (/) partition of the disk that we want to resize. Since it's encrypted, we have to unlock it first so we can see the internal partitions that we actually want to resize:

# cryptsetup luksOpen /dev/sda3 crypt

Enter your LUKS password. A new "mapper" device is then created under /dev/mapper/ for the unlocked disk. Check again the device tree to see that you have all the partitions under the encrypted volume available:

$ lsblk
NAME                     MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda                        8:0    0 223.6G  0 disk  
├─sda1                     8:1    0   512M  0 part  
├─sda2                     8:2    0   488M  0 part  
└─sda3                     8:3    0 222.6G  0 part  
  └─sda3_crypt           254:0    0 222.6G  0 crypt 
      ├─hostname--vg-root   254:1    0  27.9G  0 lvm   
      │                                               /
      ├─hostname--vg-swap_1 254:2    0   976M  0 lvm   [SWAP]
      └─hostname--vg-home   254:3    0 193.7G  0 lvm   /home

Our goal here, then is to enlarge the hostname--vg-swap_1 partition by taking some space from hostname--vg-home. Note that this machine in particular has this setup because I chose to put my user files in a separate /home partition. Other simpler setups may only have one partition for everything (root / partition).

Caution: if you're messing with anything related to the disk, always back up your data first! Do so before proceeding here!

It's time now for the command-line magic. First, shrink the partition we want to "transfer" space from. Suppose that we want to add 5GiB to swap. We then remove that space from the other partition like this:

# `-L -5G`  means "shrink the partition by 5GB"
$ doas lvresize --verbose --resizefs -L -5G /dev/mapper/hostname--vg-home

Test that the filesystem is OK after this with fsck:

# e2fsck -f /dev/mapper/hostname--vg-home

If you find errors in this step, just accept fsck's solutions by pressing y. Then it's time to fill out that gap in the volume by increasing your desired partition, in this case the swap:

# `-L +5G`  means "increase the partition by 5GB"
$ doas lvresize --verbose -L -5G /dev/mapper/hostname--vg-swap_1

The job is done, close the volume:

# cryptsetup luksClose crypt

Now reboot the machine (through the disk, not the live medium) and check the amount of swap you have with free. If you still see the old amount of swap you had before, don't panic. Just deactivate and re-activate your swap partition:

# swapon --show
NAME      TYPE      SIZE USED PRIO
/dev/dm-2 partition 976M   0B   -2

# swapoff /dev/dm-2
# mkswap /dev/dm-2
mkswap: /dev/dm-2: warning: wiping old swap signature.
Setting up swapspace version 1, size = 5 GiB (... bytes)
no label, UUID=...

# swapon -a

Check again and presto - your swap is at full capacity again!

Conclusion

Almost 15 years of Linux usage later, and I still get very nervous when it comes to disk and partition formatting and management via the command-line. I'm not exactly ashamed of it - this is the one case where a graphical program does a much better job than cryptic utilities like fdisk - but still it might be time to start learning it.

By going through this hands-on task, I felt that I learned a lot more not only about the partitioning process, but also about how Linux volumes work in general. This will be useful next time I need to resize external hard drives and disks. And in the end, my laptop now hibernates fine through systemctl hibernate and I can store it overnight and resume the next morning without the battery draining out. Double win!


What command-line tools do you use to resize disks partitions in Linux? Did you ever have to do something like this? Let me know in Mastodon!


This post is number #51 of my #100DaysToOffload project.


Last updated on 03/20/24