Skip to content

Commit

Permalink
zfs-linux-lts-poscat: sd-zfs POC
Browse files Browse the repository at this point in the history
  • Loading branch information
poscat0x04 committed Dec 14, 2024
1 parent c274511 commit 4f98531
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 3 deletions.
20 changes: 17 additions & 3 deletions archlinuxcn/zfs-linux-lts-poscat/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,28 @@ makedepends=(
arch=("x86_64")
url="https://openzfs.org/"
source=(
# source
"https://github.com/openzfs/zfs/releases/download/zfs-${pkgver}/zfs-${pkgver}.tar.gz"
# patches
'fix-bash-completions.patch'
# mkinitcpio hooks & utils
'zfs.initcpio.install'
'zfs.initcpio.hook'
'zfs.initcpio.zfsencryptssh.install'
'fix-bash-completions.patch'
'sd-zfs.initcpio.install'
'parse-cmdline'
'zfs-set-env'
'zfs-root-generator'
)
sha256sums=('b2b8e3bfabf2a6407a0132243726cb6762547a5bd095b1b1f37eaf2a9d8f7672'
'b9fa6a42f7426654fc04697b45ad1fe0fb09ff29ea76cb97ac7d09ac03de1797'
'2f09c742287f4738c7c09a9669f8055cd63d3b9474cd1f6d9447152d11a1b913'
'15b5acea44225b4364ec6472a08d3d48666d241fe84c142e1171cd3b78a5584f'
'ac9ed396465e26fa6896762c52a93eb7aaf8af6d7b2c69bd826d219ff821b2c9'
'b9fa6a42f7426654fc04697b45ad1fe0fb09ff29ea76cb97ac7d09ac03de1797')
'a7f4a033237be38d48d772a39730c00393215be6e7c24f8487d76458e9221d5e'
'61b368e73f72e548c76128f5d660366fc4d6729c76fc0a7c9b1973992edc8139'
'b2e6eb4f43b8b93212270b0c567f22105f6c4b05bf390a7b8d1b741f8dcd1783'
'7e993c7d2d9909199ce19dc3c42cbdb6390a027c6b1a75782d703f8e3f985ee0')
license=("CDDL-1.0")
depends=("kmod" "linux-lts=${_kernelver}")

