How To Convert An ext3/ext4 Root File System To btrfs On Ubuntu 12.10 - Page 2

Want to support HowtoForge? Become a subscriber!
 
Submitted by falko (Contact Author) (Forums) on Sun, 2012-11-25 19:33. ::

4 Doing A Conversion According To Ubuntu Subvolume Layout (With @ And @home Subvolumes)

This is a bit more complicated and took me some time to figure out. It is absolutely necessary to follow each step in the same order as described!

In the rescue system, log in as root. Make sure that btrfs-tools are installed:

apt-get install btrfs-tools

Do a file system check...

fsck -f /dev/sda1

... and then run the conversion tool:

btrfs-convert /dev/sda1

root@ubuntu:~# btrfs-convert /dev/sda1
creating btrfs metadata.
creating ext2fs image file.
cleaning up system chunk.
conversion complete.
root@ubuntu:~#

Next we mount our system partition and chroot to it:

mount /dev/sda1 /mnt
for fs in proc sys dev dev/pts; do mount --bind /$fs /mnt/$fs; done
chroot /mnt

ls -l

As you see, there's now a folder called ext2_saved which contains an image of our system partition before the conversion (with the original ext3 or ext4 file system). This image can be used to do a rollback later on.

root@ubuntu:/# ls -l
total 20
drwxr-xr-x   1 root root 1938 Nov 22 13:15 bin
drwxr-xr-x   1 root root  326 Nov 23 18:38 boot
drwxr-xr-x  14 root root 4060 Nov 23 18:38 dev
drwxr-xr-x   1 root root 2820 Nov 23 18:38 etc
dr-xr-xr-x   1 root root   10 Nov 23 18:40 ext2_saved
drwxr-xr-x   1 root root   26 Nov 22 13:16 home
lrwxrwxrwx   1 root root   32 Nov 22 13:11 initrd.img -> boot/initrd.img-3.5.0-17-generic
lrwxrwxrwx   1 root root   33 Nov 22 13:11 initrd.img.old -> /boot/initrd.img-3.5.0-17-generic
drwxr-xr-x   1 root root  982 Nov 22 13:15 lib
drwxr-xr-x   1 root root   40 Nov 22 13:10 lib64
drwx------   1 root root    0 Nov 22 13:10 lost+found
drwxr-xr-x   1 root root   10 Nov 22 13:10 media
drwxr-xr-x   1 root root    0 Oct  9 17:03 mnt
drwxr-xr-x   1 root root    0 Oct 17 18:22 opt
dr-xr-xr-x 186 root root    0 Nov 23 18:38 proc
drwx------   1 root root   68 Nov 23 18:38 root
drwxr-xr-x   1 root root    0 Nov 22 13:16 run
drwxr-xr-x   1 root root 3094 Nov 23 18:38 sbin
drwxr-xr-x   1 root root    0 Jun 11 20:36 selinux
drwxr-xr-x   1 root root    0 Oct 17 18:22 srv
dr-xr-xr-x  13 root root    0 Nov 23 18:38 sys
drwxrwxrwt   1 root root    0 Nov 23 18:38 tmp
drwxr-xr-x   1 root root   70 Nov 22 13:10 usr
drwxr-xr-x   1 root root  114 Nov 23 18:38 var
lrwxrwxrwx   1 root root   29 Nov 22 13:11 vmlinuz -> boot/vmlinuz-3.5.0-17-generic
lrwxrwxrwx   1 root root   29 Nov 22 13:11 vmlinuz.old -> boot/vmlinuz-3.5.0-17-generic
root@ubuntu:/#

Run

blkid /dev/sda1

root@ubuntu:/# blkid /dev/sda1
/dev/sda1: UUID="d6c9b57b-caa1-4a88-b659-930c130b337f" UUID_SUB="ea7b087e-683f-4f43-8007-bb5281f64e4c" TYPE="btrfs"
root@ubuntu:/#

We need the UUID from the output for modifying /etc/fstab:

vi /etc/fstab

