[PATCH v2 04/11] XML parsing for memory tunables

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Nikunj A. Dadhania <nikunj@xxxxxxxxxxxxxxxxxx>

Adding parsing code for memory tunables in the domain xml file

v2:
+ Fix typo min_guarantee

Signed-off-by: Nikunj A. Dadhania <nikunj@xxxxxxxxxxxxxxxxxx>
---
 src/conf/domain_conf.c     |   50 +++++++++++++++++++++++++++++++++++++-------
 src/conf/domain_conf.h     |   12 ++++++++---
 src/esx/esx_vmx.c          |   30 +++++++++++++-------------
 src/lxc/lxc_controller.c   |    2 +-
 src/lxc/lxc_driver.c       |   12 +++++------
 src/openvz/openvz_driver.c |    8 ++++---
 src/qemu/qemu_conf.c       |    8 ++++---
 src/qemu/qemu_driver.c     |   18 ++++++++--------
 src/test/test_driver.c     |   12 +++++------
 src/uml/uml_conf.c         |    2 +-
 src/uml/uml_driver.c       |   14 ++++++------
 11 files changed, 104 insertions(+), 64 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e05d5d7..0dd74e4 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4231,19 +4231,38 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     def->description = virXPathString("string(./description[1])", ctxt);
 
     /* Extract domain memory */
-    if (virXPathULong("string(./memory[1])", ctxt, &def->maxmem) < 0) {
+    if (virXPathULong("string(./memory[1])", ctxt, 
+                      &def->mem.max_balloon) < 0) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing memory element"));
         goto error;
     }
 
-    if (virXPathULong("string(./currentMemory[1])", ctxt, &def->memory) < 0)
-        def->memory = def->maxmem;
+    if (virXPathULong("string(./currentMemory[1])", ctxt, 
+                      &def->mem.cur_balloon) < 0)
+        def->mem.cur_balloon = def->mem.max_balloon;
 
     node = virXPathNode("./memoryBacking/hugepages", ctxt);
     if (node)
-        def->hugepage_backed = 1;
-
+        def->mem.hugepage_backed = 1;
+
+    /* Extract other memory tunables */
+    if (virXPathULong("string(./memtune/hard_limit)", ctxt, 
+                      &def->mem.hard_limit) < 0) 
+        def->mem.hard_limit = 0;
+    
+    if (virXPathULong("string(./memtune/soft_limit[1])", ctxt, 
+                      &def->mem.soft_limit) < 0)
+        def->mem.soft_limit = 0;
+
+    if (virXPathULong("string(./memtune/min_guarantee[1])", ctxt, 
+                      &def->mem.min_guarantee) < 0)
+        def->mem.min_guarantee = 0;
+
+    if (virXPathULong("string(./memtune/swap_hard_limit[1])", ctxt, 
+                      &def->mem.swap_hard_limit) < 0)
+        def->mem.swap_hard_limit = 0;
+    
     if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0)
         def->vcpus = 1;
 
