隠居日録

隠居日録

2016年(世にいう平成28年)、発作的に会社を辞め、隠居生活に入る。日々を読書と散歩に費やす

raspberry pi 4B上でFreeBSD13.1 zfs rootfsがブートした

前回の続き。ようやく、zfsでブートできた。何が問題だったかというと、

  1. 最初にrpi4に使っていたUSB-ATAのコントローラーとrpi4の相性が悪かった
  2. md上にシステムを書き込んで、ディスクにコピーしていた

1に関しては、よくわからないが、rpi4に1台だけつないだ場合は問題ないのだが、2台つなぐと途端に調子が悪くなる。両方ともコントローラーはCypress AT2LP RC7で、

Aug 27 02:58:57 generic kernel: (da2:umass-sim2:2:0:0): READ(10). CDB: 28 00 00 01 97 ff 00 00 01 00 
Aug 27 02:58:57 generic kernel: (da2:umass-sim2:2:0:0): CAM status: CCB request completed with an error
Aug 27 02:58:57 generic kernel: (da2:umass-sim2:2:0:0): Retrying command, 3 more tries remain
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): WRITE(10). CDB: 2a 00 00 02 35 c0 00 00 08 00 
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): CAM status: CCB request completed with an error
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): Retrying command, 3 more tries remain
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): WRITE(10). CDB: 2a 00 00 02 35 c0 00 00 08 00 
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): CAM status: SCSI Status Error
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): SCSI status: Check Condition
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): SCSI sense: ABORTED COMMAND asc:8,3 (Logical unit communication CRC error (Ultra-DMA/32))
Aug 27 02:59:12 generic kernel: (da0:umass-sim0:0:0:0): Retrying command (per sense data)

のようなカーネルのエラーが出でてくる。ただ、プログラム自体はエラー終了していないので、なんとか書き込みはできているのではと思っていたのだが、途中でこれはやはり良くないだろうと思い、rpi4上での作業は止めて、ラップトップPCに移行した。何が悪くてブートしないのかわからないから、少しでも問題になる可能性を排除した方がいいと思ったのだ。

PCに移行したので、bsdinstallを使う方法もやめて、公式のimgファイルの中身を新しいディスクにコピーすることにした。参考にしたのはこのページ

2については、物理ディスクにパーティションの追加をすると"gpart destroy -F"を実行しても、追加した時点で以前のパーティションがゾンビのように復活するので、スクリプト一発で一連のコマンドが実行しにくい。それで、まっさらのメモリディスク上で準備してから、ddで物理ディスクに書き込んでいたのだが、これを行うと十中八九zpoolが破損するのだ。これは未だに理由がわからない。これに気づくのに二日ぐらいかかった。

参考にしたページの「zfs set canmount=noauto zpi/ROOT/default」もはまったポイントだった。最初は出来上がったメモリディスクをどうやって確認したらいいのかすらわからなかったが、「zpool import」でできることが分かり、実際にimportしてみると、書き込んだはずのファイルがないのだ。このファイル消失に気づいたときは、何が起きているか全くわからなかった。この理由は「canmount=noauto」にしているから、自動でマウントされない。これでも立ち上がるのかもしれないが、自動でマウントされないと面倒なので変えた。

結局、パーティション作成することろまではメモリディスクで行って、そのイメージを物理ディスクに書き込んでから、作業を継続するようにした。

#!/bin/sh

GO=0
ORIG=""
NEW=""

case $# in
2)
  GO=1
  ORIG=$1
  NEW=$2
  ;;
*)
  ;;
esac

if [ ${GO} -eq 0 ]; then
  echo "create_gpt_zfs.sh <original boot image> <target disk>"
  exit 1
fi

# create dummy md image
TMP=/tmp/xxx.img
dd if=/dev/zero of=${TMP} bs=1G count=1

# attach image
SOURCE=$(mdconfig -a -f ${ORIG})
DEST=$(mdconfig -a -f ${TMP})

# create partitions
FAT_SIZE="50m -b 1m"
FAT_TYPE="16"

gpart destroy -F /dev/${DEST}
gpart create -s GPT /dev/${DEST}
gpart add -t efi -l efi -a 512k -s ${FAT_SIZE} ${DEST}
newfs_msdos -L efi -F ${FAT_TYPE} /dev/${DEST}p1