Comment out the old / partition line and add a new one. Replace the UUID with the UUID from the blkid output, then replace ext4 (or ext3) with btrfs, and finally replace the mount options (e.g. errors=remount-ro) with the string defaults,subvol=@ - this makes the system boot from the subvolume @ (which is to e created yet) instead of the top-level volume:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
#UUID=ad50ef37-797d-44ea-a8fa-ae61abe4d00f /               ext4    errors=remount-ro 0       1
UUID=d6c9b57b-caa1-4a88-b659-930c130b337f /               btrfs   defaults,subvol=@ 0       1
# swap was on /dev/sda5 during installation
UUID=4dc578f3-c65c-4013-b643-72e70455b21b none            swap    sw              0       0

Next open /etc/grub.d/00_header...

vi /etc/grub.d/00_header

... and comment out line 93 (if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi):

[...]
function recordfail {
  set recordfail=1
  #if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi
}
[...]

If you don't do this, you will get the error...

error: sparse file not allowed

... when you boot from the btrfs file system, and you have to press ENTER to proceed with the boot process (see Ubuntu 12.10 + btrfs: error: sparse file not allowed).

Before we update the GRUB boot loader, we must make sure that it will include the boot option rootflags=subvol=@. Check the output of

grub-mkconfig | grep " ro "

If it looks like this (i.e., it contains rootflags=subvol=@), everything is ok, and you can proceed with the update-grub command a few lines below:

root@ubuntu:/# grub-mkconfig | grep " ro "
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.5.0-17-generic
Found initrd image: /boot/initrd.img-3.5.0-17-generic
        linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro rootflags=subvol=@
                linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro rootflags=subvol=@
                linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro recovery nomodeset rootflags=subvol=@
Found memtest86+ image: /boot/memtest86+.bin
done
root@ubuntu:/#

But if the output looks as follows (no appearance of rootflags=subvol=@)...

root@ubuntu:/# grub-mkconfig | grep " ro "
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.5.0-17-generic
Found initrd image: /boot/initrd.img-3.5.0-17-generic
        linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro
                linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro
                linux   /boot/vmlinuz-3.5.0-17-generic root=UUID=d6c9b57b-caa1-4a88-b659-930c130b337f ro recovery nomodeset
Found memtest86+ image: /boot/memtest86+.bin
done
root@ubuntu:/#

... we must modify /etc/grub.d/10_linux:

vi /etc/grub.d/10_linux

Comment out lines 67 and 68 and add rootsubvol="@" in line 69:

[...]
case x"$GRUBFS" in
    xbtrfs)
        #rootsubvol="`make_system_path_relative_to_its_root /`"
        #rootsubvol="${rootsubvol#/}"
        rootsubvol="@"
        if [ "x${rootsubvol}" != x ]; then
            GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
        fi;;
    xzfs)
        rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
        bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
        LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
        ;;
esac
[...]

Now we continue with updating the GRUB boot loader:

update-grub
grub-install /dev/sda

Now we create the @ subvolume as a snapshot of the top level volume:

btrfs subvolume snapshot / /@

Then we create the @home subvolume...

btrfs subvolume create /@home

... and copy the contents from /home to it and make sure that /home and /@/home (which contains the same contents as /home because /@ is a snapshot of /) are empty so that the @home subvolume can be mounted to /home when we reboot the system:

