#!/bin/bash # ----------------------------------------------------------------------------------------------- # --------------------------------- inotify Tuning -------------------------------------------- # ----------------------------------------------------------------------------------------------- # Increases Linux inotify limits to prevent "too many open files" and inotify exhaustion. # Run once at array start via ARRAY_START_SCRIPTS in Master.conf. # # Why this matters: # Each Docker container that watches files (Sonarr, Radarr, Lidarr, NextCloud etc.) # consumes inotify instances and watches. unRAID defaults are very low — with many # containers running you can exhaust the limit silently, causing containers to miss # file events (new downloads not detected, library not updated etc.) # # max_user_instances = max number of inotify instances per user (default: 128) # max_user_watches = max number of files/dirs watched per instance (default: 8192) # max_queued_events = max events queued before dropping (default: 16384) # # These settings are lost on reboot — this script reapplies them at every array start. # All values configurable in Master.conf under unRAID Essentials. # ----------------------------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../Master.conf" source "$SCRIPT_DIR/../common.sh" parse_args "$@" # ----------------------------------------------------------------------------------------------- # ━━━ $ICON_GEAR Setup ━━━ # ----------------------------------------------------------------------------------------------- echo "" echo "━━━ $ICON_GEAR inotify Tuning ━━━" if [[ "$EUID" -ne 0 ]]; then error "Must be run as root" exit 1 fi success "Running as root" # ----------------------------------------------------------------------------------------------- # ━━━ Current Values ━━━ # ----------------------------------------------------------------------------------------------- CURRENT_INSTANCES=$(sysctl -n fs.inotify.max_user_instances 2>/dev/null || echo "?") CURRENT_WATCHES=$(sysctl -n fs.inotify.max_user_watches 2>/dev/null || echo "?") CURRENT_EVENTS=$(sysctl -n fs.inotify.max_queued_events 2>/dev/null || echo "?") info "Current: instances=$CURRENT_INSTANCES watches=$CURRENT_WATCHES queued=$CURRENT_EVENTS" info "Target: instances=${INOTIFY_MAX_INSTANCES} watches=${INOTIFY_MAX_WATCHES} queued=${INOTIFY_MAX_QUEUED_EVENTS}" if [[ "$SHOW_STATUS" == true ]]; then echo "" echo "━━━━━ $ICON_SUMMARY INOTIFY STATUS ━━━━━" echo " max_user_instances: $CURRENT_INSTANCES (target: ${INOTIFY_MAX_INSTANCES})" echo " max_user_watches: $CURRENT_WATCHES (target: ${INOTIFY_MAX_WATCHES})" echo " max_queued_events: $CURRENT_EVENTS (target: ${INOTIFY_MAX_QUEUED_EVENTS})" echo "" echo " Active inotify instances in use:" find /proc/*/fd -lname "anon_inode:inotify" 2>/dev/null | \ awk -F/ '{print $3}' | sort -u | while read -r pid; do cmd=$(cat /proc/$pid/comm 2>/dev/null || echo "?") echo " PID $pid ($cmd)" done | head -20 echo "━━━━━━━━━━━━━━━━━━━━━━━" exit 0 fi # ----------------------------------------------------------------------------------------------- # ━━━ Apply Settings ━━━ # ----------------------------------------------------------------------------------------------- echo "" CHANGED=0 FAILED=0 apply_sysctl() { local key="$1" local value="$2" local current current=$(sysctl -n "$key" 2>/dev/null || echo 0) if [[ "$current" -eq "$value" ]]; then success "$key = $value (already set)" return fi if [[ "$DRY_RUN" == true ]]; then warn "DRY RUN — would set $key = $value (currently $current)" return fi if sysctl -w "${key}=${value}" >/dev/null 2>&1; then success "$key = $value (was $current)" ((CHANGED++)) else error "Failed to set $key = $value" ((FAILED++)) fi } apply_sysctl "fs.inotify.max_user_instances" "$INOTIFY_MAX_INSTANCES" apply_sysctl "fs.inotify.max_user_watches" "$INOTIFY_MAX_WATCHES" apply_sysctl "fs.inotify.max_queued_events" "$INOTIFY_MAX_QUEUED_EVENTS" # ----------------------------------------------------------------------------------------------- # ━━━ $ICON_SUMMARY Summary ━━━ # ----------------------------------------------------------------------------------------------- echo "" echo "━━━━━ $ICON_SUMMARY INOTIFY TUNING SUMMARY ━━━━━" echo " max_user_instances: $(sysctl -n fs.inotify.max_user_instances 2>/dev/null)" echo " max_user_watches: $(sysctl -n fs.inotify.max_user_watches 2>/dev/null)" echo " max_queued_events: $(sysctl -n fs.inotify.max_queued_events 2>/dev/null)" echo "" if [[ "$DRY_RUN" == true ]]; then echo "$ICON_WARN Status: DRY RUN — no changes made" elif [[ "$FAILED" -gt 0 ]]; then echo "$ICON_ERROR Status: $FAILED setting(s) failed" notify "inotify tuning failed on $(hostname) — $FAILED setting(s) could not be applied" "inotify Tuning" "warning" exit 1 elif [[ "$CHANGED" -gt 0 ]]; then echo "$ICON_DONE Status: $ICON_SUCCESS $CHANGED setting(s) applied" else echo "$ICON_DONE Status: $ICON_SUCCESS All settings already correct" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"