From b711bc3440322872aaca9db6ec3db60d9c88e3a3 Mon Sep 17 00:00:00 2001 From: Steve Mokris Date: Wed, 6 Apr 2022 20:04:19 -0400 Subject: [PATCH 1/2] Add workaround for 90 second LX systemd stop/reboot delay On SmartOS LX, systemd uses its "legacy cgroup hierarchy" (cgroup-v1) codepath, which does not signal when the root cgroup becomes empty, causing it to wait 90 seconds before continuing to shut down. This commit modifies vmadm to send the `systemd-shutdown` process SIGCHLD every second during a `vmadm stop` or `vmadm reboot` command, which causes `systemd-shutdown` to re-check its list of remaining processes, which removes the unnecessary wait. --- src/vm/node_modules/VM.js | 40 +++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/vm/node_modules/VM.js b/src/vm/node_modules/VM.js index e75f44478..8eeb89188 100644 --- a/src/vm/node_modules/VM.js +++ b/src/vm/node_modules/VM.js @@ -17641,11 +17641,16 @@ function doShutdownStop(vmobj, options, callback) cb(); }); }, function waitInstalled(cb) { - VM.waitForZoneState(vmobj, 'installed', {timeout: STOP_TIMEOUT}, - function shutdownWaitCb(err) { - - if (err && err.hasOwnProperty('code') - && err.code === 'ETIMEOUT') { + var stop_timeout = Date.now(0) + STOP_TIMEOUT * 1000; + var ival = setInterval(function () { + // Every second, tell `systemd-shutdown` to re-check + // its list of remaining processes. + // (By default, `systemd-shutdown` waits 90 seconds + // for a root cgroup SIGCHLD that is never sent.) + killSig(vmobj.pid, 'SIGCHLD'); + + if (Date.now(0) > stop_timeout) { + clearInterval(ival); log.info('Timeout waiting for shutdown to complete; ' + 'halting.'); @@ -17660,10 +17665,22 @@ function doShutdownStop(vmobj, options, callback) } cb(_err); }); - return; } - cb(err); - }); + + var load_opts = {fields: ['zone_state'], log: log}; + vmload.getVmobj(vmobj.uuid, load_opts, function (_err, vmobj) { + if (_err) { + log.warn({err: _err, stdout: fds.stdout, + stderr: fds.stderr}, 'Error checking status while halting zone'); + return; + } + + if (vmobj.zone_state == 'installed') { + clearInterval(ival); + cb(); + } + }); + }, 1000); }, function zonecfgNoAutoboot(cb) { zonecfg(vmobj.uuid, [unset_autoboot], {log: log}, function (err, fds) { @@ -18213,6 +18230,13 @@ function doReboot(vmobj, options, callback) } ticks = 180 * 10; // (180 * 10) 100ms ticks = 3m ival = setInterval(function () { + if (ticks % 10 == 0) { + // Every second, tell `systemd-shutdown` to re-check + // its list of remaining processes. + // (By default, `systemd-shutdown` waits 90 seconds + // for a root cgroup SIGCHLD that is never sent.) + killSig(vmobj.pid, 'SIGCHLD'); + } if (reboot_complete) { log.debug('reboot marked complete, cleaning up'); clearInterval(ival); From ed6eb46468950a0aaf9d0c88d071c95c527f3ba4 Mon Sep 17 00:00:00 2001 From: Steve Mokris Date: Wed, 6 Apr 2022 21:40:06 -0400 Subject: [PATCH 2/2] Ensure vmobj.pid is systemd-shutdown before sending SIGCHLD --- src/vm/node_modules/VM.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/vm/node_modules/VM.js b/src/vm/node_modules/VM.js index 8eeb89188..96e680716 100644 --- a/src/vm/node_modules/VM.js +++ b/src/vm/node_modules/VM.js @@ -17647,7 +17647,12 @@ function doShutdownStop(vmobj, options, callback) // its list of remaining processes. // (By default, `systemd-shutdown` waits 90 seconds // for a root cgroup SIGCHLD that is never sent.) - killSig(vmobj.pid, 'SIGCHLD'); + fs.readlink('/proc/' + vmobj.pid + '/path/a.out', + function (err, link) { + if (!err && jsprim.endsWith(link, '/systemd-shutdown')) { + killSig(vmobj.pid, 'SIGCHLD'); + } + }); if (Date.now(0) > stop_timeout) { clearInterval(ival); @@ -18235,7 +18240,12 @@ function doReboot(vmobj, options, callback) // its list of remaining processes. // (By default, `systemd-shutdown` waits 90 seconds // for a root cgroup SIGCHLD that is never sent.) - killSig(vmobj.pid, 'SIGCHLD'); + fs.readlink('/proc/' + vmobj.pid + '/path/a.out', + function (err, link) { + if (!err && jsprim.endsWith(link, '/systemd-shutdown')) { + killSig(vmobj.pid, 'SIGCHLD'); + } + }); } if (reboot_complete) { log.debug('reboot marked complete, cleaning up');