Created
October 4, 2013 14:43
-
-
Save rosstimson/6827095 to your computer and use it in GitHub Desktop.
Revisions
-
rosstimson created this gist
Oct 4, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -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