Add the qemu-nbd tasks to the container cgroup to make sure those will
be killed when the container is stopped. In order to reliably get the
qemu-nbd tasks PIDs, we use /sys/devices/virtual/block/<DEV>/pid as
qemu-nbd is daemonizing itself.
---
src/libvirt_private.syms | 1 +
src/lxc/lxc_controller.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
src/util/virprocess.c | 45 ++++++++++++++++++++++++++++++++++++++
src/util/virprocess.h | 2 ++
4 files changed, 104 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8c50ea2..409bb4f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1973,6 +1973,7 @@ virProcessAbort;
virProcessExitWithStatus;
virProcessGetAffinity;
virProcessGetNamespaces;
+virProcessGetPids;
virProcessGetStartTime;
virProcessKill;
virProcessKillPainfully;
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index e144c2d..14d873e 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -107,6 +107,9 @@ struct _virLXCController {
pid_t initpid;
+ size_t nnbdpids;
+ pid_t *nbdpids;
+
size_t nveths;
char **veths;
@@ -283,6 +286,8 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl)
virObjectUnref(ctrl->server);
virLXCControllerFreeFuse(ctrl);
+ VIR_FREE(ctrl->nbdpids);
+
virCgroupFree(&ctrl->cgroup);
/* This must always be the last thing to be closed */
@@ -471,6 +476,9 @@ static int virLXCControllerSetupNBDDeviceFS(virDomainFSDefPtr fs)
return -1;
}
+ /* The NBD device will be cleaned up while the cgroup will end.
+ * For this we need to remember the qemu-nbd pid and add it to
+ * the cgroup*/
if (virFileNBDDeviceAssociate(fs->src,
fs->format,
fs->readonly,
@@ -503,6 +511,9 @@ static int virLXCControllerSetupNBDDeviceDisk(virDomainDiskDefPtr
disk)
return -1;
}
+ /* The NBD device will be cleaned up while the cgroup will end.
+ * For this we need to remember the qemu-nbd pid and add it to
+ * the cgroup*/
if (virFileNBDDeviceAssociate(src,
format,
disk->src->readonly,
@@ -525,6 +536,38 @@ static int virLXCControllerSetupNBDDeviceDisk(virDomainDiskDefPtr
disk)
return 0;
}
+static int virLXCControllerAppendNBDPids(virLXCControllerPtr ctrl,
+ const char *dev)
+{
+ char *pidpath = NULL;
+ pid_t *pids;
+ size_t npids;
+ size_t i;
+ int ret = -1;
+ pid_t pid;
+
+ if (!STRPREFIX(dev, "/dev/") ||
+ virAsprintf(&pidpath, "/sys/devices/virtual/block/%s/pid", dev + 5)
< 0)
+ goto cleanup;
+
+ if (virPidFileReadPath(pidpath, &pid) < 0)
+ goto cleanup;
+
+ if (virProcessGetPids(pid, &npids, &pids) < 0)
+ goto cleanup;
+
+ for (i = 0; i < npids; i++) {
+ if (VIR_APPEND_ELEMENT(ctrl->nbdpids, ctrl->nnbdpids, pids[i]) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(pids);
+ VIR_FREE(pidpath);
+ return ret;
+}
static int virLXCControllerSetupLoopDevices(virLXCControllerPtr ctrl)
{
@@ -570,6 +613,9 @@ static int virLXCControllerSetupLoopDevices(virLXCControllerPtr ctrl)
} else if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_NBD) {
if (virLXCControllerSetupNBDDeviceFS(fs) < 0)
goto cleanup;
+
+ if (virLXCControllerAppendNBDPids(ctrl, fs->src) < 0)
+ goto cleanup;
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("fs driver %s is not supported"),
@@ -629,6 +675,9 @@ static int virLXCControllerSetupLoopDevices(virLXCControllerPtr ctrl)
}
if (virLXCControllerSetupNBDDeviceDisk(disk) < 0)
goto cleanup;
+
+ if (virLXCControllerAppendNBDPids(ctrl, virDomainDiskGetSource(disk)) <
0)
+ goto cleanup;
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk driver %s is not supported"),
@@ -781,6 +830,7 @@ static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr
ctrl)
virBitmapPtr auto_nodeset = NULL;
int ret = -1;
virBitmapPtr nodeset = NULL;
+ size_t i;
VIR_DEBUG("Setting up cgroup resource limits");
@@ -798,6 +848,12 @@ static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr
ctrl)
if (virCgroupAddTask(ctrl->cgroup, getpid()) < 0)
goto cleanup;
+ /* Add all qemu-nbd tasks to the cgroup */
+ for (i = 0; i < ctrl->nnbdpids; i++) {
+ if (virCgroupAddTask(ctrl->cgroup, ctrl->nbdpids[i]) < 0)
+ goto cleanup;
+ }
+
if (virLXCCgroupSetup(ctrl->def, ctrl->cgroup, nodeset) < 0)
goto cleanup;
diff --git a/src/util/virprocess.c b/src/util/virprocess.c
index 7a79970..8b4b32f 100644
--- a/src/util/virprocess.c
+++ b/src/util/virprocess.c
@@ -607,6 +607,51 @@ int virProcessGetAffinity(pid_t pid ATTRIBUTE_UNUSED,
}
#endif /* HAVE_SCHED_GETAFFINITY */
+int virProcessGetPids(pid_t pid, size_t *npids, pid_t **pids)
+{
+ int ret = -1;
+ char *taskPath = NULL;
+ DIR *dir = NULL;
+ int value;
+ struct dirent *ent;
+
+ *npids = 0;
+ *pids = NULL;
+
+ if (virAsprintf(&taskPath, "/proc/%llu/task",
+ (unsigned long long)pid) < 0)
+ goto cleanup;
+
+ if (!(dir = opendir(taskPath)))
+ goto cleanup;
+
+ while ((value = virDirRead(dir, &ent, taskPath)) > 0) {
+ pid_t tmp_pid;
+
+ /* Skip . and .. */
+ if (STRPREFIX(ent->d_name, "."))
+ continue;
+
+ if (virStrToLong_i(ent->d_name, NULL, 10, &tmp_pid) < 0)
+ goto cleanup;
+
+ if (VIR_APPEND_ELEMENT(*pids, *npids, tmp_pid) < 0)
+ goto cleanup;
+ }
+
+ if (value < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ if (!dir)
+ closedir(dir);
+ VIR_FREE(taskPath);
+ if (ret < 0)
+ VIR_FREE(*pids);
+ return ret;
+}
int virProcessGetNamespaces(pid_t pid,
size_t *nfdlist,
diff --git a/src/util/virprocess.h b/src/util/virprocess.h
index c812882..86a633d 100644
--- a/src/util/virprocess.h
+++ b/src/util/virprocess.h
@@ -62,6 +62,8 @@ int virProcessGetAffinity(pid_t pid,
virBitmapPtr *map,
int maxcpu);
+int virProcessGetPids(pid_t pid, size_t *npids, pid_t **pids);
+
int virProcessGetStartTime(pid_t pid,
unsigned long long *timestamp);
--
2.1.4