cluster: STABLE3 - rgmanager: Kill processes correctly w/ force_unmount

Lon Hohberger lon at fedoraproject.org
Tue Apr 20 22:54:29 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=95fdebbfb7c62ac69b63e2b34d30fde9ecea4640
Commit:        95fdebbfb7c62ac69b63e2b34d30fde9ecea4640
Parent:        1343c79c50e8314299756a76d0ba52e2a3921590
Author:        Lon Hohberger <lhh at redhat.com>
AuthorDate:    Wed Apr 14 17:29:54 2010 -0400
Committer:     Lon Hohberger <lhh at redhat.com>
CommitterDate: Tue Apr 20 18:36:46 2010 -0400

rgmanager: Kill processes correctly w/ force_unmount

The killMountProcesses function was written about 10 years ago.
It was designed to work with lsof or fuser, and to log messages
for each process killed.  This is not a bad idea.  The problem
is that parsing the output of either is and error-prone,
particularly when mountpoints are similar to other directories
on the system.

A far less error-prone method to cleaning up a mount point is to
use 'fuser -kvm' on it.  Not only is this less error-prone, it's
a good bit faster at doing its job than iterating through output
in a shell script.

This patch makes force_unmount very reliable at killing the correct
processes, but we lose the logging functionality.  It is a fair
trade-off because there have been several bugs in the
killMountProcesses function over the years which have caused several
problems.

Resolves: bz555901 bz582754

Signed-off-by: Lon Hohberger <lhh at redhat.com>
---
 rgmanager/src/resources/clusterfs.sh |  113 ++----------------------------
 rgmanager/src/resources/fs.sh.in     |  121 ++------------------------------
 rgmanager/src/resources/netfs.sh     |  128 ++++------------------------------
 3 files changed, 23 insertions(+), 339 deletions(-)

diff --git a/rgmanager/src/resources/clusterfs.sh b/rgmanager/src/resources/clusterfs.sh
index 0ccc93d..bb0acfd 100644
--- a/rgmanager/src/resources/clusterfs.sh
+++ b/rgmanager/src/resources/clusterfs.sh
@@ -484,113 +484,6 @@ isAlive()
 
 
 #
