fix: prerm kill sweep must not kill its own ancestors
`ps | grep '/usr/bin/tachyon'` matches the hook itself, because /usr/bin/tachyon is what invoked it. The sweep therefore killed its own parent, the parent died on SIGKILL, and apk saw `tachyon-<version>.pre-upgrade: exited with error 247` (128+119) and reported a failed hook. The sweep now walks /proc/<pid>/stat to collect its own ancestor chain and skips those pids. Holders of procd's serialization lock are also cleared by descriptor rather than by name. procd_lock() does `exec 1000>` on /var/lock/procd_tachyon.lock and then `flock 1000` with no -w, so any background spawn inheriting fd 1000 keeps the lock held. On a live router the holders were watchdog workers, logread, the zapret2 supervisors, nfqws2 and a stray curl — none of which match a tachyon name pattern. While any of them lives, every init.d call blocks in flock until the package manager gives up on the hook. Same descriptor-based sweep added to install.sh, which faces the same lock left behind by pre-fix builds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
547f42e92d
commit
4ce5d7ebac
+22
@@ -1206,6 +1206,28 @@ function installer_release_init_lock() {
|
||||
for (let pattern in [ "99-tachyon-wan|flock 1000", "/etc/init.d/tachyon" ])
|
||||
system("ps 2>/dev/null | grep -E '" + pattern + "' | grep -v grep | awk '{print $1}' | " +
|
||||
"while read _pid; do kill -9 \"$_pid\" 2>/dev/null; done; true");
|
||||
|
||||
// Killing by name is not enough. procd_lock() does `exec 1000>` on
|
||||
// /var/lock/procd_tachyon.lock and then `flock 1000` with no -w, and every
|
||||
// background spawn that inherits descriptor 1000 keeps the lock held long after
|
||||
// the init script that took it exited. Builds up to 1.2.66 swept /proc/self/fd
|
||||
// only as far as 999 and so missed exactly that descriptor — on a live router
|
||||
// eleven unrelated processes (watchdog workers, logread, the zapret2 supervisors,
|
||||
// nfqws2, a stray curl) were found pinning it. None of them match a tachyon name
|
||||
// pattern, so the holders are cleared by descriptor. While any of them lives, the
|
||||
// old pre-upgrade hook blocks in flock until the package manager kills it and
|
||||
// rolls the whole transaction back.
|
||||
//
|
||||
// The installer's own process tree is skipped: this runs as a child of
|
||||
// /usr/bin/tachyon on an upgrade, and killing an ancestor takes the install down.
|
||||
system("__anc=\" \"; __p=$$; " +
|
||||
"while [ -n \"$__p\" ] && [ \"$__p\" -gt 1 ] 2>/dev/null; do " +
|
||||
"__anc=\"$__anc$__p \"; " +
|
||||
"__p=$(awk '{ sub(/.*\\) /, \"\"); print $2 }' \"/proc/$__p/stat\" 2>/dev/null); done; " +
|
||||
"for __f in /proc/[0-9]*; do [ -e \"$__f/fd/1000\" ] || continue; " +
|
||||
"case \"$(readlink \"$__f/fd/1000\" 2>/dev/null)\" in *procd_tachyon*) " +
|
||||
"__pid=${__f##*/}; case \"$__anc\" in *\" $__pid \"*) continue;; esac; " +
|
||||
"kill -9 \"$__pid\" 2>/dev/null;; esac; done; true");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user