November 5, 2015
By: gotwf

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.

Tags: zfsonlinux guides archlinux