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