-# killMountProcesses device mount_point
-#
-# Using lsof or fuser try to unmount the mount by killing of the processes
-# that might be keeping it busy.
-#
-killMountProcesses()
-{
-	typeset -i ret=$SUCCESS
-	typeset have_lsof=""
-	typeset have_fuser=""
-	typeset try
-
-	if [ $# -ne 1 ]; then
-		ocf_log err \
-			"Usage: killMountProcesses mount_point"
-		return $FAIL
-	fi
-
-	typeset mp=$1
-
-	ocf_log notice "Forcefully unmounting $mp"
-
-	#
-	# Not all distributions have lsof.  If not use fuser.  If it
-	# does, try both.
-  	#
-	file=$(which lsof 2>/dev/null)
-	if [ -f "$file" ]; then
-		have_lsof=$YES
-	fi
-
-	file=$(which fuser 2>/dev/null)
-	if [ -f "$file" ]; then
-		have_fuser=$YES
-	fi             
-
-	if [ -z "$have_lsof" -a -z "$have_fuser" ]; then
-		ocf_log warn \
-	"Cannot forcefully unmount $mp; cannot find lsof or fuser commands"
-		return $FAIL
-	fi
-
-	for try in 1 2 3; do
-		if [ -n "$have_lsof" ]; then
-			#
-			# Use lsof to free up mount point
-			#
-	    		while read command pid user
-			do
-				if [ -z "$pid" ]; then
-					continue
-				fi
-
-				if [ $try -eq 1 ]; then
-					ocf_log warn \
-			 	  "killing process $pid ($user $command $mp)"
-				elif [ $try -eq 3 ]; then
-					ocf_log crit \
-		    		  "Could not clean up mountpoint $mp"
-				ret=$FAIL
-				fi
-
-				if [ $try -gt 1 ]; then
-					kill -9 $pid
-				else
-					kill -TERM $pid
-				fi
-			done < <(lsof -b 2>/dev/null | \
-			    grep -E "$mp(/.*|)\$" | \
-			    awk '{print $1,$2,$3}' | \
-			    sort -u -k 1,3)
-		elif [ -n "$have_fuser" ]; then
-			#
-			# Use fuser to free up mount point
-			#
-			while read command pid user
-			do
-				if [ -z "$pid" ]; then
-					continue
-				fi
-
-				if [ $try -eq 1 ]; then
-					ocf_log warn \
-			 	  "killing process $pid ($user $command $mp)"
-				elif [ $try -eq 3 ]; then
-					ocf_log crit \
-				    "Could not clean up mount point $mp"
-					ret=$FAIL
-				fi
-
-				if [ $try -gt 1 ]; then
-					kill -9 $pid
-				else
-					kill -TERM $pid
-				fi
-			done < <(fuser -vm $mp 2>&1 | \
-			    grep -v PID | \
-			    sed 's;^'$mp:';;' | \
-			    awk '{print $4,$2,$1}' | \
-			    sort -u -k 1,3)
-		fi
-	done
-
-	return $ret
-}
-
-#
 # startFilesystem
 #
 startFilesystem() {
@@ -871,7 +764,11 @@ stop: Could not match $OCF_RESKEY_device with a real device"
 			umount_failed=yes
 
 			if [ "$force_umount" ]; then
-				killMountProcesses $mp
+				if [ $try -eq 1 ]; then
+					fuser -TERM -kvm "$mp"
+				else
+					fuser -kvm "$mp"
+				fi
 			fi
 
 			if [ $try -ge $max_tries ]; then
diff --git a/rgmanager/src/resources/fs.sh.in b/rgmanager/src/resources/fs.sh.in
index 1454295..adc66e3 100644
--- a/rgmanager/src/resources/fs.sh.in
+++ b/rgmanager/src/resources/fs.sh.in
@@ -680,114 +680,6 @@ isAlive()
 
 
 #
-# killMountProcesses mount_point
-#
-# Using lsof or fuser try to unmount the mount by killing of the processes
-# that might be keeping it busy.
-#
-killMountProcesses()
-{
-	typeset -i ret=$SUCCESS
-	typeset have_lsof=""
-	typeset have_fuser=""
-	typeset try
-
-	if [ $# -ne 1 ]; then
-		ocf_log err \
-			"Usage: killMountProcesses mount_point"
-		return $FAIL
-	fi
-
-	typeset mp=$1
-
-	ocf_log notice "Forcefully unmounting $mp"
-
-	#
-	# Not all distributions have lsof.  If not use fuser.  If it
-	# does, try both.
-  	#
-	file=$(which lsof 2>/dev/null)
-	if [ -f "$file" ]; then
-		have_lsof=$YES
-	fi
-
-	file=$(which fuser 2>/dev/null)
-	if [ -f "$file" ]; then
-		have_fuser=$YES
-	fi             
-
-	if [ -z "$have_lsof" -a -z "$have_fuser" ]; then
-		ocf_log warn \
-	"Cannot forcefully unmount $mp; cannot find lsof or fuser commands"
-		return $FAIL
-	fi
-
-	for try in 1 2 3; do
-		if [ -n "$have_lsof" ]; then
-			#
-			# Use lsof to free up mount point
-			#
-	    		while read command pid user
-			do
-				if [ -z "$pid" ]; then
-					continue
-				fi
-
-				if [ $try -eq 1 ]; then
-					ocf_log warn \
-			 	  "killing process $pid ($user $command $mp)"
-				elif [ $try -eq 3 ]; then
-					ocf_log crit \
-		    		  "Could not clean up mountpoint $mp"
-				ret=$FAIL
-				fi
-
-				if [ $try -gt 1 ]; then
-					kill -9 $pid
-				else
-					kill -TERM $pid
-				fi
-			done < <(lsof -bn 2>/dev/null | \
-			    grep -E " $mp(/| |$)" | \
-			    awk '{print $1,$2,$3}' | \
-			    sort -u -k 1,3)
-		elif [ -n "$have_fuser" ]; then
-			#
-			# Use fuser to free up mount point
-			#
-			while read command pid user
-			do
-				if [ -z "$pid" ]; then
-					continue
-				fi
-
-				if [ $try -eq 1 ]; then
-					ocf_log warn \
-			 	  "killing process $pid ($user $command $mp)"
-				elif [ $try -eq 3 ]; then
-					ocf_log crit \
-				    "Could not clean up mount point $mp"
-					ret=$FAIL
-				fi
-
-				if [ $try -gt 1 ]; then
-					kill -9 $pid
-				else
-					kill -TERM $pid
-				fi
-			done < <(fuser -vm $mp 2>&1 | \
-			    grep -v PID | \
-			    sed 's;^'$mp:';;' | \
-			    awk '{print $4,$2,$1}' | \
-			    sort -u -k 1,3)
-		fi
-	done
-
-	return $ret
-}
-
-
-#
 # Decide which quota options are enabled and return a string 
 # which we can pass to quotaon
 #
@@ -1188,8 +1080,9 @@ stop: Could not match $OCF_RESKEY_device with a real device"
 			umount_failed=yes
 
 			if [ "$force_umount" ]; then
-				killMountProcesses $mp
 				if [ $try -eq 1 ]; then
+				  fuser -TERM -kvm "$mp"
+
 	        		  if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
 				     [ "$OCF_RESKEY_nfslock" = "1" ]; then
 				    ocf_log warning \
@@ -1201,15 +1094,11 @@ stop: Could not match $OCF_RESKEY_device with a real device"
 				    notify_list_store $mp/.clumanager/statd
 				    nfslock_reclaim=1
 				  fi
+				else
+				  fuser -kvm "$mp"
 				fi
 			fi
 
-			if [ $try -ge $max_tries ]; then
-				done=$YES
-			else
-				sleep $sleep_time
-				let try=try+1
-			fi
 			;;
 		*)
 			return $FAIL
@@ -1218,7 +1107,7 @@ stop: Could not match $OCF_RESKEY_device with a real device"
 
 		if [ $try -ge $max_tries ]; then
 			done=$YES
-		elif [ "$done" -ne "$YES" ]; then
+		elif [ "$done" != "$YES" ]; then
 			sleep $sleep_time
 			let try=try+1
 		fi
diff --git a/rgmanager/src/resources/netfs.sh b/rgmanager/src/resources/netfs.sh
index 24b89ec..b85027a 100644
--- a/rgmanager/src/resources/netfs.sh
+++ b/rgmanager/src/resources/netfs.sh
@@ -339,113 +339,6 @@ isMounted () {
 }
 
 #
-# killMountProcesses mount_point
-#
-# Using lsof or fuser try to unmount the mount by killing of the processes
-# that might be keeping it busy.
-#
-killMountProcesses()
-{
-        typeset -i ret=$SUCCESS
-        typeset have_lsof=""
-        typeset have_fuser=""
-        typeset try
-
-        if [ $# -ne 1 ]; then
-                ocf_log err \
-                        "Usage: killMountProcesses mount_point"
-                return $FAIL
-        fi
-
-        typeset mp=$1
-
-        ocf_log notice "Forcefully unmounting $mp"
-
-        #
-        # Not all distributions have lsof.  If not use fuser.  If it
-        # does, try both.
-        #
-        file=$(which lsof 2>/dev/null)
-        if [ -f "$file" ]; then
-                have_lsof=$YES
-        fi
-
-        file=$(which fuser 2>/dev/null)
-        if [ -f "$file" ]; then
-                have_fuser=$YES
-        fi
-
-        if [ -z "$have_lsof" -a -z "$have_fuser" ]; then
-                ocf_log warn \
-        "Cannot forcefully unmount $mp; cannot find lsof or fuser commands"
-                return $FAIL
-        fi
-
-        for try in 1 2 3; do
-                if [ -n "$have_lsof" ]; then
-                        #
-                        # Use lsof to free up mount point
-                        #
-                        while read command pid user
-                        do
-                                if [ -z "$pid" ]; then
-                                        continue
-                                fi
-
-                                if [ $try -eq 1 ]; then
-                                        ocf_log warn \
-                                  "killing process $pid ($user $command $mp)"
-                                elif [ $try -eq 3 ]; then
-                                        ocf_log crit \
-                                  "Could not clean up mountpoint $mp"
-                                ret=$FAIL
-                                fi
-
-                                if [ $try -gt 1 ]; then
-                                        kill -9 $pid
-                                else
-                                        kill -TERM $pid
-                                fi
-                        done < <(lsof -w -bn 2>/dev/null | \
-                            grep -w -E "$mp(/.*|)\$" | \
-                            awk '{print $1,$2,$3}' | \
-                            sort -u -k 1,3)
-                elif [ -n "$have_fuser" ]; then
-                        #
-                        # Use fuser to free up mount point
-                        #
-                        while read command pid user
-                        do
-                                if [ -z "$pid" ]; then
-                                        continue
-                                fi
-
-                                if [ $try -eq 1 ]; then
-                                        ocf_log warn \
-                                  "killing process $pid ($user $command $mp)"
-                                elif [ $try -eq 3 ]; then
-                                        ocf_log crit \
-                                    "Could not clean up mount point $mp"
-                                        ret=$FAIL
-                                fi
-
-                                if [ $try -gt 1 ]; then
-                                        kill -9 $pid
-                                else
-                                        kill -TERM $pid
-                                fi
-			done < <(fuser -vm $mp 2>&1 | \
-                            grep -v PID | \
-			    sed 's;^'$mp:';;' | \
-                            awk '{print $4,$2,$1}' | \
-                            sort -u -k 1,3)
-                fi
-        done
-
-        return $ret
-}
-
-#
 # startNFSFilesystem
 #
 startNFSFilesystem() {
@@ -639,15 +532,20 @@ stopNFSFilesystem() {
 
 		umount_failed=yes
 
-                        if [ "$force_umount" ]; then
-                                killMountProcesses $mp
-                        fi
+		if [ "$force_umount" ]; then
+			if [ $try -eq 1 ]; then
+				fuser -TERM -kvm "$mp"
+			else
+				fuser -kvm "$mp"
+			fi
+		fi
 
-                        if [ $try -ge $max_tries ]; then
-                                done=$YES
-                        else
-                                sleep $sleep_time
-                                let try=try+1
+
+		if [ $try -ge $max_tries ]; then
+			done=$YES
+		else
+			sleep $sleep_time
+			let try=try+1
                         fi
 		;;
 	*)


More information about the cluster-commits mailing list