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