1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-20 07:59:00 +00:00

lxc: Don't reboot host on virDomainReboot

If the container is really a simple one (init is just bash and
the whole root is passed through) then virDomainReboot and
virDomainShutdown will talk to the actual init within the host.
Therefore, 'virsh shutdown $dom' will result in shutting down the
host. True, at that point the container is shut down too but
looks a bit harsh to me.

The solution is to check if the init inside the container is or
is not the same as the init running on the host.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Michal Privoznik 2019-01-25 12:42:54 +01:00
parent 64eca3d5e3
commit 94fce25546
3 changed files with 96 additions and 15 deletions

View File

@ -32,6 +32,7 @@
#include "virfile.h"
#include "virtime.h"
#include "virsystemd.h"
#include "virinitctl.h"
#define VIR_FROM_THIS VIR_FROM_LXC
#define LXC_NAMESPACE_HREF "http://libvirt.org/schemas/domain/lxc/1.0"
@ -418,3 +419,92 @@ virLXCDomainGetMachineName(virDomainDefPtr def, pid_t pid)
return ret;
}
typedef struct _lxcDomainInitctlCallbackData lxcDomainInitctlCallbackData;
struct _lxcDomainInitctlCallbackData {
int runlevel;
bool *st_valid;
struct stat *st;
};
static int
lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
void *opaque)
{
lxcDomainInitctlCallbackData *data = opaque;
size_t i;
for (i = 0; virInitctlFifos[i]; i++) {
const char *fifo = virInitctlFifos[i];
struct stat cont_sb;
if (stat(fifo, &cont_sb) < 0) {
if (errno == ENOENT)
continue;
virReportSystemError(errno, _("Unable to stat %s"), fifo);
return -1;
}
/* Check if the init fifo is not the very one that's on
* the host. We don't want to change the host's runlevel.
*/
if (data->st_valid[i] &&
data->st[i].st_dev == cont_sb.st_dev &&
data->st[i].st_ino == cont_sb.st_ino)
continue;
return virInitctlSetRunLevel(fifo, data->runlevel);
}
/* If no usable fifo was found then declare success. Caller
* will try killing the domain with signal. */
return 0;
}
int
virLXCDomainSetRunlevel(virDomainObjPtr vm,
int runlevel)
{
virLXCDomainObjPrivatePtr priv = vm->privateData;
lxcDomainInitctlCallbackData data;
size_t nfifos = 0;
size_t i;
int ret = -1;
memset(&data, 0, sizeof(data));
data.runlevel = runlevel;
for (nfifos = 0; virInitctlFifos[nfifos]; nfifos++)
;
if (VIR_ALLOC_N(data.st, nfifos) < 0 ||
VIR_ALLOC_N(data.st_valid, nfifos) < 0)
goto cleanup;
for (i = 0; virInitctlFifos[i]; i++) {
const char *fifo = virInitctlFifos[i];
if (stat(fifo, &(data.st[i])) < 0) {
if (errno == ENOENT)
continue;
virReportSystemError(errno, _("Unable to stat %s"), fifo);
goto cleanup;
}
data.st_valid[i] = true;
}
ret = virProcessRunInMountNamespace(priv->initpid,
lxcDomainInitctlCallback,
&data);
cleanup:
VIR_FREE(data.st);
VIR_FREE(data.st_valid);
return ret;
}

View File

@ -109,4 +109,8 @@ virLXCDomainObjEndJob(virLXCDriverPtr driver,
char *
virLXCDomainGetMachineName(virDomainDefPtr def, pid_t pid);
int
virLXCDomainSetRunlevel(virDomainObjPtr vm,
int runlevel);
#endif /* LIBVIRT_LXC_DOMAIN_H */

View File

@ -3272,15 +3272,6 @@ lxcConnectListAllDomains(virConnectPtr conn,
}
static int
lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
void *opaque)
{
int *command = opaque;
return virInitctlSetRunLevel(NULL, *command);
}
static int
lxcDomainShutdownFlags(virDomainPtr dom,
unsigned int flags)
@ -3318,9 +3309,7 @@ lxcDomainShutdownFlags(virDomainPtr dom,
(flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
int command = VIR_INITCTL_RUNLEVEL_POWEROFF;
if ((rc = virProcessRunInMountNamespace(priv->initpid,
lxcDomainInitctlCallback,
&command)) < 0)
if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
goto endjob;
if (rc == 0 && flags != 0 &&
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
@ -3398,9 +3387,7 @@ lxcDomainReboot(virDomainPtr dom,
(flags & VIR_DOMAIN_REBOOT_INITCTL)) {
int command = VIR_INITCTL_RUNLEVEL_REBOOT;
if ((rc = virProcessRunInMountNamespace(priv->initpid,
lxcDomainInitctlCallback,
&command)) < 0)
if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
goto endjob;
if (rc == 0 && flags != 0 &&
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {