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 esac 79done 80 81kill_zed() { 82 if [ -f "$ZED_PIDFILE" ]; then 83 PID=$(cat "$ZED_PIDFILE") 84 kill "$PID" 85 fi 86} 87 88check_modules_linux() { 89 LOADED_MODULES="" 90 MISSING_MODULES="" 91 92 for KMOD in $KMOD_SPL $KMOD_ZAVL $KMOD_ZNVPAIR $KMOD_ZUNICODE $KMOD_ZCOMMON \ 93 $KMOD_ZLUA $KMOD_ZZSTD $KMOD_ICP $KMOD_ZFS; do 94 NAME="${KMOD##*/}" 95 NAME="${NAME%.ko}" 96 97 if lsmod | grep -E -q "^${NAME}"; then 98 LOADED_MODULES="$LOADED_MODULES\t$NAME\n" 99 fi 100 101 if ! modinfo "$KMOD" >/dev/null 2>&1; then 102 MISSING_MODULES="$MISSING_MODULES\t${KMOD}\n" 103 fi 104 done 105 106 if [ -n "$LOADED_MODULES" ]; then 107 printf "Unload the kernel modules by running '%s -u':\n" "$PROG" 108 printf "%b" "$LOADED_MODULES" 109 exit 1 110 fi 111 112 if [ -n "$MISSING_MODULES" ]; then 113 printf "The following kernel modules can not be found:\n" 114 printf "%b" "$MISSING_MODULES" 115 exit 1 116 fi 117 118 return 0 119} 120 121load_module_linux() { 122 KMOD=$1 123 124 FILE=$(modinfo "$KMOD" | awk '/^filename:/ {print $2}') 125 VERSION=$(modinfo "$KMOD" | awk '/^version:/ {print $2}') 126 127 if [ "$VERBOSE" = "yes" ]; then 128 echo "Loading: $FILE ($VERSION)" 129 fi 130 131 if ! $LDMOD "$KMOD" >/dev/null 2>&1; then 132 echo "Failed to load $KMOD" 133 return 1 134 fi 135 136 return 0 137} 138 139load_modules_freebsd() { 140 kldload "$KMOD_FREEBSD" || return 1 141 142 if [ "$VERBOSE" = "yes" ]; then 143 echo "Successfully loaded ZFS module stack" 144 fi 145 146 return 0 147} 148 149load_modules_linux() { 150 mkdir -p /etc/zfs 151 152 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 153 modprobe "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 154 fi 155 156 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 157 modprobe "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 158 fi 159 160 for KMOD in $KMOD_SPL $KMOD_ZAVL $KMOD_ZNVPAIR \ 161 $KMOD_ZUNICODE $KMOD_ZCOMMON $KMOD_ZLUA $KMOD_ZZSTD \ 162 $KMOD_ICP $KMOD_ZFS; do 163 load_module_linux "$KMOD" || return 1 164 done 165 166 if [ "$VERBOSE" = "yes" ]; then 167 echo "Successfully loaded ZFS module stack" 168 fi 169 170 return 0 171} 172 173unload_module_linux() { 174 KMOD=$1 175 176 NAME="${KMOD##*/}" 177 NAME="${NAME%.ko}" 178 FILE=$(modinfo "$KMOD" | awk '/^filename:/ {print $2}') 179 VERSION=$(modinfo "$KMOD" | awk '/^version:/ {print $2}') 180 181 if [ "$VERBOSE" = "yes" ]; then 182 echo "Unloading: $KMOD ($VERSION)" 183 fi 184 185 rmmod "$NAME" || echo "Failed to unload $NAME" 186 187 return 0 188} 189 190unload_modules_freebsd() { 191 kldunload "$KMOD_FREEBSD" || echo "Failed to unload $KMOD_FREEBSD" 192 193 if [ "$VERBOSE" = "yes" ]; then 194 echo "Successfully unloaded ZFS module stack" 195 fi 196 197 return 0 198} 199 200unload_modules_linux() { 201 for KMOD in $KMOD_ZFS $KMOD_ICP $KMOD_ZZSTD $KMOD_ZLUA $KMOD_ZCOMMON \ 202 $KMOD_ZUNICODE $KMOD_ZNVPAIR $KMOD_ZAVL $KMOD_SPL; do 203 NAME="${KMOD##*/}" 204 NAME="${NAME%.ko}" 205 USE_COUNT=$(lsmod | awk '/^'"${NAME}"'/ {print $3}') 206 207 if [ "$USE_COUNT" = "0" ] ; then 208 unload_module_linux "$KMOD" || return 1 209 elif [ "$USE_COUNT" != "" ] ; then 210 echo "Module ${NAME} is still in use!" 211 return 1 212 fi 213 done 214 215 if modinfo "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1; then 216 modprobe -r "$KMOD_ZLIB_DEFLATE" >/dev/null 2>&1 217 fi 218 219 if modinfo "$KMOD_ZLIB_INFLATE">/dev/null 2>&1; then 220 modprobe -r "$KMOD_ZLIB_INFLATE" >/dev/null 2>&1 221 fi 222 223 if [ "$VERBOSE" = "yes" ]; then 224 echo "Successfully unloaded ZFS module stack" 225 fi 226 227 return 0 228} 229 230stack_clear_linux() { 231 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 232 STACK_TRACER_ENABLED=/proc/sys/kernel/stack_tracer_enabled 233 234 if [ "$STACK_TRACER" = "yes" ] && [ -e "$STACK_MAX_SIZE" ]; then 235 echo 1 >"$STACK_TRACER_ENABLED" 236 echo 0 >"$STACK_MAX_SIZE" 237 fi 238} 239 240stack_check_linux() { 241 STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size 242 STACK_TRACE=/sys/kernel/debug/tracing/stack_trace 243 STACK_LIMIT=15362 244 245 if [ -e "$STACK_MAX_SIZE" ]; then 246 STACK_SIZE=$(cat "$STACK_MAX_SIZE") 247 248 if [ "$STACK_SIZE" -ge "$STACK_LIMIT" ]; then 249 echo 250 echo "Warning: max stack size $STACK_SIZE bytes" 251 cat "$STACK_TRACE" 252 fi 253 fi 254} 255 256if [ "$(id -u)" != 0 ]; then 257 echo "Must run as root" 258 exit 1 259fi 260 261UNAME=$(uname -s) 262 263if [ "$UNLOAD" = "yes" ]; then 264 kill_zed 265 umount -t zfs -a 266 case $UNAME in 267 FreeBSD) 268 unload_modules_freebsd 269 ;; 270 Linux) 271 stack_check_linux 272 unload_modules_linux 273 ;; 274 esac 275fi 276if [ "$LOAD" = "yes" ]; then 277 case $UNAME in 278 FreeBSD) 279 load_modules_freebsd 280 ;; 281 Linux) 282 stack_clear_linux 283 check_modules_linux 284 load_modules_linux "$@" 285 udevadm trigger 286 udevadm settle 287 ;; 288 esac 289fi 290 291exit 0 292