@@ -6382,10 +6401,25 @@ char *virDomainDefFormat(virDomainDefPtr def,
         virBufferEscapeString(&buf, "  <description>%s</description>\n",
                               def->description);
 
-    virBufferVSprintf(&buf, "  <memory>%lu</memory>\n", def->maxmem);
+    virBufferVSprintf(&buf, "  <memory>%lu</memory>\n", def->mem.max_balloon);
     virBufferVSprintf(&buf, "  <currentMemory>%lu</currentMemory>\n",
-                      def->memory);
-    if (def->hugepage_backed) {
+                      def->mem.cur_balloon);
+    virBufferVSprintf(&buf, "  <memtune>\n");
+    if (def->mem.hard_limit) {
+        virBufferVSprintf(&buf, "    <hard_limit>%lu</hard_limit>\n", 
+                          def->mem.hard_limit);
+    }
+    if (def->mem.soft_limit) {
+        virBufferVSprintf(&buf, "    <soft_limit>%lu</soft_limit>\n", 
+                          def->mem.soft_limit);
+    }
+    if (def->mem.swap_hard_limit) {
+        virBufferVSprintf(&buf, "    <swap_hard_limit>%lu</swap_hard_limit>\n", 
+                          def->mem.swap_hard_limit);
+    }
+    virBufferVSprintf(&buf, "  </memtune>\n");
+
+    if (def->mem.hugepage_backed) {
         virBufferAddLit(&buf, "  <memoryBacking>\n");
         virBufferAddLit(&buf, "    <hugepages/>\n");
         virBufferAddLit(&buf, "  </memoryBacking>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7195c04..2ecc2af 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -864,9 +864,15 @@ struct _virDomainDef {
     char *name;
     char *description;
 
-    unsigned long memory;
-    unsigned long maxmem;
-    unsigned char hugepage_backed;
+    struct {
+        unsigned long max_balloon;
+        unsigned long cur_balloon;
+        unsigned long hugepage_backed;
+        unsigned long hard_limit;
+        unsigned long soft_limit;
+        unsigned long min_guarantee;
+        unsigned long swap_hard_limit;
+    } mem;
     unsigned long vcpus;
     int cpumasklen;
     char *cpumask;
diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
index 59eb3b2..6f1eb17 100644
--- a/src/esx/esx_vmx.c
+++ b/src/esx/esx_vmx.c
@@ -48,8 +48,8 @@ domain-xml                        <=>   vmx
 def->id = <value>                 <=>   ???                                     # not representable
 def->uuid = <value>               <=>   uuid.bios = "<value>"
 def->name = <value>               <=>   displayName = "<value>"
-def->maxmem = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
-def->memory = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->memory = def->maxmem
+def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
+def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
 def->vcpus = <value>              <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
 def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"
 
@@ -979,7 +979,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
         *tmp2 = '\0';
     }
 
-    /* vmx:memsize -> def:maxmem */
+    /* vmx:memsize -> def:mem.max_balloon */
     if (esxUtil_GetConfigLong(conf, "memsize", &memsize, 32, true) < 0) {
         goto cleanup;
     }
@@ -991,7 +991,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
         goto cleanup;
     }
 
-    def->maxmem = memsize * 1024; /* Scale from megabytes to kilobytes */
+    def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */
 
     /* vmx:sched.mem.max -> def:memory */
     if (esxUtil_GetConfigLong(conf, "sched.mem.max", &memory, memsize,
@@ -1003,10 +1003,10 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
         memory = memsize;
     }
 
-    def->memory = memory * 1024; /* Scale from megabytes to kilobytes */
+    def->mem.cur_balloon = memory * 1024; /* Scale from megabytes to kilobytes */
 
-    if (def->memory > def->maxmem) {
-        def->memory = def->maxmem;
+    if (def->mem.cur_balloon > def->mem.max_balloon) {
+        def->mem.cur_balloon = def->mem.max_balloon;
     }
 
     /* vmx:numvcpus -> def:vcpus */
@@ -2469,32 +2469,32 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
         virBufferVSprintf(&buffer, "annotation = \"%s\"\n", annotation);
     }
 
-    /* def:maxmem -> vmx:memsize */
-    if (def->maxmem <= 0 || def->maxmem % 4096 != 0) {
+    /* def:mem.max_balloon -> vmx:memsize */
+    if (def->mem.max_balloon <= 0 || def->mem.max_balloon % 4096 != 0) {
         ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Expecting domain XML entry 'memory' to be an unsigned "
                     "integer (multiple of 4096) but found %lld"),
-                  (unsigned long long)def->maxmem);
+                  (unsigned long long)def->mem.max_balloon);
         goto cleanup;
     }
 
     /* Scale from kilobytes to megabytes */
     virBufferVSprintf(&buffer, "memsize = \"%d\"\n",
-                      (int)(def->maxmem / 1024));
+                      (int)(def->mem.max_balloon / 1024));
 
     /* def:memory -> vmx:sched.mem.max */