Expand Down Expand Up @@ -60,7 +71,7 @@ build() {
package_zfs-utils-poscat() {
pkgdesc='ZFS userspace tools'
provides=('zfs-utils' "zfs-utils=${pkgver}")
conflicts=('zfs-utils')
conflicts=('zfs-utils' 'mkinitcpio-sd-zfs')
depends+=('libunwind')
optdepends=('python: for arcstat/arc_summary/dbufstat')

Expand All @@ -72,6 +83,9 @@ package_zfs-utils-poscat() {
install -Dvm644 "${srcdir}"/zfs.initcpio.hook "${pkgdir}"/usr/lib/initcpio/hooks/zfs
install -Dvm644 "${srcdir}"/zfs.initcpio.install "${pkgdir}"/usr/lib/initcpio/install/zfs
install -Dvm644 "${srcdir}"/zfs.initcpio.zfsencryptssh.install "${pkgdir}"/usr/lib/initcpio/install/zfsencryptssh
install -Dvm644 "${srcdir}"/sd-zfs.initcpio.install "${pkgdir}"/usr/lib/initcpio/install/sd-zfs

install -Dvm755 -t "${pkgdir}"/usr/lib/zfs/initcpio/ "${srcdir}"/{parse-cmdline,zfs-set-env,zfs-root-generator}

# cleanup
## empty files
Expand Down
61 changes: 61 additions & 0 deletions archlinuxcn/zfs-linux-lts-poscat/parse-cmdline
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/awk -f
# input variable:
# command: "mode" or "pool" or "dataset" (default to "mode" when non is given)
#
# mode checks the boot mode, returns "dataset", "import", "import_all" or "none"
# dataset: use a particular dataset
# import: import a specific pool, use bootfs to determine the dataset
# import_all: import all pools, use the first one with a bootfs property
# none: not using zfs for root
# pool checks the root pool, returns the pool name (used with mode "dataset" and "import")
# dataset checks the root dataset, returns the dataset name (used with mode "dataset")
{
split($0, args, " ")

for (i in args) {
if (match(args[i], /^root=/)) {
root = substr(args[i], 6)
}
}

if (root == "zfs") {
# import all pools
if (command == "pool" || command == "dataset") {
print "using auto detection for pool and dataset" > "/dev/stderr"
exit 1
} else {
printf "import_all"
}
} else if (match(root, /^zfs:[^\/]+$/)) {
# import a specific pool
if (command == "dataset") {
print "using auto detection for dataset" > "/dev/stderr"
exit 1
} else if (command == "pool") {
printf "%s", substr(root, 5)
} else {
printf "import"
}
} else if (match(root, /^zfs:[^\/]+(\/[^\/]+)+$/)) {
# use a particular dataset
dSet = substr(root, 5)
paths = split(dSet, p, "/")
pool = p[1]
if (command == "pool") {
printf "%s", pool
} else if (command == "dataset") {
printf "%s", dSet
} else {
printf "dataset"
}
} else {
if (command == "pool" || command == "dataset") {
print "not using zfs for root" > "/dev/stderr"
exit 1
} else {
printf "none"
}
}

exit 0
}
51 changes: 51 additions & 0 deletions archlinuxcn/zfs-linux-lts-poscat/sd-zfs.initcpio.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash
shopt -s nullglob

true || source /usr/lib/initcpio/functions
true || source /usr/lib/initcpio/install/systemd

build() {
map add_module \
zfs \
spl

map add_file \
/usr/lib/udev/rules.d/60-zvol.rules \
/usr/lib/udev/rules.d/69-vdev.rules \
/usr/lib/udev/rules.d/90-zfs.rules

map add_binary \
mount.zfs \
zfs \
zpool \
/lib/udev/vdev_id \
/lib/udev/zvol_id

add_systemd_unit "systemd-udev-settle.service"

{
copied_files=(
/etc/hostid
/etc/zfs/zpool.cache # not needed, still include it for compatibility
/etc/modprobe.d/{*spl*,*zfs*}.conf
)

for f in "${copied_files[@]}"; do
add_file "$f"
done

# Include hostid when it's not written to file
if [[ ! -f /etc/hostid ]]; then
AA="$(hostid | cut -b 1,2)"
BB="$(hostid | cut -b 3,4)"
CC="$(hostid | cut -b 5,6)"
DD="$(hostid | cut -b 7,8)"
printf "\x${DD}\x${CC}\x${BB}\x${AA}" > "${BUILDROOT}/etc/hostid"
fi
}

# generator and its dependencies
add_binary /usr/lib/zfs/initcpio/zfs-root-generator /usr/lib/systemd/system-generators/
add_binary /usr/lib/zfs/initcpio/zfs-set-env /usr/bin/
add_binary /usr/lib/zfs/initcpio/parse-cmdline /usr/bin/
}
120 changes: 120 additions & 0 deletions archlinuxcn/zfs-linux-lts-poscat/zfs-root-generator
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/bin/sh
# shellcheck shell=ash
# cmdline format:
#
# use a particular dataset:
# root=zfs:pool/dataset
# use the bootfs property of a pool:
# root=zfs:pool
# import all pools and use the first one with a bootfs property:
# root=zfs

# usage: klog "message" [level]
klog() {
if [ -n "$DEBUG_CMDLINE" ]; then
return
fi
echo "<${2:-6}>zfs-root-generator: $1" | tee /dev/kmsg
}

write_sysroot_override_unit() {
klog "writing sysroot.mount override"
mkdir -p "$GENERATOR_DIR"/sysroot.mount.d
{
echo "[Unit]"
echo "After=zfs-import.target"
echo
echo "[Mount]"
echo "PassEnvironment=ROOT_DATASET"
echo "Type=zfs"
echo "What=${ROOT_DATASET}"
} > "$GENERATOR_DIR"/sysroot.mount.d/zfs-override.conf
}

write_set_env_unit() {
klog "generating zfs-set-env.service"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Before=sysroot.mount"
echo "Requires=$1"
echo
echo "[Service]"
echo "Type=oneshot"
echo "RemainAfterExit=yes"
echo "ExecStart=/usr/bin/zfs-set-env"
} > "$GENERATOR_DIR"/zfs-set-env.service
}

enable_unit() {
local unit="$1"
klog "enabling $unit"
ln -fs "$GENERATOR_DIR"/"$unit" "$GENERATOR_DIR"/initrd-root-device.target.wants/
}

GENERATOR_DIR="$1"
[ -n "$GENERATOR_DIR" ] || {
klog "impossible: no generator directory specified" 2
exit 1
}
CMDLINE=${DEBUG_CMDLINE:-/proc/cmdline}

mode=$(parse-cmdline "$CMDLINE")
klog "mode: $mode"

case $mode in
import_all)
write_sysroot_override_unit

write_set_env_unit zfs-import-all.service
enable_unit zfs-set-env.service

klog "generating zfs-import-all.service"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Wants=systemd-udev-settle.service"
echo "After=systemd-udev-settle.service cryptsetup.target"
echo "Before=sysroot.mount zfs-set-env.service"
echo
echo "[Service]"
echo "Type=oneshot"
echo "RemainAfterExit=yes"
echo "ExecStart=/usr/bin/zpool import -aN"
} > "$GENERATOR_DIR"/zfs-import-all.service
enable_unit zfs-import-all.service
;;
import|dataset)
write_sysroot_override_unit

