#!/bin/sh # $FreeBSD$ # # PROVIDE: memzil # REQUIRE: FILESYSTEMS # KEYWORD: nojail # # Add/Remove a memory based LOG device to a zfs pool at system boot/shutdown time. # # memzil_enable=YES|NO Enable memzil pools # memzil_pools="list of pools|AUTO" Pools to add a memory based log to # memzil_bootfs=YES|NO Only add a log to a bootfs pool if set to YES # memzil_size="512M" Size of md(4) device -s option # # WARNING: This rc script will dynamically add an md(4) LOG device to a # WARNING: ZFS pool at boot time and remove it correctly at system shudown # WARNING: time. However, if the system panics, resets, or is otherwise # WARNING: hard powered off, the associated pool with the memory based # WARNING: LOG device will not be usable until it is recovered. # # WARNING: For instance, for a beadm(1) configured system: # WARNING: zpool import -f -m sys # WARNING: zpool remove md0 sys # WARNING: zfs set mountpoint=/mnt sys/ROOT/default sys # WARNING: zpool set cachefile=/mnt/boot/zfs/zpool.cache sys # WARNING: zfs set mountpoint=legacy sys/ROOT/default sys # WARNING: zfs unmount -a # WARNING: reboot # # WARNING: Data loss is possible!! Use at your own risk!! # WARNING: Data loss is possible!! Use at your own risk!! # WARNING: Data loss is possible!! Use at your own risk!! . /etc/rc.subr name="memzil" rcvar="${name}_enable" start_cmd="${name}_start" stop_cmd="${name}_stop" show_cmd="${name}_show" extra_commands="show" memzil_show() { if [ -z "${memzil_pools}" ]; then err 1 "You must define memzil_pools with at least one pool name or AUTO" fi case "${memzil_pools:-NONE}" in [Aa][Uu][Tt][Oo]) pools=`zpoollist` ;; * ) pools="${memzil_pools:-NONE}" esac for pool in $pools; do # Validate any non-AUTO memzil_pools # zpool list $pool > /dev/null 2>&1 if [ $? -ne 0 ]; then warn "Pool $pool does not exist" continue fi logdevs $pool | while read line; do echo $line done done } memzil_start() { if [ -z "${memzil_pools}" ]; then err 1 "You must define memzil_pools with at least one pool name or AUTO" fi case "${memzil_pools}" in [Aa][Uu][Tt][Oo]) pools=`zpoollist` ;; * ) pools="${memzil_pools}" esac echo "Adding an md(4) based log to pools: $pools" for pool in $pools; do # Validate any non-AUTO memzil_pools # zpool list $pool > /dev/null 2>&1 if [ $? -ne 0 ]; then warn "Pool $pool does not exist" continue fi # log device already present? # logs=`logdevs $pool | wc -l` if [ $logs -gt 0 ]; then echo "Pool $pool already contains ${logs##*[[:blank:]]} log device(s)" continue else echo "No log devices present on pool $pool" fi # Is this a bootfs? # bootfs=`zpool get bootfs $pool | grep bootfs | awk '{ print $3; }'` if [ "$bootfs" != "-" ]; then if [ "${memzil_bootfs:-NO}" = "YES" ]; then echo "Adding memzil to bootfs pool $pool" echo "zpool set bootfs=\"\" ${pool:-badpool}" zpool set bootfs="" ${pool:-badpool} else echo "Not adding memzil to bootfs pool $pool" continue fi fi # Add the device # logdev=`mdconfig -a -t malloc -s ${memzil_size:-512M} -o reserve` echo "Adding $logdev to pool $pool" zpool add ${pool:-badpool} log ${logdev:-nologdev} # Restore possible bootfs value # if [ "$bootfs" != "-" ]; then zpool set "bootfs=$bootfs" $pool zpool get bootfs $pool fi done } memzil_stop() { case "${memzil_pools:-NONE}" in [Aa][Uu][Tt][Oo]) pools=`zpoollist` ;; * ) pools="${memzil_pools:-NONE}" esac echo "Removing any md log devices from pool(s): $pools" for pool in $pools; do # Validate any non-AUTO memzil_pools # zpool list $pool > /dev/null 2>&1 if [ $? -ne 0 ]; then warn "Pool $pool does not exist" continue fi # Even though memzil only adds non-mirrored md devices, remove # both mirrored and non-mirrored units. # logdevs $pool | while read poolname ismirror device junk; do if [ "${device%%[[:digit:]]*}" = "md" ]; then echo "zpool remove ${pool:-badpool} $device" zpool remove ${pool:-badpool} $device if [ "$?" != "0" ]; then echo "zpool detach ${pool:-badpool} $device" zpool detach ${pool:-badpool} $device fi echo "mdconfig -d -u $device" mdconfig -d -u $device fi done done } zpoollist() { while read t1 tx; do echo $t1 done << __EOT__ $(zpool list -H) __EOT__ } logdevs() { pool="${1:-nopool}" output=0 ismirror="nomirror" zpool status $pool | while read _line; do if [ "`echo $_line | cut -f1 -d':'`" = "errors" -o "$_line" = "cache" ]; then output=0 fi if [ "$output" = "1" -a "$_line" != "" ]; then if [ "`echo $_line | cut -f1 -d'-'`" = "mirror" ]; then ismirror=`echo $_line | awk '{ print $1; }'` else echo $pool $ismirror $_line fi else if [ "$_line" = "logs" ]; then output=1 fi fi done } load_rc_config $name run_rc_command "$1"