initrd.scripts: refactor setup_real_root and rootdev_init functions

These two functions were a real mess, and the cure is painful.
${REAL_ROOT} setup code and ${REAL_ROOT} init code are now cleaner
and easier to read. ZFS support should have been preserved but
I may have caused new regressions. These changes should be tested.
master
Fabio Erculiani 12 years ago
parent fb3073c7a9
commit 5f9050e1a6

@ -0,0 +1,48 @@
#!/bin/sh
. /etc/initrd.d/00-common.sh
find_real_device() {
local device="${1}"
local out=
case "${device}" in
UUID=*|LABEL=*)
local real_device=""
local retval=1
if [ "${retval}" -ne 0 ]; then
real_device=$(findfs "${device}" 2>/dev/null)
retval=$?
fi
if [ "$retval" -ne 0 ]; then
real_device=$(busybox findfs "${device}" 2>/dev/null)
retval=$?
fi
if [ "${retval}" -ne 0 ]; then
real_device=$(blkid -o device -l -t "${device}")
retval=$?
fi
if [ "${retval}" -eq 0 ] && [ -n "${real_device}" ]; then
out="${real_device}"
fi
;;
*)
out="${device}"
;;
esac
echo -n "${out}"
}
get_device_fstype() {
local device=$(find_real_device "${1}")
if [ -n "${device}" ]; then
blkid -o value -s TYPE "${device}"
return ${?} # readability
else
bad_msg "Cannot resolve device: ${1}"
return 1
fi
}

