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 fi 202 done 203 204 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 205 modprobe -r "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 206 fi 207 208 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 209 modprobe -r "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 210 fi 211 212 if [ "$VERBOSE" = "yes" ]; then 213 echo "Successfully unloaded ZFS module stack" 214 fi 215 216 return 0 217} 218 219stack_clear_linux() { 220 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 221 STACK_TRACER_ENABLED=/proc/sys/kernel/stack_tracer_enabled 222 223 if [ "$STACK_TRACER" = "yes" ] && [ -e "$STACK_MAX_SIZE" ]; then 224 echo 1 >"$STACK_TRACER_ENABLED" 225 echo 0 >"$STACK_MAX_SIZE" 226 fi 227} 228 229stack_check_linux() { 230 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 231 STACK_TRACE=/sys/kernel/debug/tracing/stack_trace 232 STACK_LIMIT=15362 233 234 if [ -e "$STACK_MAX_SIZE" ]; then 235 STACK_SIZE=$(cat "$STACK_MAX_SIZE") 236 237 if [ "$STACK_SIZE" -ge "$STACK_LIMIT" ]; then 238 echo 239 echo "Warning: max stack size $STACK_SIZE bytes" 240 cat "$STACK_TRACE" 241 fi 242 fi 243} 244 245if [ "$(id -u)" != 0 ]; then 246 echo "Must run as root" 247 exit 1 248fi 249 250UNAME=$(uname -s) 251 252if [ "$UNLOAD" = "yes" ]; then 253 kill_zed 254 umount -t zfs -a 255 case $UNAME in 256 FreeBSD) 257 unload_modules_freebsd 258 ;; 259 Linux) 260 stack_check_linux 261 unload_modules_linux 262 ;; 263 esac 264else 265 case $UNAME in 266 FreeBSD) 267 load_modules_freebsd 268 ;; 269 Linux) 270 stack_clear_linux 271 check_modules_linux 272 load_modules_linux "$@" 273 udevadm trigger 274 udevadm settle 275 ;; 276 esac 277fi 278 279exit 0 280