Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151128544
D22953.id66089.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D22953.id66089.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D22953: libbe(3): promote dependent clones when destroying an environment
Attached
Detach File
Event Timeline
Log In to Comment