-    if (def->memory < def->maxmem) {
-        if (def->memory <= 0 || def->memory % 1024 != 0) {
+    if (def->mem.cur_balloon < def->mem.max_balloon) {
+        if (def->mem.cur_balloon <= 0 || def->mem.cur_balloon % 1024 != 0) {
             ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML entry 'currentMemory' to be an "
                         "unsigned integer (multiple of 1024) but found %lld"),
-                      (unsigned long long)def->memory);
+                      (unsigned long long)def->mem.cur_balloon);
             goto cleanup;
         }
 
         /* Scale from kilobytes to megabytes */
         virBufferVSprintf(&buffer, "sched.mem.max = \"%d\"\n",
-                          (int)(def->memory / 1024));
+                          (int)(def->mem.cur_balloon / 1024));
     }
 
     /* def:vcpus -> vmx:numvcpus */
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 7dc51a5..82ecce0 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -102,7 +102,7 @@ static int lxcSetContainerResources(virDomainDefPtr def)
         goto cleanup;
     }
 
-    rc = virCgroupSetMemory(cgroup, def->maxmem);
+    rc = virCgroupSetMemory(cgroup, def->mem.max_balloon);
     if (rc != 0) {
         virReportSystemError(-rc,
                              _("Unable to set memory limit for domain %s"),
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 9a4843d..9e37906 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -500,7 +500,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
 
     if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
         info->cpuTime = 0;
-        info->memory = vm->def->memory;
+        info->memory = vm->def->mem.cur_balloon;
     } else {
         if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
             lxcError(VIR_ERR_INTERNAL_ERROR,
@@ -520,7 +520,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
         }
     }
 
-    info->maxMem = vm->def->maxmem;
+    info->maxMem = vm->def->mem.max_balloon;
     info->nrVirtCpu = 1;
     ret = 0;
 
@@ -580,7 +580,7 @@ static unsigned long lxcDomainGetMaxMemory(virDomainPtr dom) {
         goto cleanup;
     }
 
-    ret = vm->def->maxmem;
+    ret = vm->def->mem.max_balloon;
 
 cleanup:
     if (vm)
@@ -605,13 +605,13 @@ static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
         goto cleanup;
     }
 
-    if (newmax < vm->def->memory) {
+    if (newmax < vm->def->mem.cur_balloon) {
         lxcError(VIR_ERR_INVALID_ARG,
                          "%s", _("Cannot set max memory lower than current memory"));
         goto cleanup;
     }
 
-    vm->def->maxmem = newmax;
+    vm->def->mem.max_balloon = newmax;
     ret = 0;
 
 cleanup:
@@ -637,7 +637,7 @@ static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
         goto cleanup;
     }
 
-    if (newmem > vm->def->maxmem) {
+    if (newmem > vm->def->mem.max_balloon) {
         lxcError(VIR_ERR_INVALID_ARG,
                  "%s", _("Cannot set memory higher than max memory"));
         goto cleanup;
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index edef080..beee006 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -403,8 +403,8 @@ static int openvzDomainGetInfo(virDomainPtr dom,
         }
     }
 
-    info->maxMem = vm->def->maxmem;
-    info->memory = vm->def->memory;
+    info->maxMem = vm->def->mem.max_balloon;
+    info->memory = vm->def->mem.cur_balloon;
     info->nrVirtCpu = vm->def->vcpus;
     ret = 0;
 
@@ -934,8 +934,8 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml)
         }
     }
 
