Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F172526633
D22953.id66174.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.id66174.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,98 @@
zfs_nicenum(num, buf, buflen);
}
+/*
+ * This is executed from be_promote_dependent_clones via zfs_iter_dependents,
+ * It checks if the dependent type is a snapshot then attempts to find any clones
+ * associated with it. Any clones not related to the destroy target are added to the
+ * promote list.
+ */
+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;
+ 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);
+
+ found = false;
+ SLIST_FOREACH(entry, &bdd->promotelist, link) {
+ if (strcmp(entry->name, name) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ free(newentry);
+ continue;
+ }
+
+ if ((newentry->name = strdup(name)) == NULL) {
+ free(newentry);
+ return (ENOMEM);
+ }
+
+ 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 +350,7 @@
bdd.lbh = lbh;
bdd.snapname = NULL;
+ SLIST_INIT(&bdd.promotelist);
force = options & BE_DESTROY_FORCE;
*origin = '\0';
@@ -311,6 +411,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
@@ -162,6 +162,25 @@
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 and repeat, then start
+ # deleting environments. Arbitraialy chose default3 as the first.
+ # 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
Sun, Sep 20, 1:29 AM (8 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39264664
Default Alt Text
D22953.id66174.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