Whamcloud - gitweb
LU-14074 scripts: automatic LNet unconfigure
[fs/lustre-release.git] / lustre / scripts / lustre_rmmod
1 #!/bin/bash
2 #
3 # Takes a list of modules and unloads them and all dependent modules.
4 # If a module cannot be unloaded (e.g. it's in use), an error is
5 # returned.
6 ###############################################################################
7
8 SCRIPT_NAME="$(basename "$0")"
9 LCTL=${LCTL:-lctl}
10 DEBUG='false'
11
12 # Print help message
13 print_usage() {
14         echo "$SCRIPT_NAME -h|--help"
15         echo "$SCRIPT_NAME [-d|--debug-kernel] [modulesname...]"
16         echo
17         echo -e "\t-h, --help\t\tDisplay this help message"
18         echo -e "\t-d, --debug-kernel\tDisplay lustre kernel debug messages"
19         echo -e "\tmodulesname\t\tList of lustre modules to unload. By default"
20         echo -e "\t\t\t\tldiskfs and libcfs (and their dependencies) are"
21         echo -e "\t\t\t\tselected."
22 }
23
24 # Print kernel debug message for lustre modules
25 print_debug() {
26         $LCTL mark "$SCRIPT_NAME : Stop debug"
27         $LCTL debug_kernel
28         DEBUG='false'
29 }
30
31 # Unload all modules dependent on $1 (exclude removal of $1)
32 unload_dep_modules_exclusive() {
33         local MODULE=$1
34
35         local DEPS="$(lsmod | awk '($1 == "'$MODULE'") { print $4 }')"
36         for SUBMOD in $(echo $DEPS | tr ',' ' '); do
37                 unload_dep_modules_inclusive $SUBMOD || return 1
38         done
39         return 0
40 }
41
42 # Unload all modules dependent on $1 (include removal of $1)
43 unload_dep_modules_inclusive() {
44         local MODULE=$1
45
46         # if $MODULE not loaded, return 0
47         lsmod | egrep -q "^\<$MODULE\>" || return 0
48         unload_dep_modules_exclusive $MODULE || return 1
49
50         if $DEBUG; then
51                 if [ "$MODULE" = 'libcfs' ]; then
52                         print_debug
53                 fi
54                 $LCTL mark "$SCRIPT_NAME : Unload $MODULE"
55         fi
56
57         rmmod $MODULE || return 1
58         return 0
59 }
60
61 declare -a modules
62 while [ $# -gt 0 ]; do
63         case "$1" in
64                 -h|--help)
65                         print_usage >&2
66                         exit 0
67                         ;;
68                 -d|--debug-kernel)
69                         if lsmod | egrep -q '^libcfs'; then
70                                 DEBUG='true'
71                         else
72                                 echo "Debug unavailable: libcfs is not loaded" >&2
73                         fi
74                         ;;
75                 -*)
76                         echo "Error invalid option" >&2
77                         print_usage >&2
78                         exit 2
79                         ;;
80                 *)
81                         modules+=("$1")
82                         ;;
83         esac
84         shift
85 done
86
87 # To maintain backwards compatibility, ldiskfs and libcfs must be
88 # unloaded if no parameters are given, or if only the ldiskfs parameter
89 # is given. It's ugly, but is needed to emulate the prior functionality
90 if [ "${#modules[@]}" -eq 0 ] || [ "${modules[*]}" = "ldiskfs" ]; then
91         unload_all=true
92         modules=('lnet_selftest' 'ldiskfs' 'libcfs')
93 else
94         unload_all=false
95 fi
96
97 if [ -f /sys/kernel/debug/kmemleak ] ; then
98         cat /proc/modules >/tmp/kmemleak-modules-list.txt
99         echo scan > /sys/kernel/debug/kmemleak
100         cat /sys/kernel/debug/kmemleak > /tmp/kmemleak-before-unload.txt
101         test -s /tmp/kmemleak-before-unload.txt && logger -t leak-pre -f /tmp/kmemleak-before-unload.txt
102         rm /tmp/kmemleak-before-unload.txt
103         # Clear everything here so that only new leaks show up
104         # after module unload
105         echo clear > /sys/kernel/debug/kmemleak
106 fi
107
108 # Manage debug
109 if $DEBUG; then
110         echo "Lustre debug parameters:" >&2
111         $LCTL get_param debug >&2
112         $LCTL get_param debug_mb >&2
113
114         $LCTL mark "$SCRIPT_NAME : Start debug"
115 fi
116
117 if $unload_all; then
118         unload_dep_modules_inclusive 'ptlrpc' || exit 1
119         # LNet may have an internal ref which can prevent LND modules from
120         # unloading. Try to drop it before unloading modules.
121         # NB: we squelch stderr because lnetctl/lctl may complain about
122         # LNet being "busy", but this is normal. We're making a best effort
123         # here.
124         # Prefer lnetctl if it is present
125         if [ -n "$(which lnetctl 2>/dev/null)" ]; then
126                 lnetctl lnet unconfigure 2>/dev/null
127         elif [ -n "$(which lctl 2>/dev/null)" ]; then
128                 lctl net down 2>/dev/null
129         fi
130 fi
131
132 for mod in ${modules[*]}; do
133         unload_dep_modules_inclusive $mod || exit 1
134 done
135
136 if $DEBUG; then
137         print_debug
138 fi
139
140 if [ -f /sys/kernel/debug/kmemleak ] ; then
141         echo scan > /sys/kernel/debug/kmemleak
142         cat /sys/kernel/debug/kmemleak > /tmp/kmemleak-after-unload.txt
143         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
144         rm -f /tmp/kmemleak-after-unload.txt /tmp/kmemleak-modules-list.txt
145 fi
146
147 exit 0