From a1f57b8cad0717090eb12014d7847a35bd0563a3 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 31 Oct 2016 21:43:47 +0000 Subject: [PATCH] lib: common-functions: Fix tmpfs umounting It has been observed that some chroot operations spawn additional processes which rely on chroot files. More specifically, zypper, uses gpg-agent to import and validate gpg keys for its repositories. This gpg-agent process may stay alive for longer which prevents unmounting of the tmpfs directory since the gpg-agent process still uses libraries etc which were present in the chroot. We try to solve this by using walking all the pids in /proc to find out the running processes in the chroot and kill them gracefully. If that fails for whatever reason, then we simply keep trying to umount the tmpfs directory before we give up. The gpg-agent process usually terminates soon after its home directory disappears but on fast systems we can reach the 'umount tmpfs' point before gpg-agent terminates by itself. The solution is generic enough so other 'chroot processes' can also be handled appropriately. Change-Id: Iccf332678c79266113e76f062884fc5ee79e515d --- lib/common-functions | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/common-functions b/lib/common-functions index 25452586..92c42f88 100644 --- a/lib/common-functions +++ b/lib/common-functions @@ -134,21 +134,48 @@ function eval_run_d () { trap - ERR } +function kill_chroot_processes () { + if [ -z "${1}" ]; then + echo "ERROR: no chroot directory specified" + exit 1 + fi + for piddir in /proc/[0-9]*; do + pid=${piddir##/proc/} + pidname=$(cat $piddir/comm 2>/dev/null || echo "unknown") + # If there are open files from the chroot, just kill the process using + # these files. + if sudo readlink -f $piddir/root | grep -q $TMP_BUILD_DIR; then + echo "Killing chroot process: '${pidname}($pid)'" + sudo kill $pid + fi + done +} + function cleanup_build_dir () { if ! timeout 5 sh -c " while ! sudo rm -rf $TMP_BUILD_DIR/built; do sleep 1; done"; then echo "ERROR: unable to cleanly remove $TMP_BUILD_DIR/built" exit 1 fi sudo rm -rf $TMP_BUILD_DIR/mnt + kill_chroot_processes $TMP_BUILD_DIR if tmpfs_check 0; then - sudo umount -f $TMP_BUILD_DIR || true + # If kill_chroot_processes did not succeed then we have to wait for + # init to reap the orphaned chroot processes + if ! timeout 120 sh -c "while ! sudo umount -f $TMP_BUILD_DIR; do sleep 1; done"; then + echo "ERROR: failed to umount the $TMP_BUILD_DIR tmpfs mount point" + exit 1 + fi fi rm -rf --one-file-system $TMP_BUILD_DIR } function cleanup_image_dir () { + kill_chroot_processes $TMP_IMAGE_DIR if tmpfs_check 0; then - sudo umount -f $TMP_IMAGE_DIR || true + if ! timeout 120 sh -c "while ! sudo umount -f $TMP_IMAGE_DIR; do sleep 1; done"; then + echo "ERROR: failed to umount the $TMP_IMAGE_DIR tmpfs mount point" + exit 1 + fi fi rm -rf --one-file-system $TMP_IMAGE_DIR }