☂️ rain.re

Poor Man's LVM on OpenBSD

2025-12-10

THIS POST IS WIP

Too Long, Didn't Read

Currently, there is no support for LVM in OpenBSD, but you can sort of approximate it by mounting files.

This is cursed in many ways.

What's LVM?

LVM is the Logical Volume Manager. It enables one to resize partitions as they wish, among other things.

For now, LVM is not ported on OpenBSD. Thus, when a partition is full, you have to do some re-partitioning wizardry. Let's create our own LVM!

Mom, can we have LVM at home ? No, there is LVM at home. LVM at home... swapon /pool/swap.img; mount /pool/home.img /home; ...

Step 0: Install OpenBSD

Please just mostly follow the installation guide. Make sure you have at least 30 GiB available.

At the Disk Partitioning step, only add a partition for "/".

Encrypt the root disk => "no"
Use (W)hole disk MBR, whole disk (G)PT or (E)dit? => "G" if using UEFI, "W" otherwise
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? "C"
wd0> a
partition to add: [a] a
[... keep the defaults]
mount point: [none] /
sd0*> w
sd0> x

Then, continue normally and reboot.

Personnally, I use a pre-built Virtual Machine but YMMV.

Step 1: Configure the kernel to have enough virtual disks

On a default OpenBSD installation, you can create up to 4 virtual disks. As we are going to use 1 disk per partition, that won't be enough.

You can reconfigure your kernel to allow 10 virtual disks (for example), then don't forget to reboot.

# vnconfig -l
vnd0: not in use
vnd1: not in use
vnd2: not in use
vnd3: not in use
# config -e -f /bsd
OpenBSD 7.8 (GENERIC.MP) #54: Sun Oct 12 12:58:11 MDT 2025
    deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Enter 'help' for information
ukc> change vnd
506 vnd count 4 (pseudo device)
change [n] y
count [4] ? 10
506 vnd changed
506 vnd count 10 (pseudo device)
ukc> quit
Saving modified kernel.
# reboot
[snip]
# vnconfig -l
vnd0: not in use
vnd1: not in use
vnd2: not in use
vnd3: not in use
vnd4: not in use
vnd5: not in use
vnd6: not in use
vnd7: not in use
vnd8: not in use
vnd9: not in use

Step 2: stop all services that might interfere

Step 3: add the swapfile (easy)

Step 4: add the partitions (hard)

Final script

#!/usr/bin/env sh

# adapted from https://github.com/hcartiaux/openbsd-cloud-image/blob/fd12c211f720efee3398b6342e4ec6b39716193c/custom/create_partitions.sh

vnd_devices="$(vnconfig -l | wc -l)"

if [ "$vnd_devices" -lt 6 ]
then
    echo Setting up more virtual devices.
    printf 'change vnd\ny\n10\nquit\n' >> /etc/bsd.re-config
    config -e -c /etc/bsd.re-config -f /bsd
    echo Please reboot before continuing.
    exit 1
fi

function stop_services {
    /etc/rc.d/sndiod stop
    /etc/rc.d/ntpd stop
    /etc/rc.d/smtpd stop
    /etc/rc.d/cron stop
}

function start_services {
    /etc/rc.d/sndiod start
    /etc/rc.d/ntpd start
    /etc/rc.d/smtpd start
    /etc/rc.d/cron start
}

function add_swap {
    size=$1

    echo "Adding swap (size=${size})"
    dd if=/dev/zero of=/lvm/swap seek="$size" bs=1 count=0
    echo "/lvm/swap none swap sw" >> /etc/fstab
    swapon /lvm/swap
    if [ "$?" -ne 0 ]; then
        echo "Error during swap partition creation"
        exit 1
    fi
}

function add_part {
    part=/lvm/$1
    path=$2
    size=$3
    options=$4
    vnd=$5

    echo "Adding ${path} to ${part} (size=${size})"
    dd if=/dev/zero of="$part" seek="$size" bs=1 count=0
    echo "$part /dev/${vnd}c vnd rw 0 0" >> /etc/fstab
    echo "/dev/${vnd}c $path ffs $options 0 0" >> /etc/fstab
    cd /dev/
    sh /dev/MAKEDEV $vnd
    cd -
    mount ${part}
    newfs ${vnd}c

    if [ "$?" -eq 0 ]; then
        mkdir -p ${path}
        mv ${path} ${path}.orig
        mkdir -p ${path}
        mount ${path}
        mv  ${path}.orig/* ${path}/
        rm -rf ${path}.orig/
    else
        echo "Error during partition and filesystem creation"
        exit 1
    fi
}

stop_services
mkdir -p /lvm/
add_swap 400m
add_part tmp /tmp 1000m rw,nodev,nosuid vnd0
chmod 1777 /tmp
add_part var /var 4000m rw,nodev,nosuid vnd1
add_part usr /usr 5000m rw,nodev vnd2
add_part usr_local /usr/local 6000m rw,wxallowed,nodev vnd3
add_part usr_src /usr/src 2000m rw,nodev,nosuid vnd4
add_part usr_obj /usr/obj 2000m rw,nodev,nosuid vnd5
add_part home /home 5000m rw,nodev,nosuid vnd6
start_services