diff --git a/install.ps1 b/install.ps1 index 1482bf574f..e2d69390f6 100644 --- a/install.ps1 +++ b/install.ps1 @@ -2153,13 +2153,10 @@ exit 0 substep "in an ADMINISTRATOR PowerShell run: wsl --install" "Cyan" substep "reboot, then re-run: irm https://unsloth.ai/install.ps1 | iex" "Cyan" } - # Deferred until reboot: restore any rolled-aside previous venv and signal not-complete. - # `exit 1` for -File (plain return exits 0); under `irm | iex` (no $PSCommandPath) return, - # since exit would kill the user's shell. - Restore-StudioVenvRollback - $global:LASTEXITCODE = 1 - if ($PSCommandPath) { exit 1 } - return + # Deferred until reboot: signal not-complete through Exit-InstallFailure + # (restores the rolled-aside venv, exits 1 for -File, throws under iex so + # -Command automation cannot see a deferred setup as success). + return (Exit-InstallFailure "WSL setup deferred: enable WSL2 and reboot, then re-run the installer") } $distro = if ($env:UNSLOTH_WSL_DISTRO) { $env:UNSLOTH_WSL_DISTRO } else { "Ubuntu-24.04" } @@ -2252,6 +2249,11 @@ exit 0 # below requires it, so a run that dies mid-install can no longer coast on # a stale venv passing the torch/CLI probes. $_fwdEnv += 'export UNSLOTH_SKIP_WSL_WINDOWS_SHORTCUT=1; mkdir -p /root/.unsloth; touch /root/.unsloth/.skip-wsl-windows-shortcut; rm -f /root/.unsloth/.install-ok; ' + # Root login shells reset PATH via /etc/profile and can drop /usr/lib/wsl/lib, + # the only nvidia-smi location under WSL2 GPU-PV; without it install.sh's GPU + # detection picks CPU torch wheels and the torch.cuda probe then fails the + # whole install. Appended (not prepended) so a PATH nvidia-smi still wins. + $_fwdEnv += 'export PATH="$PATH:/usr/lib/wsl/lib"; ' # Forward a non-default --package into the WSL install (already validated # against ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ at parse time, so splicing is safe); # previously it was silently dropped and the user got stock unsloth. @@ -2284,10 +2286,9 @@ exit 0 # probes below would only re-validate a stale venv from a previous install. if ($wslRc -eq 86) { step "wsl" "could not download install.sh inside WSL (network or bad ref) -- the installer never ran." "Yellow" - Restore-StudioVenvRollback - $global:LASTEXITCODE = 1 - if ($PSCommandPath) { exit 1 } - return + # Exit-InstallFailure restores the rollback and fails the process in every + # invocation mode (exit for -File, throw for iex/-Command automation). + return (Exit-InstallFailure "could not download install.sh inside WSL; the installer never ran") } # $wslRc can be non-zero from the llama.cpp prebuilt step even on success, so verify torch.cuda directly. $torchOk = $false @@ -2541,12 +2542,10 @@ exit 0 $global:LASTEXITCODE = 0 return } - # Failed (torch.cuda unavailable): restore any rolled-aside previous venv and report non-zero - # (plain return exits 0 for -File; under iex `exit` would kill the caller's shell). - Restore-StudioVenvRollback - $global:LASTEXITCODE = 1 - if ($PSCommandPath) { exit 1 } - return + # Failed (torch.cuda unavailable): Exit-InstallFailure restores the rolled-aside + # venv and fails the process in every invocation mode, so iex/-Command + # automation cannot read this as success. + return (Exit-InstallFailure "WSL Studio install did not finish cleanly (torch.cuda not detected; inner exit $wslRc)") } # ── GPU arch → newest compatible Windows ROCm wheel release ── diff --git a/install.sh b/install.sh index 17baa76550..0980f539a4 100755 --- a/install.sh +++ b/install.sh @@ -1554,6 +1554,11 @@ _has_usable_nvidia_gpu() { _nvsmi="" if command -v nvidia-smi >/dev/null 2>&1; then _nvsmi="nvidia-smi" + elif [ -x "/usr/lib/wsl/lib/nvidia-smi" ]; then + # WSL2 GPU-PV ships nvidia-smi ONLY here, and root login shells drop + # the dir from PATH; without this fallback the WSL install detects no + # NVIDIA GPU and picks CPU torch wheels. + _nvsmi="/usr/lib/wsl/lib/nvidia-smi" elif [ -x "/usr/bin/nvidia-smi" ]; then _nvsmi="/usr/bin/nvidia-smi" fi @@ -2074,6 +2079,9 @@ get_torch_index_url() { _nvidia_detected=1 if command -v nvidia-smi >/dev/null 2>&1; then _smi="nvidia-smi" + elif [ -x "/usr/lib/wsl/lib/nvidia-smi" ]; then + # Same WSL2 GPU-PV location fallback as _has_usable_nvidia_gpu. + _smi="/usr/lib/wsl/lib/nvidia-smi" elif [ -x "/usr/bin/nvidia-smi" ]; then _smi="/usr/bin/nvidia-smi" fi diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 index cbee753dbd..0b9ad96ae8 100644 --- a/scripts/uninstall.ps1 +++ b/scripts/uninstall.ps1 @@ -605,15 +605,18 @@ function Uninstall-UnslothStudio { if (Get-Command wsl.exe -ErrorAction SilentlyContinue) { try { # Probe candidates by exit code ('' = default distro) since `wsl --list` emits UTF-16 PS - # mis-parses. rm runs FIRST (the kills could SIGKILL this shell) and drops the dangling - # /root/.local/bin/unsloth symlink. Scope STRICTLY to /root (the fallback's install dir); - # /home/*/.unsloth may be another user's. The 8888 kill only targets a listener whose - # process cmdline is under /root/.unsloth (Studio's bind), so an unrelated service on 8888 - # -- Jupyter et al. default to it -- is NOT killed; it's also gated on an Unsloth install - # having existed (checked BEFORE rm deletes the marker). pkill matches argv containing - # /root/.unsloth/ (not bare names that would hit a user's own llama-server); the backslash - # + [h]-bracket in '/root/\.unslot[h]/' keep it from matching this command's own argv. - $_clean = '_had=0; if [ -d /root/.unsloth ] || [ -L /root/.local/bin/unsloth ]; then _had=1; fi; rm -rf /root/.unsloth /root/llama-cuda /root/provision_llama_cuda.sh /root/llama_cuda_build.log 2>/dev/null; rm -f /root/.local/bin/unsloth 2>/dev/null; if [ $_had -eq 1 ]; then for _p in $(fuser 8888/tcp 2>/dev/null); do grep -qa /root/\.unsloth/ /proc/$_p/cmdline 2>/dev/null && kill -9 $_p 2>/dev/null; done; fi; pkill -9 -f ''/root/\.unslot[h]/'' 2>/dev/null; true' + # mis-parses. Kills run BEFORE rm: a live CUDA build (cmake/nvcc under + # /root/.unsloth/llama.cpp) would otherwise keep burning CPU/GPU and recreate files after + # the rm. Each matched PID's whole process GROUP is signalled (cmake --build children carry + # relative argv no pattern can match), guarded against this shell's own pgid, plus direct + # children via pkill -P; this shell cannot self-match (its argv carries an extra backslash + # and the [h]-bracket in the pkill pattern). Scope STRICTLY to /root (the fallback's + # install dir); /home/*/.unsloth may be another user's. The 8888 kill only targets a + # listener whose process cmdline is under /root/.unsloth (Studio's bind), so an unrelated + # service on 8888 -- Jupyter et al. default to it -- is NOT killed; it's also gated on an + # Unsloth install having existed. /proc cmdline greps still work after kills since they + # read process state, not files. + $_clean = '_had=0; if [ -d /root/.unsloth ] || [ -L /root/.local/bin/unsloth ]; then _had=1; fi; _mypg=$(ps -o pgid= -p $$ 2>/dev/null | tr -d " "); for _p in $(pgrep -f ''/root/\.unslot[h]/'' 2>/dev/null); do _pg=$(ps -o pgid= -p $_p 2>/dev/null | tr -d " "); case "$_pg" in ""|0|1|"$_mypg") pkill -9 -P $_p 2>/dev/null; kill -9 $_p 2>/dev/null ;; *) kill -9 -- -$_pg 2>/dev/null || kill -9 $_p 2>/dev/null ;; esac; done; if [ $_had -eq 1 ]; then for _p in $(fuser 8888/tcp 2>/dev/null); do grep -qa /root/\.unsloth/ /proc/$_p/cmdline 2>/dev/null && kill -9 $_p 2>/dev/null; done; fi; rm -rf /root/.unsloth /root/llama-cuda /root/provision_llama_cuda.sh /root/llama_cuda_build.log 2>/dev/null; rm -f /root/.local/bin/unsloth 2>/dev/null; true' # Clean only distros with evidence of a fallback install: the wsl-distro.txt marker or an # explicit UNSLOTH_WSL_DISTRO. The broad candidate probe is only for legacy marker-less # installs (ARM64 only); on x86 it would delete distros this installer never touched diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index eb8512e758..137034e392 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -236,7 +236,7 @@ if command -v pkill >/dev/null 2>&1; then _pgid=$(ps -o pgid= -p "$_pid" 2>/dev/null | tr -d '[:space:]') case "$_pgid" in ''|0|1|"$_self_pgid") - pkill "-$_sig" -P "$_pid" 2>/dev/null + pkill "-$_sig" -P "$_pid" 2>/dev/null || true kill -s "$_sig" "$_pid" 2>/dev/null || true ;; *) kill -s "$_sig" -- "-$_pgid" 2>/dev/null \ || kill -s "$_sig" "$_pid" 2>/dev/null || true ;;