ZOL - Archlinux
Archlinux uses a rolling release model, shipping upstream project software’s "latest stable", sans the distro specific "enhancements and tweaks" favored by some distributions. Arch’s package manager, Pacman, simply put, rocks when it comes to keeping things up to date. Hence, Archlinux offers a nice platform for developers who want to focus on debugging their project software, not their platform. Or exploring ZFS on Linux.
Presently at the number nine slot, evidently so do many others. A base installation of Archlinux provides us with a minimalist system platform to build out as we best see fit for the task at hand. This has given rise to a predisposition by some inclined towards elitism to opine that Arch is for "intermediate to advanced" users. I do not share that opinion. However, you’re going to need to be willing to spend time reading man pages, archwiki articles, etc. This article will leave you to your own devices once we have a working ZOL on root configuration suitable for a laptop device, i.e. single drive.
Okay, then, with an endorsement like that, what are we waiting for? Well.. you knew it was coming… be sure to see some of my previous zfsonlinux posts to understand some of the ZOL related decisions I’ll be making along the way.
I’m going to assume have booted into the archzfs live medium of your choice and that you have a clean drive for this little project. If not, rewind yourself and a bit and then pick up back here.
Let’s partition that drive. I’ll use gdisk and /dev/sdc here:
root@archiso ~ # gdisk /dev/sdc
GPT fdisk (gdisk) version 1.0.1
Partition table scan:
MBR: not present
BSD: not present
APM: not present
GPT: not present
Creating new GPT entries.
Command (? for help): p
Disk /dev/sdc: 1465149168 sectors, 698.6 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 354799FF-512F-4650-B5BD-C7A30BB55393
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 1465149134
Partitions will be aligned on 2048-sector boundaries
Total free space is 1465149101 sectors (698.6 GiB)
Number Start (sector) End (sector) Size Code Name
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-1465149134, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-1465149134, default = 1465149134) or {+-}size{KMGTP}: +4M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-1465149134, default = 10240) or {+-}size{KMGTP}: +128M
Last sector (272384-1465149134, default = 1465149134) or {+-}size{KMGTP}: -350M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): bf00
Changed type of partition to 'Solaris root'
Command (? for help): p
Disk /dev/sdc: 1465149168 sectors, 698.6 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 354799FF-512F-4650-B5BD-C7A30BB55393
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 1465149134
Partitions will be aligned on 2048-sector boundaries
Total free space is 980958 sectors (479.0 MiB)
Number Start (sector) End (sector) Size Code Name
1 2048 10239 4.0 MiB EF02 BIOS boot partition
2 272384 1464432334 698.2 GiB BF00 Solaris root
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdc.
The operation has completed successfully.
If you’ve read my ZOL on boot and root post - that’s not what we’re doing here. Archlinux is a rolling release so we’re adjusting and adapting accordingly. The 4MiB partition is for GRUB Legacy BOIS/BOOT. The rest of the drive is for our platform and home. We’ll get a working zfs on root booting from a known good working grub-git. Then we’re going to pin our kernel and that grub-git in our pacman.conf and mind them manually.
Okay, /dev/sdc2 is for zfs so let’s make our pool:
2 root@archiso ~ # zpool create -o ashift=9 -o cachefile= -m none -O compression=lz4 \
-R /mnt/arch frodo /dev/sdc2
I like using container datasets so let’s create that and a couple more:
root@archiso ~ # zfs create frodo/ROOT
root@archiso ~ # zfs create -o mountpoint=/ frodo/ROOT/arch
root@archiso ~ # zfs create -o mountpoint=legacy frodo/HOME
You may well want to adjust to taste but in this instance we’re going to just give it a little KISS, in keeping with Arch’s philosophy. We’ll let zfs and grub mount the main dataset, and then manage everything else in /etc/fstab.
This is lappie set up and we’re not concerned with compatability with other ZFS platforms. So we’ll go ahead and set some zol’isms to placate systemd:
root@archiso ~ # zfs set xattr=sa frodo/ROOT/arch
root@archiso ~ # zfs set acltype=posixacl frodo/ROOT/arch
Hmmm.. getting ahead of myself. Let’s export the pool and reimport by disk-id:
root@archiso ~ # zpool export frodo
root@archiso ~ # zpool import -d /dev/disk/by-id -R /mnt/arch frodo
Quick status check:
root@archiso ~ # zpool status
pool: frodo
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
frodo ONLINE 0 0 0
ata-WDC_WD7500AYYS-01RCA0_WD-WCAPT0577337-part2 ONLINE 0 0 0
errors: No known data errors
Confirming mounts we note that only the root dataset is mounted:
root@archiso ~ # zfs list
NAME USED AVAIL REFER MOUNTPOINT
frodo 172K 674G 19K none
frodo/HOME 19K 674G 19K legacy
frodo/ROOT 38K 674G 19K none
frodo/ROOT/arch 19K 674G 19K /mnt/arch
root@archiso ~ # zfs mount
frodo/ROOT/arch /mnt/arch
We don’t really need /home mounted for installation but we’ll mount it anyhow to take advantage of arch’s genfstab:
root@archiso ~ # mount | grep zfs
frodo/ROOT/arch on /mnt/arch type zfs (rw,relatime,xattr,posixacl)
frodo/HOME on /home type zfs (rw,relatime,xattr,noacl)
Time to install some bits…
root@archiso ~ # pacstrap /mnt/arch base base-devel
==> Creating install root at /mnt/arch
==> Installing packages to /mnt/arch
:: Synchronizing package databases...
.
.
... bunches o' stuff...
... and then pacstrap finishes up doing it's thing...
.
pacstrap /mnt/arch base base-devel 44.21s user 17.09s system 1% cpu 54:05.22 total
root@archiso ~ #
Alrighty then. The rest is just boring 'chit until we get to grub-git, and I’m going to presume not news to you.
We’ll manage our root dataset via grub-git and home dataset under /etc/fstab:
root@archiso ~ # genfstab -U /mnt/arch > /mnt/arch/etc/fstab
root@archiso ~ # cat /mnt/arch/etc/fstab
# frodo/ROOT/arch
#frodo/ROOT/arch / zfs rw,relatime,xattr,posixacl 0 0
# frodo/HOME
frodo/HOME /home zfs rw,relatime 0 0
Chroot, set locale and timezone. Good. Now we’ll build our ZOL initramfs. To do so we need the demz-repo-core
Import Jesus’s key, verify, and local sign:
[root@archiso /]# dirmngr < /dev/null
dirmngr[264.0]: error opening '/root/.gnupg/dirmngr_ldapservers.conf': No such file or directory
dirmngr[264.0]: permanently loaded certificates: 0
dirmngr[264.0]: runtime cached certificates: 0
dirmngr[264.0]: failed to open cache dir file '/root/.gnupg/dirmngr-cache.d/DIR.txt': No such file or directory
dirmngr[264.0]: creating directory '/root/.gnupg'
dirmngr[264.0]: creating directory '/root/.gnupg/dirmngr-cache.d'
dirmngr[264.0]: new cache dir file '/root/.gnupg/dirmngr-cache.d/DIR.txt' created
# Home: ~/.gnupg
# Config: [none]
OK Dirmngr 2.1.9 at your service
[root@archiso /]# pacman-key -r 5E1ABF240EE7A126
gpg: key 0EE7A126: public key "Jesus Alvarez <jeezusjr@gmail.com>" imported
gpg: Total number processed: 1
gpg: imported: 1
==> Updating trust database...
gpg: next trustdb check due at 2016-01-22
[root@archiso /]# pacman-key -f 5E1ABF240EE7A126
pub rsa2048/0EE7A126 2012-10-24
Key fingerprint = B18A 9C9F 1E4E EAFF 072D AB9E 5E1A BF24 0EE7 A126
uid [ unknown] Jesus Alvarez <jeezusjr@gmail.com>
sub rsa2048/DAB97A2B 2012-10-24
[root@archiso /]# pacman-key --lsign-key 5E1ABF240EE7A126
-> Locally signing key 5E1ABF240EE7A126...
==> Updating trust database...
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 6 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1 valid: 6 signed: 64 trust: 1-, 0q, 0n, 5m, 0f, 0u
gpg: depth: 2 valid: 64 signed: 6 trust: 64-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2016-01-22
Cool. Now edit /etc/pacman.conf to point to the repo:
# zfs stuff
[demz-repo-core]
Server = http://demizerone.com/$repo/$arch
Now we’re ready to install:
[root@archiso /]# pacman -Syu archzfs-git
:: Synchronizing package databases...
core is up to date
extra is up to date
community is up to date
demz-repo-core is up to date
:: There are 4 members in group archzfs-git:
:: Repository demz-repo-core
1) spl-git 2) spl-utils-git 3) zfs-git 4) zfs-utils-git
Enter a selection (default=all):
:: Starting full system upgrade...
resolving dependencies...
looking for conflicting packages...
Packages (4) spl-git-0.6.5.3_r0_g7e85f6b_4.2.5_1-1
spl-utils-git-0.6.5.3_r0_g7e85f6b_4.2.5_1-1
zfs-git-0.6.5.3_r0_g9aaf60b_4.2.5_1-1
zfs-utils-git-0.6.5.3_r0_g9aaf60b_4.2.5_1-1
Total Download Size: 2.11 MiB
Total Installed Size: 8.62 MiB
:: Proceed with installation? [Y/n] Y
Now that we have the zfs mods:
[root@archiso /]# lsmod | grep zfs
zfs 2641920 1
zunicode 331776 1 zfs
zcommon 45056 1 zfs
znvpair 61440 2 zfs,zcommon
spl 73728 3 zfs,zcommon,znvpair
zavl 16384 1 zfs
Let’s tune some hooks:
[root@archiso /]# grep zfs /etc/mkinitcpio.conf
HOOKS="base udev autodetect modconf block keyboard zfs filesystems"
And mkinitcpio time:
[root@archiso /]# mkinitcpio -p linux
==> Building image from preset: /etc/mkinitcpio.d/linux.preset: 'default'
-> -k /boot/vmlinuz-linux -c /etc/mkinitcpio.conf -g /boot/initramfs-linux.img
.
.
. ;D
==> Image generation successful
We’re ready to build grub-git from AUR. I already have on this workstation so I’m just going to do a git pull and build it here. One the box under construction, you’d want to make yourself a user, wget the latest build snapshot and go from there. End result being same, that we’ll have a zfs aware grub-git and a zfs modularized initramfs to bring up our system. If, for some reason, this build fails, wait a couple days and try again. What can I say? I told ya' from the outset that it was grub-git, baby! Maybe file a bug? Cool.
In any case, we’ve our package on our build now:
[root@archiso ~]# pacman -U grub-git-2.02.beta2.534.g7cc27ae-1-x86_64.pkg.tar.xz
loading packages...
resolving dependencies...
looking for conflicting packages...
Packages (1) grub-git-2.02.beta2.534.g7cc27ae-1
Total Installed Size: 26.60 MiB
:: Proceed with installation? [Y/n] y
(1/1) checking keys in keyring [#############################] 100%
(1/1) checking package integrity [#############################] 100%
(1/1) loading package files [#############################] 100%
(1/1) checking for file conflicts [#############################] 100%
(1/1) checking available disk space [#############################] 100%
(1/1) installing grub-git [#############################] 100%
Generating grub.cfg.example config file...
This may fail on some machines running a custom kernel.
done.
Optional dependencies for grub-git
freetype2: For grub-mkfont usage
fuse: For grub-mount usage
dosfstools: For grub-mkrescue FAT FS and EFI support
efibootmgr: For grub-install EFI support
libisoburn: Provides xorriso for generating grub rescue iso using grub-mkrescue
os-prober: To detect other OSes when generating grub.cfg in BIOS systems
mtools: For grub-mkrescue FAT FS support
[root@archiso ~]# grub-install --recheck /dev/sdc
Installing for i386-pc platform.
Installation finished. No error reported.
[root@archiso ~]# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initramfs image: /boot/initramfs-linux-fallback.img
done
grub’s mkconfig has improved substantially since I last used it. Here’s the grub.cfg it generated:
[root@archiso grub]# cat grub.cfg
#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#
### BEGIN /etc/grub.d/00_header ###
insmod part_gpt
insmod part_msdos
if [ -s $prefix/grubenv ]; then
load_env
fi
if [ "${next_entry}" ] ; then
set default="${next_entry}"
set next_entry=
save_env next_entry
set boot_once=true
else
set default="0"
fi
if [ x"${feature_menuentry_id}" = xy ]; then
menuentry_id_option="--id"
else
menuentry_id_option=""
fi
export menuentry_id_option
if [ "${prev_saved_entry}" ]; then
set saved_entry="${prev_saved_entry}"
save_env saved_entry
set prev_saved_entry=
save_env prev_saved_entry
set boot_once=true
fi
function savedefault {
if [ -z "${boot_once}" ]; then
saved_entry="${chosen}"
save_env saved_entry
fi
}
function load_video {
if [ x$feature_all_video_module = xy ]; then
insmod all_video
else
insmod efi_gop
insmod efi_uga
insmod ieee1275_fb
insmod vbe
insmod vga
insmod video_bochs
insmod video_cirrus
fi
}
if [ x$feature_default_font_path = xy ] ; then
font=unicode
else
insmod part_gpt
insmod zfs
set root='hd2,gpt2'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd2,gpt2 --hint-efi=hd2,gpt2 --hint-baremetal=ahci2,gpt2 9a7f0fec9c53d66f
else
search --no-floppy --fs-uuid --set=root 9a7f0fec9c53d66f
fi
font="/ROOT/arch@/usr/share/grub/unicode.pf2"
fi
if loadfont $font ; then
set gfxmode=auto
load_video
insmod gfxterm
set locale_dir=$prefix/locale
set lang=en_US
insmod gettext
fi
terminal_input console
terminal_output gfxterm
if [ x$feature_timeout_style = xy ] ; then
set timeout_style=menu
set timeout=5
# Fallback normal timeout code in case the timeout_style feature is
# unavailable.
else
set timeout=5
fi
### END /etc/grub.d/00_header ###
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Arch Linux, with Linux linux' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-linux-advanced-9a7f0fec9c53d66f' {
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod zfs
set root='hd2,gpt2'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd2,gpt2 --hint-efi=hd2,gpt2 --hint-baremetal=ahci2,gpt2 9a7f0fec9c53d66f
else
search --no-floppy --fs-uuid --set=root 9a7f0fec9c53d66f
fi
echo 'Loading Linux linux ...'
linux /ROOT/arch@/boot/vmlinuz-linux root=ZFS=frodo/ROOT/arch rw quiet
echo 'Loading initial ramdisk ...'
initrd /ROOT/arch@/boot/initramfs-linux.img
}
menuentry 'Arch Linux, with Linux linux (fallback initramfs)' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-linux-fallback-9a7f0fec9c53d66f' {
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod zfs
set root='hd2,gpt2'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd2,gpt2 --hint-efi=hd2,gpt2 --hint-baremetal=ahci2,gpt2 9a7f0fec9c53d66f
else
search --no-floppy --fs-uuid --set=root 9a7f0fec9c53d66f
fi
echo 'Loading Linux linux ...'
linux /ROOT/arch@/boot/vmlinuz-linux root=ZFS=frodo/ROOT/arch rw quiet
echo 'Loading initial ramdisk ...'
initrd /ROOT/arch@/boot/initramfs-linux-fallback.img
}
### END /etc/grub.d/10_linux ###
### BEGIN /etc/grub.d/20_linux_xen ###
### END /etc/grub.d/20_linux_xen ###
### BEGIN /etc/grub.d/30_os-prober ###
### END /etc/grub.d/30_os-prober ###
### BEGIN /etc/grub.d/40_custom ###
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
### END /etc/grub.d/40_custom ###
### BEGIN /etc/grub.d/41_custom ###
if [ -f ${config_directory}/custom.cfg ]; then
source ${config_directory}/custom.cfg
elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then
source $prefix/custom.cfg;
fi
### END /etc/grub.d/41_custom ###
### BEGIN /etc/grub.d/60_memtest86+ ###
### END /etc/grub.d/60_memtest86+ ###
Let’s tell our beloved furher about zfs:
[root@archiso grub]# systemctl enable zfs.target
Created symlink from /etc/systemd/system/multi-user.target.wants/zfs.target to /usr/lib/systemd/system/zfs.target.
Install OpenSSH:
sh-4.3# pacman -Syu openssh
:: Synchronizing package databases...
core is up to date
extra is up to date
community 3.1 MiB 70.0K/s 00:45 [#############################] 100%
demz-repo-core is up to date
:: Starting full system upgrade...
resolving dependencies...
looking for conflicting packages...
Packages (4) dnssec-anchors-20150403-1 ldns-1.6.17-3 libedit-20150325_3.1-2
openssh-7.1p1-1
Total Download Size: 1.19 MiB
Total Installed Size: 6.21 MiB
:: Proceed with installation? [Y/n] y
Enable sshd to start at boot:
sh-4.3# systemctl enable sshd
Created symlink from /etc/systemd/system/multi-user.target.wants/sshd.service to /usr/lib/systemd/system/sshd.service.
Alas, I never did get around to giving this box a hostname.