-    if (vm->def->memory > 0) {
-        if (openvzDomainSetMemoryInternal(vm, vm->def->memory) < 0) {
+    if (vm->def->mem.cur_balloon > 0) {
+        if (openvzDomainSetMemoryInternal(vm, vm->def->mem.cur_balloon) < 0) {
             openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                         _("Could not set memory size"));
              goto cleanup;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 7a37c70..731c554 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -3846,7 +3846,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
      * is set post-startup using the balloon driver. If balloon driver
      * is not supported, then they're out of luck anyway
      */
-    snprintf(memory, sizeof(memory), "%lu", def->maxmem/1024);
+    snprintf(memory, sizeof(memory), "%lu", def->mem.max_balloon/1024);
     snprintf(domid, sizeof(domid), "%d", def->id);
 
     ADD_ENV_LIT("LC_ALL=C");
@@ -3892,7 +3892,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
         ADD_ARG_LIT("-enable-kvm");
     ADD_ARG_LIT("-m");
     ADD_ARG_LIT(memory);
-    if (def->hugepage_backed) {
+    if (def->mem.hugepage_backed) {
         if (!driver->hugetlbfs_mount) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("hugetlbfs filesystem is not mounted"));
@@ -6119,7 +6119,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
     virUUIDGenerate(def->uuid);
 
     def->id = -1;
-    def->memory = def->maxmem = 64 * 1024;
+    def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
     def->vcpus = 1;
     def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
     def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
@@ -6234,7 +6234,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
                                 _("cannot parse memory level '%s'"), val);
                 goto error;
             }
-            def->memory = def->maxmem = mem * 1024;
+            def->mem.cur_balloon = def->mem.max_balloon = mem * 1024;
         } else if (STREQ(arg, "-smp")) {
             WANT_VALUE();
             if (qemuParseCommandLineSmp(def, val) < 0)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d6dd1da..17d4fbe 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3939,7 +3939,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
 
     DEBUG0("Setting initial memory amount");
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
-    if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
+    if (qemuMonitorSetBalloon(priv->mon, vm->def->mem.cur_balloon) < 0) {
         qemuDomainObjExitMonitorWithDriver(driver, vm);
         goto cleanup;
     }
@@ -4862,7 +4862,7 @@ static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
         goto cleanup;
     }
 
-    ret = vm->def->maxmem;
+    ret = vm->def->mem.max_balloon;
 
 cleanup:
     if (vm)
@@ -4893,7 +4893,7 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
         goto cleanup;
     }
 
-    if (newmem > vm->def->maxmem) {
+    if (newmem > vm->def->mem.max_balloon) {
         qemuReportError(VIR_ERR_INVALID_ARG,
                         "%s", _("cannot set memory higher than max memory"));
         goto cleanup;
@@ -4957,14 +4957,14 @@ static int qemudDomainGetInfo(virDomainPtr dom,
         }
     }
 
-    info->maxMem = vm->def->maxmem;
+    info->maxMem = vm->def->mem.max_balloon;
 
     if (virDomainObjIsActive(vm)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
 
         if ((vm->def->memballoon != NULL) &&
             (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
-            info->memory = vm->def->maxmem;
+            info->memory = vm->def->mem.max_balloon;
         } else if (!priv->jobActive) {
             if (qemuDomainObjBeginJob(vm) < 0)
                 goto cleanup;
@@ -4980,7 +4980,7 @@ static int qemudDomainGetInfo(virDomainPtr dom,
 
             if (err == 0)
                 /* Balloon not supported, so maxmem is always the allocation */
-                info->memory = vm->def->maxmem;
+                info->memory = vm->def->mem.max_balloon;
             else
                 info->memory = balloon;
 
@@ -4989,10 +4989,10 @@ static int qemudDomainGetInfo(virDomainPtr dom,
                 goto cleanup;
             }
         } else {
-            info->memory = vm->def->memory;
+            info->memory = vm->def->mem.cur_balloon;
         }
     } else {
-        info->memory = vm->def->memory;
+        info->memory = vm->def->mem.cur_balloon;
     }
 
     info->nrVirtCpu = vm->def->vcpus;
@@ -6774,7 +6774,7 @@ static char *qemudDomainDumpXML(virDomainPtr dom,
             if (err < 0)
                 goto cleanup;
             if (err > 0)
-                vm->def->memory = balloon;
+                vm->def->mem.cur_balloon = balloon;
             /* err == 0 indicates no balloon support, so ignore it */
         }
     }
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 3560a19..382d5a8 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -1681,8 +1681,8 @@ static int testGetDomainInfo (virDomainPtr domain,
     }
 
     info->state = privdom->state;
-    info->memory = privdom->def->memory;
-    info->maxMem = privdom->def->maxmem;
+    info->memory = privdom->def->mem.cur_balloon;
+    info->maxMem = privdom->def->mem.max_balloon;
     info->nrVirtCpu = privdom->def->vcpus;
     info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll  * 1000ll) + (tv.tv_usec * 1000ll));
     ret = 0;
