]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add support for RAM filesystems for LXC
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 8 May 2012 16:50:48 +0000 (17:50 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 25 Jun 2012 09:17:56 +0000 (10:17 +0100)
Introduce a new syntax for filesystems to allow use of a RAM
filesystem

   <filesystem type='ram'>
      <source usage='10' units='MiB'/>
      <target dir='/mnt'/>
   </filesystem>

The usage units default to KiB to limit consumption of host memory.

* docs/formatdomain.html.in: Document new syntax
* docs/schemas/domaincommon.rng: Add new attributes
* src/conf/domain_conf.c: Parsing/formatting of RAM filesystems
* src/lxc/lxc_container.c: Mounting of RAM filesystems

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/lxc/lxc_container.c

index e1c0af52243353740fcc400062eea1a63a9d2ee9..c13916ae2b8c5a13474c9d6be3c05d346ee5579c 100644 (file)
         </dd>
         <dt><code>type='file'</code></dt>
         <dd>
-        Currently unused.
+        A host file will be treated as an image and mounted in
+        the guest. The filesystem format will be autodetected.
+        Only used by LXC driver.
         </dd>
         <dt><code>type='block'</code></dt>
         <dd>
         format will be autodetected. Only used by LXC driver
         <span class="since">(since 0.9.5)</span>.
         </dd>
+        <dt><code>type='ram'</code></dt>
+        <dd>
+          An in-memory filesystem, using memory from the host OS.
+          The source element has a single attribute <code>usage</code>
+          which gives the memory usage limit in kibibytes. Only used
+          by LXC driver.
+          <span class="since"> (since 0.9.13)</span></dd>
         </dl>
 
       The filesystem block has an optional attribute <code>accessmode</code>
         The resource on the host that is being accessed in the guest. The
         <code>name</code> attribute must be used with
         <code>type='template'</code>, and the <code>dir</code> attribute must
-        be used with <code>type='mount'</code>
+        be used with <code>type='mount'</code>. The <code>usage</code> attribute
+        is used with <code>type='ram'</code> to set the memory limit in KB.
       </dd>
 
       <dt><code>target</code></dt>
index 86306252d8b72087ee809051d1aad3f09da40f53..7f0cfe89cf6b4414312efd5a6bb5593fc5a8e385 100644 (file)
             </element>
           </interleave>
         </group>
+        <group>
+          <attribute name="type">
+            <value>ram</value>
+          </attribute>
+          <interleave>
+            <element name="source">
+              <attribute name="usage">
+                <ref name="unsignedLong"/>
+              </attribute>
+              <optional>
+                <attribute name='unit'>
+                  <ref name='unit'/>
+                </attribute>
+              </optional>
+              <empty/>
+            </element>
+          </interleave>
+        </group>
       </choice>
       <interleave>
         <element name="target">
index 46517652b8a7995fb596c3da8cb715f8cd9673c9..774334068c586cb1aa08ae53103098f53b67792b 100644 (file)
@@ -264,7 +264,8 @@ VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
               "mount",
               "block",
               "file",
-              "template")
+              "template",
+              "ram")
 
 VIR_ENUM_IMPL(virDomainFSDriverType, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
               "default",
@@ -4213,6 +4214,8 @@ virDomainFSDefParseXML(xmlNodePtr node,
     char *target = NULL;
     char *accessmode = NULL;
     char *wrpolicy = NULL;
+    char *usage = NULL;
+    char *unit = NULL;
 
     ctxt->node = node;
 
@@ -4269,6 +4272,10 @@ virDomainFSDefParseXML(xmlNodePtr node,
                     source = virXMLPropString(cur, "dev");
                 else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
                     source = virXMLPropString(cur, "name");
+                else if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
+                    usage = virXMLPropString(cur, "usage");
+                    unit = virXMLPropString(cur, "unit");
+                }
             } else if (!target &&
                        xmlStrEqual(cur->name, BAD_CAST "target")) {
                 target = virXMLPropString(cur, "dir");
@@ -4300,7 +4307,8 @@ virDomainFSDefParseXML(xmlNodePtr node,
         def->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
     }
 
-    if (source == NULL) {
+    if (source == NULL &&
+        def->type != VIR_DOMAIN_FS_TYPE_RAM) {
         virDomainReportError(VIR_ERR_NO_SOURCE,
                              target ? "%s" : NULL, target);
         goto error;
@@ -4312,6 +4320,25 @@ virDomainFSDefParseXML(xmlNodePtr node,
         goto error;
     }
 
+    if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
+        if (!usage) {
+            virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                                 _("missing 'usage' attribute for RAM filesystem"));
+            goto error;
+        }
+        if (virStrToLong_ull(usage, NULL, 10, &def->usage) < 0) {
+            virDomainReportError(VIR_ERR_XML_ERROR,
+                                 _("cannot parse usage '%s' for RAM filesystem"),
+                                 usage);
+            goto error;
+        }
+        if (unit &&
+            virScaleInteger(&def->usage, unit,
+                            1024, ULONG_LONG_MAX) < 0)
+            goto error;
+        fprintf(stderr, "Useage %lld\n", def->usage);
+    }
+
     def->src = source;
     source = NULL;
     def->dst = target;
@@ -4328,6 +4355,8 @@ cleanup:
     VIR_FREE(source);
     VIR_FREE(accessmode);
     VIR_FREE(wrpolicy);
+    VIR_FREE(usage);
+    VIR_FREE(unit);
 
     return def;
 
@@ -11322,27 +11351,31 @@ virDomainFSDefFormat(virBufferPtr buf,
         virBufferAddLit(buf, "/>\n");
     }
 
-    if (def->src) {
-        switch (def->type) {
-        case VIR_DOMAIN_FS_TYPE_MOUNT:
-            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
-                                  def->src);
-            break;
+    switch (def->type) {
+    case VIR_DOMAIN_FS_TYPE_MOUNT:
+        virBufferEscapeString(buf, "      <source dir='%s'/>\n",
+                              def->src);
+        break;
 
-        case VIR_DOMAIN_FS_TYPE_BLOCK:
-            virBufferEscapeString(buf, "      <source dev='%s'/>\n",
-                                  def->src);
-            break;
+    case VIR_DOMAIN_FS_TYPE_BLOCK:
+        virBufferEscapeString(buf, "      <source dev='%s'/>\n",
+                              def->src);
+        break;
 
-        case VIR_DOMAIN_FS_TYPE_FILE:
-            virBufferEscapeString(buf, "      <source file='%s'/>\n",
-                                  def->src);
-            break;
+    case VIR_DOMAIN_FS_TYPE_FILE:
+        virBufferEscapeString(buf, "      <source file='%s'/>\n",
+                              def->src);
+        break;
 
-        case VIR_DOMAIN_FS_TYPE_TEMPLATE:
-            virBufferEscapeString(buf, "      <source name='%s'/>\n",
-                                  def->src);
-        }
+    case VIR_DOMAIN_FS_TYPE_TEMPLATE:
+        virBufferEscapeString(buf, "      <source name='%s'/>\n",
+                              def->src);
+        break;
+
+    case VIR_DOMAIN_FS_TYPE_RAM:
+        virBufferAsprintf(buf, "      <source usage='%lld' units='KiB'/>\n",
+                          def->usage / 1024);
+        break;
     }
 
     virBufferEscapeString(buf, "      <target dir='%s'/>\n",
index 371278586c2fb2efc41e2de54d71b210caef1a2a..7ce0694441955e29d2057673a4540f0394dd6d20 100644 (file)
@@ -661,6 +661,7 @@ enum virDomainFSType {
     VIR_DOMAIN_FS_TYPE_BLOCK,
     VIR_DOMAIN_FS_TYPE_FILE,
     VIR_DOMAIN_FS_TYPE_TEMPLATE,
+    VIR_DOMAIN_FS_TYPE_RAM,
 
     VIR_DOMAIN_FS_TYPE_LAST
 };
@@ -691,11 +692,15 @@ enum virDomainFSWrpolicy {
     VIR_DOMAIN_FS_WRPOLICY_LAST
 };
 
+/* Allow 2 MB ram usage */
+# define VIR_DOMAIN_FS_RAM_DEFAULT_USAGE (1024 * 2)
+
 struct _virDomainFSDef {
     int type;
     int fsdriver;
     int accessmode;
     int wrpolicy; /* enum virDomainFSWrpolicy */
+    unsigned long long usage;
     char *src;
     char *dst;
     unsigned int readonly : 1;
index 24b101735e1739a1ca3ac4415fea128968f587d2..b69255e026d4da5b4e2d14b93851b21480c8bcc7 100644 (file)
@@ -335,6 +335,8 @@ static int lxcContainerPivotRoot(virDomainFSDefPtr root)
 
     ret = -1;
 
+    VIR_DEBUG("Pivot via %s", root->src);
+
     /* root->parent must be private, so make / private. */
     if (mount("", "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
         virReportSystemError(errno, "%s",
@@ -966,6 +968,47 @@ cleanup:
 }
 
 
+static int lxcContainerMountFSTmpfs(virDomainFSDefPtr fs)
+{
+    int ret = -1;
+    char *data = NULL;
+
+    if (virAsprintf(&data, "size=%lldk", fs->usage) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virFileMakePath(fs->dst) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to create %s"),
+                             fs->dst);
+        goto cleanup;
+    }
+
+    if (mount("tmpfs", fs->dst, "tmpfs", MS_NOSUID|MS_NODEV, data) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to mount directory %s as tmpfs"),
+                             fs->dst);
+        goto cleanup;
+    }
+
+    if (fs->readonly) {
+        VIR_DEBUG("Binding %s readonly", fs->dst);
+        if (mount(fs->dst, fs->dst, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+            virReportSystemError(errno,
+                                 _("Failed to make directory %s readonly"),
+                                 fs->dst);
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(data);
+    return ret;
+}
+
+
 static int lxcContainerMountFS(virDomainFSDefPtr fs,
                                const char *srcprefix)
 {
@@ -978,6 +1021,10 @@ static int lxcContainerMountFS(virDomainFSDefPtr fs,
         if (lxcContainerMountFSBlock(fs, srcprefix) < 0)
             return -1;
         break;
+    case VIR_DOMAIN_FS_TYPE_RAM:
+        if (lxcContainerMountFSTmpfs(fs) < 0)
+            return -1;
+        break;
     case VIR_DOMAIN_FS_TYPE_FILE:
         lxcError(VIR_ERR_INTERNAL_ERROR,
                  _("Unexpected filesystem type %s"),
@@ -1441,6 +1488,8 @@ static int lxcContainerResolveSymlinks(virDomainDefPtr vmDef)
 
     for (i = 0 ; i < vmDef->nfss ; i++) {
         virDomainFSDefPtr fs = vmDef->fss[i];
+        if (!fs->src)
+            continue;
         if (virFileResolveAllLinks(fs->src, &newroot) < 0)
             return -1;