mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-28 03:49:38 +03:00
33df62d052
This change modifies the import service to use the default cache file to perform a verbatim import of pools at boot. This fixes code that searches all devices and imported all visible pools. Using the cache file is in keeping with the way ZFS has always worked, how Solaris, Illumos, FreeBSD, and systemd performs imports, and is how it is written in the man page (zpool(1M,8)): All pools in this cache are automatically imported when the system boots. Importantly, the cache contains important information for importing multipath devices, and helps control which pools get imported in more dynamic environments like SANs, which may have thousands of visible and constantly changing pools, which the ZFS_POOL_EXCEPTIONS variable is not equipped to handle. Verbatim imports prevent rogue pools from being automatically imported and mounted where they shouldn't be. The change also stops the service from exporting pools at shutdown. Exporting pools is only meant to be performed explicitly by the administrator of the system. The old behavior of searching and importing all visible pools is preserved and can be switched on by heeding the warning and toggling the ZPOOL_IMPORT_ALL_VISIBLE variable in /etc/default/zfs. Signed-off-by: James Lee <jlee@thestaticvoid.com> Signed-off-by: Richard Yao <ryao@gentoo.org> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3777 Closes #3526
340 lines
8.3 KiB
Plaintext
Executable File
340 lines
8.3 KiB
Plaintext
Executable File
#!@SHELL@
|
|
#
|
|
# zfs-import This script will import ZFS pools
|
|
#
|
|
# chkconfig: 2345 01 99
|
|
# description: This script will perform a verbatim import of ZFS pools
|
|
# during system boot.
|
|
# probe: true
|
|
#
|
|
### BEGIN INIT INFO
|
|
# Provides: zfs-import
|
|
# Required-Start: mtab
|
|
# Required-Stop: $local_fs mtab
|
|
# Default-Start: S
|
|
# Default-Stop: 0 1 6
|
|
# X-Start-Before: checkfs
|
|
# X-Stop-After: zfs-mount
|
|
# Short-Description: Import ZFS pools
|
|
# Description: Run the `zpool import` command.
|
|
### END INIT INFO
|
|
#
|
|
# NOTE: Not having '$local_fs' on Required-Start but only on Required-Stop
|
|
# is on purpose. If we have '$local_fs' in both (and X-Start-Before=checkfs)
|
|
# we get conflicts - import needs to be started extremely early,
|
|
# but not stopped too late.
|
|
#
|
|
# Released under the 2-clause BSD license.
|
|
#
|
|
# The original script that acted as a template for this script came from
|
|
# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
|
|
# licensing stansa) in the commit dated Mar 24, 2011:
|
|
# https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
|
|
|
|
# Source the common init script
|
|
. @sysconfdir@/zfs/zfs-functions
|
|
|
|
# ----------------------------------------------------
|
|
|
|
do_depend()
|
|
{
|
|
after sysfs udev
|
|
keyword -lxc -openvz -prefix -vserver
|
|
}
|
|
|
|
# Use the zpool cache file to import pools
|
|
do_verbatim_import()
|
|
{
|
|
if [ -f "$ZPOOL_CACHE" ]
|
|
then
|
|
zfs_action "Importing ZFS pool(s)" \
|
|
"$ZPOOL" import -c "$ZPOOL_CACHE" -N -a
|
|
fi
|
|
}
|
|
|
|
# Support function to get a list of all pools, separated with ';'
|
|
find_pools()
|
|
{
|
|
local CMD="$*"
|
|
local pools
|
|
|
|
pools=$($CMD 2> /dev/null | \
|
|
grep -E "pool:|^[a-zA-Z0-9]" | \
|
|
sed 's@.*: @@' | \
|
|
sort | \
|
|
while read pool; do \
|
|
echo -n "$pool;"
|
|
done)
|
|
|
|
echo "${pools%%;}" # Return without the last ';'.
|
|
}
|
|
|
|
# Find and import all visible pools, even exported ones
|
|
do_import_all_visible()
|
|
{
|
|
local already_imported available_pools pool npools
|
|
local exception dir ZPOOL_IMPORT_PATH RET=0 r=1
|
|
|
|
# In case not shutdown cleanly.
|
|
[ -n "$init" ] && rm -f /etc/dfs/sharetab
|
|
|
|
# Just simplify code later on.
|
|
if [ -n "$USE_DISK_BY_ID" -a "$USE_DISK_BY_ID" != 'yes' ]
|
|
then
|
|
# It's something, but not 'yes' so it's no good to us.
|
|
unset USE_DISK_BY_ID
|
|
fi
|
|
|
|
# Find list of already imported pools.
|
|
already_imported=$(find_pools "$ZPOOL" list -H -oname)
|
|
available_pools=$(find_pools "$ZPOOL" import)
|
|
|
|
# Just in case - seen it happen (that a pool isn't visable/found
|
|
# with a simple "zpool import" but only when using the "-d"
|
|
# option or setting ZPOOL_IMPORT_PATH).
|
|
if [ -d "/dev/disk/by-id" ]
|
|
then
|
|
npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id)
|
|
if [ -n "$npools" ]
|
|
then
|
|
# Because we have found extra pool(s) here, which wasn't
|
|
# found 'normaly', we need to force USE_DISK_BY_ID to
|
|
# make sure we're able to actually import it/them later.
|
|
USE_DISK_BY_ID='yes'
|
|
|
|
if [ -n "$available_pools" ]
|
|
then
|
|
# Filter out duplicates (pools found with the simpl
|
|
# "zpool import" but which is also found with the
|
|
# "zpool import -d ...").
|
|
npools=$(echo "$npools" | sed "s,$available_pools,,")
|
|
|
|
# Add the list to the existing list of
|
|
# available pools
|
|
available_pools="$available_pools;$npools"
|
|
else
|
|
available_pools="$npools"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Filter out any exceptions...
|
|
if [ -n "$ZFS_POOL_EXCEPTIONS" ]
|
|
then
|
|
local found=""
|
|
local apools=""
|
|
OLD_IFS="$IFS" ; IFS=";"
|
|
|
|
for pool in $available_pools
|
|
do
|
|
for exception in $ZFS_POOL_EXCEPTIONS
|
|
do
|
|
[ "$pool" = "$exception" ] && continue 2
|
|
found="$pool"
|
|
done
|
|
|
|
if [ -n "$found" ]
|
|
then
|
|
if [ -n "$apools" ]
|
|
then
|
|
apools="$apools;$pool"
|
|
else
|
|
apools="$pool"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
IFS="$OLD_IFS"
|
|
available_pools="$apools"
|
|
fi
|
|
|
|
# For backwards compability, make sure that ZPOOL_IMPORT_PATH is set
|
|
# to something we can use later with the real import(s). We want to
|
|
# make sure we find all by* dirs, BUT by-vdev should be first (if it
|
|
# exists).
|
|
if [ -n "$USE_DISK_BY_ID" -a -z "$ZPOOL_IMPORT_PATH" ]
|
|
then
|
|
local dirs
|
|
dirs="$(for dir in $(echo /dev/disk/by-*)
|
|
do
|
|
# Ignore by-vdev here - we wan't it first!
|
|
echo "$dir" | grep -q /by-vdev && continue
|
|
[ ! -d "$dir" ] && continue
|
|
|
|
echo -n "$dir:"
|
|
done | sed 's,:$,,g')"
|
|
|
|
if [ -d "/dev/disk/by-vdev" ]
|
|
then
|
|
# Add by-vdev at the beginning.
|
|
ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:"
|
|
fi
|
|
|
|
# Help with getting LUKS partitions etc imported.
|
|
if [ -d "/dev/mapper" ]; then
|
|
if [ -n "$ZPOOL_IMPORT_PATH" ]; then
|
|
ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH:/dev/mapper:"
|
|
else
|
|
ZPOOL_IMPORT_PATH="/dev/mapper:"
|
|
fi
|
|
fi
|
|
|
|
# ... and /dev at the very end, just for good measure.
|
|
ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev"
|
|
fi
|
|
|
|
# Needs to be exported for "zpool" to catch it.
|
|
[ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH
|
|
|
|
# Mount all availible pools (except those set in ZFS_POOL_EXCEPTIONS.
|
|
#
|
|
# If not interactive (run from init - variable init='/sbin/init')
|
|
# we get ONE line for all pools being imported, with just a dot
|
|
# as status for each pool.
|
|
# Example: Importing ZFS pool(s)... [OK]
|
|
#
|
|
# If it IS interactive (started from the shell manually), then we
|
|
# get one line per pool importing.
|
|
# Example: Importing ZFS pool pool1 [OK]
|
|
# Importing ZFS pool pool2 [OK]
|
|
# [etc]
|
|
[ -n "$init" ] && zfs_log_begin_msg "Importing ZFS pool(s)"
|
|
OLD_IFS="$IFS" ; IFS=";"
|
|
for pool in $available_pools
|
|
do
|
|
[ -z "$pool" ] && continue
|
|
|
|
# We have pools that haven't been imported - import them
|
|
if [ -n "$init" ]
|
|
then
|
|
# Not interactive - a dot for each pool.
|
|
# Except on Gentoo where this doesn't work.
|
|
zfs_log_progress_msg "."
|
|
else
|
|
# Interactive - one 'Importing ...' line per pool
|
|
zfs_log_begin_msg "Importing ZFS pool $pool"
|
|
fi
|
|
|
|
# Import by using ZPOOL_IMPORT_PATH (either set above or in
|
|
# the config file) _or_ with the 'built in' default search
|
|
# paths. This is the prefered way.
|
|
"$ZPOOL" import -N ${ZPOOL_IMPORT_OPTS} "$pool" 2> /dev/null
|
|
r="$?" ; RET=$((RET + r))
|
|
if [ "$r" -eq 0 ]
|
|
then
|
|
# Output success and process the next pool
|
|
[ -z "$init" ] && zfs_log_end_msg 0
|
|
continue
|
|
fi
|
|
# We don't want a fail msg here, we're going to try import
|
|
# using the cache file soon and that might succeed.
|
|
[ ! -f "$ZPOOL_CACHE" ] && zfs_log_end_msg "$RET"
|
|
|
|
if [ "$r" -gt 0 -a -f "$ZPOOL_CACHE" ]
|
|
then
|
|
# Failed to import without a cache file. Try WITH...
|
|
if [ -z "$init" ] && check_boolean "$VERBOSE_MOUNT"
|
|
then
|
|
# Interactive + Verbose = more information
|
|
zfs_log_progress_msg " using cache file"
|
|
fi
|
|
|
|
"$ZPOOL" import -c "$ZPOOL_CACHE" -N ${ZPOOL_IMPORT_OPTS} \
|
|
"$pool" 2> /dev/null
|
|
r="$?" ; RET=$((RET + r))
|
|
if [ "$r" -eq 0 ]
|
|
then
|
|
[ -z "$init" ] && zfs_log_end_msg 0
|
|
continue 3 # Next pool
|
|
fi
|
|
zfs_log_end_msg "$RET"
|
|
fi
|
|
done
|
|
[ -n "$init" ] && zfs_log_end_msg "$RET"
|
|
|
|
IFS="$OLD_IFS"
|
|
[ -n "$already_imported" -a -z "$available_pools" ] && return 0
|
|
|
|
return "$RET"
|
|
}
|
|
|
|
do_import()
|
|
{
|
|
if check_boolean "$ZPOOL_IMPORT_ALL_VISIBLE"
|
|
then
|
|
do_import_all_visible
|
|
else
|
|
# This is the default option
|
|
do_verbatim_import
|
|
fi
|
|
}
|
|
|
|
# Output the status and list of pools
|
|
do_status()
|
|
{
|
|
check_module_loaded "zfs" || exit 0
|
|
|
|
"$ZPOOL" status && echo "" && "$ZPOOL" list
|
|
}
|
|
|
|
do_start()
|
|
{
|
|
if check_boolean "$VERBOSE_MOUNT"
|
|
then
|
|
zfs_log_begin_msg "Checking if ZFS userspace tools present"
|
|
fi
|
|
|
|
if checksystem
|
|
then
|
|
check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
|
|
|
|
check_boolean "$VERBOSE_MOUNT" && \
|
|
zfs_log_begin_msg "Loading kernel ZFS infrastructure"
|
|
|
|
if ! load_module "zfs"
|
|
then
|
|
check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 1
|
|
return 5
|
|
fi
|
|
check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
|
|
|
|
do_import && udev_trigger # just to make sure we get zvols.
|
|
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ----------------------------------------------------
|
|
|
|
if [ ! -e /etc/gentoo-release ]
|
|
then
|
|
case "$1" in
|
|
start)
|
|
do_start
|
|
;;
|
|
stop)
|
|
# no-op
|
|
;;
|
|
status)
|
|
do_status
|
|
;;
|
|
force-reload|condrestart|reload|restart)
|
|
# no-op
|
|
;;
|
|
*)
|
|
[ -n "$1" ] && echo "Error: Unknown command $1."
|
|
echo "Usage: $0 {start|status}"
|
|
exit 3
|
|
;;
|
|
esac
|
|
|
|
exit $?
|
|
else
|
|
# Create wrapper functions since Gentoo don't use the case part.
|
|
depend() { do_depend; }
|
|
start() { do_start; }
|
|
status() { do_status; }
|
|
fi
|