16

I thought I might experement with btrfs as the root partition to see how it handles file corruption during power cuts. But I can't get it to boot.

What I did:

  1. on the PI before switching:

    apt-get install btrfs-tools 2. From a linux computer:

    btrfs-convert /dev/sda2

  2. In /etc/fstab change ext4 to btrfs

  3. In /cmdline.txt change ext4 to btrfs

I get a kernel panic if I try do boot. Should I do anything else?

GuySoft
  • 935
  • 2
  • 10
  • 25

5 Answers5

9

If btrfs is compiled as a kernel module, then you need to create an initramfs to load the module at boot. On Raspian (and other debian derivatives), update-initramfs is the easiest method to do this.

If initramfs-tools is installed, then any time apt-get installs a new kernel, it should trigger update-initramfs automatically.

sudo apt-get update
sudo apt-get install initramfs-tools

However, if you use rpi-update to install a new kernel, then you'll need to run update-initramfs manually before rebooting into the new kernel:

sudo update-initramfs -u -k <kernel-version>

This will create or update the initramfs in /boot/initrd.img-<kernel-version>.

The final step is to add it to your boot config: add the following line to /boot/config.txt:

initramfs initrd.img-<kernel-version> followkernel

initrd-<kernel-version> must match exactly the name of the file in /boot.

You'll need to repeat these steps every time you run rpi-update.

bennettp123
  • 271
  • 2
  • 5
7

Raspbian kernel doesn't include support btrfs by default; the initial boot stages run normally, but when the kernel loads, it won't see any filesystem which it could mount - and panics. A solution exists: add btrfs as a kernel module, in initramfs. Largely thanks to three different articles, I have set it up thus:

  • Install the required packages - the kernel module, and the tools to update initramfs with it: sudo apt install btrfs-tools initramfs-tools
  • Tell initramfs to load the btrfs module (should be happening automagically, for some reason, didn't work on my RPi1) - append a line with "btrfs" to the list of required modules: echo 'btrfs' | sudo tee -a /etc/initramfs-tools/modules
  • Create an initramfs hook (for building the image) and script (for booting) for btrfs - defaults are provided, but in my testing, they were not used automagically, had to copy them into /etc. sudo mkdir -p /etc/initramfs-tools/hooks ; sudo mkdir -p /etc/initramfs-tools/scripts/local-premount ; sudo cp /usr/share/initramfs-tools/hooks/btrfs /etc/initramfs-tools/hooks ; sudo cp /usr/share/initramfs-tools/scripts/local-premount/btrfs /etc/initramfs-tools/scripts/local-premount; sudo chmod +x /etc/initramfs-tools/hooks/btrfs /etc/initramfs-tools/scripts/local-premount/btrfs
  • Create (-c) the new initramfs for current kernel version (uname -r) - if you're updating an existing one, you'll need to use update (-u) instead. This will create a file named like /boot/initrd.img-*, where the * is the current kernel version. Note the name generated (the script will output it), we'll use it in next step. update-initramfs -c -k $(uname -r)
  • Edit /boot/config.txt to use this initramfs, adding initramfs initrd.img-3.11.0+ followkernel The file name is without path, it's the one generated in previous step; "followkernel" controls location in memory (config.txt documentation).
  • That solves the current kernel, but as @Ingo pointed out, upgrading the kernel would break the system. To fix this, I used his kernel-install hook scripts:

    • Edit /etc/default/raspberrypi-kernel and uncomment INITRD=Yes
    • delete /etc/kernel/postinst.d/initramfs-tools
    • add rpi-initramfs-tools to /etc/kernel/postinst.d/ and chmod +x it
    • optionally, download update-rpi-initramfs for simpler manual updates of the initramfs.
  • At this point, we have a system which could use btrfs as root device. Test by rebooting: the system will still boot from the ext4 partition (or whatever is in your /boot/cmdline.txt), but dmesg | grep -i btrfs should now show a line containing "Btrfs loaded". Now we need to actually make and use a btrfs partition.

  • Make a backup of the / (ext4) partition - assuming this is /dev/mmcblk0p2 - typically: shutdown the RPi, take out the SD card, mount it somewhere else (in this example sudo mount /dev/mmcblk0p2 /mnt on a Linux computer) and archive the contents; note that you need to use a tool which preserves the ownership and permissions, e.g. tar: cd /mnt; sudo tar -czvf ~/rpi-rootfs-backup.tgz * (and then unmount the SD card again)

  • Create a btrfs partition somewhere - I have re-used the SD card, replacing the ext4 partition (/dev/mmcblk0p2); if you're looking to create a btrfs-raid array, this is the time to do this (it's one of the arguments to mkfs.btrfs, beyond the scope of this answer): mkfs.btrfs /dev/mmcblk0p2
  • Mount the btrfs partition and restore the backup into it: sudo partprobe; sudo mount /dev/mmcblk0p2 /mnt; cd /mnt; tar -xzvf ~/rpi-rootfs-backup.tgz
  • Edit fstab on the btrfs partition: sudo nano /mnt/etc/fstab

There should be a row similar to this:

