diff --git a/defaults/initrd.d/00-fsdev.sh b/defaults/initrd.d/00-fsdev.sh new file mode 100755 index 0000000..1dd2523 --- /dev/null +++ b/defaults/initrd.d/00-fsdev.sh @@ -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 +} \ No newline at end of file diff --git a/defaults/initrd.d/00-zfs.sh b/defaults/initrd.d/00-zfs.sh index 4d48bbc..3541e58 100755 --- a/defaults/initrd.d/00-zfs.sh +++ b/defaults/initrd.d/00-zfs.sh @@ -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 -} \ No newline at end of file +} + +# 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}" +} diff --git a/defaults/initrd.scripts b/defaults/initrd.scripts index 036421a..8d91d50 100755 --- a/defaults/initrd.scripts +++ b/defaults/initrd.scripts @@ -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 diff --git a/defaults/linuxrc b/defaults/linuxrc index 34585b0..ec14891 100755 --- a/defaults/linuxrc +++ b/defaults/linuxrc @@ -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