Skip to content

Instantly share code, notes, and snippets.

@sathlan
Created April 8, 2013 13:39
Show Gist options
  • Save sathlan/5336814 to your computer and use it in GitHub Desktop.
Save sathlan/5336814 to your computer and use it in GitHub Desktop.
modification to mfsbsd zfsinstall to take into account ssd alignment.
#!/usr/bin/env sh
IP_PREFIX='10.11.12'
help () {
cat<<EOF
USAGE: $0 [-h] -i LAST_BLOCK_IP -m CIDR -v VLAN -n NAME
DESCRIPTION:
Simple wrapper around the creation of a new jails with
some default.
LAST_BLOCK_IP in XXX.XXX.XXX.YYY is YYY. The current
ip prefix is $IP_PREFIX
EOF
}
net_exists () {
ifconfig -l | grep -q $1
}
add_network() {
TAP=tap${IP}
net_exists ${TAP} || ifconfig ${TAP} create up
net_exists ${TAP}.${VLAN} || ifconfig ${TAP}.${VLAN} create \
vlan ${VLAN} vlandev ${TAP} up
BDG=bridge${VLAN}
net_exists $BDG || ifconfig $BDG create up
ifconfig bridge${VLAN} addm ${TAP}.${VLAN}
}
add_jail() {
ezjail-admin create -f `hostname -s` -c zfs $NAME "tap${IP}.${VLAN}|${IP_PREFIX}.${IP}/${MASK}"
/usr/local/etc/rc.d/ezjail start $NAME
}
while getopts :hi:v:n:m: OPT; do
case $OPT in
h|+h)
help
exit 0
;;
i|+i)
IP="$OPTARG"
;;
v|+v)
VLAN="$OPTARG"
;;
n|+n)
NAME="$OPTARG"
;;
m|+m)
MASK="$OPTARG"
;;
*)
help
exit 2
esac
done
shift `expr $OPTIND - 1`
OPTIND=1
if [ -z "$IP" -o -z "$VLAN" -o -z "$NAME" -o -z "$MASK" ]; then
echo "Missing argument." >&2
help
exit 4
fi
add_network
add_jail
jls
echo ezjail-admin console $NAME
#!/bin/sh
# $Id$
#
# mfsBSD ZFS install script
# Copyright (c) 2011 Martin Matuska <mm at FreeBSD.org>
#
FS_LIST="var tmp"
# SSD page size (or sector size) in byte.
usage() {
echo "Usage: $0 [-h] -d geom_provider [-d geom_provider ...] [-r mirror|raidz] [-m mount_point] [-p zfs_pool_name] [-V zfs_pool_version] [-s swap_partition_size] [-z zfs_partition_size] [-c] [-l] [-4]"
}
help() {
echo; echo "Install FreeBSD using ZFS"
echo; echo "Required flags:"
echo "-d geom_provider : geom provider(s) to install to (e.g. da0)"
echo " supported compression formats are: gzip, bzip2, xz"
echo; echo "Optional flags:"
echo "-r raidz|mirror : select raid mode if more than one -d provider given"
echo "-s swap_part_size : create a swap partition with given size (default: no swap)"
echo "-z zfs_part_size : create zfs parition of this size (default: all space left)"
echo "-p pool_name : specify a name for the ZFS pool (default: tank)"
echo "-V pool_version : specify a version number for ZFS pool (default: 13)"
echo "-m mount_point : use this mount point for operations (default: /mnt)"
echo "-c : enable lzjb compression for all datasets"
echo "-l : use legacy mounts (via fstab) instead of ZFS mounts"
echo "-4 : use fletcher4 as default checksum algorithm"
echo "-a alignment : specify alignment for disk creation"
echo; echo "Examples:"
echo "Install on a single drive with 2GB swap:"
echo "$0 -d ad4 -s 2G"
echo "Install on a mirror without swap, pool name rpool:"
echo "$0 -d ad4 -d ad6 -r mirror -p rpool"
echo; echo "Notes:"
echo "When using swap and raidz/mirror, the swap partition is created on all drives."
echo "The /etc/fstab entry will contatin only the first drive's swap partition."
echo "You can enable all swap partitions and/or make a gmirror-ed swap later."
}
while getopts d:r:p:s:z:m:V:hcl4S: o; do
case "$o" in
d) DEVS="$DEVS ${OPTARG##/dev/}" ;;
p) POOL="${OPTARG}" ;;
s) SWAP="${OPTARG}" ;;
m) MNT="${OPTARG}" ;;
r) RAID="${OPTARG}" ;;
z) ZPART="${OPTARG}" ;;
V) VERSION="${OPTARG}" ;;
S) SECTOR="${OPTARG}" ;;
a) ALIGN="${OPTARG}" ;;
c) LZJB=1 ;;
l) LEGACY=1 ;;
4) FLETCHER=1 ;;
h) help; exit 1;;
[?]) usage; exit 1;;
esac
done
if ! `/sbin/kldstat -m zfs >/dev/null 2>/dev/null`; then
/sbin/kldload zfs >/dev/null 2>/dev/null
fi
ZFS_VERSION=`/sbin/sysctl -n vfs.zfs.version.spa 2>/dev/null`
if [ -z "$ZFS_VERSION" ]; then
echo "Error: failed to load ZFS module"
exit 1
elif [ "$ZFS_VERSION" -lt "13" ]; then
echo "Error: ZFS module too old, version 13 or higher required"
exit 1
fi
if [ -z "$DEVS" ]; then
usage
exit 1
fi
if [ -z "$POOL" ]; then
POOL=tank
fi
if [ -z "$VERSION" ]; then
VERSION=${ZFS_VERSION}
elif [ "$VERSION" -gt "$ZFS_VERSION" ]; then
echo "Error: invalid ZFS pool version (maximum: $ZFS_VERSION)"
exit 1
fi
if [ "$VERSION" = "5000" ]; then
VERSION=
else
VERSION="-o version=${VERSION}"
fi
if /sbin/zpool list $POOL > /dev/null 2> /dev/null; then
echo Error: ZFS pool \"$POOL\" already exists
echo Please choose another pool name or rename/destroy the existing pool.
exit 1
fi
EXPOOLS=`/sbin/zpool import | /usr/bin/grep pool: | /usr/bin/awk '{ print $2 }'`
if [ -n "${EXPOOLS}" ]; then
for P in ${EXPOOLS}; do
if [ "$P" = "$POOL" ]; then
echo Error: An exported ZFS pool \"$POOL\" already exists
echo Please choose another pool name or rename/destroy the exported pool.
exit 1
fi
done
fi
COUNT=`echo ${DEVS} | /usr/bin/wc -w | /usr/bin/awk '{ print $1 }'`
if [ "$COUNT" -lt "3" -a "$RAID" = "raidz" ]; then
echo "Error: raidz needs at least three devices (-d switch)"
exit 1
elif [ "$COUNT" = "1" -a "$RAID" = "mirror" ]; then
echo "Error: mirror needs at least two devices (-d switch)"
exit 1
elif [ "$COUNT" = "2" -a "$RAID" != "mirror" ]; then
echo "Notice: two drives selected, automatically choosing mirror mode"
RAID="mirror"
elif [ "$COUNT" -gt "2" -a "$RAID" != "mirror" -a "$RAID" != "raidz" ]; then
echo "Error: please choose raid mode with the -r switch (mirror or raidz)"
exit 1
fi
for DEV in ${DEVS}; do
if ! [ -c "/dev/${DEV}" ]; then
echo "Error: /dev/${DEV} is not a block device"
exit 1
fi
if /sbin/gpart show $DEV > /dev/null 2> /dev/null; then
echo "Error: /dev/${DEV} already contains a partition table."
echo ""
/sbin/gpart show $DEV
echo "You may erase the partition table manually with the destroygeom command"
exit 1
fi
done
if [ -z "$MNT" ]; then
MNT=/mnt
fi
if ! [ -d "${MNT}" ]; then
echo "Error: $MNT is not a directory"
exit 1
fi
if [ -n "${ZPART}" ]; then
SZPART="-s ${ZPART}"
fi
if [ "${LEGACY}" = "1" ]; then
ALTROOT=
ROOTMNT=legacy
else
# / is mounted readonly
mkdir -p /var/zfs
ALTROOT="-o altroot=${MNT} -o cachefile=/var/zfs/zpool.cache"
ROOTMNT=/
fi
# Create GPT
for DEV in ${DEVS}; do
echo -n "Creating GUID partitions on ${DEV} ..."
# size is in byte. See the comment to freebsd-ufs for the
# rational.
size_available=`diskinfo /dev/${DEV} | awk '{print $3}'`
size_free=$(( $size_available * 90 / 100 ))
sector_size=`diskinfo /dev/${DEV} | awk '{print $2}'`
# ALIGN should divisible by what the system thinks is the
# sector size or else there is a problem.
if [ $(($ALIGN % $sector_size)) -ne 0 ]; then
echo " error, align value \"$ALIGN\" is not divisible by sector size \"$sector_size\"."
exit 1
else
# alignment in gpart add is in number of block of whatever
# it believes to be the block size. Here, my problem is
# that the SSD is reporting a invalid block size of 512b.
# To have a 8kb alignment (which is the real sector size
# of my SSD - crucial M4 256M, according to
# http://www.hardware.fr/articles/830-2/crucial-m4-128-go-256-go-test.html
# - ), I must use 8192/512=16 as option to gpart add.
# With 8196 passed to gpart add, I get a 4Mb alignment, as
# 8192*512=4Mb. For gnop, the sector size argument is in
# byte so there is no problem.
# Now ... I can certainly pass "-a ${ALIGN}b" to "gpart
# add" with SI unit suffix, but all this calculus make a
# good verification that the value is valid.
GPART_ALIGN=$(($ALIGN / $sector_size))
fi
if ! /sbin/gpart create -s GPT /dev/${DEV} > /dev/null; then
echo " error"
exit 1
fi
/bin/sleep 1
# if ! echo "a 1" | /sbin/fdisk -f - ${DEV} > /dev/null 2> /dev/null; then
# echo " error"
# exit 1
# fi
# get block of 512Kb ?
# 96 * 512 = 49152 is aligned with 8Kb block
# 32 * 512 = 16384 is aligned with 8Kb block
# 65536 = 96*512 + 32*512 is aligned with 8Kb block
if ! /sbin/gpart add -t freebsd-boot -a ${GPART_ALIGN} -b 16384b -s 49152b ${DEV} > /dev/null; then
echo " error"
exit 1
fi
if [ -n "${SWAP}" ]; then
if ! /sbin/gpart add -t freebsd-swap -a ${GPART_ALIGN} -s "${SWAP}" ${DEV} > /dev/null; then
echo " error"
exit 1
fi
SWAPPART=`/sbin/glabel status ${DEV}p2 | /usr/bin/grep gptid | /usr/bin/awk '{ print $1 }'`
if [ -z "$SWAPPART" ]; then
echo " error determining swap partition"
fi
if [ -z "$FSWAP" ]; then
FSWAP=${SWAPPART}
fi
fi
if ! /sbin/gpart add -t freebsd-zfs -a ${GPART_ALIGN} -s ${size_free}b ${DEV} > /dev/null; then
echo " error"
exit 1
fi
# add a ufs partition to send the trim command on 10% of the
# disk to improve ssd performance, until this patch
# http://svnweb.freebsd.org/base?view=revision&revision=240868
# is backported or upgrade to 10
if ! /sbin/gpart add -t freebsd-ufs -a ${GPART_ALIGN} ${DEV} > /dev/null; then
echo " error"
exit 1
fi
if ! bsdlabel -w ${DEV}p3 ; then
echo " error: could not write bsd partitions"
exit 1
fi
if ! newfs -O1 -m0 -L 'trim' -n -t ${DEV}p3a; then
echo " error: could not format bsd partition"
exit 1
fi
if ! mkdir -p /tmp/ufs-trim; then
echo " error, could not create trim mount point"
exit 1
fi
if ! mount -t ufs /dev/${DEV}p3a /tmp/ufs-trim; then
echo " error, could not mount trim partition"
exit 1
fi
dd if=/dev/zero of=/tmp/ufs-trim/to-be-removed-and-send-trim bs=$ALIGN
# send the trim command!
sync
rm -f /tmp/ufs-trim/to-be-removed-and-send-trim
# /bin/dd if=/dev/zero of=/dev/${DEV}p2 bs=512 count=560 > /dev/null 2> /dev/null
# if [ -n "${SWAP}" ]; then
# /bin/dd if=/dev/zero of=/dev/${DEV}p3 bs=512 count=560 > /dev/null 2> /dev/null
# fi
echo " done"
echo -n "Configuring ZFS bootcode on ${DEV} ..."
if ! /sbin/gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ${DEV} > /dev/null; then
echo " error"
exit 1
fi
echo " done"
/sbin/gpart show ${DEV}
done
# Create zpool and zfs
for DEV in ${DEVS}; do
PART=`/sbin/gpart show ${DEV} | /usr/bin/grep freebsd-zfs | /usr/bin/awk '{ print $3 }'`
if [ -z "${PART}" ]; then
echo Error: freebsd-zfs partition not found on /dev/$DEV
exit 1
fi
GPART=`/sbin/glabel list ${DEV}p${PART} | /usr/bin/grep gptid | /usr/bin/awk -F"gptid/" '{ print "gptid/" $2 }'`
GPARTS="${GPARTS} ${GPART}"
PARTS="${PARTS} ${DEV}p${PART}"
done
# align for 8k block (crucial m4 >= 256M)
for part in ${PARTS}; do
if ! /sbin/gnop create -S ${ALIGN} ${part}; then
echo " error creating nop partition ${part}"
fi
PARTS_NOP=" $PARTS_NOP ${part}.nop"
done
echo -n "Creating ZFS pool ${POOL} on${PARTS_NOP} ..."
if ! /sbin/zpool create -f -m none ${ALTROOT} ${VERSION} ${POOL} ${RAID} ${PARTS_NOP} > /dev/null 2> /dev/null; then
echo " error"
exit 1
fi
echo " done"
if [ "${FLETCHER}" = "1" ]; then
echo -n "Setting default checksum to fletcher4 for ${POOL} ..."
if ! /sbin/zfs set checksum=fletcher4 ${POOL} > /dev/null 2> /dev/null; then
echo " error"
exit 1
fi
echo " done"
fi
if [ "${LZJB}" = "1" ]; then
echo -n "Setting default compression to lzjb for ${POOL} ..."
if ! /sbin/zfs set compression=lzjb ${POOL} > /dev/null 2> /dev/null; then
echo " error"
exit 1
fi
echo " done"
fi
echo -n "Creating ${POOL} root partition:"
if ! /sbin/zfs create -o mountpoint=${ROOTMNT} ${POOL}/root > /dev/null 2> /dev/null; then
echo " error"
exit 1
fi
echo " ... done"
echo -n "Creating ${POOL} partitions:"
for FS in ${FS_LIST}; do
if [ "${LEGACY}" = 1 ]; then
MNTPT="-o mountpoint=legacy"
else
MNTPT=
fi
# if ! /sbin/zfus create ${MNTPT} ${POOL}/root/${FS} > /dev/null 2> /dev/null; then
# echo " error"
# exit 1
# fi
# echo -n " ${FS}"
done
zfs create -o compression=on -o exec=on -o setuid=off ${POOL}/root/tmp
zfs create ${POOL}/root/usr
zfs create ${POOL}/root/usr/home
zfs create -o compression=lzjb -o setuid=off ${POOL}/root/usr/ports
zfs create -o compression=off -o exec=off -o setuid=off ${POOL}/root/usr/ports/distfiles
zfs create -o compression=off -o exec=off -o setuid=off ${POOL}/root/usr/ports/packages
zfs create -o compression=lzjb -o exec=off -o setuid=off ${POOL}/root/usr/src
zfs create ${POOL}/root/var
zfs create -o compression=lzjb -o exec=off -o setuid=off ${POOL}/root/var/crash
zfs create -o exec=off -o setuid=off ${POOL}/root/var/db
zfs create -o compression=lzjb -o exec=on -o setuid=off ${POOL}/root/var/db/pkg
zfs create -o exec=off -o setuid=off ${POOL}/root/var/empty
zfs create -o compression=lzjb -o exec=off -o setuid=off ${POOL}/root/var/log
zfs create -o compression=gzip -o exec=off -o setuid=off ${POOL}/root/var/mail
zfs create -o exec=off -o setuid=off ${POOL}/root/var/run
zfs create -o compression=lzjb -o exec=on -o setuid=off ${POOL}/root/var/tmp
chmod 1777 /${MNT}/var/tmp
echo " ... done"
echo -n "Setting bootfs for ${POOL} to ${POOL}/root ..."
if ! /sbin/zpool set bootfs=${POOL}/root ${POOL} > /dev/null 2> /dev/null; then
echo " error"
exit 1
fi
echo " done"
/sbin/zfs list -r ${POOL}
# Mount and populate zfs (if legacy)
if [ "${LEGACY}" = "1" ]; then
echo -n "Mounting ${POOL} on ${MNT} ..."
/bin/mkdir -p ${MNT}
if ! /sbin/mount -t zfs ${POOL}/root ${MNT} > /dev/null 2> /dev/null; then
echo " error mounting pool/root"
exit 1
fi
for FS in ${FS_LIST}; do
/bin/mkdir -p ${MNT}/${FS}
if ! /sbin/mount -t zfs ${POOL}/root/${FS} ${MNT}/${FS} > /dev/null 2> /dev/null; then
echo " error mounting ${POOL}/root/${FS}"
exit 1
fi
done
echo " done"
fi
echo -n "Extracting FreeBSD distribution ..."
# https://calomel.org/zfs_freebsd_root_install.html
cd /usr/freebsd-dist
export DESTDIR=${MNT}
for file in base.txz lib32.txz kernel.txz doc.txz ports.txz src.txz; do
(cat $file | tar --unlink -xpJf - -C ${DESTDIR:-/});
done
echo " done"
# Adjust configuration files
echo -n "Writing /boot/loader.conf..."
echo "zfs_load=\"YES\"" > ${MNT}/boot/loader.conf
echo "vfs.root.mountfrom=\"zfs:${POOL}/root\"" >> ${MNT}/boot/loader.conf
echo " done"
# Write fstab if swap or legacy
echo -n "Writing /etc/fstab..."
rm -f ${MNT}/etc/fstab
touch ${MNT}/etc/fstab
if [ -n "${FSWAP}" -o "${LEGACY}" = "1" ]; then
if [ -n "${FSWAP}" ]; then
echo "/dev/${FSWAP} none swap sw 0 0" > ${MNT}/etc/fstab
fi
if [ "${LEGACY}" = "1" ]; then
for FS in ${FS_LIST}; do
echo ${POOL}/root/${FS} /${FS} zfs rw 0 0 >> ${MNT}/etc/fstab
done
fi
fi
if [ "${LEGACY}" != "1" ]; then
echo -n "Writing /etc/rc.conf..."
echo 'zfs_enable="YES"' >> ${MNT}/etc/rc.conf
fi
echo " done"
echo -n "Copying /var/zfs/zpool.cache ..."
if [ -n "${LEGACY}" ]; then
for FS in ${FS_LIST}; do
/sbin/umount ${MNT}/${FS} > /dev/null 2> /dev/null
done
/sbin/umount ${MNT} > /dev/null 2> /dev/null
fi
if ! /sbin/zpool export ${POOL} > /dev/null 2> /dev/null; then
echo " error exporting pool"
exit 1
fi
for part in ${PARTS_NOP}; do
if ! /sbin/gnop destroy ${part}; then
echo " error deleting nop ${part}"
fi
done
if ! /sbin/zpool import ${ALTROOT} ${POOL} > /dev/null 2> /dev/null; then
echo " error importing pool"
exit 1
fi
if [ -n "${LEGACY}" ]; then
if ! /sbin/mount -t zfs ${POOL}/root ${MNT} > /dev/null 2> /dev/null; then
echo " error mounting ${POOL}/root"
exit 1
fi
fi
if ! /bin/cp /var/zfs/zpool.cache ${MNT}/boot/zfs/ > /dev/null 2> /dev/null; then
echo " error copying zpool.cache"
exit 1
fi
if [ -n "${LEGACY}" ]; then
for FS in ${FS_LIST}; do
if ! /sbin/mount -t zfs ${POOL}/${FS} ${MNT}/${FS} > /dev/null 2> /dev/null; then
echo " error mounting ${POOL}/${FS}"
exit 1
fi
done
fi
echo " done"
# Mount devfs for post-configuration
if ! /sbin/mount -t devfs devfs ${MNT}/dev; then
echo "Error mounting devfs on ${MNT}/dev"
fi
echo "Copying packages ...."
mkdir -p /usr/ports/packages
if ! cp -ap /packages/* /usr/ports/packages; then
echo " error copying packages"
exit 1
fi
echo "Installing specific configurations ...."
if ! tar -C ${MNT} -x -z -f /usr/freebsd-usr/confs.tar.gz; then
echo " error installing configurations"
exit 1
fi
echo ""
echo "Installation complete."
echo "The system will boot from ZFS with clean install on next reboot"
echo ""
echo "You may type \"chroot ${MNT}\" and make any adjustments you need."
echo "For example, change the root password or edit/create /etc/rc.conf for"
echo "for system services. "
echo ""
echo "WARNING - Don't export ZFS pool \"${POOL}\"!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment