129 lines
4.9 KiB
Bash
129 lines
4.9 KiB
Bash
|
#!/usr/bin/env bash
|
||
|
#
|
||
|
# SPDX-License-Identifier: GPL-2.0
|
||
|
#
|
||
|
# Copyright (c) 2013-2023 Igor Pecovnik, igor@armbian.com
|
||
|
#
|
||
|
# This file is a part of the Armbian Build Framework
|
||
|
# https://github.com/armbian/build/
|
||
|
|
||
|
# Call: prepare_tmpfs_for "NAME_OF_TMPFS_DIR" "${PATH_TO_DIR}" # this adds its own cleanup handler
|
||
|
function prepare_tmpfs_for() {
|
||
|
declare tmpfs_name="${1}"
|
||
|
declare tmpfs_path="${2}"
|
||
|
# validate parameters
|
||
|
if [[ -z "${tmpfs_name}" ]]; then
|
||
|
exit_with_error "prepare_tmpfs_for: tmpfs_name (arg 1) is empty"
|
||
|
fi
|
||
|
if [[ -z "${tmpfs_path}" ]]; then
|
||
|
exit_with_error "prepare_tmpfs_for: tmpfs_path (arg 2) is empty"
|
||
|
fi
|
||
|
|
||
|
# params for the handler; initially just repeat our own params
|
||
|
declare -a cleanup_params=("${tmpfs_name}" "${tmpfs_path}")
|
||
|
|
||
|
# create the dir if not exists and note that down for the cleanup handler
|
||
|
if [[ ! -d "${tmpfs_path}" ]]; then
|
||
|
display_alert "prepare_tmpfs_for: creating dir" "${tmpfs_path}" "cleanup"
|
||
|
mkdir -p "${tmpfs_path}"
|
||
|
cleanup_params+=("remove_dir")
|
||
|
else
|
||
|
display_alert "prepare_tmpfs_for: dir exists" "${tmpfs_path}" "cleanup"
|
||
|
cleanup_params+=("no_remove_dir")
|
||
|
fi
|
||
|
|
||
|
# Do nothing if we're not on Linux (detect via OSTYPE) and root. Still, setup the cleanup handler.
|
||
|
if [[ "${OSTYPE}" != "linux"* ]] || [[ "${EUID}" -ne 0 ]]; then
|
||
|
display_alert "prepare_tmpfs_for: not on Linux or not root, skipping" "${tmpfs_name}" "cleanup"
|
||
|
cleanup_params+=("no_umount_tmpfs")
|
||
|
elif [[ "${ARMBIAN_INSIDE_DOCKERFILE_BUILD}" == "yes" ]]; then
|
||
|
display_alert "prepare_tmpfs_for: inside Dockerfile build, skipping" "${tmpfs_name}" "cleanup"
|
||
|
cleanup_params+=("no_umount_tmpfs")
|
||
|
elif [[ "${USE_TMPFS}" == "no" ]]; then
|
||
|
display_alert "prepare_tmpfs_for:" "USE_TMPFS=no, skipping: '${tmpfs_name}'" "warning"
|
||
|
cleanup_params+=("no_umount_tmpfs")
|
||
|
else
|
||
|
display_alert "prepare_tmpfs_for: on Linux and root, MOUNTING TMPFS" "${tmpfs_name}" "cleanup"
|
||
|
# mount tmpfs on it
|
||
|
mount -t tmpfs -o "size=99%" tmpfs "${tmpfs_path}" # size=50% is the Linux default, but we need more.
|
||
|
cleanup_params+=("umount_tmpfs")
|
||
|
|
||
|
#cleanup_params+=("no_umount_tmpfs")
|
||
|
fi
|
||
|
|
||
|
# add the cleanup handler
|
||
|
declare cleanup_handler="cleanup_tmpfs_for ${cleanup_params[*]@Q}"
|
||
|
display_alert "prepare_tmpfs_for: add cleanup handler" "${cleanup_handler}" "cleanup"
|
||
|
add_cleanup_handler "${cleanup_handler}"
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
function cleanup_tmpfs_for() {
|
||
|
declare tmpfs_name="${1}"
|
||
|
declare tmpfs_path="${2}"
|
||
|
declare remove_dir="${3}"
|
||
|
declare umount_tmpfs="${4}"
|
||
|
|
||
|
# validate parameters
|
||
|
if [[ -z "${tmpfs_name}" ]]; then
|
||
|
exit_with_error "cleanup_tmpfs_for: tmpfs_name (arg 1) is empty"
|
||
|
fi
|
||
|
if [[ -z "${tmpfs_path}" ]]; then
|
||
|
exit_with_error "cleanup_tmpfs_for: tmpfs_path (arg 2) is empty"
|
||
|
fi
|
||
|
if [[ -z "${remove_dir}" ]]; then
|
||
|
exit_with_error "cleanup_tmpfs_for: remove_dir (arg 3) is empty"
|
||
|
fi
|
||
|
if [[ -z "${umount_tmpfs}" ]]; then
|
||
|
exit_with_error "cleanup_tmpfs_for: umount_tmpfs (arg 4) is empty"
|
||
|
fi
|
||
|
|
||
|
# umount tmpfs
|
||
|
if [[ "${umount_tmpfs}" == "umount_tmpfs" ]]; then
|
||
|
display_alert "cleanup_tmpfs_for: umount tmpfs" "${tmpfs_name}" "cleanup"
|
||
|
cd "${SRC}" || echo "cleanup_tmpfs_for: cd failed to ${SRC}" >&2 # avoid cwd in use error
|
||
|
wait_for_disk_sync "before tmps cleanup ${tmpfs_name}" # let disk coalesce
|
||
|
umount "${tmpfs_path}" &> /dev/null || {
|
||
|
display_alert "cleanup_tmpfs_for: umount failed" "${tmpfs_name} tmpfs umount failed, will try lazy" "cleanup"
|
||
|
# Do a lazy umount... last-resort...
|
||
|
wait_for_disk_sync "before tmps cleanup ${tmpfs_name} lazy" # let disk coalesce
|
||
|
umount -l "${tmpfs_path}" &> /dev/null || display_alert "cleanup_tmpfs_for: lazy umount failed" "${tmpfs_name} tmpfs lazy umount also failed" "cleanup"
|
||
|
wait_for_disk_sync "after tmps cleanup ${tmpfs_name} lazy" # let disk coalesce
|
||
|
}
|
||
|
|
||
|
# Check if the tmpfs is still mounted after all that trying, log error, show debug, and give up with error
|
||
|
mountpoint -q "${tmpfs_path}" && {
|
||
|
display_alert "cleanup_tmpfs_for: umount failed" "${tmpfs_name} tmpfs still mounted after retries/lazy umount" "err"
|
||
|
# Show last-resort what's in there / what's using it to stderr
|
||
|
ls -la "${tmpfs_path}" >&2 || echo "cleanup_tmpfs_for: ls failed" >&2
|
||
|
lsof "${tmpfs_path}" >&2 || echo "cleanup_tmpfs_for: lsof dir failed" >&2
|
||
|
return 1 # sorry, we tried.
|
||
|
} || {
|
||
|
display_alert "cleanup_tmpfs_for: umount success" "${tmpfs_name}" "cleanup"
|
||
|
}
|
||
|
else
|
||
|
display_alert "cleanup_tmpfs_for: not umounting tmpfs" "${tmpfs_name}" "cleanup"
|
||
|
fi
|
||
|
|
||
|
# remove the dir if we created it
|
||
|
if [[ "${remove_dir}" == "remove_dir" ]]; then
|
||
|
display_alert "cleanup_tmpfs_for: removing dir" "${tmpfs_path}" "cleanup"
|
||
|
rm -rf "${tmpfs_path:?}"
|
||
|
else
|
||
|
display_alert "cleanup_tmpfs_for: not removing dir" "${tmpfs_path}" "cleanup"
|
||
|
fi
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
# Debugging utility.
|
||
|
function debug_tmpfs_show_usage() {
|
||
|
if [[ "${SHOW_TMPFS}" == "yes" ]]; then
|
||
|
display_alert "TMPFS debugging:" "${CURRENT_LOGGING_SECTION:-none} $*" "debug"
|
||
|
run_host_command_logged df -h -t tmpfs "||" true
|
||
|
run_host_command_logged free -m "||" true
|
||
|
fi
|
||
|
return 0
|
||
|
}
|