X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Fscripts%2Flustre_rmmod;h=637c6a0ba20ab370175b43369b8fc33c34c05000;hb=d106dfc1458702865118e73bfcdfc2ec2676a7d6;hp=6663ec6d6d622542b45a6ffb17803800a1ed306a;hpb=073e67f1647008c721d452ee3862c3f643f6c248;p=fs%2Flustre-release.git diff --git a/lustre/scripts/lustre_rmmod b/lustre/scripts/lustre_rmmod index 6663ec6..637c6a0 100755 --- a/lustre/scripts/lustre_rmmod +++ b/lustre/scripts/lustre_rmmod @@ -1,18 +1,143 @@ -#!/bin/sh +#!/bin/bash # -# remove all lustre modules. Won't succeed if they're in use, or if you -# manually did a 'lctl network up'. +# Takes a list of modules and unloads them and all dependent modules. +# If a module cannot be unloaded (e.g. it's in use), an error is +# returned. ############################################################################### -SRCDIR=`dirname $0` -PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$PATH +SCRIPT_NAME="$(basename "$0")" +LCTL=${LCTL:-lctl} +DEBUG='false' -case `uname -r` in -2.4.*) RMMOD="modprobe -r";; -*) RMMOD="rmmod";; -esac +# Print help message +print_usage() { + echo "$SCRIPT_NAME -h|--help" + echo "$SCRIPT_NAME [-d|--debug-kernel] [modulesname...]" + echo + echo -e "\t-h, --help\t\tDisplay this help message" + echo -e "\t-d, --debug-kernel\tDisplay lustre kernel debug messages" + echo -e "\tmodulesname\t\tList of lustre modules to unload. By default" + echo -e "\t\t\t\tldiskfs and libcfs (and their dependencies) are" + echo -e "\t\t\t\tselected." +} -lctl modules | awk '{ print $2 }' | xargs $RMMOD >/dev/null 2>&1 -# do it again, in case we tried to unload the lnd's too early -lsmod | grep lnet > /dev/null && lctl modules | awk '{ print $2 }' | xargs $RMMOD +# Print kernel debug message for lustre modules +print_debug() { + $LCTL mark "$SCRIPT_NAME : Stop debug" + $LCTL debug_kernel + DEBUG='false' +} +# Unload all modules dependent on $1 (exclude removal of $1) +unload_dep_modules_exclusive() { + local MODULE=$1 + + local DEPS="$(lsmod | awk '($1 == "'$MODULE'") { print $4 }')" + for SUBMOD in $(echo $DEPS | tr ',' ' '); do + unload_dep_modules_inclusive $SUBMOD || return 1 + done + return 0 +} + +# Unload all modules dependent on $1 (include removal of $1) +unload_dep_modules_inclusive() { + local MODULE=$1 + + # if $MODULE not loaded, return 0 + lsmod | egrep -q "^\<$MODULE\>" || return 0 + unload_dep_modules_exclusive $MODULE || return 1 + + if $DEBUG; then + if [ "$MODULE" = 'libcfs' ]; then + print_debug + fi + $LCTL mark "$SCRIPT_NAME : Unload $MODULE" + fi + + rmmod $MODULE || return 1 + return 0 +} + +declare -a modules +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + print_usage >&2 + exit 0 + ;; + -d|--debug-kernel) + if lsmod | egrep -q '^libcfs'; then + DEBUG='true' + else + echo "Debug unavailable: libcfs is not loaded" >&2 + fi + ;; + -*) + echo "Error invalid option" >&2 + print_usage >&2 + exit 2 + ;; + *) + modules+=("$1") + ;; + esac + shift +done + +# To maintain backwards compatibility, ldiskfs and libcfs must be +# unloaded if no parameters are given, or if only the ldiskfs parameter +# is given. It's ugly, but is needed to emulate the prior functionality +if [ "${#modules[@]}" -eq 0 ] || [ "${modules[*]}" = "ldiskfs" ]; then + modules=('ptlrpc' 'lnet_selftest' 'ldiskfs' 'libcfs') +fi + +if [ -f /sys/kernel/debug/kmemleak ] ; then + cat /proc/modules >/tmp/kmemleak-modules-list.txt + echo scan > /sys/kernel/debug/kmemleak + cat /sys/kernel/debug/kmemleak > /tmp/kmemleak-before-unload.txt + test -s /tmp/kmemleak-before-unload.txt && logger -t leak-pre -f /tmp/kmemleak-before-unload.txt + rm /tmp/kmemleak-before-unload.txt + # Clear everything here so that only new leaks show up + # after module unload + echo clear > /sys/kernel/debug/kmemleak +fi + +# Manage debug +if $DEBUG; then + echo "Lustre debug parameters:" >&2 + $LCTL get_param debug >&2 + $LCTL get_param debug_mb >&2 + + $LCTL mark "$SCRIPT_NAME : Start debug" +fi + +# LNet may have an internal ref which can prevent LND modules from +# unloading. Try to drop it before unloading modules. +# NB: we squelch stderr because lnetctl/lctl may complain about +# LNet being "busy", but this is normal. We're making a best effort +# here. +if lsmod | grep -q lnet; then + # Prefer lnetctl if it is present + if [ -n "$(which lnetctl 2>/dev/null)" ]; then + lnetctl lnet unconfigure 2>/dev/null + elif [ -n "$(which lctl 2>/dev/null)" ]; then + lctl net down 2>/dev/null + fi +fi + +for mod in ${modules[*]}; do + unload_dep_modules_inclusive $mod || exit 1 +done + +if $DEBUG; then + print_debug +fi + +if [ -f /sys/kernel/debug/kmemleak ] ; then + echo scan > /sys/kernel/debug/kmemleak + cat /sys/kernel/debug/kmemleak > /tmp/kmemleak-after-unload.txt + test -s /tmp/kmemleak-after-unload.txt && logger -t leak-mods -f /tmp/kmemleak-modules-list.txt && logger -t leak-post -f /tmp/kmemleak-after-unload.txt + rm -f /tmp/kmemleak-after-unload.txt /tmp/kmemleak-modules-list.txt +fi + +exit 0