gpart add -t freebsd-ufs -l rootfs -a 64k /dev/${DEST}
newfs -U -L rootfs  /dev/${DEST}p2

# deatch image and write it to disk
mdconfig -d -u ${DEST}

dd if=${TMP} of=/dev/${NEW} bs=16M
gpart recover ${NEW}
gpart resize -i 2 ${NEW}
rm -f ${TMP}

# write files
DSOURCE=/media/source
DDEST=/media/dest
CONT=0

mkdir -p ${DSOURCE}
mkdir -p ${DDEST}

# create dataset
zpool destroy zpi || true
zpool create -f -O compress=lz4 -O atime=off -o altroot=${DDEST} -m none zpi ${NEW}p2

zfs create -o mountpoint=none zpi/ROOT
zfs create -o mountpoint=/ zpi/ROOT/default
zfs create -o mountpoint=/tmp -o exec=on -o setuid=off zpi/tmp
zfs create -o mountpoint=/usr -o canmount=off zpi/usr
zfs create zpi/usr/home
zfs create -o setuid=off zpi/usr/ports
zfs create zpi/usr/src
zfs create -o mountpoint=/var -o canmount=off zpi/var
zfs create -o exec=off -o setuid=off zpi/var/audit
zfs create -o exec=off -o setuid=off zpi/var/crash
zfs create -o exec=off -o setuid=off zpi/var/log
zfs create -o atime=on zpi/var/mail
zfs create -o setuid=off zpi/var/tmp

zfs set mountpoint=/zpi zpi

chmod 1777 ${DDEST}/tmp
chmod 1777 ${DDESt}/var/tmp

zpool set bootfs=zpi/ROOT/default zpi

#zfs set canmount=noauto zpi/ROOT/default
zfs set canmount=on zpi/ROOT/default

# copy files
mount /dev/${SOURCE}s2a ${DSOURCE}

mkdir -p ${DDEST}/boot
mkdir -p ${DDEST}/boot/msdos
if [ -d ${DSOURCE}/boot/msdos ]; then
  mount -t msdos /dev/${SOURCE}s1 ${DSOURCE}/boot/msdos
  mount -t msdos /dev/${NEW}p1 ${DDEST}/boot/msdos
  CONT=1
fi

if [ ${CONT} -eq 0 ]; then
  echo "Abort. No FreeBSD loader directory is detected"
  exit 2
fi

tar cf - -C ${DSOURCE} . | tar -xpf - -C ${DDEST}

FREEBSD_VER=$(${DDEST}/bin/freebsd-version -u | cut -d "-" -f 1)
if [ ${FREEBSD_VER} == "13.1" ]; then
  (cd ${DDEST}/home; mv -i * ../usr/home; cd ..; rmdir home; ln -sf usr/home home)
fi

# file modification for zfs and others
echo 'kern.geom.label.disk_ident.enable="0"' >> ${DDEST}/boot/loader.conf
echo 'kern.geom.label.gptid.enable="0"' >> ${DDEST}/boot/loader.conf
echo 'cryptodev_load="YES"' >> ${DDEST}/boot/loader.conf
echo 'zfs_load="YES"' >> ${DDEST}/boot/loader.conf
echo 'autoboot_delay="3"' >> ${DDEST}/boot/loader.conf
sed -i '' '/boot_serial/ s/^/#/' ${DDEST}/boot/loader.conf
sed -i '' '/beastie_disable/ s/^/#/' ${DDEST}/boot/loader.conf
echo 'zfs_enable="YES"' >> ${DDEST}/etc/rc.conf
echo 'ntpdate_enable="YES"' >> ${DDEST}/etc/rc.conf
echo 'powerd_enable="YES"' >> ${DDEST}/etc/rc.conf
sed -i '' /ufs/d ${DDEST}/etc/fstab
sed -i '' /^tmpfs/d ${DDEST}/etc/fstab
sed -i '' s/MSDOSBOOT/EFI/ ${DDEST}/etc/fstab

# unmount
sync

umount /dev/${SOURCE}s1
umount /dev/${SOURCE}s2a
umount /dev/${NEW}p1

zpool sync zpi
zfs unmount -a
zpool export zpi

# detach
mdconfig -d -u ${SOURCE}
rmdir ${DSOURCE}
rmdir ${DDEST}

今のところケース付属のファンはジャンパーの設定で動かしているが、結構ノイズがあるので、これも何とかした。