To prevent this, I've composed short script, which handles NFS unmounting before shutdown.
In general, this script has to be called before poweroff or reboot. It needs to be executed with root rights, so either you can execute it as root or you can add entry to sudoers.
Short description:
First step is to get all nfs mounted filesystems from mount command. Then it tries to unmount them, if it fails
fuser command is used to get PIDs of processes holding this mount point and ask then to end, following with kill if necessary. In the end it stops php-fpm service.
#!/bin/bash
################
# krisko 2014
# Simple script to umount all nfs mounts and stop php-fpm
# this should be used before system shutdown/reboot, because of hanging nfs mounts
#
# it needs sudoers entry with NOPASSWD for user krisko (i3 is running under krisko)
################
# set default values
EXIT=0
# end process and umount
endproc(){
PID=$1
MOUNT=$2
NAME=$(cat /proc/$PID/status | grep "Name:" | awk '{print $2}')
# send SIGTERM and wait for proccess to end
echo INFO: asking to quit $NAME, PID: $PID
kill -15 $PID && sleep 1
# if the process is still running, send SIGKILL
if [ -d /proc/$PID ]; then
echo INFO: killing $NAME, PID: $PID
kill -9 $PID && sleep 0.5
# if it is still here, show error and set exit status to 1
if [ -d /proc/$PID ]; then
echo ERROR: $NAME, PID: $PID still running...
EXIT=1
else
echo -n "INFO: umounting \"$MOUNT\"... "
if [ $(umount $MOUNT 1>/dev/null 2>&1; echo $?) -eq 0 ]; then
echo DONE
else
echo FAILED
EXIT=1
fi
fi
else
echo -n "INFO: umounting \"$MOUNT\"... "
if [ $(umount $MOUNT 1>/dev/null 2>&1; echo $?) -eq 0 ]; then
echo DONE
else
echo FAILED
EXIT=1
fi
fi
}
# do the umounting...
nfsumount(){
# get process numbers holding for mountpoint
MOUNT=$1
PIDs=$(fuser $MOUNT 2>/dev/null | cut -d: -f2)
# if fuser does not find blocking process, try lsof
if [ -z "$PIDs" ]; then
echo INFO: no blocking process found, trying lsof...
PIDs=$(lsof $MOUNT 2>/dev/null | awk '{print $2}' | grep -v PID)
fi
# if there is some process blocking umount, end it
if [ ! -z "$PIDs" ]; then
for PID in $PIDs; do
endproc $PID $MOUNT;
done
else
echo ERROR: no blocking process found...
EXIT=1
fi
}
phpstop(){
#stop php-fpm
if [ $(pgrep -c php-fpm) -gt 0 ]; then
echo INFO: stopping php-fpm
systemctl stop php-fpm
else
echo INFO: php-fpm not running
fi
}
# # # # # # #
# BEGINNING #
# # # # # # #
#we need to have privileges
if [ "$UID" != 0 ]; then
exec sudo $0
fi
# get all nfs mounts
MOUNTS=$(\mount | grep "type nfs" | awk '{print $3}')
echo HINT: Use -f option if NFS server is gone...
if [ x$1 == "x-f" ]; then
if [ ! -z "$MOUNTS" ]; then
echo -n "INFO: umount -f -l $MOUNTS... "
umount -f -l $MOUNTS
phpstop
echo DONE
exit 0
else
echo INFO: no nfs mounts
phpstop
exit 0
fi
fi
if [ ! -z "$MOUNTS" ]; then
for MOUNT in $MOUNTS; do
echo -n "INFO: umounting \"$MOUNT\"... "
if [ $(umount $MOUNT 1>/dev/null 2>&1; echo $?) -eq 0 ]; then
echo DONE
else
echo ENDING PROCESSES...
nfsumount $MOUNT
fi
done
else
echo INFO: no nfs mounts
fi
#stop php-fpm
phpstop
# exit
if [ $EXIT -eq 1 ]; then
exit 1
else
exit 0
fi
##################
# ChangeLog/TODO #
##################
# 1.0.0 20140316 Added changelog/todo section
##################
Krisko thanks script works well here on 5.15.73-1-lts. Had 4 of 6 nfs shares mounted and all umounted fine and quick. Non expert or professional here - just personal use.
ReplyDelete