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 $LDMOD "$KMOD" >/dev/null 2>&1 124 # shellcheck disable=SC2181 125 if [ $? -ne 0 ]; then 126 echo "Failed to load $KMOD" 127 return 1 128 fi 129 130 return 0 131} 132 133load_modules_freebsd() { 134 kldload "$KMOD_FREEBSD" || return 1 135 136 if [ "$VERBOSE" = "yes" ]; then 137 echo "Successfully loaded ZFS module stack" 138 fi 139 140 return 0 141} 142 143load_modules_linux() { 144 mkdir -p /etc/zfs 145 146 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 147 modprobe "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 148 fi 149 150 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 151 modprobe "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 152 fi 153 154 for KMOD in $KMOD_SPL $KMOD_ZAVL $KMOD_ZNVPAIR \ 155 $KMOD_ZUNICODE $KMOD_ZCOMMON $KMOD_ZLUA $KMOD_ZZSTD \ 156 $KMOD_ICP $KMOD_ZFS; do 157 load_module_linux "$KMOD" || return 1 158 done 159 160 if [ "$VERBOSE" = "yes" ]; then 161 echo "Successfully loaded ZFS module stack" 162 fi 163 164 return 0 165} 166 167unload_module_linux() { 168 KMOD=$1 169 170 NAME=$(basename "$KMOD" .ko) 171 FILE=$(modinfo "$KMOD" | awk '/^filename:/ {print $2}') 172 VERSION=$(modinfo "$KMOD" | awk '/^version:/ {print $2}') 173 174 if [ "$VERBOSE" = "yes" ]; then 175 echo "Unloading: $KMOD ($VERSION)" 176 fi 177 178 rmmod "$NAME" || echo "Failed to unload $NAME" 179 180 return 0 181} 182 183unload_modules_freebsd() { 184 kldunload "$KMOD_FREEBSD" || echo "Failed to unload $KMOD_FREEBSD" 185 186 if [ "$VERBOSE" = "yes" ]; then 187 echo "Successfully unloaded ZFS module stack" 188 fi 189 190 return 0 191} 192 193unload_modules_linux() { 194 for KMOD in $KMOD_ZFS $KMOD_ICP $KMOD_ZZSTD $KMOD_ZLUA $KMOD_ZCOMMON \ 195 $KMOD_ZUNICODE $KMOD_ZNVPAIR $KMOD_ZAVL $KMOD_SPL; do 196 NAME=$(basename "$KMOD" .ko) 197 USE_COUNT=$(lsmod | grep -E "^${NAME} " | awk '{print $3}') 198 199 if [ "$USE_COUNT" = "0" ] ; then 200 unload_module_linux "$KMOD" || return 1 201 elif [ "$USE_COUNT" != "" ] ; then 202 echo "Module ${NAME} is still in use!" 203 return 1 204 fi 205 done 206 207 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 208 modprobe -r "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 209 fi 210 211 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 212 modprobe -r "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 213 fi 214 215 if [ "$VERBOSE" = "yes" ]; then 216 echo "Successfully unloaded ZFS module stack" 217 fi 218 219 return 0 220} 221 222stack_clear_linux() { 223 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 224 STACK_TRACER_ENABLED=/proc/sys/kernel/stack_tracer_enabled 225 226 if [ "$STACK_TRACER" = "yes" ] && [ -e "$STACK_MAX_SIZE" ]; then 227 echo 1 >"$STACK_TRACER_ENABLED" 228 echo 0 >"$STACK_MAX_SIZE" 229 fi 230} 231 232stack_check_linux() { 233 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 234 STACK_TRACE=/sys/kernel/debug/tracing/stack_trace 235 STACK_LIMIT=15362 236 237 if [ -e "$STACK_MAX_SIZE" ]; then 238 STACK_SIZE=$(cat "$STACK_MAX_SIZE") 239 240 if [ "$STACK_SIZE" -ge "$STACK_LIMIT" ]; then 241 echo 242 echo "Warning: max stack size $STACK_SIZE bytes" 243 cat "$STACK_TRACE" 244 fi 245 fi 246} 247 248if [ "$(id -u)" != 0 ]; then 249 echo "Must run as root" 250 exit 1 251fi 252 253UNAME=$(uname -s) 254 255if [ "$UNLOAD" = "yes" ]; then 256 kill_zed 257 umount -t zfs -a 258 case $UNAME in 259 FreeBSD) 260 unload_modules_freebsd 261 ;; 262 Linux) 263 stack_check_linux 264 unload_modules_linux 265 ;; 266 esac 267else 268 case $UNAME in 269 FreeBSD) 270 load_modules_freebsd 271 ;; 272 Linux) 273 stack_clear_linux 274 check_modules_linux 275 load_modules_linux "$@" 276 udevadm trigger 277 udevadm settle 278 ;; 279 esac 280fi 281 282exit 0 283