@ -1,12 +1,45 @@
#!/bin/sh
. /etc/initrd.d/00-common.sh
. /etc/initrd.d/00-fsdev.sh
is_zfs() {
_is_zfs() {
# Note: this only works after zfs_real_root_init
# (thus, only after real_root_init)
[ "${USE_ZFS}" = "1" ] && return 0
return 1
}
is_zfs_fstype() {
local fstype="${1}"
[ "${fstype}" = "zfs_member" ] && return 0
return 1
}
zfs_real_root_init() {
case "${REAL_ROOT}" in
ZFS=*)
ZFS_POOL=${REAL_ROOT#*=}
ZFS_POOL=${ZFS_POOL%%/*}
USE_ZFS=1
;;
ZFS)
USE_ZFS=1
;;
esac
# Verify that zfs support has been compiled in
if [ "USE_ZFS" = "1" ]; then
for i in /sbin/zfs /sbin/zpool; do
if [ ! -x "${i}" ]; then
USE_ZFS=0
bad_msg 'Aborting use of zfs because ${i} not found!'
break
fi
done
fi
}
# This helper function is to be called using _call_func_timeout. This
# works around the inability of busybox modprobe to handle complex
# module dependencies. This also enables us to wait a reasonable
@ -29,35 +62,10 @@ _call_func_timeout() {
return 0
}
zfs_init() {
# Set variables based on the value of REAL_ROOT
case "${REAL_ROOT}" in
ZFS=*)
ZFS_POOL=${REAL_ROOT#*=}
ZFS_POOL=${ZFS_POOL%%/*}
USE_ZFS=1
;;
ZFS)
USE_ZFS=1
;;
esac
# Verify that it is safe to use ZFS
if [ "USE_ZFS" = "1" ]
then
for i in /sbin/zfs /sbin/zpool
do
if [ ! -x ${i} ]
then
USE_ZFS=0
bad_msg 'Aborting use of zfs because ${i} not found!'
break
fi
done
fi
}
zfs_start_volumes() {
# is ZFS enabled?
_is_zfs || return 0
# Avoid race involving asynchronous module loading
if _call_func_timeout wait_for_zfs 5; then
bad_msg "Cannot import ZFS pool because /dev/zfs is missing"
@ -65,7 +73,7 @@ zfs_start_volumes() {
elif [ -z "${ZFS_POOL}" ]; then
good_msg "Importing ZFS pools"
/sbin/zpool import -N -a ${ZPOOL_FORCE}
zpool import -N -a ${ZPOOL_FORCE}
if [ "${?}" = "0" ]; then
good_msg "Importing ZFS pools succeeded"
else
@ -79,12 +87,12 @@ zfs_start_volumes() {
if [ -n "${CRYPT_ROOT}" ] || [ -n "${CRYPT_SWAP}" ]; then
good_msg "LUKS detected. Reimporting ${ZFS_POOL}"
/sbin/zpool export -f "${ZFS_POOL}"
/sbin/zpool import -N ${ZPOOL_FORCE} "${ZFS_POOL}"
zpool export -f "${ZFS_POOL}"
zpool import -N ${ZPOOL_FORCE} "${ZFS_POOL}"
fi
else
good_msg "Importing ZFS pool ${ZFS_POOL}"
/sbin/zpool import -N ${ZPOOL_FORCE} "${ZFS_POOL}"
zpool import -N ${ZPOOL_FORCE} "${ZFS_POOL}"
if [ "${?}" = "0" ]; then
good_msg "Import of ${ZFS_POOL} succeeded"
@ -93,4 +101,44 @@ zfs_start_volumes() {
fi
fi
fi
}
}
# Initialize the zfs root filesystem device and
# tweak ${REAL_ROOT}. In addition, set ${ZFS_POOL}
# for later use.
# Return 0 if initialization is successful.
zfs_rootdev_init() {
local root_dev="${REAL_ROOT#*=}"
ZFS_POOL="${root_dev%%/*}"
if [ "${root_dev}" != "ZFS" ]; then
local ztype=$(zfs get type -o value -H "${root_dev}")
if [ "${ztype}" = "filesystem" ]; then
REAL_ROOT="${root_dev}"
good_msg "Detected zfs root: ${REAL_ROOT}"
return 0
else
bad_msg "${root_dev} is not a zfs filesystem"
return 1
fi
fi
local bootfs=$(zpool list -H -o bootfs)
[ "${bootfs}" = "-" ] && return 1
for i in ${bootfs}; do
if zfs get type "${i}" > /dev/null; then
REAL_ROOT="${i}"
good_msg "Detected zfs bootfs root: ${REAL_ROOT}"
return 0
fi
done
return 1
}
zfs_get_real_root_mount_flags() {
local flags=rw,zfsutil
local zmtype=$(zfs get -H -o value mountpoint "${REAL_ROOT}")
[ "${zmtype}" = "legacy" ] && flags=rw
echo "${flags}"
}

@ -3,6 +3,7 @@
. /etc/initrd.defaults
. /etc/initrd.d/00-splash.sh
. /etc/initrd.d/00-common.sh
. /etc/initrd.d/00-fsdev.sh
. /etc/initrd.d/00-devmgr.sh
. /etc/initrd.d/00-zfs.sh
@ -84,16 +85,19 @@ uppercase() {
echo ${1} | tr 'a-z' 'A-Z'
}
setup_real_root() {
if [ -z "${REAL_ROOT}" -a "${FAKE_ROOT}" != "/dev/ram0" ]; then
real_root_init() {
if [ -z "${REAL_ROOT}" ] && [ "${FAKE_ROOT}" != "/dev/ram0" ]; then
REAL_ROOT="${FAKE_ROOT}"
fi
if [ -z "${REAL_INIT}" -a "${FAKE_INIT}" != "/linuxrc" ]; then
if [ -z "${REAL_INIT}" ] && [ "${FAKE_INIT}" != "/linuxrc" ]; then
REAL_INIT="${FAKE_INIT}"
fi
if [ -z "${REAL_ROOTFLAGS}" ]; then
REAL_ROOTFLAGS="${FAKE_ROOTFLAGS}"
fi
# let zfs code setup its parameters
zfs_real_root_init
}
findmediamount() {
@ -342,51 +346,6 @@ find_nfs() {
fi
}
find_real_device() {
local device="${1}"
local out=
case "${device}" in
UUID=*|LABEL=*)
local REAL_DEVICE=""
local retval=1
if [ "${retval}" -ne 0 ]; then
REAL_DEVICE=$(findfs "${device}" 2>/dev/null)
retval=$?
fi
if [ "$retval" -ne 0 ]; then
REAL_DEVICE=$(busybox findfs "${device}" 2>/dev/null)
retval=$?
fi
if [ "${retval}" -ne 0 ]; then
REAL_DEVICE=$(blkid -o device -l -t "${device}")
retval=$?
fi
if [ "${retval}" -eq 0 ] && [ -n "${REAL_DEVICE}" ]; then
out="${REAL_DEVICE}"
fi
;;
*)
out="${device}"
;;
esac
echo -n "${out}"
}
get_device_fstype() {
local device=$(find_real_device "${1}")
if [ -n "${device}" ]; then
blkid -o value -s TYPE "${device}"
return ${?} # readability
else
echo "Cannot resolve device: ${1}" >&2
return 1
fi
}
check_loop() {
if [ -z "${LOOP}" ] || [ ! -e "${CDROOT_PATH}/${LOOP}" ]; then
bad_msg "Invalid loop location: ${LOOP}"
@ -772,7 +731,8 @@ start_volumes() {
fi
fi
is_zfs && zfs_start_volumes
# If zfs is enabled, this will initialize the volumes
zfs_start_volumes
is_udev && udevadm settle
}
@ -1549,97 +1509,92 @@ fstype_init() {
fi
}
rootdev_init() {
good_msg "Initializing root device..."
_rootdev_detect() {
local got_good_root=0
while [ "${got_good_root}" != "1" ]; do
while true
do
local got_good_root=
while [ "${got_good_root}" != "1" ]; do
case "${REAL_ROOT}" in
LABEL=*|UUID=*)
local root_dev=$(find_real_device "${REAL_ROOT}")
if [ -n "${root_dev}" ]; then
REAL_ROOT="${root_dev}"
good_msg "Detected root: ${REAL_ROOT}"
else
bad_msg "Unable to resolve root: ${REAL_ROOT}"
case "${REAL_ROOT}" in
LABEL=*|UUID=*)
got_good_root=0
prompt_user "REAL_ROOT" "root block device"
continue
fi
;;
local root_dev=$(find_real_device "${REAL_ROOT}")
if [ -n "${root_dev}" ]; then
REAL_ROOT="${root_dev}"
good_msg "Detected root: ${REAL_ROOT}"
else
bad_msg "Unable to resolve root: ${REAL_ROOT}"
prompt_user "REAL_ROOT" "root block device"
got_good_root=0
continue
fi
;;
# move this cruft into a separate function? do we really need
# the crazy root=ZFS= thing? can't we just detect the fstype?
ZFS*)
if [ "${USE_ZFS}" = "0" ]; then
prompt_user "REAL_ROOT" "root block device"
continue
fi
ZFS*)
# zfs_rootdev_init will tweak ${REAL_ROOT}
zfs_rootdev_init
if [ "${?}" = "0" ]; then
got_good_root=1
else
got_good_root=0
prompt_user "REAL_ROOT" "root block device"
continue
fi
;;
esac
ROOT_DEV="${REAL_ROOT#*=}"
if [ "${ROOT_DEV}" != "ZFS" ]; then
local ztype=$(zfs get type -o value -H "${ROOT_DEV}")
if [ "${ztype}" = "filesystem" ]; then
got_good_root=1;
REAL_ROOT=${ROOT_DEV}
ROOTFSTYPE=zfs
else
bad_msg "${ROOT_DEV} is not a filesystem"
prompt_user "REAL_ROOT" "root block device"
got_good_root=0
continue
fi
else
BOOTFS=$(/sbin/zpool list -H -o bootfs)
if [ "${BOOTFS}" != "-" ]; then
if [ -z "${REAL_ROOT}" ]; then
# No REAL_ROOT determined/specified.
# Prompt user for root block device.
prompt_user "REAL_ROOT" "root block device"
got_good_root=0
for i in ${BOOTFS}; do
zfs get type ${i} > /dev/null
retval=$?
# Check for a block device or NFS
elif [ -b "${REAL_ROOT}" ] || is_nfs; then
got_good_root=1
else
bad_msg "${REAL_ROOT} is an invalid root device..."
REAL_ROOT=""
got_good_root=0
fi
done
if [ ${retval} -eq 0 ]; then
got_good_root=1
REAL_ROOT=${i}
ROOTFSTYPE=zfs
break
fi
done
else
got_good_root=0
fi
return 0
}
fi
_rootdev_mount() {
local mount_opts=ro
local mount_fstype="${ROOTFSTYPE}"
local fstype=$(get_device_fstype "${REAL_ROOT}")
if is_zfs_fstype "${fstype}"; then
mount_fstype=zfs
mount_opts=$(zfs_get_real_root_mount_flags)
fi
if [ ${got_good_root} -ne 1 ]; then
prompt_user "REAL_ROOT" "root block device"
got_good_root=0
fi
continue
;;
esac
if [ -z "${REAL_ROOT}" ]; then
# No REAL_ROOT determined/specified.
# Prompt user for root block device.
prompt_user "REAL_ROOT" "root block device"
got_good_root=0
# Check for a block device or NFS
elif [ -b "${REAL_ROOT}" ] || is_nfs; then
got_good_root=1
else
bad_msg "${REAL_ROOT} is an invalid root device..."
REAL_ROOT=""
got_good_root=0
fi
done
good_msg "Detected fstype: ${fstype}"
good_msg "Using mount fstype: ${mount_fstype}"
fstype_init "${fstype}"
local mopts="${mount_opts}"
[ -n "${REAL_ROOTFLAGS}" ] && \
mopts="${mopts},${REAL_ROOTFLAGS}"
good_msg "Using mount opts: -o ${mopts}"
if [ "${got_good_root}" = "1" ] && is_livecd && ! is_nfs; then
mount -t "${mount_fstype}" -o "${mopts}" \
"${REAL_ROOT}" "${NEW_ROOT}" || return 1
return 0
}
rootdev_init() {
good_msg "Initializing root device..."
while true; do
if ! _rootdev_detect; then
bad_msg "Could not mount specified ROOT, try again"
prompt_user "REAL_ROOT" "root block device"
continue
fi
if is_livecd && ! is_nfs; then
# CD already mounted; no further checks necessary
break
fi
@ -1649,37 +1604,13 @@ rootdev_init() {
break
fi
local fstype=$(get_device_fstype "${REAL_ROOT}")
good_msg "Initializing ${REAL_ROOT} if needed"
good_msg "Detected fstype: ${fstype}"
fstype_init "${fstype}"
good_msg "Mounting ${REAL_ROOT} as root..."
local mount_state=ro
# TODO(lxnay): determine if it's possible to move this
# crufty thing into fstype_init
if [ "${ROOTFSTYPE}" = "zfs" ]; then
local zmtype=$(zfs get -H -o value mountpoint "${REAL_ROOT}")
if [ "${zmtype}" = "legacy" ]; then
mount_state=rw
else
mount_state=rw,zfsutil
fi
fi
# Try to mount the device as ${NEW_ROOT}
if is_nfs; then
find_nfs # sets ${?} checked below
else
# mount ro so fsck doesn't barf later
local mopts="${mount_state}"
[ -n "${REAL_ROOTFLAGS}" ] && \
mopts="${mopts},${REAL_ROOTFLAGS}"
good_msg "Using mount -t ${ROOTFSTYPE} -o ${mopts}"
mount -t "${ROOTFSTYPE}" -o "${mopts}" \
"${REAL_ROOT}" "${NEW_ROOT}"
_rootdev_mount # sets ${?} checked below
fi
# If mount is successful break out of the loop
@ -1713,7 +1644,6 @@ rootdev_init() {
break
else
bad_msg "Could not mount specified ROOT, try again"
got_good_root=0
REAL_ROOT=''
fi
done

@ -97,10 +97,9 @@ for x in ${CMDLINE}; do
good_msg "Booting with multipath activated."
USE_MULTIPATH_NORMAL=1
;;
dozfs*)
USE_ZFS=1
if [ "${x#*=}" = "force" ]; then
dozfs=*)
ZFS_OPTS=${x#*=}
if [ "${ZFS_OPTS}" = "force" ]; then
ZPOOL_FORCE=-f
fi
;;
@ -241,9 +240,7 @@ done
quiet_kmsg
is_livecd || setup_real_root
zfs_init
is_livecd || real_root_init
cmdline_hwopts

Loading…
Cancel
Save