diff --git a/docs/Getting Started/Ubuntu/Ubuntu 20.04 Root on ZFS for Raspberry Pi.rst b/docs/Getting Started/Ubuntu/Ubuntu 20.04 Root on ZFS for Raspberry Pi.rst index ac76833..5a8817b 100644 --- a/docs/Getting Started/Ubuntu/Ubuntu 20.04 Root on ZFS for Raspberry Pi.rst +++ b/docs/Getting Started/Ubuntu/Ubuntu 20.04 Root on ZFS for Raspberry Pi.rst @@ -12,7 +12,7 @@ Overview Caution ~~~~~~~ -- This HOWTO uses a whole physical SD card. +- This HOWTO uses a whole physical disk. - Backup your data. Any existing data will be lost. System Requirements @@ -22,11 +22,13 @@ System Requirements :doc:`Ubuntu 20.04 Root on ZFS`.) - `Ubuntu Server 20.04.3 (“Focal”) for Raspberry Pi 4 `__ -- A microSD card. For recommendations, see Jeff Geerling's `performance - comparison +- A microSD card or USB disk. For microSD card recommendations, see Jeff + Geerling's `performance comparison `__. -- An Ubuntu system (with the ability to write to the SD card) other than the - target Raspberry Pi. + When using a USB enclosure, `ensure it supports UASP + `__. +- An Ubuntu system (with the ability to write to the microSD card or USB disk) + other than the target Raspberry Pi. 4 GiB of memory is recommended. Do not use deduplication, as it needs `massive amounts of RAM `__. @@ -97,6 +99,53 @@ entered at the console. Performance is good, but LUKS sits underneath ZFS, so if multiple disks (mirror or raidz topologies) are used, the data has to be encrypted once per disk. +USB Disks +~~~~~~~~~ + +The Raspberry Pi 4 runs much faster using a USB Solid State Drive (SSD) than +a microSD card. These instructions can also be used to install Ubuntu on a +USB-connected SSD or other USB disk. USB disks have three requirements that +do not apply to microSD cards: + +#. The Raspberry Pi's Bootloader EEPROM must be dated 2020-09-03 or later. + + To check the bootloader version, power up the Raspberry Pi without an SD + card inserted or a USB boot device attached; the date will be on the + ``bootloader`` line. (If you do not see the ``bootloader`` line, the + bootloader is too old.) Alternatively, run ``sudo rpi-eeprom-update`` + on an existing OS on the Raspberry Pi (which on Ubuntu requires + ``apt install rpi-eeprom``). + + If needed, the bootloader can be updated from an existing OS on the + Raspberry Pi using ``rpi-eeprom-update -a`` and rebooting. + For other options, see `Updating the Bootloader + `_. + +#. The Raspberry Pi must configured for USB boot. The bootloader will show a + ``boot`` line; if ``order`` includes ``4``, USB boot is enabled. + + If not already enabled, it can be enabled from an existing OS on the + Raspberry Pi using ``rpi-eeprom-config -e``: set ``BOOT_ORDER=0xf41`` + and reboot to apply the change. On subsequent reboots, USB boot will be + enabled. + + Otherwise, it can be enabled without an existing OS as follows: + + - Download the `Raspberry Pi Imager Utility + `_. + - Flash the ``USB Boot`` image to a microSD card. The ``USB Boot`` image is + listed under ``Bootload`` in the ``Misc utility images`` folder. + - Boot the Raspberry Pi from the microSD card. USB Boot should be enabled + automatically. + +#. U-Boot on Ubuntu 20.04 does not seem to support the Raspberry Pi USB. + `Ubuntu 20.10 may work + `_. As a + work-around, the Raspberry Pi bootloader is configured to directly boot + Linux. For this to work, the Linux kernel must not be compressed. These + instructions decompress the kernel and add a script to + ``/etc/kernel/postinst.d`` to handle kernel upgrades. + Step 1: Disk Formatting ----------------------- @@ -143,19 +192,34 @@ be deleted. 3 : start=$((2048+BOOT+ROOT)), size=$ROOT, type=83 EOF -#. Connect the SD card: +#. Connect the disk: - Connect the SD card to a machine other than the target Raspberry Pi. If - any filesystems are automatically mounted (e.g. by GNOME), unmount them. - Determine the device name (which is almost certainly as shown below) and - set it in a variable:: + Connect the disk to a machine other than the target Raspberry Pi. If any + filesystems are automatically mounted (e.g. by GNOME) unmount them. + Determine the device name. For SD, the device name is almost certainly + ``/dev/mmcblk0``. For USB SSDs, the device name is ``/dev/sdX``, where + ``X`` is a lowercase letter. ``lsblk`` can help determine the device name. + Set the ``DISK`` environment variable to the device name:: - DISK=/dev/mmcblk0 + DISK=/dev/mmcblk0 # microSD card + DISK=/dev/sdX # USB disk + + Because partitions are named differently for ``/dev/mmcblk0`` and ``/dev/sdX`` + devices, set a second variable used when working with partitions:: + + export DISKP=${DISK}p # microSD card + export DISKP=${DISK} # USB disk ($DISKP == $DISK for /dev/sdX devices) + + **Hint**: microSD cards connected using a USB reader also have ``/dev/sdX`` + names. + + **WARNING**: The following steps destroy the existing data on the disk. Ensure + ``DISK`` and ``DISKP`` are correct before proceeding. #. Ensure swap partitions are not in use:: swapon -v - # If a partition is in use from the SD card, disable it: + # If a partition is in use from the disk, disable it: sudo swapoff THAT_PARTITION #. Clear old ZFS labels:: @@ -167,14 +231,14 @@ be deleted. **Hint:** If you do not already have the ZFS utilities installed, you can install them with: ``sudo apt install zfsutils-linux`` Alternatively, you - can zero the entire SD card with: + can zero the entire disk with: ``sudo dd if=/dev/zero of=${DISK} bs=1M status=progress`` #. Delete existing partitions:: echo "label: dos" | sudo sfdisk ${DISK} sudo partprobe - ls ${DISK}* + ls ${DISKP}* Make sure there are no partitions, just the file for the disk itself. This step is not strictly necessary; it exists to catch problems. @@ -190,11 +254,11 @@ be deleted. #. Copy the bootloader data:: - sudo dd if=${IMG}p1 of=${DISK}p1 bs=1M + sudo dd if=${IMG}p1 of=${DISKP}1 bs=1M #. Clear old label(s) from partition 2:: - sudo wipefs -a ${DISK}p2 + sudo wipefs -a ${DISKP}2 If a filesystem with the ``writable`` label from the Ubuntu image is still present in partition 2, the system will not boot initially. @@ -202,15 +266,59 @@ be deleted. #. Copy the root filesystem data:: # NOTE: the destination is p3, not p2. - sudo dd if=${IMG}p2 of=${DISK}p3 bs=1M status=progress conv=fsync + sudo dd if=${IMG}p2 of=${DISKP}3 bs=1M status=progress conv=fsync #. Unmount the image:: sudo losetup -d $IMG +#. If setting up a USB disk: + + Decompress the kernel:: + + sudo -sE + + MNT=$(mktemp -d /mnt/XXXXXXXX) + mkdir -p $MNT/boot $MNT/root + mount ${DISKP}1 $MNT/boot + mount ${DISKP}3 $MNT/root + + zcat -qf $MNT/boot/vmlinuz >$MNT/boot/vmlinux + + Modify boot config:: + + cat >> $MNT/boot/usercfg.txt << EOF + kernel=vmlinux + initramfs initrd.img followkernel + boot_delay + EOF + + Create a script to automatically decompress the kernel after an upgrade:: + + cat >$MNT/root/etc/kernel/postinst.d/zz-decompress-kernel << 'EOF' + #!/bin/sh + + set -eu + + echo "Updating decompressed kernel..." + [ -e /boot/firmware/vmlinux ] && \ + cp /boot/firmware/vmlinux /boot/firmware/vmlinux.bak + vmlinuxtmp=$(mktemp /boot/firmware/vmlinux.XXXXXXXX) + zcat -qf /boot/vmlinuz > "$vmlinuxtmp" + mv "$vmlinuxtmp" /boot/firmware/vmlinux + EOF + + chmod +x $MNT/root/etc/kernel/postinst.d/zz-decompress-kernel + + Cleanup:: + + umount $MNT/* + rm -rf $MNT + exit + #. Boot the Raspberry Pi. - Move the SD card into the Raspberry Pi. Boot it and login (e.g. via SSH) + Move the SD/USB disk to the Raspberry Pi. Boot it and login (e.g. via SSH) with ``ubuntu`` as the username and password. If you are using SSH, note that it takes a little bit for cloud-init to enable password logins on the first boot. Set a new password when prompted and login again using that @@ -225,11 +333,17 @@ Step 2: Setup ZFS sudo -i -#. Set a variable with the disk name:: +#. Set the DISK and DISKP variables again:: - DISK=/dev/mmcblk0 + DISK=/dev/mmcblk0 # microSD card + DISKP=${DISK}p # microSD card - On the Pi, this is always ``mmcblk0``. + DISK=/dev/sdX # USB disk + DISKP=${DISK} # USB disk + + **WARNING:** Device names can change when moving a device to a different + computer or switching the microSD card from a USB reader to a built-in + slot. Double check the device name before continuing. #. Install ZFS:: @@ -252,7 +366,7 @@ Step 2: Setup ZFS -O acltype=posixacl -O canmount=off -O compression=lz4 \ -O dnodesize=auto -O normalization=formD -O relatime=on \ -O xattr=sa -O mountpoint=/ -R /mnt \ - rpool ${DISK}p2 + rpool ${DISKP}2 **WARNING:** Encryption has not yet been tested on the Raspberry Pi. @@ -265,11 +379,11 @@ Step 2: Setup ZFS -O acltype=posixacl -O canmount=off -O compression=lz4 \ -O dnodesize=auto -O normalization=formD -O relatime=on \ -O xattr=sa -O mountpoint=/ -R /mnt \ - rpool ${DISK}p2 + rpool ${DISKP}2 - LUKS:: - cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha256 ${DISK}p2 + cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha256 ${DISKP}2 cryptsetup luksOpen ${DISK}-part4 luks1 zpool create \ -o ashift=12 \ @@ -416,7 +530,7 @@ Step 3: System Installation #. Optional: Ignore synchronous requests: - SD cards are relatively slow. If you want to increase performance + microSD cards are relatively slow. If you want to increase performance (especially when installing packages) at the cost of some safety, you can disable flushing of synchronous requests (e.g. ``fsync()``, ``O_[D]SYNC``): @@ -509,7 +623,6 @@ Step 4: System Configuration #. Setup system groups:: addgroup --system lpadmin - addgroup --system lxd addgroup --system sambashare #. Patch a dependency loop: @@ -598,10 +711,16 @@ Step 5: First Boot sudo -i +#. Set the DISK variable again:: + + DISK=/dev/mmcblk0 # microSD card + + DISK=/dev/sdX # USB disk + #. Delete the ext4 partition and expand the ZFS partition:: - sfdisk /dev/mmcblk0 --delete 3 - echo ", +" | sfdisk --no-reread -N 2 /dev/mmcblk0 + sfdisk $DISK --delete 3 + echo ", +" | sfdisk --no-reread -N 2 $DISK **Note:** This does not automatically expand the pool. That will be happen on reboot. @@ -643,7 +762,13 @@ Step 5: First Boot If it did not automatically expand, try to expand it manually:: - zpool online -e rpool mmcblk0p2 + DISK=/dev/mmcblk0 # microSD card + DISKP=${DISK}p # microSD card + + DISK=/dev/sdX # USB disk + DISKP=${DISK} # USB disk + + zpool online -e rpool ${DISKP}2 #. Delete the ``ubuntu`` user:: @@ -658,11 +783,13 @@ Step 6: Full Software Installation .. code-block:: yaml - network: - version: 2 - ethernets: - eth0: - dhcp4: true + network: + version: 2 + ethernets: + eth0: + dhcp4: true + + :: rm /etc/netplan/50-cloud-init.yaml apt purge --autoremove ^cloud-init