/dev/mmcblk0p2  / ext4 foo,bar,baz 0 1

Change it to this (the new FS type is btrfs, and it uses default options):

/dev/mmcblk0p2  / btrfs defaults 0 1
  • Unmount the partition, but don't remove the SD card yet! sudo umount /mnt
  • We need to tell the RPi that it's going to boot from btrfs
  • Find the UUID of your new btrfs partition - find the line with /dev/mmcblk0p2, and copy the UUID= part, with the (not UUID_SUB, not PARTUUID! That would trigger a bug in the bootloader, and the kernel wouldn't boot.): sudo blkid

    /dev/mmcblk0p2: UUID="cafebeef-0000-1234-aaaa-12346589" UUID_SUB="ababccdd-2345-cafe-beee-587989991110" TYPE="btrfs" PARTUUID="beef0bee-02"

  • Mount the boot (FAT32) partition: sudo mount /dev/mmcblk0p1 /mnt

  • Edit cmdline.txt: sudo nano /mnt/cmdline.txt

Find these two parameters

 root=PARTUUID=1234-5678 rootfstype=ext4

And replace with

 root=UUID=cafebeef-0000-1234-aaaa-12346589 rootfstype=btrfs

Note that the UUID is the one we copied earlier, just without quotes.

  • Unmount the RPi boot partition: sudo umount /mnt
  • Replace the SD card into RPi, and boot.
  • On the RPi, see that you're indeed running from a btrfs root mount: mount

    /dev/mmcblk0p2 on / type btrfs (rw,space_cache,subvol=/)

  • Et voilĂ ! Not quite point-and-click, but by standing on the shoulders of giants, I could make it work. (Made this into a repo, too.)

6

A lot has changed since the answer from @Piskvor-left-the-building. Let me list the changes:

  • the config.txt and cmdline.txt files have been changed from /boot/ to /boot/firmware/ directory.
  • BTRFS tools and binary package is btrfs-progs and not btrfs-tools.
  • There is no need to manually add the initramfs image in config.txt, as it automatically detects the latest initramfs according to the current Kernel with the support of auto_initramfs=1 option in config.txt and it's enabled by default. This also means no extra work on making kernel-install hooks which was necessary earlier.

So, I have put together a high-level step-by-step process to achieve the same.

  1. Write a Raspberry Pi OS of your choosing to the disk. Choose the Lite image for a minimal installation.
  2. Manually add a small empty partition at the end to prevent the image from growing fully at the first startup. Remove this once the device is up.
  3. Manually resize the image by growing the partition to support additional data to be written to it. Recommended to add +1GB from the base size.
  4. Let the Kernel know about the changes to the partition and grow the FS
    partprobe /dev/disk-name
    resize2fs /dev/partition-name
    
  5. Update the system
    sudo apt update
    sudo apt upgrade
    
  6. Install important packages
    sudo apt install btrfs-progs initramfs-tools rsync
    
  7. Add BTRFS into the initramfs modules
    echo 'btrfs' | sudo tee -a /etc/initramfs-tools/modules
    
  8. Update Initramfs
    update-initramfs -c -k $(uname -r)
    
  9. Now, Reboot the machine and check if BTRFS is loaded.
    dmesg | grep -i btrfs
    
  10. Now, take a backup of the current FS and store it incase something goes wrong.
  11. Make a new partition for BTRFS and prepare your FS in it, all the sub-volumes and everything.
  12. Once the root sub-volume is made, use Rsync to clone the filesystem from the previous partition to the new BTRFS partition.
    rsync -avxHW / /mnt/btrfs/\@root/
    
  13. Make changes to the cmdline.txt file about the new root FS being BTRFS.(Includes changing the UUID to the new partition too)

Now you have a Raspberry Pi running on BTRFS. Congratulations.

Garo
  • 113
  • 1
redEye
  • 61
  • 1
  • 1
2

To get it to find my external BTRFS root partition, I needed to explicitly specify the root partition's UUID in the boot partition's cmdline.txt. For example:

dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=123e4567-e89b-12d3-a456-426655440000 rootfstype=btrfs elevator=deadline rootwait quiet splash

You can determine the BTRFS partition's UUID using lsblk -f.

Geremia
  • 173
  • 1
  • 13
2

My quick test shows that btrfs support is built as a external module in raspbian, not linked directly into the kernel.

That means that the kernel has to be able to load that module (which is stored on the root file system) before it knows how to mount the root file system. Obviously, this doesn't work.

Approach 1:

Build your own kernel, and tweak it's build config to pre-link btrfs. Tweaking the config is easy if you've figured out how to build and load your own kernel.

Approach 2:

Readjust things so the kernel and modules are on an ext4 filesystem and the data you most want to compress is on a btrfs partition.

Approach 2A:

Leave the root partition as ext4 and creating a new partition that's btrfs based, but that doesn't help shrink the OS installation (if that's your goal).

Approach 2B:

Create a boot partition that is small, and holds the kernel and modules, while leaving everything else on the btrfs. I have no idea how to do this for a Pi's bootloader, or what the limitations are around this.

DonGar
  • 273
  • 2
  • 3
  • 9