]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
mod_rdep(): Write path and name of clone to file
authorChristian Brauner <christianvanbrauner@gmail.com>
Tue, 11 Aug 2015 08:33:46 +0000 (10:33 +0200)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Thu, 27 Aug 2015 20:14:18 +0000 (15:14 -0500)
If we currently create clone-snapshots via lxc-clone only the plain total
number of the containers it serves as a base-container is written to the file
"lxc-snapshots". This commit modifies mod_rdep() so it will store the paths and
names to the containers that are clone-snapshots (similar to the "lxc_rdepends"
file for the clones). **Users which still have containers that have a non-empty
(with a number > 0 as an entry) "lxc-snapshots" file in the old format are not
affected by this change. It will be used until all old clones have been
deleted!** For all others, the "lxc_snapshots" file placed under the original
container now looks like this:

      /var/lib/lxc
      bb
      /var/lib/lxc
      cc
      /opt
      dd

This is an example of a container that provides the base for three
clone-snapshots bb, cc, and dd. Where bb and cc both are placed in the usual
path for privileged containers and dd is placed in a custom path.

- Add additional argument to function that takes in the clone-snapshotted
  lxc_container.
- Have mod_rdep() write the path and name of the clone-snapshotted container the
  file lxc_snapshots of the original container.
- If a clone-snapshot gets deleted the corresponding line in the file
  lxc_snapshot of the original container will be deleted and the file updated
  via mmap() + memmove() + munmap().
- Adapt has_fs_snapshots().
- **If an lxc-snapshot file in the old format is found we'll keep using it.**

Signed-off-by: Christian Brauner <christianvanbrauner@gmail.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
src/lxc/lxccontainer.c

index 529163449ee36b0107186ff3ca7b3a652f923749..f022f0d042f7a60f5d69384dfccf2ad742a6c980 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #define _GNU_SOURCE
+#include <sys/mman.h>
 #include <assert.h>
 #include <stdarg.h>
 #include <pthread.h>
@@ -1970,47 +1971,130 @@ out:
 
 WRAP_API_1(bool, lxcapi_save_config, const char *)
 
-static bool mod_rdep(struct lxc_container *c, bool inc)
+
+static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc)
 {
+       FILE *f1;
+       struct stat fbuf;
+       char *buf = NULL;
+       char *del;
        char path[MAXPATHLEN];
-       int ret, v = 0;
-       FILE *f;
+       char newpath[MAXPATHLEN];
+       int fd, ret, n = 0, v = 0;
        bool bret = false;
+       size_t len;
 
-       if (container_disk_lock(c))
+       if (container_disk_lock(c0))
                return false;
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
-                       c->name);
+
+       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
        if (ret < 0 || ret > MAXPATHLEN)
                goto out;
