Commit 0ea055b3 by Christian Brauner Committed by Serge Hallyn

mod_rdep(): Write path and name of clone to file

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: 's avatarChristian Brauner <christianvanbrauner@gmail.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent 5e8757ed
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <sys/mman.h>
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <pthread.h> #include <pthread.h>
...@@ -1970,47 +1971,130 @@ out: ...@@ -1970,47 +1971,130 @@ out:
WRAP_API_1(bool, lxcapi_save_config, const char *) 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]; char path[MAXPATHLEN];
int ret, v = 0; char newpath[MAXPATHLEN];
FILE *f; int fd, ret, n = 0, v = 0;
bool bret = false; bool bret = false;
size_t len;
if (container_disk_lock(c)) if (container_disk_lock(c0))
return false; 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) if (ret < 0 || ret > MAXPATHLEN)
goto out; goto out;
f = fopen(path, "r"); ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
if (f) { if (ret < 0 || ret > MAXPATHLEN)
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);
goto out; 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 (n == 1) {
if (ret != 0) { v += inc ? 1 : -1;
SYSERROR("Error writing to or closing snapshots file"); f1 = fopen(path, "w");
goto out; 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; bret = true;
out: out:
container_disk_unlock(c); container_disk_unlock(c0);
return bret; return bret;
} }
...@@ -2052,8 +2136,8 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc) ...@@ -2052,8 +2136,8 @@ static void mod_all_rdeps(struct lxc_container *c, bool inc)
lxcpath, lxcname); lxcpath, lxcname);
continue; continue;
} }
if (!mod_rdep(p, inc)) if (!mod_rdep(p, c, inc))
ERROR("Failed to increase numsnapshots for %s:%s", ERROR("Failed to update snapshots file for %s:%s",
lxcpath, lxcname); lxcpath, lxcname);
lxc_container_put(p); lxc_container_put(p);
} }
...@@ -2065,22 +2149,30 @@ out: ...@@ -2065,22 +2149,30 @@ out:
static bool has_fs_snapshots(struct lxc_container *c) static bool has_fs_snapshots(struct lxc_container *c)
{ {
FILE *f;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
int ret, v; int ret, v;
FILE *f; struct stat fbuf;
bool bret = false; bool bret = false;
ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
c->name); c->name);
if (ret < 0 || ret > MAXPATHLEN) if (ret < 0 || ret > MAXPATHLEN)
goto out; goto out;
f = fopen(path, "r"); /* If the file doesn't exist there are no snapshots. */
if (!f) if (stat(path, &fbuf) < 0)
goto out;
ret = fscanf(f, "%d", &v);
fclose(f);
if (ret != 1)
goto out; 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; bret = v != 0;
out: out:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment