Hi, With the input of Martin, and following my own suggestions:
On Sat, Oct 28, 2006, Loïc Minier wrote: > On the topic of mounts, I'd like to add: > * a sanity check to popup a shell if a mount point isn't an empty > directory after umount > * reverse order of umounts so that /proc is umounted last > * perhaps a sanity check to grep /proc/mounts for the base path to the > chroot and see if anything mounted remains I completely reworked the patch. A newer version is attached, which I tested in some scenarios already: ----- Unmounting /proc twice: -> unmounting proc filesystem W: Could not unmount proc: umount: /home/lool/.pbuilder/build/sid/cow.2610/proc: not mounted W: Ignored error in unmount ----- Unmounting /etc: -> unmounting etc filesystem W: Could not unmount etc: umount: /home/lool/.pbuilder/build/sid/cow.4574/etc: not mounted W: etc not empty W: Tried ignoring error in unmount, but sanity check failed: etc might still be mounted W: Retrying to unmount etc in 5s ----- Unmounting /etc/passwd: -> unmounting etc/passwd filesystem W: Could not unmount etc/passwd: umount: /home/lool/.pbuilder/build/sid/cow.6381/etc/passwd: not mounted W: etc/passwd isn't a directory W: Tried ignoring error in unmount, but sanity check failed: etc/passwd might still be mounted W: Retrying to unmount etc/passwd in 5s ----- Launching a process with CWD in the filesystem being unmounted: -> unmounting dev/pts filesystem W: Could not unmount dev/pts: umount: /home/lool/.pbuilder/build/sid/cow.8223/dev/pts: device is busy umount: /home/lool/.pbuilder/build/sid/cow.8223/dev/pts: device is busy W: Retrying to unmount dev/pts in 5s umount: /home/lool/.pbuilder/build/sid/cow.8223/dev/pts: device is busy It adds a sanity checking function, seems_truly_unmounted, which goes through great length to fail if there's a slight change that a mountpoint is still mounted. I will commit this patch and change the order of umounts so that bind mounts are unmounted first, and /proc last. Bye, -- Loïc Minier <[EMAIL PROTECTED]>
Index: ChangeLog =================================================================== RCS file: /cvsroot/pbuilder/pbuilder/ChangeLog,v retrieving revision 1.412 diff -u -r1.412 ChangeLog --- ChangeLog 29 Oct 2006 02:16:49 -0000 1.412 +++ ChangeLog 29 Oct 2006 23:44:28 -0000 @@ -1,3 +1,10 @@ +2006-10-29 Loic Minier <[EMAIL PROTECTED]> + + * pbuilder-modules: add sanity checks during umount_one(); ignore + umount errors of the type "umount: /foobar: not mounted" and "umount: + /foobar: not found" as retries will be useless anyway, and these + errors shouldn't cause data loss; fixes #391390. + 2006-10-29 Junichi Uekawa <[EMAIL PROTECTED]> * Documentation/pbuilder-doc.xml: developer info is updated. Index: pbuilder-modules =================================================================== RCS file: /cvsroot/pbuilder/pbuilder/pbuilder-modules,v retrieving revision 1.99 diff -u -r1.99 pbuilder-modules --- pbuilder-modules 24 Aug 2006 22:58:57 -0000 1.99 +++ pbuilder-modules 29 Oct 2006 23:44:28 -0000 @@ -86,6 +86,41 @@ exit 1 } +# test whether a directory is empty +# fails if "$*" exists but isn't a directory +# fails and outputs garbage if "$*" doesn't actually exist +is_empty_dir() { + return "$(find "$*" -maxdepth 0 -type d -empty -printf 0 -o -printf 1)" +} + +# sanity checks to ensure mountpoint $1 is truly unmounted in $BUILDPLACE +# (fails relatively often to ensure we don't "rm -rf" a bind mount) +function seems_truly_unmounted() { + local mountpoint + mountpoint="$1" + if ! [ -e "$BUILDPLACE/$mountpoint" ]; then + echo "W: $mountpoint doesn't exist" + return 1 + fi + if ! [ -d "$BUILDPLACE/$mountpoint" ]; then + echo "W: $mountpoint isn't a directory" + return 1 + fi + if [ -r "$BUILDPLACE/proc/mounts" ] && grep -q "^[^ ]* $mountpoint " "$BUILDPLACE/proc/mounts"; then + echo "W: $mountpoint is mounted according to build place's /proc/mounts" + return 1 + fi + if [ -r "/proc/mounts" ] && grep -q "^[^ ]* $BUILDPLACE/$mountpoint " "/proc/mounts"; then + echo "W: $mountpoint is mounted according to system's /proc/mounts" + return 1 + fi + if ! is_empty_dir "$BUILDPLACE/$mountpoint"; then + echo "W: $mountpoint not empty" + return 1 + fi + return 0 +} + function umount_one () { if [ "${IGNORE_UMOUNT}" = "yes" ]; then # support ignore umount option. @@ -93,24 +128,45 @@ return fi echo " -> unmounting $1 filesystem" - if ! umount "$BUILDPLACE/$1"; then - echo "W: Retrying to unmount $1" + local UMOUNT_OUTPUT + if ! UMOUNT_OUTPUT="$(LC_ALL=C umount "$BUILDPLACE/$1" 2>&1)"; then + echo "W: Could not unmount $1: $UMOUNT_OUTPUT" + local ignore_umount_error="no" + case $UMOUNT_OUTPUT in + "umount: "*": not found"|"umount:"*": not mounted") + # run an additional set of sanity checks + if seems_truly_unmounted "$1"; then + ignore_umount_error="yes" + else + echo "W: Tried ignoring error in unmount, but sanity check failed: $1 might still be mounted" + fi + ;; + *) + ;; + esac + if [ "$ignore_umount_error" != "yes" ]; then + echo "W: Retrying to unmount $1 in 5s" sleep 5s while ! umount "$BUILDPLACE/$1"; do sleep 5s cat <<EOF - Could not unmount $1, there might be some program - still using files in /proc (klogd?). - Please check and kill the process manually so that I can unmount $1 + Could not unmount $1, some programs might + still be using files in /proc (klogd?). + Please check and kill these processes manually + so that I can unmount $1. Last umount error was: +$UMOUNT_OUTPUT - This error is only happens with chroot; try using user-mode-linux to - avoid this message. + This error only affects chroots; you may want to use + user-mode-linux to avoid this message. EOF chroot "$BUILDPLACE" bin/sh done - fi + else + echo "W: Ignored error in unmount" + fi + fi } function umountproc () {