[libvirt] [PATCH] lxc: properly clean up qemu-nbd

Cédric Bosdonnat cbosdonnat at suse.com
Wed May 27 08:56:06 UTC 2015


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




More information about the libvir-list mailing list