Update zfs.fedora init script

Apply all of Rudd-O's changes for the Fedora init script.  The
initial init script was one I threw together based on Rudd-O's
original work.  It worked for me but it has some flaws.

Rudd-O has invested considerable time updating it to be significantly
smarter.  It now handles using ZFS as your root filesystem plus
various other quirks.  Since he is familiar with the right
way to do things on Fedora and has tested this init script we
are integrating all of his changes.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Manuel Amador (Rudd-O) 2011-04-07 10:34:20 -07:00 committed by Brian Behlendorf
parent 6583dcacdc
commit f5ef7150ea
1 changed files with 175 additions and 48 deletions

View File

@ -11,8 +11,8 @@
# #
### BEGIN INIT INFO ### BEGIN INIT INFO
# Provides: zfs # Provides: zfs
# Required-Start: $local_fs # Required-Start:
# Required-Stop: $local_fs # Required-Stop:
# Should-Start: # Should-Start:
# Should-Stop: # Should-Stop:
# Default-Start: 2 3 4 5 # Default-Start: 2 3 4 5
@ -23,72 +23,196 @@
# filesystems and starts all related zfs services. # filesystems and starts all related zfs services.
### END INIT INFO ### END INIT INFO
# Source function library. export PATH=/usr/local/sbin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
# Source function library & LSB routines
. /etc/rc.d/init.d/functions . /etc/rc.d/init.d/functions
# Source zfs configuration. # script variables
[ -f /etc/sysconfig/zfs ] && . /etc/sysconfig/zfs
RETVAL=0 RETVAL=0
ZPOOL=zpool
ZFS=zfs
servicename=zfs
LOCKFILE=/var/lock/subsys/$servicename
LOCKFILE=/var/lock/subsys/zfs # functions
CACHEFILE=/etc/zfs/zpool.cache zfs_installed() {
ZPOOL=/usr/sbin/zpool modinfo zfs > /dev/null 2>&1 || return 5
ZFS=/usr/sbin/zfs $ZPOOL > /dev/null 2>&1
[ $? == 127 ] && return 5
$ZFS > /dev/null 2>&1
[ $? == 127 ] && return 5
return 0
}
[ -x $ZPOOL ] || exit 1 reregister_mounts() {
[ -x $ZFS ] || exit 2 cat /etc/mtab | while read -r fs mntpnt fstype opts rest ; do
fs=`printf '%b\n' "$fs"`
mntpnt=`printf '%b\n' "$mntpnt"`
if [ "$fstype" == "zfs" ] ; then
if [ "$mntpnt" == "/" ] ; then
mount -f -o zfsutil -t zfs --move / /removethismountpointhoweverpossible
umount --fake /removethismountpointhoweverpossible
else
umount --fake "$mntpnt"
fi
elif echo "$fs" | grep -q "^/dev/zd" ; then
if [ "$mntpnt" == "/" ] ; then
mount -f -t "$fstype" --move / /removethismountpointhoweverpossible
umount --fake /removethismountpointhoweverpossible
else
umount --fake "$mntpnt"
fi
fi
done
cat /proc/mounts | while read -r fs mntpnt fstype opts rest ; do
fs=`printf '%b\n' "$fs"`
mntpnt=`printf '%b\n' "$mntpnt"`
if [ "$fstype" == "zfs" ] ; then
mount -f -t zfs -o zfsutil "$fs" "$mntpnt"
elif echo "$fs" | grep -q "^/dev/zd" ; then
mount -f -t "$fstype" -o "$opts" "$fs" "$mntpnt"
fi
done
}
# i need a bash guru to simplify this, since this is copy and paste, but donno how
# to correctly dereference variable names in bash, or how to do this right
declare -A MTAB
declare -A FSTAB
# first parameter is a regular expression that filters mtab
read_mtab() {
for fs in "${!MTAB[@]}" ; do unset MTAB["$fs"] ; done
while read -r fs mntpnt fstype opts blah ; do
fs=`printf '%b\n' "$fs"`
MTAB["$fs"]=$mntpnt
done < <(grep "$1" /etc/mtab)
}
in_mtab() {
[ "${MTAB[$1]}" != "" ]
return $?
}
# first parameter is a regular expression that filters fstab
read_fstab() {
for fs in "${!FSTAB[@]}" ; do unset FSTAB["$fs"] ; done
while read -r fs mntpnt fstype opts blah ; do
fs=`printf '%b\n' "$fs"`
FSTAB["$fs"]=$mntpnt
done < <(grep "$1" /etc/fstab)
}
in_fstab() {
[ "${FSTAB[$1]}" != "" ]
return $?
}
start() start()
{ {
[ -f $LOCKFILE ] && return 3 if [ -f "$LOCKFILE" ] ; then return 0 ; fi
# check if ZFS is installed. If not, comply to FC standards and bail
zfs_installed || {
action $"Checking if ZFS is installed: not installed" /bin/false
return 5
}
# Requires selinux policy which has not been written. # Requires selinux policy which has not been written.
if [ -r "/selinux/enforce" ] && if [ -r "/selinux/enforce" ] &&
[ "$(cat /selinux/enforce)" = "1" ]; then [ "$(cat /selinux/enforce)" = "1" ]; then
action "SELinux ZFS policy required: " /bin/false action $"SELinux ZFS policy required: " /bin/false || return 6
return 4
fi fi
# Load the zfs module stack # load kernel module infrastructure
/sbin/modprobe zfs if ! grep -q zfs /proc/modules ; then
action $"Loading kernel ZFS infrastructure: " modprobe zfs || return 5
fi
# Ensure / exists in /etc/mtab, if not update mtab accordingly. # fix mtab to include already-mounted fs filesystems, in case there are any
# This should be handled by rc.sysinit but lets be paranoid. # we ONLY do this if mtab does not point to /proc/mounts
awk '$2 == "/" { exit 1 }' /etc/mtab # which is the case in some systems (systemd may bring that soon)
if ! readlink /etc/mtab | grep -q /proc ; then
if grep -qE "(^/dev/zd| zfs )" /proc/mounts ; then
action $"Registering already-mounted ZFS filesystems and volumes: " reregister_mounts || return 150
fi
fi
if [ -f /etc/zfs/zpool.cache ] ; then
echo -n $"Importing ZFS pools not yet imported: "
$ZPOOL import -c /etc/zfs/zpool.cache -aN || true # stupid zpool will fail if all pools are already imported
RETVAL=$? RETVAL=$?
if [ $RETVAL -eq 0 ]; then if [ $RETVAL -ne 0 ]; then
/bin/mount -f / failure "Importing ZFS pools not yet imported: "
return 151
fi
success "Importing ZFS pools not yet imported: "
fi fi
# Import all pools described by the cache file, and then mount action $"Mounting ZFS filesystems not yet mounted: " $ZFS mount -a || return 152
# all filesystem based on their properties.
if [ -f $CACHEFILE ] ; then
action $"Importing ZFS pools: " \
$ZPOOL import -c $CACHEFILE -aN 2>/dev/null
action $"Mounting ZFS filesystems: " \
$ZFS mount -a
fi
touch $LOCKFILE # hack to read mounted file systems because otherwise
# zfs returns EPERM when a non-root user reads a mounted filesystem before root did
savepwd="$PWD"
mount | grep " type zfs " | sed 's/.*on //' | sed 's/ type zfs.*$//' | while read line ; do
cd "$line" > /dev/null 2>&1
ls > /dev/null
done
cd "$savepwd"
read_mtab "^/dev/zd"
read_fstab "^/dev/zd"
template=$"Mounting volume %s registered in fstab: "
for volume in "${!FSTAB[@]}" ; do
if in_mtab "$volume" ; then continue ; fi
string=`printf "$template" "$volume"`
action "$string" mount "$volume"
done
touch "$LOCKFILE"
} }
stop() stop()
{ {
[ ! -f $LOCKFILE ] && return 3 if [ ! -f "$LOCKFILE" ] ; then return 0 ; fi
action $"Unmounting ZFS filesystems: " $ZFS umount -a # check if ZFS is installed. If not, comply to FC standards and bail
zfs_installed || {
action $"Checking if ZFS is installed: not installed" /bin/false
return 5
}
rm -f $LOCKFILE # the poweroff of the system takes care of this
} # but it never unmounts the root filesystem itself
# shit
status()
{ action $"Syncing ZFS filesystems: " sync
[ ! -f $LOCKFILE ] && return 3 # about the only thing we can do, and then we
# hope that the umount process will succeed
$ZPOOL status && echo && $ZPOOL list # unfortunately the umount process does not dismount
# the root file system, there ought to be some way
# we can tell zfs to just flush anything in memory
# when a request to remount,ro comes in
#echo -n $"Unmounting ZFS filesystems: "
#$ZFS umount -a
#RETVAL=$?
#if [ $RETVAL -ne 0 ]; then
# failure
# return 8
#fi
#success
rm -f "$LOCKFILE"
} }
# See how we are called
case "$1" in case "$1" in
start) start)
start start
@ -99,21 +223,24 @@ case "$1" in
RETVAL=$? RETVAL=$?
;; ;;
status) status)
status lsmod | grep -q zfs || RETVAL=3
RETVAL=$? $ZPOOL status && echo && $ZFS list || {
[ -f "$LOCKFILE" ] && RETVAL=2 || RETVAL=4
}
;; ;;
restart) restart)
stop stop
start start
;; ;;
condrestart) condrestart)
if [ -f $LOCKFILE ]; then if [ -f "$LOCKFILE" ] ; then
stop stop
start start
fi fi
;; ;;
*) *)
echo $"Usage: $0 {start|stop|status|restart|condrestart}" echo $"Usage: $0 {start|stop|status|restart|condrestart}"
RETVAL=3
;; ;;
esac esac