write_set_env_unit zfs-import-root-pool.service
enable_unit zfs-set-env.service

pool=$(parse-cmdline -v command=pool "$CMDLINE")
klog "generating zfs-import-root-pool.service for pool $pool"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Requires=systemd-udev-settle.service"
echo "After=systemd-udev-settle.service cryptsetup.target"
echo "Before=sysroot.mount zfs-set-env.service"
echo
echo "[Service]"
echo "Type=oneshot"
echo "RemainAfterExit=yes"
echo "ExecStart=/usr/bin/zpool import -N \"$pool\""
} > "$GENERATOR_DIR"/zfs-import-root-pool.service
enable_unit zfs-import-root-pool.service
;;
none)
klog "not using zfs for root: stopping"
exit 0
;;
*)
klog "impossible: unknown mode $mode" 2
exit 1
;;
esac

klog "finished generating"
exit 0
44 changes: 44 additions & 0 deletions archlinuxcn/zfs-linux-lts-poscat/zfs-set-env
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh
# shellcheck shell=ash

CMDLINE=${DEBUG_CMDLINE:-/proc/cmdline}

# usage: log "message" [level]
log() {
echo "<${2:-6}>$1"
}

mode=$(parse-cmdline "$CMDLINE")
log "mode: $mode"

case $mode in
import_all)
if line=$(zpool list -Ho bootfs | grep -m1 -vFx -); then
:
else
log "no pool with bootfs property found" 2
exit 1
fi
dSet=$(echo "$line" | tr -d '\n')
;;
import)
pool=$(parse-cmdline -v command=pool "$CMDLINE")
if line=$(zpool list -Ho bootfs "$pool" | grep -m1 -vFx -); then
:
else
log "no bootfs property found for pool $pool" 2
exit 1
fi
dSet=$(echo "$line" | tr -d '\n')
;;
dataset)
dSet=$(parse-cmdline -v command=dataset "$CMDLINE")
;;
none)
log "no zfs root specified" 2
exit 1
;;
esac

log "setting ROOT_DATASET to $dSet"
exec systemctl set-environment ROOT_DATASET="$dSet"

0 comments on commit 4f98531

Please sign in to comment.