rsync --progress -aHAX /home/* /@home
rm -fr /home/*
rm -fr /@/home/*

Then open /etc/fstab...

vi /etc/fstab

... and add the line UUID=d6c9b57b-caa1-4a88-b659-930c130b337f /home btrfs defaults,subvol=@home 0 2 (make sure you use the same UUID as for the / partition!) to it:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
#UUID=ad50ef37-797d-44ea-a8fa-ae61abe4d00f /               ext4    errors=remount-ro 0       1
UUID=d6c9b57b-caa1-4a88-b659-930c130b337f /               btrfs   defaults,subvol=@ 0       1
UUID=d6c9b57b-caa1-4a88-b659-930c130b337f /home               btrfs   defaults,subvol=@home 0       2
# swap was on /dev/sda5 during installation
UUID=4dc578f3-c65c-4013-b643-72e70455b21b none            swap    sw              0       0

Next copy the modifed fstab to our @ subvolume:

cp /etc/fstab /@/etc/fstab

Leave the chroot:

exit

Unmount /mnt and mount the @ subvolume to it:

umount /mnt/dev/pts
umount /mnt/dev
umount /mnt/sys
umount /mnt/proc
umount /mnt

mount -o subvol=@ /dev/sda1 /mnt
for fs in proc sys dev dev/pts; do mount --bind /$fs /mnt/$fs; done
chroot /mnt

grub-mkconfig | grep " ro "

should show the correct output (i.e., it contains rootflags=subvol=@).

Update GRUB and leave the chroot:

update-grub
grub-install /dev/sda

exit

Unmount /mnt again and mount the top-level volume to it again:

umount /mnt/dev/pts
umount /mnt/dev
umount /mnt/sys
umount /mnt/proc
umount /mnt

mount /dev/sda1 /mnt

Now we delete everything from the top level volume because our @ subvolume (from which we will boot) has the same contents, and having the same contents twice just uses up disk space:

find /mnt -xdev -delete

We should now have three subvolumes - ext2_saved, @home, and @:

btrfs subvolume list /mnt

root@ubuntu:~# btrfs subvolume list /mnt
ID 256 top level 5 path ext2_saved
ID 275 top level 5 path @home
ID 276 top level 5 path @
root@ubuntu:~#

Reboot into the normal system (make sure you remove the Live CD from the CD drive):

reboot

If everything goes well, the system should come up without problems, now running on btrfs (from the subvolume @).

ls -l /

root@server1:~# ls -l /
total 16
drwxr-xr-x  1 root root 1938 Nov 22 13:15 bin
drwxr-xr-x  1 root root  326 Nov 23 18:58 boot
drwxr-xr-x 14 root root 4080 Nov 23 19:07 dev
drwxr-xr-x  1 root root 2820 Nov 23 19:08 etc
drwxr-xr-x  1 root root    0 Nov 23 19:09 ext2_saved
drwxr-xr-x  1 root root   26 Nov 23 19:04 home
lrwxrwxrwx  1 root root   32 Nov 22 13:11 initrd.img -> boot/initrd.img-3.5.0-17-generic
lrwxrwxrwx  1 root root   33 Nov 22 13:11 initrd.img.old -> /boot/initrd.img-3.5.0-17-generic
drwxr-xr-x  1 root root  982 Nov 22 13:15 lib
drwxr-xr-x  1 root root   40 Nov 22 13:10 lib64
drwx------  1 root root    0 Nov 22 13:10 lost+found
drwxr-xr-x  1 root root   10 Nov 22 13:10 media
drwxr-xr-x  1 root root    0 Oct  9 17:03 mnt
drwxr-xr-x  1 root root    0 Oct 17 18:22 opt
dr-xr-xr-x 98 root root    0 Nov 23 19:07 proc
drwx------  1 root root   84 Nov 23 19:08 root
drwxr-xr-x 17 root root  620 Nov 23 19:07 run
drwxr-xr-x  1 root root 3094 Nov 23 18:58 sbin
drwxr-xr-x  1 root root    0 Jun 11 20:36 selinux
drwxr-xr-x  1 root root    0 Oct 17 18:22 srv
dr-xr-xr-x 13 root root    0 Nov 23 19:07 sys
drwxrwxrwt  1 root root    0 Nov 23 19:07 tmp
drwxr-xr-x  1 root root   70 Nov 22 13:10 usr
drwxr-xr-x  1 root root  114 Nov 23 18:58 var
lrwxrwxrwx  1 root root   29 Nov 22 13:11 vmlinuz -> boot/vmlinuz-3.5.0-17-generic
lrwxrwxrwx  1 root root   29 Nov 22 13:11 vmlinuz.old -> boot/vmlinuz-3.5.0-17-generic
root@server1:~#

Let's check if the @home subvolume gout mounted correctly (if /home is empty, there's probably something wrong, unless /home was empty before):

ls -l /home/

root@server1:~# ls -l /home/
total 0
drwxr-xr-x 1 administrator administrator 92 Nov 22 13:18 administrator
root@server1:~#

/ext2_saved is empty because we didn't mount the ext2_saved subvolume:

ls -l /ext2_saved/

root@server1:~# ls -l /ext2_saved/
total 0
root@server1:~#

Let's check our subvolumes again:

btrfs subvolume list /

root@server1:~# btrfs subvolume list /
ID 256 top level 5 path ext2_saved
ID 275 top level 5 path @
ID 276 top level 5 path @home
root@server1:~#

If you are sure you want to stay with btrfs and don't want to do a rollback, you can delete the ext2_saved subvolume. To do this, we mount /dev/sda1 to an empty folder (e.g. /ext2_saved):

mount /dev/sda1 /ext2_saved
ls -l /ext2_saved/

root@server1:~# ls -l /ext2_saved/
total 4
drwxr-xr-x 1 root root 272 Nov 22 13:11 @
dr-xr-xr-x 1 root root  10 Nov 23 19:01 ext2_saved
drwxr-xr-x 1 root root  26 Nov 23 19:04 @home
root@server1:~#

The rollback image can now be deleted as follows:

btrfs subvolume delete /ext2_saved/ext2_saved/

Unmount /ext2_saved and delete the empty folder:

umount /ext2_saved
rm -fr /ext2_saved/

Now only the @ and @home subvolumes should be left:

btrfs subvolume list /

root@server1:~# btrfs subvolume list /
ID 275 top level 5 path @
ID 276 top level 5 path @home
root@server1:~#

 

5 Doing A Rollback

Doing a rollback is the same, no matter if you did the conversion according to chapter 3 or 4. Of course, a rollback is possible only if you didn't delete the ext2_saved subvolume.

Simply boot into a rescue system again. In the rescue system, make sure that btrfs-tools are installed:

apt-get install btrfs-tools

Then do the rollback:

btrfs-convert -r /dev/sda1

root@ubuntu:~# btrfs-convert -r /dev/sda1
rollback complete.
root@ubuntu:~#

Mount the system partition and chroot to it:

mount /dev/sda1 /mnt
for fs in proc sys dev dev/pts; do mount --bind /$fs /mnt/$fs; done
chroot /mnt

Then update the GRUB boot loader:

update-grub

grub-install /dev/sda

Leave the chroot...

exit

... and boot into your normal system again (running on ext3/ext4 again):

reboot

 

6 Links


Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.
Submitted by Wout Mertens (not registered) on Wed, 2014-01-29 13:38.

 Thanks for the guide, I just did this for my Ubuntu 14.04 preview which I upgraded from 12.04. Some notes:

  • No need to comment out the line in the 00_header file. I saw some changes in the file that special-cased btrfs so I left it alone; the system booted without errors.
  • I didn't have a livecd handy so I used a server usb stick and simply copied btrfs-convert to /tmp from the root filesystem. Then I did the conversion, it didn't need any libraries.
  • If you first change /etc/fstab and handle the @home subvolume, then you can create the /@ subvolume later and have less to do — especially the rm -rf /@/home is a bit scary ;-)
  • Looks like the rsync should instead be cp -ax --reflink=always home/. /@home/. — apparently cross-device reflinks are in btrfs since Linux 3.6 (See Can I take a snapshot of a directory?). That would solve the space issue with copying /home.

Submitted by Henrik (not registered) on Mon, 2014-01-27 20:29.
Great guide otherwise, but you should put a tiny notice to the rsync command - you have to have atleast your /home worth of free space available before attempting to copy /home to /@home. Not everyone has big drives or small home directories :)