@@ -1963,7 +1963,7 @@ static unsigned long testGetMaxMemory(virDomainPtr domain) {
         goto cleanup;
     }
 
-    ret = privdom->def->maxmem;
+    ret = privdom->def->mem.max_balloon;
 
 cleanup:
     if (privdom)
@@ -1989,7 +1989,7 @@ static int testSetMaxMemory(virDomainPtr domain,
     }
 
     /* XXX validate not over host memory wrt to other domains */
-    privdom->def->maxmem = memory;
+    privdom->def->mem.max_balloon = memory;
     ret = 0;
 
 cleanup:
@@ -2015,12 +2015,12 @@ static int testSetMemory(virDomainPtr domain,
         goto cleanup;
     }
 
-    if (memory > privdom->def->maxmem) {
+    if (memory > privdom->def->mem.max_balloon) {
         testError(VIR_ERR_INVALID_ARG, __FUNCTION__);
         goto cleanup;
     }
 
-    privdom->def->memory = memory;
+    privdom->def->mem.cur_balloon = memory;
     ret = 0;
 
 cleanup:
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index f2eaef5..33b2b04 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -502,7 +502,7 @@ int umlBuildCommandLine(virConnectPtr conn,
         }                                                               \
     } while (0)
 
-    snprintf(memory, sizeof(memory), "%luK", vm->def->memory);
+    snprintf(memory, sizeof(memory), "%luK", vm->def->mem.cur_balloon);
 
     ADD_ENV_LIT("LC_ALL=C");
 
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 50c8152..9003e9a 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -1420,7 +1420,7 @@ static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
                        _("no domain with matching uuid '%s'"), uuidstr);
         goto cleanup;
     }
-    ret = vm->def->maxmem;
+    ret = vm->def->mem.max_balloon;
 
 cleanup:
     if (vm)
@@ -1446,13 +1446,13 @@ static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
         goto cleanup;
     }
 
-    if (newmax < vm->def->memory) {
+    if (newmax < vm->def->mem.cur_balloon) {
         umlReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("cannot set max memory lower than current memory"));
         goto cleanup;
     }
 
-    vm->def->maxmem = newmax;
+    vm->def->mem.max_balloon = newmax;
     ret = 0;
 
 cleanup:
@@ -1485,13 +1485,13 @@ static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
         goto cleanup;
     }
 
-    if (newmem > vm->def->maxmem) {
+    if (newmem > vm->def->mem.max_balloon) {
         umlReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("cannot set memory higher than max memory"));
         goto cleanup;
     }
 
-    vm->def->memory = newmem;
+    vm->def->mem.cur_balloon = newmem;
     ret = 0;
 
 cleanup:
@@ -1528,8 +1528,8 @@ static int umlDomainGetInfo(virDomainPtr dom,
         }
     }
 
-    info->maxMem = vm->def->maxmem;
-    info->memory = vm->def->memory;
+    info->maxMem = vm->def->mem.max_balloon;
+    info->memory = vm->def->mem.cur_balloon;
     info->nrVirtCpu = vm->def->vcpus;
     ret = 0;
 

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]