diff --git a/Makefile b/Makefile index 972f671f..ad81be40 100755 --- a/Makefile +++ b/Makefile @@ -167,6 +167,8 @@ install: precheck $(SM_STAGING)/$(SYSTEMD_SERVICE_DIR) install -m 644 systemd/sr_health_check.timer \ $(SM_STAGING)/$(SYSTEMD_SERVICE_DIR) + install -m 644 systemd/SMGC@.service \ + $(SM_STAGING)/$(SYSTEMD_SERVICE_DIR) for i in $(UDEV_RULES); do \ install -m 644 udev/$$i.rules \ $(SM_STAGING)$(UDEV_RULES_DIR); done diff --git a/drivers/FileSR.py b/drivers/FileSR.py index cceecc02..ba9b1863 100755 --- a/drivers/FileSR.py +++ b/drivers/FileSR.py @@ -379,7 +379,7 @@ def _process_replay(self, data): def _kickGC(self): util.SMlog("Kicking GC") - cleanup.start_gc(self.session, self.uuid) + cleanup.start_gc_service(self.uuid) def _isbind(self): # os.path.ismount can't deal with bind mount diff --git a/drivers/LVHDSR.py b/drivers/LVHDSR.py index 2c7bec15..c710790c 100755 --- a/drivers/LVHDSR.py +++ b/drivers/LVHDSR.py @@ -892,7 +892,7 @@ def _handleInterruptedCoalesceLeaf(self): entries = self.journaler.getAll(cleanup.VDI.JRN_LEAF) if len(entries) > 0: util.SMlog("*** INTERRUPTED COALESCE-LEAF OP DETECTED ***") - cleanup.gc_force(self.session, self.uuid) + cleanup.start_gc_service(self.uuid) self.lvmCache.refresh() def _handleInterruptedCloneOp(self, origUuid, jval, forceUndo=False): @@ -1290,7 +1290,7 @@ def _prepareTestMode(self): def _kickGC(self): util.SMlog("Kicking GC") - cleanup.start_gc(self.session, self.uuid) + cleanup.start_gc_service(self.uuid) def ensureCBTSpace(self): # Ensure we have space for at least one LV diff --git a/drivers/cleanup.py b/drivers/cleanup.py index 6f9917b7..6c9c356b 100755 --- a/drivers/cleanup.py +++ b/drivers/cleanup.py @@ -3206,6 +3206,10 @@ def gc(session, srUuid, inBackground, dryRun=False): def start_gc(session, sr_uuid): + """ + This function is used to try to start a backgrounded GC session by forking + the current process. If using the systemd version, call start_gc_service() instead. + """ # don't bother if an instance already running (this is just an # optimization to reduce the overhead of forking a new process if we # don't have to, but the process will check the lock anyways) @@ -3230,6 +3234,16 @@ def start_gc(session, sr_uuid): subprocess.run([__file__, '-b', '-u', sr_uuid, '-g'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) +def start_gc_service(sr_uuid): + """ + This starts the templated systemd service which runs GC on the given SR UUID. + If the service was already started, this is a no-op. + """ + sr_uuid_esc = sr_uuid.replace("-", "\\x2d") + util.SMlog(f"Kicking SMGC@{sr_uuid}...") + subprocess.run(["/usr/bin/systemctl", "--quiet", "--no-block", "start", f"SMGC@{sr_uuid_esc}"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + def gc_force(session, srUuid, force=False, dryRun=False, lockSR=False): """Garbage collect all deleted VDIs in SR "srUuid". The caller must ensure diff --git a/mk/sm.spec.in b/mk/sm.spec.in index dc7661d3..faee7bf1 100755 --- a/mk/sm.spec.in +++ b/mk/sm.spec.in @@ -212,6 +212,7 @@ tests/run_python_unittests.sh %{_unitdir}/usb-scan.socket %{_unitdir}/mpathcount.service %{_unitdir}/mpathcount.socket +%{_unitdir}/SMGC@.service %config /etc/udev/rules.d/65-multipath.rules %config /etc/udev/rules.d/55-xs-mpath-scsidev.rules %config /etc/udev/rules.d/58-xapi.rules diff --git a/systemd/SMGC@.service b/systemd/SMGC@.service new file mode 100644 index 00000000..54ab1b7d --- /dev/null +++ b/systemd/SMGC@.service @@ -0,0 +1,12 @@ +[Unit] +Description=Garbage Collector for SR %I +DefaultDependencies=no + +[Service] +Type=oneshot +Restart=no +ExecStart=/opt/xensource/sm/cleanup.py -g -u %I +# This is the default, but just to make it clear we may run this +# service multiple times. When running, it will show as "activating"; +# when not running, it will show as "dead" +RemainAfterExit=no