|
|
@@ -0,0 +1,383 @@ |
|
|
# ---- Makefile for Vermaden's FreeBSD 9.1 root on ZFS manual install |
|
|
# $Id: Makefile,v 1.18 2013/08/07 13:31:29 root Exp root $ |
|
|
# |
|
|
# Copyright (c) 2013 Adriaan van Roosmalen <j65nko daemonforums.org>> |
|
|
# |
|
|
# Permission to use, copy, modify, and distribute this software for any |
|
|
# purpose with or without fee is hereby granted, provided that the above |
|
|
# copyright notice and this permission notice appear in all copies. |
|
|
# |
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
# |
|
|
# This BSD makefile merely automates Vermaden's "'ZFS madness / boot |
|
|
# environments" mirrored disk setup. |
|
|
# |
|
|
# For a complete description of this particular ZFS only setup see below. |
|
|
# |
|
|
# The ZFS configuration described by Vermaden does not align the |
|
|
# disk partitions for 'Avanced Format' 4K disks and also does not |
|
|
# instruct ZFS to use 4K blocks for the write and read operations. |
|
|
# |
|
|
# The procedure implemented here does align the EFI/gpt partitions |
|
|
# used on a 4K (8 x 512) # sector boundary. By using the 'gnop' trick |
|
|
# the FreeBSD ZFS implementation is coached to use an 'ashift' value |
|
|
# of 12 (2^12 = 4096) |
|
|
# This value makes ZFS read and write on 4K boundaries |
|
|
# |
|
|
# Credits for the ZFS install procedure: |
|
|
# |
|
|
# Slawomir Wojciech Wojtczak (vermaden) |
|
|
# http://forums.freebsd.org/showthread.php?t=31662 |
|
|
# http://www.daemonforums.org/showthread.php?t=7099 |
|
|
# |
|
|
# Sources and credits for the 4K alignment issue and gnop hack: |
|
|
# |
|
|
# Warren Block (wblock@) for his numerous posts about partition alignment: |
|
|
# http://forums.freebsd.org (Installation and Storage sections) |
|
|
# http://www.wonkity.com/~wblock/docs/html/disksetup.html#_the_new_standard_gpt |
|
|
# Ivan Voras for the gnop workaround: |
|
|
# http://ivoras.sharanet.org/blog/tree/2011-01-01.freebsd-on-4k-sector-drives.html |
|
|
# George Kontostanos (gkontos) for using gnop and a ZFS cache file: |
|
|
# http://forums.freebsd.org/showthread.php?t=23544 |
|
|
# http://www.aisecure.net/2012/01/16/rootzfs/ |
|
|
# |
|
|
|
|
|
# --- variables start |
|
|
#DEBUG = echo |
|
|
|
|
|
POOL = rpool |
|
|
ROOT_SET = ${POOL}/ROOT |
|
|
BOOT_SET = ${ROOT_SET}/default |
|
|
|
|
|
# --- installation file sets |
|
|
SETS = base.txz kernel.txz |
|
|
DIR = /usr/freebsd-dist # On FreeBSD liveCD/DVD/memstick |
|
|
.for X in ${SETS} |
|
|
INSTALL_SETS += ${DIR}/${X} |
|
|
.endfor |
|
|
|
|
|
DISKTYPE = ada |
|
|
DISKTYPE = md |
|
|
|
|
|
.if ${DISKTYPE} == "md" |
|
|
|
|
|
# --- memory disks see md(4) and mdconfig(8) |
|
|
# size of disk needs to be at least 64M else you encounter this error: |
|
|
# "cannot create 'pool': one or more devices is less than the minimum size (64M)" |
|
|
|
|
|
MD_SIZE = 2g |
|
|
SWAPSIZE = 256m |
|
|
DISK_1 = /dev/md1 |
|
|
DISK_2 = /dev/md2 |
|
|
DISKS = ${DISK_1} ${DISK_2} |
|
|
# --- gpt/EFI labels |
|
|
LABEL_ZFS = mdisk_ |
|
|
LABEL_BOOT = mdboot |
|
|
|
|
|
.else |
|
|
|
|
|
# --- real spinning rust disks |
|
|
DISK_1 = /dev/ada1 |
|
|
DISK_2 = /dev/ada2 |
|
|
DISKS = ${DISK_1} ${DISK_2} |
|
|
SWAPSIZE = 4G |
|
|
# --- gpt/EFI labels |
|
|
LABEL_ZFS = SYSTEM_ |
|
|
LABEL_BOOT = BOOT_ |
|
|
|
|
|
.endif |
|
|
|
|
|
TMP = /tmp |
|
|
CACHEFILE = ${TMP}/zpool.cache |
|
|
TEMPLATE_RC_CONF= ${TMP}/template_rc.conf |
|
|
MOUNT = /mnt |
|
|
RC_CONF = ${MOUNT}/etc/rc.conf |
|
|
LOADER_CONF = ${MOUNT}/boot/loader.conf |
|
|
FSTAB = ${MOUNT}/etc/fstab |
|
|
|
|
|
# --- variables end |
|
|
|
|
|
show: |
|
|
@echo ------------------------- |
|
|
@echo Current variable settings |
|
|
@echo ------------------------- |
|
|
@printf "%-20s : [%s]\n" DEBUG "${DEBUG}" |
|
|
@printf "%-20s : [%s]\n" POOL "${POOL}" |
|
|
@printf "%-20s : [%s]\n" ROOT_SET "${ROOT_SET}" |
|
|
@printf "%-20s : [%s]\n" BOOT_SET "${BOOT_SET}" |
|
|
@printf "%-20s : [%s]\n" SETS "${SETS}" |
|
|
@printf "%-20s : [%s]\n" DIR "${DIR}" |
|
|
@printf "%-20s : [%s]\n" INSTALL_SETS "${INSTALL_SETS}" |
|
|
@printf "%-20s : [%s]\n" DISKTYPE "${DISKTYPE}" |
|
|
@printf "%-20s : [%s]\n" MD_SIZE "${MD_SIZE}" |
|
|
@printf "%-20s : [%s]\n" SWAPSIZE "${SWAPSIZE}" |
|
|
@printf "%-20s : [%s]\n" DISK_1 "${DISK_1}" |
|
|
@printf "%-20s : [%s]\n" DISK_2 "${DISK_2}" |
|
|
@printf "%-20s : [%s]\n" DISKS "${DISKS}" |
|
|
@printf "%-20s : [%s]\n" LABEL_ZFS "${LABEL_ZFS}" |
|
|
@printf "%-20s : [%s]\n" LABEL_BOOT "${LABEL_BOOT}" |
|
|
@printf "%-20s : [%s]\n" SWAPSIZE "${SWAPSIZE}" |
|
|
@printf "%-20s : [%s]\n" TMP "${TMP}" |
|
|
@printf "%-20s : [%s]\n" CACHEFILE "${CACHEFILE}" |
|
|
@printf "%-20s : [%s]\n" MOUNT "${MOUNT}" |
|
|
@printf "%-20s : [%s]\n" TEMPLATE_RC_CONF "${TEMPLATE_RC_CONF}" |
|
|
@printf "%-20s : [%s]\n" RC_CONF "${RC_CONF}" |
|
|
@printf "%-20s : [%s]\n" LOADER_CONF "${LOADER_CONF}" |
|
|
@printf "%-20s : [%s]\n" FSTAB "${FSTAB}" |
|
|
@echo ------------------------- |
|
|
@echo "Checking for installation sets ..." |
|
|
|
|
|
.for X in ${INSTALL_SETS} |
|
|
@printf "Set $X : " |
|
|
@if [ -f ${X} ] ; then echo found! ; else echo missing! ; fi |
|
|
.endfor |
|
|
@echo "Checking for 'rc.conf' template ..." |
|
|
|
|
|
.if exists(${TEMPLATE_RC_CONF}) |
|
|
@echo ----------- rc.conf template ---------- |
|
|
cat ${TEMPLATE_RC_CONF} |
|
|
.else |
|
|
@echo ${TEMPLATE_RC_CONF} not found |
|
|
exit 100 |
|
|
.endif |
|
|
|
|
|
# ----------------------------------------------------------------------------- |
|
|
# WARNING: you can 'make' all targets except the 'trailer' target!! |
|
|
# 'trailer' is a makefile macro and only works as prerequisite of other targets |
|
|
# Scroll down to the end of the Makefile and read the reason why ..... |
|
|
# ----------------------------------------------------------------------------- |
|
|
|
|
|
diskinfo: trailer |
|
|
.for X in ${DISKS} |
|
|
if [ -e ${X} ] ; then diskinfo -v ${X} ; fi |
|
|
.endfor |
|
|
|
|
|
# --- Load FreeBSD ZFS kernel modules |
|
|
|
|
|
zfsload: trailer |
|
|
kldload -n zfs |
|
|
kldload -n opensolaris |
|
|
kldstat |
|
|
|
|
|
# --------- using make '.for .. in ... .endfor' construct |
|
|
# make variables you can refer to with a single '$' as in ${X} |
|
|
# for shell variables you must use a double $$ as $${NR} |
|
|
|
|
|
partition: trailer |
|
|
.for X in ${DISKS} |
|
|
if gpart show ${X} ; then gpart destroy -F ${X} ; fi |
|
|
gpart create -s gpt ${X} |
|
|
NR=$$( echo ${X} | tr -c -d '0-9' ) ;\ |
|
|
gpart add -b 40 -s 128k -t freebsd-boot -l ${LABEL_BOOT}$${NR} ${X} ;\ |
|
|
gpart add -t freebsd-zfs -l ${LABEL_ZFS}$${NR} ${X} |
|
|
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ${X} |
|
|
gpart show ${X} |
|
|
.endfor |
|
|
ls -l /dev/gpt |
|
|
|
|
|
# --- Procedure to coach ZFS to use 4K sector aligned read/writes |
|
|
|
|
|
gnop4k: trailer |
|
|
@echo Creating gnop devices with 4K sectors ..... |
|
|
for X in ${DISKS} ; do \ |
|
|
NR=$$( echo $${X} | tr -c -d '0-9' ) ;\ |
|
|
gnop create -S 4096 /dev/gpt/${LABEL_ZFS}$${NR} ;\ |
|
|
done |
|
|
ls -l /dev/gpt |
|
|
gnop list |
|
|
gnop status |
|
|
|
|
|
pool4k: trailer |
|
|
@echo Creating zpool with 4K gnop devices |
|
|
if [ -f ${CACHEFILE} ] ; then mv ${CACHEFILE} ${CACHEFILE}.prev ; fi |
|
|
ls -l /dev/gpt |
|
|
# ---- creating a ZFS mirror pool without automatically mounting it (-m none) ..... |
|
|
zpool create -f -o cachefile=${CACHEFILE} -m none ${POOL} mirror /dev/gpt/${LABEL_ZFS}*nop |
|
|
zpool list ${POOL} |
|
|
zpool status ${POOL} |
|
|
zfs list |
|
|
|
|
|
export: trailer |
|
|
@echo Exporting ${POOL} ...... |
|
|
@echo --------------------------------- |
|
|
zpool export ${POOL} |
|
|
@echo --------------------------------- |
|
|
@echo Showing import status of ${POOL} ...... |
|
|
@echo --------------------------------- |
|
|
zpool import |
|
|
|
|
|
gnop_destroy: trailer |
|
|
@echo Destroy the 4K gnop devices |
|
|
for X in ${DISKS} ; do \ |
|
|
NR=$$( echo $${X} | tr -c -d '0-9' ) ;\ |
|
|
gnop destroy /dev/gpt/${LABEL_ZFS}$${NR}.nop ;\ |
|
|
done |
|
|
ls -l /dev/gpt |
|
|
for X in ${DISKS} ; do gpart show $${X} ; done |
|
|
|
|
|
import: trailer |
|
|
@echo Import the pool |
|
|
zpool import -o cachefile=${CACHEFILE} ${POOL} |
|
|
zpool list ${POOL} |
|
|
@echo --------------------------------- |
|
|
zpool status ${POOL} |
|
|
@echo --------------------------------- |
|
|
mount |
|
|
|
|
|
chk_ashift: trailer |
|
|
@echo "Verify that ashift value is 12 (2^12 = 4096 ; 2^9 = 512)" |
|
|
@echo ========================================================= |
|
|
zdb -C -U ${CACHEFILE} ${POOL} |
|
|
@echo ==================================== |
|
|
zdb -C -U ${CACHEFILE} ${POOL} | grep ashift |
|
|
|
|
|
# --- Having a 4K aligned pool we now continue with the Vermaden 'ZFS madness' procedure |
|
|
|
|
|
zfs_options: trailer |
|
|
zfs set mountpoint=none ${POOL} |
|
|
zfs set checksum=fletcher4 ${POOL} |
|
|
zfs set atime=off ${POOL} |
|
|
zpool list ${POOL} |
|
|
zpool status ${POOL} |
|
|
zfs list |
|
|
|
|
|
zfs_fs: trailer |
|
|
@echo --------------------------------- |
|
|
zfs create ${ROOT_SET} |
|
|
zfs create -o mountpoint=${MOUNT} ${BOOT_SET} |
|
|
zpool set bootfs=${BOOT_SET} ${POOL} |
|
|
zfs list |
|
|
@echo --------------------------------- |
|
|
mount |
|
|
|
|
|
# --- alternatively you can configure ZFS swap after reboot |
|
|
|
|
|
zfs_swap: trailer |
|
|
zfs create -V ${SWAPSIZE} ${POOL}/swap |
|
|
zfs set org.freebsd:swap=on ${POOL}/swap |
|
|
zfs set checksum=off ${POOL}/swap |
|
|
zfs set sync=disabled ${POOL}/swap |
|
|
zfs set primarycache=none ${POOL}/swap |
|
|
zfs set secondarycache=none ${POOL}/swap |
|
|
zfs list |
|
|
|
|
|
# ========================================================== |
|
|
pre_install: trailer partition gnop4k pool4k export gnop_destroy import \ |
|
|
chk_ashift zfs_options zfs_fs zfs_swap |
|
|
|
|
|
install: trailer |
|
|
for THIS in ${INSTALL_SETS} ; do \ |
|
|
tar --unlink -xvpJf $${THIS} -C ${MOUNT} ;\ |
|
|
done |
|
|
ls -l ${MOUNT} |
|
|
zpool status ${POOL} |
|
|
zpool iostat ${POOL} |
|
|
zfs list |
|
|
|
|
|
post_install: trailer loader.conf fstab rc.conf zfs_boot zfs_umount mountpoint |
|
|
|
|
|
all: trailer pre_install install post_install |
|
|
# ========================================================== |
|
|
|
|
|
loader.conf: trailer |
|
|
echo 'zfs_load=YES' >> ${LOADER_CONF} |
|
|
echo 'vfs.root.mountfrom="zfs:${BOOT_SET}"' >> ${LOADER_CONF} |
|
|
@echo =========== loader.conf ========================= |
|
|
@cat ${LOADER_CONF} |
|
|
|
|
|
fstab: trailer |
|
|
# ---- create empty /etc/fstab file |
|
|
touch ${FSTAB} |
|
|
|
|
|
rc.conf: trailer |
|
|
cat ${TEMPLATE_RC_CONF} >> ${RC_CONF} |
|
|
echo 'zfs_enable="YES"' >> ${RC_CONF} |
|
|
@echo =========== rc.conf ========================= |
|
|
@cat ${RC_CONF} |
|
|
|
|
|
zfs_boot: trailer |
|
|
if [ ! -d ${MOUNT}/boot/zfs ] ; then echo Cannot copy ${CACHEFILE} to ${MOUNT}/boot/zfs ! ; exit 2 ; fi |
|
|
cp -p ${CACHEFILE} ${MOUNT}/boot/zfs/ |
|
|
ls -l ${MOUNT}/boot/zfs |
|
|
|
|
|
zfs_umount: trailer |
|
|
zfs unmount -a |
|
|
zfs list |
|
|
@echo ------ |
|
|
mount |
|
|
|
|
|
mountpoint: trailer |
|
|
ls -l ${TMP} |
|
|
zfs set mountpoint=legacy ${BOOT_SET} |
|
|
zfs list |
|
|
@echo Setup is finished ............ |
|
|
@echo ----------------- done ! --------------------------------- |
|
|
@echo you can now reboot into your new ZFS only system now ..... |
|
|
@echo ---------------------------------------------------------- |
|
|
@echo Or you could finish the elementary setup with: |
|
|
@echo |
|
|
@echo "1. Remount your ZFS file system : mount -t zfs ${BOOT_SET} ${MOUNT}" |
|
|
@echo "2. Chroot into ${MOUNT} : chroot ${MOUNT}" |
|
|
@echo "3. Change the root password : passwd" |
|
|
@echo "4. Create the /etc/mail/aliases.db : newaliases" |
|
|
@echo "5. Set up your time zone : tzsetup" |
|
|
@echo |
|
|
@echo "6. Exit the chroot : exit" |
|
|
@echo "7. Unmount : umount ${MOUNT}" |
|
|
|
|
|
# ====================== U t i l i t i e s ================================ |
|
|
# --- if something went wrong with the pool/zfs creation you clean up with: |
|
|
|
|
|
pool_destroy: trailer |
|
|
zfs destroy -r ${POOL} |
|
|
zfs list |
|
|
zpool destroy ${POOL} |
|
|
zpool status |
|
|
zfs list |
|
|
|
|
|
# --- destroy gpart partition scheme and zero out first 256 MB of disk(s) |
|
|
|
|
|
gpart_destroy: trailer |
|
|
.for X in ${DISKS} |
|
|
if gpart show ${X} ; then gpart destroy -F ${X} ; fi |
|
|
dd if=/dev/zero of=${X} bs=1m count=256 |
|
|
.endfor |
|
|
|
|
|
# --- create FreeBSD memory disks (for testing Makefile modifications) |
|
|
|
|
|
md_create: trailer |
|
|
@${DEBUG} echo Creating Memory disk devices ${DISKS}: |
|
|
@${DEBUG} mdconfig -a -t swap -s ${MD_SIZE} -u 1 |
|
|
@${DEBUG} mdconfig -a -t swap -s ${MD_SIZE} -u 2 |
|
|
@${DEBUG} echo Memory disk devices: |
|
|
@${DEBUG} mdconfig -lv -u 1 |
|
|
@${DEBUG} mdconfig -lv -u 2 |
|
|
@${DEBUG} ls -l /dev/md* |
|
|
|
|
|
md_destroy: trailer |
|
|
@${DEBUG} mdconfig -d -u 1 |
|
|
@${DEBUG} mdconfig -d -u 2 |
|
|
@${DEBUG} echo Memory disk devices: |
|
|
@${DEBUG} ls -l /dev/md* |
|
|
|
|
|
# --- don't make the target 'trailer'. I once tried for fun and ran out of swap space! |
|
|
# From 'dmesg' |
|
|
# swap_pager: out of swap space |
|
|
# swap_pager_getswapspace(16): failed |
|
|
# pid 1812 (make), uid 0, was killed: out of swap space |
|
|
|
|
|
trailer: .USE |
|
|
@echo -------------end of ${.TARGET} -------------------- |
|
|
|
|
|
.PHONY: show diskinfo zfsload md_create md_destroy partition gnop4k pool4k export |
|
|
.PHONY: gnop_destroy import chk_ashift zfs_options zfs_fs zfs_swap install |
|
|
.PHONY: loader.conf fstab rc.conf zfs_boot zfs_umount mountpoint pool_destroy |
|
|
.PHONY: gpart_destroy pre_install post_install all trailer |
|
|
|
|
|
# ---- end of Makefile |