1#!/bin/sh 2# 3# A simple script to load/unload the ZFS module stack. 4# 5 6BASE_DIR=$(dirname "$0") 7SCRIPT_COMMON=common.sh 8if [ -f "${BASE_DIR}/${SCRIPT_COMMON}" ]; then 9 . "${BASE_DIR}/${SCRIPT_COMMON}" 10else 11 echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 12fi 13 14PROG=zfs.sh 15VERBOSE="no" 16UNLOAD="no" 17LOAD="yes" 18STACK_TRACER="no" 19 20ZED_PIDFILE=${ZED_PIDFILE:-/var/run/zed.pid} 21LDMOD=${LDMOD:-/sbin/modprobe} 22 23KMOD_ZLIB_DEFLATE=${KMOD_ZLIB_DEFLATE:-zlib_deflate} 24KMOD_ZLIB_INFLATE=${KMOD_ZLIB_INFLATE:-zlib_inflate} 25KMOD_SPL=${KMOD_SPL:-spl} 26KMOD_ZAVL=${KMOD_ZAVL:-zavl} 27KMOD_ZNVPAIR=${KMOD_ZNVPAIR:-znvpair} 28KMOD_ZUNICODE=${KMOD_ZUNICODE:-zunicode} 29KMOD_ZCOMMON=${KMOD_ZCOMMON:-zcommon} 30KMOD_ZLUA=${KMOD_ZLUA:-zlua} 31KMOD_ICP=${KMOD_ICP:-icp} 32KMOD_ZFS=${KMOD_ZFS:-zfs} 33KMOD_FREEBSD=${KMOD_FREEBSD:-openzfs} 34KMOD_ZZSTD=${KMOD_ZZSTD:-zzstd} 35 36 37usage() { 38cat << EOF 39USAGE: 40$0 [hvudS] [module-options] 41 42DESCRIPTION: 43 Load/unload the ZFS module stack. 44 45OPTIONS: 46 -h Show this message 47 -v Verbose 48 -r Reload modules 49 -u Unload modules 50 -S Enable kernel stack tracer 51EOF 52} 53 54while getopts 'hvruS' OPTION; do 55 case $OPTION in 56 h) 57 usage 58 exit 1 59 ;; 60 v) 61 VERBOSE="yes" 62 ;; 63 r) 64 UNLOAD="yes" 65 LOAD="yes" 66 ;; 67 u) 68 UNLOAD="yes" 69 LOAD="no" 70 ;; 71 S) 72 STACK_TRACER="yes" 73 ;; 74 ?) 75 usage 76 exit 77 ;; 78 *) 79 ;; 80 esac 81done 82 83kill_zed() { 84 if [ -f "$ZED_PIDFILE" ]; then 85 PID=$(cat "$ZED_PIDFILE") 86 kill "$PID" 87 fi 88} 89 90check_modules_linux() { 91 LOADED_MODULES="" 92 MISSING_MODULES="" 93 94 for KMOD in $KMOD_SPL $KMOD_ZAVL $KMOD_ZNVPAIR $KMOD_ZUNICODE $KMOD_ZCOMMON \ 95 $KMOD_ZLUA $KMOD_ZZSTD $KMOD_ICP $KMOD_ZFS; do 96 NAME="${KMOD##*/}" 97 NAME="${NAME%.ko}" 98 99 if lsmod | grep -E -q "^${NAME}"; then 100 LOADED_MODULES="$LOADED_MODULES\t$NAME\n" 101 fi 102 103 if ! modinfo "$KMOD" >/dev/null 2>&1; then 104 MISSING_MODULES="$MISSING_MODULES\t${KMOD}\n" 105 fi 106 done 107 108 if [ -n "$LOADED_MODULES" ]; then 109 printf "Unload the kernel modules by running '%s -u':\n" "$PROG" 110 printf "%b" "$LOADED_MODULES" 111 exit 1 112 fi 113 114 if [ -n "$MISSING_MODULES" ]; then 115 printf "The following kernel modules can not be found:\n" 116 printf "%b" "$MISSING_MODULES" 117 exit 1 118 fi 119 120 return 0 121} 122 123load_module_linux() { 124 KMOD=$1 125 126 FILE=$(modinfo "$KMOD" | awk '/^filename:/ {print $2}') 127 VERSION=$(modinfo "$KMOD" | awk '/^version:/ {print $2}') 128 129 if [ "$VERBOSE" = "yes" ]; then 130 echo "Loading: $FILE ($VERSION)" 131 fi 132 133 if ! $LDMOD "$KMOD" >/dev/null 2>&1; then 134 echo "Failed to load $KMOD" 135 return 1 136 fi 137 138 return 0 139} 140 141load_modules_freebsd() { 142 kldload "$KMOD_FREEBSD" || return 1 143 144 if [ "$VERBOSE" = "yes" ]; then 145 echo "Successfully loaded ZFS module stack" 146 fi 147 148 return 0 149} 150 151load_modules_linux() { 152 mkdir -p /etc/zfs 153 154 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 155 modprobe "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 156 fi 157 158 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 159 modprobe "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 160 fi 161 162 for KMOD in $KMOD_SPL $KMOD_ZAVL $KMOD_ZNVPAIR \ 163 $KMOD_ZUNICODE $KMOD_ZCOMMON $KMOD_ZLUA $KMOD_ZZSTD \ 164 $KMOD_ICP $KMOD_ZFS; do 165 load_module_linux "$KMOD" || return 1 166 done 167 168 if [ "$VERBOSE" = "yes" ]; then 169 echo "Successfully loaded ZFS module stack" 170 fi 171 172 return 0 173} 174 175unload_module_linux() { 176 KMOD=$1 177 178 NAME="${KMOD##*/}" 179 NAME="${NAME%.ko}" 180 FILE=$(modinfo "$KMOD" | awk '/^filename:/ {print $2}') 181 VERSION=$(modinfo "$KMOD" | awk '/^version:/ {print $2}') 182 183 if [ "$VERBOSE" = "yes" ]; then 184 echo "Unloading: $KMOD ($VERSION)" 185 fi 186 187 rmmod "$NAME" || echo "Failed to unload $NAME" 188 189 return 0 190} 191 192unload_modules_freebsd() { 193 kldunload "$KMOD_FREEBSD" || echo "Failed to unload $KMOD_FREEBSD" 194 195 if [ "$VERBOSE" = "yes" ]; then 196 echo "Successfully unloaded ZFS module stack" 197 fi 198 199 return 0 200} 201 202unload_modules_linux() { 203 for KMOD in $KMOD_ZFS $KMOD_ICP $KMOD_ZZSTD $KMOD_ZLUA $KMOD_ZCOMMON \ 204 $KMOD_ZUNICODE $KMOD_ZNVPAIR $KMOD_ZAVL $KMOD_SPL; do 205 NAME="${KMOD##*/}" 206 NAME="${NAME%.ko}" 207 USE_COUNT=$(lsmod | awk '/^'"${NAME}"'/ {print $3}') 208 209 if [ "$USE_COUNT" = "0" ] ; then 210 unload_module_linux "$KMOD" || return 1 211 elif [ "$USE_COUNT" != "" ] ; then 212 echo "Module ${NAME} is still in use!" 213 return 1 214 fi 215 done 216 217 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 218 modprobe -r "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 219 fi 220 221 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 222 modprobe -r "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 223 fi 224 225 if [ "$VERBOSE" = "yes" ]; then 226 echo "Successfully unloaded ZFS module stack" 227 fi 228 229 return 0 230} 231 232stack_clear_linux() { 233 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 234 STACK_TRACER_ENABLED=/proc/sys/kernel/stack_tracer_enabled 235 236 if [ "$STACK_TRACER" = "yes" ] && [ -e "$STACK_MAX_SIZE" ]; then 237 echo 1 >"$STACK_TRACER_ENABLED" 238 echo 0 >"$STACK_MAX_SIZE" 239 fi 240} 241 242stack_check_linux() { 243 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 244 STACK_TRACE=/sys/kernel/debug/tracing/stack_trace 245 STACK_LIMIT=15362 246 247 if [ -e "$STACK_MAX_SIZE" ]; then 248 STACK_SIZE=$(cat "$STACK_MAX_SIZE") 249 250 if [ "$STACK_SIZE" -ge "$STACK_LIMIT" ]; then 251 echo 252 echo "Warning: max stack size $STACK_SIZE bytes" 253 cat "$STACK_TRACE" 254 fi 255 fi 256} 257 258if [ "$(id -u)" != 0 ]; then 259 echo "Must run as root" 260 exit 1 261fi 262 263UNAME=$(uname -s) 264 265if [ "$UNLOAD" = "yes" ]; then 266 kill_zed 267 umount -t zfs -a 268 case $UNAME in 269 FreeBSD) 270 unload_modules_freebsd 271 ;; 272 Linux) 273 stack_check_linux 274 unload_modules_linux 275 ;; 276 *) 277 echo "unknown system: $UNAME" >&2 278 exit 1 279 ;; 280 esac 281fi 282if [ "$LOAD" = "yes" ]; then 283 case $UNAME in 284 FreeBSD) 285 load_modules_freebsd 286 ;; 287 Linux) 288 stack_clear_linux 289 check_modules_linux 290 load_modules_linux "$@" 291 udevadm trigger 292 udevadm settle 293 ;; 294 *) 295 echo "unknown system: $UNAME" >&2 296 exit 1 297 ;; 298 esac 299fi 300 301exit 0 302