[libvirt] [PATCH 2/3] Implementation deficiency in virInitctlSetRunLevel v2

Implement fork & setns for lxcDomainShutdownFlags --- src/lxc/lxc_driver.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c499182..9d200b2 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2619,6 +2619,50 @@ lxcDomainShutdownFlags(virDomainPtr dom, goto cleanup; } +#ifdef HAVE_SETNS + if (flags == 0 || flags & VIR_DOMAIN_SHUTDOWN_INITCTL) { + int pid = -1; + int status = -1; + int mfd = -1; + + if (virAsprintf(&vroot, "/proc/%llu/ns/mnt", + (unsigned long long)priv->initpid) < 0) { + goto cleanup; + } + + if ((mfd = open(vroot, O_RDONLY)) < 0) { + virReportSystemError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Kernel does not provide mount namespace")); + goto cleanup; + } + + switch (pid = fork()) { + case 0: + if (setns(mfd, 0) == -1) { + exit(-1); + } + rc = virInitctlSetRunLevel(VIR_INITCTL_RUNLEVEL_POWEROFF, NULL); + exit(rc); + break; + case -1: + virReportSystemError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fork failed")); + goto cleanup; + default: + if (waitpid(pid, &status, 0) < 0 || status < 0) { + virReportSystemError(errno, + _("Sending shutdown failed with status %i"), + status); + rc = 0; + } else { + rc = status; + } + close(mfd); + } + } else { + rc = 0; + } +#else if (virAsprintf(&vroot, "/proc/%llu/root", (unsigned long long)priv->initpid) < 0) goto cleanup; @@ -2638,6 +2682,7 @@ lxcDomainShutdownFlags(virDomainPtr dom, } else { rc = 0; } +#endif if (rc == 0 && (flags == 0 || -- 1.7.10.4

On Thu, Dec 19, 2013 at 08:07:50PM +0400, Reco wrote:
Implement fork & setns for lxcDomainShutdownFlags
--- src/lxc/lxc_driver.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c499182..9d200b2 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2619,6 +2619,50 @@ lxcDomainShutdownFlags(virDomainPtr dom, goto cleanup; }
+#ifdef HAVE_SETNS + if (flags == 0 || flags & VIR_DOMAIN_SHUTDOWN_INITCTL) { + int pid = -1; + int status = -1; + int mfd = -1; + + if (virAsprintf(&vroot, "/proc/%llu/ns/mnt", + (unsigned long long)priv->initpid) < 0) { + goto cleanup; + } + + if ((mfd = open(vroot, O_RDONLY)) < 0) { + virReportSystemError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Kernel does not provide mount namespace")); + goto cleanup; + } + + switch (pid = fork()) { + case 0: + if (setns(mfd, 0) == -1) { + exit(-1); + } + rc = virInitctlSetRunLevel(VIR_INITCTL_RUNLEVEL_POWEROFF, NULL); + exit(rc); + break; + case -1: + virReportSystemError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fork failed")); + goto cleanup; + default: + if (waitpid(pid, &status, 0) < 0 || status < 0) { + virReportSystemError(errno, + _("Sending shutdown failed with status %i"), + status); + rc = 0; + } else { + rc = status; + } + close(mfd); + } + } else { + rc = 0; + }
Since this is a fairly tedious large piece of code I think it is worth hiding it in a helper function. I'd suggest that in the src/util/virprocess.{c,h} file we create a typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque); virProcessRunInMountNamespace(pid_t pid, virProcessNamespaceCallback cb, void *opaque) This lxcDomainShutdownFlags code would then use that and pass a callback function which does the virInitctlSetRunLevel() API call. That should reduce the code size significantly, since we also need to fix all the other places in this file which use /proc/$PID/root. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Reco