-       f = fopen(path, "r");
-       if (f) {
-               ret = fscanf(f, "%d", &v);
-               fclose(f);
-               if (ret != 1) {
-                       ERROR("Corrupted file %s", path);
-                       goto out;
-               }
-       }
-       v += inc ? 1 : -1;
-       f = fopen(path, "w");
-       if (!f)
-               goto out;
-       if (fprintf(f, "%d\n", v) < 0) {
-               ERROR("Error writing new snapshots value");
-               fclose(f);
+       ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
+       if (ret < 0 || ret > MAXPATHLEN)
                goto out;
+
+       /* If we find an lxc-snapshot file using the old format only listing the
+        * number of snapshots we will keep using it. */
+       f1 = fopen(path, "r");
+       if (f1) {
+               n = fscanf(f1, "%d", &v);
+               fclose(f1);
+               if (n == 1 && v == 0) {
+                       remove(path);
+                       n = 0;
+               }
        }
-       ret = fclose(f);
-       if (ret != 0) {
-               SYSERROR("Error writing to or closing snapshots file");
-               goto out;
+       if (n == 1) {
+               v += inc ? 1 : -1;
+               f1 = fopen(path, "w");
+               if (!f1)
+                       goto out;
+               if (fprintf(f1, "%d\n", v) < 0) {
+                       ERROR("Error writing new snapshots value");
+                       fclose(f1);
+                       goto out;
+               }
+               ret = fclose(f1);
+               if (ret != 0) {
+                       SYSERROR("Error writing to or closing snapshots file");
+                       goto out;
+               }
+       } else {
+               /* Here we know that we have or can use an lxc-snapshot file
+                * using the new format. */
+               if (inc) {
+                       f1 = fopen(path, "a");
+                       if (!f1)
+                               goto out;
+
+                       if (fprintf(f1, "%s", newpath) < 0) {
+                               ERROR("Error writing new snapshots entry");
+                               ret = fclose(f1);
+                               if (ret != 0)
+                                       SYSERROR("Error writing to or closing snapshots file");
+                               goto out;
+                       }
+
+                       ret = fclose(f1);
+                       if (ret != 0) {
+                               SYSERROR("Error writing to or closing snapshots file");
+                               goto out;
+                       }
+               } else if (!inc) {
+                       fd = open(path, O_RDWR | O_CLOEXEC);
+                       if (fd < 0)
+                               goto out;
+
+                       ret = fstat(fd, &fbuf);
+                       if (ret < 0) {
+                               close(fd);
+                               goto out;
+                       }
+
+                       if (fbuf.st_size != 0) {
+                               buf = mmap(NULL, fbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+                               if (buf == MAP_FAILED) {
+                                       SYSERROR("Failed to create mapping %s", path);
+                                       close(fd);
+                                       goto out;
+                               }
+                       }
+
+                       len = strlen(newpath);
+
+                       /* mmap()ed memory is only \0-terminated when it is not
+                        * a multiple of a pagesize. Hence, we'll use memmem(). */
+                       if ((del = memmem(buf, fbuf.st_size, newpath, len))) {
+                               /* remove container entry */
+                               memmove(del, del + len, strlen(del) - len + 1);
+
+                               munmap(buf, fbuf.st_size);
+
+                               if (ftruncate(fd, fbuf.st_size - len) < 0) {
+                                       SYSERROR("Failed to truncate file %s", path);
+                                       close(fd);
+                                       goto out;
+                               }
+                       } else {
+                               munmap(buf, fbuf.st_size);
+                       }
+
+                       close(fd);
+               }
+
+               /* If the lxc-snapshot file is empty, remove it. */
+               if (stat(path, &fbuf) < 0)
+                       goto out;
+               if (!fbuf.st_size) {
+                       remove(path);
+               }
        }
 
        bret = true;
 
 out:
-       container_disk_unlock(c);
+       container_disk_unlock(c0);
        return bret;
 }
 
@@ -2052,8 +2136,8 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc)
                                lxcpath, lxcname);
                        continue;
                }
-               if (!mod_rdep(p, inc))
-                       ERROR("Failed to increase numsnapshots for %s:%s",
+               if (!mod_rdep(p, c, inc))
+                       ERROR("Failed to update snapshots file for %s:%s",
                                lxcpath, lxcname);
                lxc_container_put(p);
        }
@@ -2065,22 +2149,30 @@ out:
 
 static bool has_fs_snapshots(struct lxc_container *c)
 {
+       FILE *f;
        char path[MAXPATHLEN];
        int ret, v;
-       FILE *f;
+       struct stat fbuf;
        bool bret = false;
 
        ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
                        c->name);
        if (ret < 0 || ret > MAXPATHLEN)
                goto out;
-       f = fopen(path, "r");
-       if (!f)
-               goto out;
-       ret = fscanf(f, "%d", &v);
-       fclose(f);
-       if (ret != 1)
+       /* If the file doesn't exist there are no snapshots. */
+       if (stat(path, &fbuf) < 0)
                goto out;
+       v = fbuf.st_size;
+       if (v != 0) {
+               f = fopen(path, "r");
+               if (!f)
+                       goto out;
+               ret = fscanf(f, "%d", &v);
+               fclose(f);
+               // TODO: Figure out what to do with the return value of fscanf.
+               if (ret != 1)
+                       INFO("Container uses new lxc-snapshots format %s", path);
+       }
        bret = v != 0;
 
 out: