-#!/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.
###############################################################################
-FSTYPE=${1:-ldiskfs}
+# 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
+ rmmod $MODULE || return 1
+ return 0
+}
-TMP=${TMP:-/tmp}
-LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
-LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
-[ ! -f "$LCTL" ] && export LCTL=$(which lctl 2> /dev/null)
+modules="$@"
-RMMOD=rmmod
-if [ `uname -r | cut -c 3` -eq 4 ]; then
- RMMOD="modprobe -r"
+# 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 [ -z "$modules" ] || [ "$modules" = "ldiskfs" ]; then
+ modules="ptlrpc lnet_selftest ldiskfs libcfs"
fi
-unload_dep_module() {
- # libcfs 107852 17 llite_lloop,lustre,obdfilter,ost,...
- local MODULE=$1
- local DEPS="$(lsmod | awk '($1 == "'$MODULE'") { print $4 }' | tr ',' ' ')"
- for SUBMOD in $DEPS; do
- unload_dep_module $SUBMOD
- done
- [ "$MODULE" = "libcfs" ] && $LCTL dk $TMP/debug >/dev/null || true
- $RMMOD $MODULE 2>/dev/null || true
- return 0
-}
+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
-lsmod | grep obdclass > /dev/null && $LCTL dl
-lsmod | grep $FSTYPE > /dev/null && unload_dep_module $FSTYPE
-lsmod | grep libcfs > /dev/null && unload_dep_module libcfs
+for mod in $modules; do
+ unload_dep_modules_inclusive $mod || exit 1
+done
-MODULES=$($LCTL modules | awk '{ print $2 }')
-if [ -n "$MODULES" ]; then
- echo "Modules still loaded: "
- echo $MODULES
- exit 1
+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
+exit 0