Page MenuHomeFreeBSD

D22953.id66089.diff
No OneTemporary

D22953.id66089.diff

Index: lib/libbe/be.c
===================================================================
--- lib/libbe/be.c
+++ lib/libbe/be.c
@@ -33,7 +33,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/ucred.h>
-
+#include <sys/queue.h>
#include <sys/zfs_context.h>
#include <sys/mntent.h>
@@ -48,9 +48,16 @@
#include "be.h"
#include "be_impl.h"
+struct promote_entry {
+ SLIST_ENTRY(promote_entry) link;
+ char *name;
+};
+
struct be_destroy_data {
- libbe_handle_t *lbh;
- char *snapname;
+ libbe_handle_t *lbh;
+ char target_name[BE_MAXPATHLEN];
+ char *snapname;
+ SLIST_HEAD(, promote_entry) promotelist;
};
#if SOON
@@ -194,6 +201,91 @@
zfs_nicenum(num, buf, buflen);
}
+/*
+ * This is executed from zfs_iter_dependents, it checks if the dependent
+ * type is a snapshot then attempts to find any clones associated with it.
+ * Any clones that are not children of the target environment to be
+ * destroyed are promoted.
+ */
+static int
+be_dependent_clone_cb(zfs_handle_t *zfs_hdl, void *data)
+{
+ int err;
+ bool found;
+ char *name;
+ struct nvlist *nvl;
+ struct nvpair *nvp;
+ struct be_destroy_data *bdd;
+ struct promote_entry *newentry, *entry;
+
+ nvp = NULL;
+ err = 0;
+ found = false;
+ bdd = (struct be_destroy_data *)data;
+
+ if (zfs_get_type(zfs_hdl) == ZFS_TYPE_SNAPSHOT &&
+ (nvl = zfs_get_clones_nvl(zfs_hdl)) != NULL) {
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+ name = nvpair_name(nvp);
+
+ /*
+ * Skip if the clone is equal to, or a child of the destroy target.
+ */
+ if (strncmp(name, bdd->target_name, strlen(bdd->target_name)) == 0 ||
+ strstr(name, bdd->target_name) == name) {
+ continue;
+ }
+
+ if ((newentry = malloc(sizeof(struct promote_entry))) == NULL)
+ return (ENOMEM);
+
+ SLIST_FOREACH(entry, &bdd->promotelist, link) {
+ if(strcmp(entry->name, name) == 0)
+ found = true;
+ }
+
+ if(!found) {
+ newentry->name = strdup(name);
+ SLIST_INSERT_HEAD(&bdd->promotelist, newentry, link);
+ }
+ }
+ nvlist_free(nvl);
+ }
+ zfs_close(zfs_hdl);
+ return (err);
+}
+
+/*
+ * This is called before a destroy, so that any datasets(environments) that are
+ * dependent on this one get promoted before destroying the target
+ */
+static int
+be_promote_dependent_clones(zfs_handle_t *zfs_hdl, struct be_destroy_data *bdd)
+{
+ int err;
+ zfs_handle_t *clone;
+ struct promote_entry *entry;
+
+ snprintf(bdd->target_name, BE_MAXPATHLEN, "%s/", zfs_get_name(zfs_hdl));
+ err = zfs_iter_dependents(zfs_hdl, true, be_dependent_clone_cb, bdd);
+
+ while(!SLIST_EMPTY(&bdd->promotelist)) {
+ entry = SLIST_FIRST(&bdd->promotelist);
+ SLIST_REMOVE_HEAD(&bdd->promotelist, link);
+
+ if(err == 0 && (clone = zfs_open(bdd->lbh->lzh, entry->name, ZFS_TYPE_FILESYSTEM)) != NULL) {
+ err = zfs_promote(clone);
+ zfs_close(clone);
+ }
+ free(entry->name);
+ free(entry);
+ }
+
+ return (err);
+}
+
+
+
static int
be_destroy_cb(zfs_handle_t *zfs_hdl, void *data)
{
@@ -251,6 +343,7 @@
bdd.lbh = lbh;
bdd.snapname = NULL;
+ SLIST_INIT(&bdd.promotelist);
force = options & BE_DESTROY_FORCE;
*origin = '\0';
@@ -311,6 +404,11 @@
}
}
+ if((err = be_promote_dependent_clones(fs, &bdd)) != 0){
+ free(bdd.snapname);
+ return (set_error(lbh, BE_ERR_DESTROYMNT));
+ }
+
err = be_destroy_cb(fs, &bdd);
zfs_close(fs);
free(bdd.snapname);
Index: sbin/bectl/tests/bectl_test.sh
===================================================================
--- sbin/bectl/tests/bectl_test.sh
+++ sbin/bectl/tests/bectl_test.sh
@@ -148,7 +148,7 @@
disk=${cwd}/disk.img
mount=${cwd}/mnt
root=${mount}/root
-
+
bectl_create_setup ${zpool} ${disk} ${mount}
atf_check bectl -r ${zpool}/ROOT create -e default default2
atf_check -o not-empty zfs get mountpoint ${zpool}/ROOT/default2
@@ -162,6 +162,24 @@
atf_check bectl -r ${zpool}/ROOT create -e default default3
atf_check bectl -r ${zpool}/ROOT destroy -o default3
atf_check bectl -r ${zpool}/ROOT unmount default
+
+ # create two be from the same parent and destroy the parent
+ atf_check bectl -r ${zpool}/ROOT create -e default default2
+ atf_check bectl -r ${zpool}/ROOT create -e default default3
+ atf_check bectl -r ${zpool}/ROOT destroy default
+ atf_check bectl -r ${zpool}/ROOT destroy default2
+ atf_check bectl -r ${zpool}/ROOT rename default3 default
+
+ # create a be, have it be the parent for another, then create another
+ # delete the first be. sleeps are required to prevent conflicting snapshots
+ atf_check bectl -r ${zpool}/ROOT create -e default default2
+ sleep 1
+ atf_check bectl -r ${zpool}/ROOT create -e default2 default3
+ sleep 1
+ atf_check bectl -r ${zpool}/ROOT create -e default3 default4
+ atf_check bectl -r ${zpool}/ROOT destroy default3
+ atf_check bectl -r ${zpool}/ROOT destroy default2
+ atf_check bectl -r ${zpool}/ROOT destroy default4
}
bectl_destroy_cleanup()
{

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 7, 6:51 AM (15 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31017201
Default Alt Text
D22953.id66089.diff (4 KB)

Event Timeline