Commit 18aa217b by Serge Hallyn

snapshots: move snapshot directory

Originally we kept snapshots under /var/lib/lxcsnaps. If a separate btrfs is mounted at /var/lib/lxc, then we can't make btrfs snapshots under /var/lib/lxcsnaps. This patch moves the default directory to /var/lib/lxc/c/snaps. If /var/lib/lxcsnaps already exists, then we continue to use that. add c->destroy_with_snapshots() and c->snapshot_destroy_all() API methods. c->snashot_destroy_all() can be triggered from lxc-snapshot using '-d ALL'. There is no command to call c->destroy_with_snapshots(c) as of yet. lxclock: use ".$lxcname" for container lock files that way we can use /run/lock/lxc/$lxcpath/$lxcname/snaps as a directory when locking snapshots without having to worry about /run/lock//lxc/$lxcpath/$lxcname being a file. destroy: split off a container_destroy container_destroy() doesn't check for snapshots, so snapshot_rename can use it. api_destroy() now does check for snapshots (previously it only checked for fs - i.e. overlayfs/aufs - snapshots). Add destroy to the manpage, as it was previously undocumented. Update snapshot testcase accordingly. [ rebased in the face of commits 840f05df and 7e36f87e. ] Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarS.Çağlar Onur <caglar@10ur.org> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 3dbcf8b2
...@@ -55,6 +55,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -55,6 +55,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<cmdsynopsis> <cmdsynopsis>
<command>lxc-snapshot</command> <command>lxc-snapshot</command>
<arg choice="req">-n, --name <replaceable>name</replaceable></arg> <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
<arg choice="req">-d, -destroy <replaceable>snapshot-name</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>lxc-snapshot</command>
<arg choice="req">-n, --name <replaceable>name</replaceable></arg>
<arg choice="req">-L, --list </arg> <arg choice="req">-L, --list </arg>
<arg choice="opt">-C, --showcomments </arg> <arg choice="opt">-C, --showcomments </arg>
</cmdsynopsis> </cmdsynopsis>
...@@ -92,6 +97,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -92,6 +97,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <option>-d,--destroy snapshot-name</option> </term>
<listitem>
<para> Destroy the named snapshot. If the named snapshot is ALL, then all snapshots
will be destroyed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term> <option>-L,--list </option> </term> <term> <option>-L,--list </option> </term>
<listitem> <listitem>
<para> List existing snapshots. </para> <para> List existing snapshots. </para>
......
...@@ -482,7 +482,7 @@ static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna ...@@ -482,7 +482,7 @@ static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
static int dir_destroy(struct bdev *orig) static int dir_destroy(struct bdev *orig)
{ {
if (lxc_rmdir_onedev(orig->src) < 0) if (lxc_rmdir_onedev(orig->src, NULL) < 0)
return -1; return -1;
return 0; return 0;
} }
...@@ -2073,7 +2073,7 @@ static int overlayfs_destroy(struct bdev *orig) ...@@ -2073,7 +2073,7 @@ static int overlayfs_destroy(struct bdev *orig)
if (!upper) if (!upper)
return -22; return -22;
upper++; upper++;
return lxc_rmdir_onedev(upper); return lxc_rmdir_onedev(upper, NULL);
} }
/* /*
...@@ -2350,7 +2350,7 @@ static int aufs_destroy(struct bdev *orig) ...@@ -2350,7 +2350,7 @@ static int aufs_destroy(struct bdev *orig)
if (!upper) if (!upper)
return -22; return -22;
upper++; upper++;
return lxc_rmdir_onedev(upper); return lxc_rmdir_onedev(upper, NULL);
} }
/* /*
......
...@@ -112,7 +112,13 @@ static int do_restore_snapshots(struct lxc_container *c) ...@@ -112,7 +112,13 @@ static int do_restore_snapshots(struct lxc_container *c)
static int do_destroy_snapshots(struct lxc_container *c) static int do_destroy_snapshots(struct lxc_container *c)
{ {
if (c->snapshot_destroy(c, snapshot)) bool bret;
if (strcmp(snapshot, "ALL") == 0)
bret = c->snapshot_destroy_all(c);
else
bret = c->snapshot_destroy(c, snapshot);
if (bret)
return 0; return 0;
ERROR("Error destroying snapshot %s", snapshot); ERROR("Error destroying snapshot %s", snapshot);
...@@ -154,7 +160,8 @@ Options :\n\ ...@@ -154,7 +160,8 @@ Options :\n\
-C, --showcomments show snapshot comments in list\n\ -C, --showcomments show snapshot comments in list\n\
-c, --comment=file add file as a comment\n\ -c, --comment=file add file as a comment\n\
-r, --restore=name restore snapshot name, i.e. 'snap0'\n\ -r, --restore=name restore snapshot name, i.e. 'snap0'\n\
-d, --destroy=name destroy snapshot name, i.e. 'snap0'\n", -d, --destroy=name destroy snapshot name, i.e. 'snap0'\n\
use ALL to destroy all snapshots\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
......
...@@ -296,6 +296,17 @@ struct lxc_container { ...@@ -296,6 +296,17 @@ struct lxc_container {
bool (*destroy)(struct lxc_container *c); bool (*destroy)(struct lxc_container *c);
/*! /*!
* \brief Delete the container and all its snapshots.
*
* \param c Container.
*
* \return \c true on success, else \c false.
*
* \note Container must be stopped.
*/
bool (*destroy_with_snapshots)(struct lxc_container *c);
/*!
* \brief Save configuaration to a file. * \brief Save configuaration to a file.
* *
* \param c Container. * \param c Container.
...@@ -659,7 +670,7 @@ struct lxc_container { ...@@ -659,7 +670,7 @@ struct lxc_container {
* \brief Create a container snapshot. * \brief Create a container snapshot.
* *
* Assuming default paths, snapshots will be created as * Assuming default paths, snapshots will be created as
* \c /var/lib/lxcsnaps/\<c\>/snap\<n\> * \c /var/lib/lxc/\<c\>/snaps/snap\<n\>
* where \c \<c\> represents the container name and \c \<n\> * where \c \<c\> represents the container name and \c \<n\>
* represents the zero-based snapshot number. * represents the zero-based snapshot number.
* *
...@@ -701,7 +712,7 @@ struct lxc_container { ...@@ -701,7 +712,7 @@ struct lxc_container {
* fail if the snapshot is overlay-based, since the snapshots * fail if the snapshot is overlay-based, since the snapshots
* will pin the original container. * will pin the original container.
* \note As an example, if the container exists as \c /var/lib/lxc/c1, snapname might be \c 'snap0' * \note As an example, if the container exists as \c /var/lib/lxc/c1, snapname might be \c 'snap0'
* (representing \c /var/lib/lxcsnaps/c1/snap0). If \p newname is \p c2, * (representing \c /var/lib/lxc/c1/snaps/snap0). If \p newname is \p c2,
* then \c snap0 will be copied to \c /var/lib/lxc/c2. * then \c snap0 will be copied to \c /var/lib/lxc/c2.
*/ */
bool (*snapshot_restore)(struct lxc_container *c, const char *snapname, const char *newname); bool (*snapshot_restore)(struct lxc_container *c, const char *snapname, const char *newname);
...@@ -717,6 +728,15 @@ struct lxc_container { ...@@ -717,6 +728,15 @@ struct lxc_container {
bool (*snapshot_destroy)(struct lxc_container *c, const char *snapname); bool (*snapshot_destroy)(struct lxc_container *c, const char *snapname);
/*! /*!
* \brief Destroy all the container's snapshot.
*
* \param c Container.
*
* \return \c true on success, else \c false.
*/
bool (*snapshot_destroy_all)(struct lxc_container *c);
/*!
* \brief Determine if the caller may control the container. * \brief Determine if the caller may control the container.
* *
* \param c Container. * \param c Container.
......
...@@ -108,8 +108,8 @@ static char *lxclock_name(const char *p, const char *n) ...@@ -108,8 +108,8 @@ static char *lxclock_name(const char *p, const char *n)
* $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
*/ */
/* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */ /* length of "/lock/lxc/" + $lxcpath + "/" + "." + $lxcname + '\0' */
len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2; len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 3;
rundir = get_rundir(); rundir = get_rundir();
if (!rundir) if (!rundir)
return NULL; return NULL;
...@@ -129,7 +129,7 @@ static char *lxclock_name(const char *p, const char *n) ...@@ -129,7 +129,7 @@ static char *lxclock_name(const char *p, const char *n)
ret = mkdir_p(dest, 0755); ret = mkdir_p(dest, 0755);
if (ret < 0) { if (ret < 0) {
/* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */ /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */
int l2 = 33 + strlen(n) + strlen(p); int l2 = 34 + strlen(n) + strlen(p);
if (l2 > len) { if (l2 > len) {
char *d; char *d;
d = realloc(dest, l2); d = realloc(dest, l2);
...@@ -147,9 +147,9 @@ static char *lxclock_name(const char *p, const char *n) ...@@ -147,9 +147,9 @@ static char *lxclock_name(const char *p, const char *n)
free(rundir); free(rundir);
return NULL; return NULL;
} }
ret = snprintf(dest, len, "/tmp/%d/lxc/%s/%s", geteuid(), p, n); ret = snprintf(dest, len, "/tmp/%d/lxc/%s/.%s", geteuid(), p, n);
} else } else
ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n); ret = snprintf(dest, len, "%s/lock/lxc/%s/.%s", rundir, p, n);
free(rundir); free(rundir);
......
...@@ -46,12 +46,14 @@ ...@@ -46,12 +46,14 @@
lxc_log_define(lxc_utils, lxc); lxc_log_define(lxc_utils, lxc);
static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) static int _recursive_rmdir_onedev(char *dirname, dev_t pdev,
const char *exclude, int level)
{ {
struct dirent dirent, *direntp; struct dirent dirent, *direntp;
DIR *dir; DIR *dir;
int ret, failed=0; int ret, failed=0;
char pathname[MAXPATHLEN]; char pathname[MAXPATHLEN];
bool hadexclude = false;
dir = opendir(dirname); dir = opendir(dirname);
if (!dir) { if (!dir) {
...@@ -76,6 +78,29 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) ...@@ -76,6 +78,29 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
failed=1; failed=1;
continue; continue;
} }
if (!level && exclude && !strcmp(direntp->d_name, exclude)) {
ret = rmdir(pathname);
if (ret < 0) {
switch(errno) {
case ENOTEMPTY:
INFO("Not deleting snapshots");
hadexclude = true;
break;
case ENOTDIR:
ret = unlink(pathname);
if (ret)
INFO("%s: failed to remove %s", __func__, pathname);
break;
default:
SYSERROR("%s: failed to rmdir %s", __func__, pathname);
failed = 1;
break;
}
}
continue;
}
ret = lstat(pathname, &mystat); ret = lstat(pathname, &mystat);
if (ret) { if (ret) {
ERROR("%s: failed to stat %s", __func__, pathname); ERROR("%s: failed to stat %s", __func__, pathname);
...@@ -85,7 +110,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) ...@@ -85,7 +110,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
if (mystat.st_dev != pdev) if (mystat.st_dev != pdev)
continue; continue;
if (S_ISDIR(mystat.st_mode)) { if (S_ISDIR(mystat.st_mode)) {
if (_recursive_rmdir_onedev(pathname, pdev) < 0) if (_recursive_rmdir_onedev(pathname, pdev, exclude, level+1) < 0)
failed=1; failed=1;
} else { } else {
if (unlink(pathname) < 0) { if (unlink(pathname) < 0) {
...@@ -96,8 +121,10 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) ...@@ -96,8 +121,10 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
} }
if (rmdir(dirname) < 0) { if (rmdir(dirname) < 0) {
ERROR("%s: failed to delete %s", __func__, dirname); if (!hadexclude) {
failed=1; ERROR("%s: failed to delete %s", __func__, dirname);
failed=1;
}
} }
ret = closedir(dir); ret = closedir(dir);
...@@ -110,7 +137,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) ...@@ -110,7 +137,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
} }
/* returns 0 on success, -1 if there were any failures */ /* returns 0 on success, -1 if there were any failures */
extern int lxc_rmdir_onedev(char *path) extern int lxc_rmdir_onedev(char *path, const char *exclude)
{ {
struct stat mystat; struct stat mystat;
...@@ -119,7 +146,7 @@ extern int lxc_rmdir_onedev(char *path) ...@@ -119,7 +146,7 @@ extern int lxc_rmdir_onedev(char *path)
return -1; return -1;
} }
return _recursive_rmdir_onedev(path, mystat.st_dev); return _recursive_rmdir_onedev(path, mystat.st_dev, exclude, 0);
} }
static int mount_fs(const char *source, const char *target, const char *type) static int mount_fs(const char *source, const char *target, const char *type)
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "config.h" #include "config.h"
/* returns 1 on success, 0 if there were any failures */ /* returns 1 on success, 0 if there were any failures */
extern int lxc_rmdir_onedev(char *path); extern int lxc_rmdir_onedev(char *path, const char *exclude);
extern void lxc_setup_fs(void); extern void lxc_setup_fs(void);
extern int get_u16(unsigned short *val, const char *arg, int base); extern int get_u16(unsigned short *val, const char *arg, int base);
extern int mkdir_p(const char *dir, mode_t mode); extern int mkdir_p(const char *dir, mode_t mode);
......
...@@ -32,28 +32,21 @@ ...@@ -32,28 +32,21 @@
static void try_to_remove(void) static void try_to_remove(void)
{ {
struct lxc_container *c; struct lxc_container *c;
char snappath[1024];
c = lxc_container_new(RESTNAME, NULL); c = lxc_container_new(RESTNAME, NULL);
if (c) { if (c) {
if (c->is_defined(c)) c->snapshot_destroy_all(c);
c->destroy(c);
lxc_container_put(c);
}
snprintf(snappath, 1024, "%ssnaps/%s", lxc_get_global_config_item("lxc.lxcpath"), MYNAME);
c = lxc_container_new("snap0", snappath);
if (c) {
if (c->is_defined(c)) if (c->is_defined(c))
c->destroy(c); c->destroy(c);
lxc_container_put(c); lxc_container_put(c);
} }
c = lxc_container_new(MYNAME2, NULL); c = lxc_container_new(MYNAME2, NULL);
if (c) { if (c) {
if (c->is_defined(c)) c->destroy_with_snapshots(c);
c->destroy(c);
lxc_container_put(c); lxc_container_put(c);
} }
c = lxc_container_new(MYNAME, NULL); c = lxc_container_new(MYNAME, NULL);
if (c) { if (c) {
c->snapshot_destroy_all(c);
if (c->is_defined(c)) if (c->is_defined(c))
c->destroy(c); c->destroy(c);
lxc_container_put(c); lxc_container_put(c);
...@@ -77,7 +70,7 @@ int main(int argc, char *argv[]) ...@@ -77,7 +70,7 @@ int main(int argc, char *argv[])
if (c->is_defined(c)) { if (c->is_defined(c)) {
fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME); fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
(void) c->destroy(c); (void) c->destroy_with_snapshots(c);
} }
if (!c->set_config_item(c, "lxc.network.type", "empty")) { if (!c->set_config_item(c, "lxc.network.type", "empty")) {
fprintf(stderr, "%s: %d: failed to set network type\n", __FILE__, __LINE__); fprintf(stderr, "%s: %d: failed to set network type\n", __FILE__, __LINE__);
...@@ -95,11 +88,11 @@ int main(int argc, char *argv[]) ...@@ -95,11 +88,11 @@ int main(int argc, char *argv[])
goto err; goto err;
} }
// rootfs should be ${lxcpath}snaps/${lxcname}/snap0/rootfs // rootfs should be ${lxcpath}${lxcname}/snaps/snap0/rootfs
struct stat sb; struct stat sb;
int ret; int ret;
char path[1024]; char path[1024];
snprintf(path, 1024, "%ssnaps/%s/snap0/rootfs", lxc_get_global_config_item("lxc.lxcpath"), MYNAME); snprintf(path, 1024, "%s/%s/snaps/snap0/rootfs", lxc_get_global_config_item("lxc.lxcpath"), MYNAME);
ret = stat(path, &sb); ret = stat(path, &sb);
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "%s: %d: snapshot was not actually created\n", __FILE__, __LINE__); fprintf(stderr, "%s: %d: snapshot was not actually created\n", __FILE__, __LINE__);
...@@ -169,17 +162,7 @@ int main(int argc, char *argv[]) ...@@ -169,17 +162,7 @@ int main(int argc, char *argv[])
goto err; goto err;
} }
if (!c2->destroy(c2)) {
fprintf(stderr, "%s: %d: failed to destroy container\n", __FILE__, __LINE__);
goto err;
}
good: good:
if (!c->destroy(c)) {
fprintf(stderr, "%s: %d: failed to destroy container\n", __FILE__, __LINE__);
goto err;
}
lxc_container_put(c); lxc_container_put(c);
try_to_remove(); try_to_remove();
......
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