Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
diff sbin/fzfs @ 500:7d498093d4c2
fzfs: Try to unmount filesystems that have been mounted by this tool when an error occurs
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 30 Aug 2024 18:50:12 +0200 |
| parents | 46406503a635 |
| children | 7d08fd78775c |
line wrap: on
line diff
--- a/sbin/fzfs Fri Aug 30 17:29:20 2024 +0200 +++ b/sbin/fzfs Fri Aug 30 18:50:12 2024 +0200 @@ -43,6 +43,7 @@ _p_datadir="$(dirname "$0")"/../share/local-bsdtools . "${_p_datadir}/common.subr" +. "${_p_datadir}/array.sh" # @@ -123,6 +124,14 @@ zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" \ | { + + # + # _mounted_datasets is an array of ZFS datasets that have been + # mounted by this routine and should be unmounted on errors + # -- if possible. + # + array_create _mounted_datasets + while IFS=$'\t' read -r _name _mp _canmount _mounted ; do # Skip filesystems that are already mounted [ "${_mounted}" = "yes" ] && continue @@ -151,8 +160,9 @@ if [ "${_mp}" = "${_rootds_mountpoint}" ]; then if [ "${_name}" != "${_dsname}" ]; then echo "ERROR: child dataset mounts over root dataset" >&2 + _umount_datasets _mounted_datasets || true return 1 - fi + fi _relative_mp="" _real_mp="${_mountpoint}" else @@ -161,6 +171,7 @@ _relative_mp="${_relative_mp%/}" if [ -z "${_relative_mp}" ]; then echo "ERROR: got an empty relative mountpoint in child" >&2 + _umount_datasets _mounted_datasets || true return 1 fi # The real effective full mountpoint @@ -175,6 +186,7 @@ if [ "${_opt_mount_natural}" = "yes" ]; then if [ "${_real_mp}" != "${_mp}" ]; then echo "ERROR: mountpoint mismatch" >&2 + _umount_datasets _mounted_datasets || true return 1 fi fi @@ -183,9 +195,14 @@ echo "Would mount ${_name} on ${_real_mp}" else mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \ - { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; } + { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; _umount_datasets _mounted_datasets || true; return 1; } echo "Mounting ${_name} on ${_real_mp}" - mount -t zfs "${_name}" "${_real_mp}" || return 1 + if mount -t zfs "${_name}" "${_real_mp}"; then + array_append _mounted_datasets "${_name}" + else + _umount_datasets _mounted_datasets || true + return 1 + fi fi ;; *) @@ -194,7 +211,12 @@ echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}" else echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" - zfs mount "${_name}" || return 1 + if zfs mount "${_name}"; then + array_append _mounted_datasets "${_name}" + else + _umount_datasets _mounted_datasets || true + return 1 + fi fi else echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 @@ -202,13 +224,42 @@ ;; esac done - + array_destroy _mounted_datasets return 0 } } #: +#: Helper to unmount mounted ZFS filesystems +#: +#: Args: +#: $1 (str): The name of the array that contains the datasets to unmount to +#: +#: Returns: +#: 0 if successfully unmounted all given datasets, +#: 1 otherwise +#: +#: Unmounting is done in the reverse order. +#: +_umount_datasets() { + array_reversed_for_each "$1" _umount_datasets_umount +} + + +#: +#: Array callback to unmount a single ZFS filesystem +#: +_umount_datasets_umount() { + if ! zfs umount "$3" ; then + warn "Dataset \`${3}' cannot unmounted" + return 1 + fi + return 0 +} + + +#: #: Implement the "umount" command. #: #: Umount a datasets and recursively all its children datasets.
