Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Apr 2019 03:49:40 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r346802 - in stable: 11/etc/mtree 11/lib/libbe 11/lib/libbe/tests 12/etc/mtree 12/lib/libbe 12/lib/libbe/tests
Message-ID:  <201904280349.x3S3nesu010686@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Sun Apr 28 03:49:40 2019
New Revision: 346802
URL: https://svnweb.freebsd.org/changeset/base/346802

Log:
  MFC r346545-r346546, r346680, r346700, r346705
  
  r346545:
  libbe(3): allow creation of arbitrary depth boot environments
  
  libbe currently only provides an API to create a recursive boot environment,
  without any formal support for intentionally limiting the depth. This
  changeset adds an API, be_create_depth, that may be used to arbitrarily
  restrict the depth of the new BE.
  
  r346546:
  libbe(3): Add a test for be creation
  
  r346680:
  libbe(3): Copy received properties as well
  
  This was inherently broken on send|recv datasets.
  
  r346700:
  libbe(3): Fix mis-application of patch (SHLIBDIR)
  
  Rob's patch in D18564 cemented the SHLIBDIR because bsd.own.mk (included by
  src.opts.mk) sets it to /usr/lib. r346546 did somehow not apply this part of
  the patch, leaving it to get installed to the wrong place and subsequently
  removed via ObsoleteFiles.
  
  r346705:
  libbe(3): Fix libcompat build
  
  SHLIBDIR should still be optionally set, just before src.opts.mk is included
  so that libcompat can properly override it. This fixes lib32 failures
  reported by both Jenkins and Michael Butler.

Added:
  stable/11/lib/libbe/tests/
     - copied from r346546, head/lib/libbe/tests/
Modified:
  stable/11/etc/mtree/BSD.tests.dist
  stable/11/lib/libbe/Makefile
  stable/11/lib/libbe/be.c
  stable/11/lib/libbe/be.h
  stable/11/lib/libbe/be_impl.h
  stable/11/lib/libbe/libbe.3
Directory Properties:
  stable/11/   (props changed)

Changes in other areas also in this revision:
Added:
  stable/12/lib/libbe/tests/
     - copied from r346546, head/lib/libbe/tests/
Modified:
  stable/12/etc/mtree/BSD.tests.dist
  stable/12/lib/libbe/Makefile
  stable/12/lib/libbe/be.c
  stable/12/lib/libbe/be.h
  stable/12/lib/libbe/be_impl.h
  stable/12/lib/libbe/libbe.3
Directory Properties:
  stable/12/   (props changed)

Modified: stable/11/etc/mtree/BSD.tests.dist
==============================================================================
--- stable/11/etc/mtree/BSD.tests.dist	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/etc/mtree/BSD.tests.dist	Sun Apr 28 03:49:40 2019	(r346802)
@@ -264,6 +264,8 @@
         ..
         libarchive
         ..
+        libbe
+        ..
         libc
             c063
             ..

Modified: stable/11/lib/libbe/Makefile
==============================================================================
--- stable/11/lib/libbe/Makefile	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/lib/libbe/Makefile	Sun Apr 28 03:49:40 2019	(r346802)
@@ -1,8 +1,11 @@
 # $FreeBSD$
 
+SHLIBDIR?=	/lib
+
+.include <src.opts.mk>
+
 PACKAGE=	lib${LIB}
 LIB=		be
-SHLIBDIR?= /lib
 SHLIB_MAJOR=	1
 SHLIB_MINOR=	0
 
@@ -27,5 +30,8 @@ CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/
 CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/head
 
 CFLAGS+= -DNEED_SOLARIS_BOOLEAN
+
+HAS_TESTS=	YES
+SUBDIR.${MK_TESTS}+= tests
 
 .include <bsd.lib.mk>

Modified: stable/11/lib/libbe/be.c
==============================================================================
--- stable/11/lib/libbe/be.c	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/lib/libbe/be.c	Sun Apr 28 03:49:40 2019	(r346802)
@@ -372,7 +372,6 @@ be_snapshot(libbe_handle_t *lbh, const char *source, c
 		    sizeof(buf)) >= sizeof(buf))
 			return (set_error(lbh, BE_ERR_INVALIDNAME));
 	}
-
 	if ((err = zfs_snapshot(lbh->lzh, buf, recursive, NULL)) != 0) {
 		switch (err) {
 		case EZFS_INVALIDNAME:
@@ -432,8 +431,12 @@ be_deep_clone_prop(int prop, void *cb)
 		/* Just continue if we fail to read a property */
 		return (ZPROP_CONT);
 
-	/* Only copy locally defined properties */
-	if (src != ZPROP_SRC_LOCAL)
+	/*
+	 * Only copy locally defined or received properties.  This continues
+	 * to avoid temporary/default/local properties intentionally without
+	 * breaking received datasets.
+	 */
+	if (src != ZPROP_SRC_LOCAL && src != ZPROP_SRC_RECEIVED)
 		return (ZPROP_CONT);
 
 	/* Augment mountpoint with altroot, if needed */
@@ -446,43 +449,78 @@ be_deep_clone_prop(int prop, void *cb)
 	return (ZPROP_CONT);
 }
 
+/*
+ * Return the corresponding boot environment path for a given
+ * dataset path, the constructed path is placed in 'result'.
+ *
+ * example: say our new boot environment name is 'bootenv' and
+ *          the dataset path is 'zroot/ROOT/default/data/set'.
+ *
+ * result should produce: 'zroot/ROOT/bootenv/data/set'
+ */
 static int
-be_deep_clone(zfs_handle_t *ds, void *data)
+be_get_path(struct libbe_deep_clone *ldc, const char *dspath, char *result, int result_size)
 {
+	char *pos;
+	char *child_dataset;
+
+	/* match the root path for the boot environments */
+	pos = strstr(dspath, ldc->lbh->root);
+
+	/* no match, different pools? */
+	if (pos == NULL)
+		return (BE_ERR_BADPATH);
+
+	/* root path of the new boot environment */
+	snprintf(result, result_size, "%s/%s", ldc->lbh->root, ldc->bename);
+
+        /* gets us to the parent dataset, the +1 consumes a trailing slash */
+	pos += strlen(ldc->lbh->root) + 1;
+
+	/* skip the parent dataset */
+	if ((child_dataset = strchr(pos, '/')) != NULL)
+		strlcat(result, child_dataset, result_size);
+
+	return (BE_ERR_SUCCESS);
+}
+
+static int
+be_clone_cb(zfs_handle_t *ds, void *data)
+{
 	int err;
 	char be_path[BE_MAXPATHLEN];
 	char snap_path[BE_MAXPATHLEN];
 	const char *dspath;
-	char *dsname;
 	zfs_handle_t *snap_hdl;
 	nvlist_t *props;
-	struct libbe_deep_clone *isdc, sdc;
+	struct libbe_deep_clone *ldc;
 	struct libbe_dccb dccb;
 
-	isdc = (struct libbe_deep_clone *)data;
+	ldc = (struct libbe_deep_clone *)data;
 	dspath = zfs_get_name(ds);
-	if ((dsname = strrchr(dspath, '/')) == NULL)
-		return (BE_ERR_UNKNOWN);
-	dsname++;
 
-	if (isdc->bename == NULL)
-		snprintf(be_path, sizeof(be_path), "%s/%s", isdc->be_root, dsname);
-	else
-		snprintf(be_path, sizeof(be_path), "%s/%s", isdc->be_root, isdc->bename);
+	snprintf(snap_path, sizeof(snap_path), "%s@%s", dspath, ldc->snapname);
 
-	snprintf(snap_path, sizeof(snap_path), "%s@%s", dspath, isdc->snapname);
+	/* construct the boot environment path from the dataset we're cloning */
+	if (be_get_path(ldc, dspath, be_path, sizeof(be_path)) != BE_ERR_SUCCESS)
+		return (set_error(ldc->lbh, BE_ERR_UNKNOWN));
 
-	if (zfs_dataset_exists(isdc->lbh->lzh, be_path, ZFS_TYPE_DATASET))
-		return (set_error(isdc->lbh, BE_ERR_EXISTS));
+	/* the dataset to be created (i.e. the boot environment) already exists */
+	if (zfs_dataset_exists(ldc->lbh->lzh, be_path, ZFS_TYPE_DATASET))
+		return (set_error(ldc->lbh, BE_ERR_EXISTS));
 
+	/* no snapshot found for this dataset, silently skip it */
+	if (!zfs_dataset_exists(ldc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT))
+		return (0);
+
 	if ((snap_hdl =
-	    zfs_open(isdc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT)) == NULL)
-		return (set_error(isdc->lbh, BE_ERR_ZFSOPEN));
+	    zfs_open(ldc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT)) == NULL)
+		return (set_error(ldc->lbh, BE_ERR_ZFSOPEN));
 
 	nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
 	nvlist_add_string(props, "canmount", "noauto");
 
-	dccb.lbh = isdc->lbh;
+	dccb.lbh = ldc->lbh;
 	dccb.zhp = ds;
 	dccb.props = props;
 	if (zprop_iter(be_deep_clone_prop, &dccb, B_FALSE, B_FALSE,
@@ -490,58 +528,55 @@ be_deep_clone(zfs_handle_t *ds, void *data)
 		return (-1);
 
 	if ((err = zfs_clone(snap_hdl, be_path, props)) != 0)
-		err = BE_ERR_ZFSCLONE;
+		return (set_error(ldc->lbh, BE_ERR_ZFSCLONE));
 
 	nvlist_free(props);
 	zfs_close(snap_hdl);
 
-	/* Failed to clone */
-	if (err != BE_ERR_SUCCESS)
-		return (set_error(isdc->lbh, err));
+	if (ldc->depth_limit == -1 || ldc->depth < ldc->depth_limit) {
+		ldc->depth++;
+		err = zfs_iter_filesystems(ds, be_clone_cb, ldc);
+		ldc->depth--;
+	}
 
-	sdc.lbh = isdc->lbh;
-	sdc.bename = NULL;
-	sdc.snapname = isdc->snapname;
-	sdc.be_root = (char *)&be_path;
-
-	err = zfs_iter_filesystems(ds, be_deep_clone, &sdc);
-
-	return (err);
+	return (set_error(ldc->lbh, err));
 }
 
 /*
- * Create the boot environment from pre-existing snapshot
- */
-int
-be_create_from_existing_snap(libbe_handle_t *lbh, const char *name,
-    const char *snap)
+ * Create a boot environment with a given name from a given snapshot.
+ * Snapshots can be in the format 'zroot/ROOT/default@snapshot' or
+ * 'default@snapshot'. In the latter case, 'default@snapshot' will be prepended
+ * with the root path that libbe was initailized with.
+*/
+static int
+be_clone(libbe_handle_t *lbh, const char *bename, const char *snapshot, int depth)
 {
 	int err;
-	char be_path[BE_MAXPATHLEN];
 	char snap_path[BE_MAXPATHLEN];
-	const char *bename;
 	char *parentname, *snapname;
 	zfs_handle_t *parent_hdl;
-	struct libbe_deep_clone sdc;
+	struct libbe_deep_clone ldc;
 
-	if ((err = be_validate_name(lbh, name)) != 0)
+        /* ensure the boot environment name is valid */
+	if ((err = be_validate_name(lbh, bename)) != 0)
 		return (set_error(lbh, err));
-	if ((err = be_root_concat(lbh, snap, snap_path)) != 0)
+
+	/*
+	 * prepend the boot environment root path if we're
+	 * given a partial snapshot name.
+	 */
+	if ((err = be_root_concat(lbh, snapshot, snap_path)) != 0)
 		return (set_error(lbh, err));
+
+	/* ensure the snapshot exists */
 	if ((err = be_validate_snap(lbh, snap_path)) != 0)
 		return (set_error(lbh, err));
 
-	if ((err = be_root_concat(lbh, name, be_path)) != 0)
-		return (set_error(lbh, err));
-
-	if ((bename = strrchr(name, '/')) == NULL)
-		bename = name;
-	else
-		bename++;
-
+        /* get a copy of the snapshot path so we can disect it */
 	if ((parentname = strdup(snap_path)) == NULL)
 		return (set_error(lbh, BE_ERR_UNKNOWN));
 
+        /* split dataset name from snapshot name */
 	snapname = strchr(parentname, '@');
 	if (snapname == NULL) {
 		free(parentname);
@@ -550,32 +585,56 @@ be_create_from_existing_snap(libbe_handle_t *lbh, cons
 	*snapname = '\0';
 	snapname++;
 
-	sdc.lbh = lbh;
-	sdc.bename = bename;
-	sdc.snapname = snapname;
-	sdc.be_root = lbh->root;
+        /* set-up the boot environment */
+        ldc.lbh = lbh;
+        ldc.bename = bename;
+        ldc.snapname = snapname;
+	ldc.depth = 0;
+	ldc.depth_limit = depth;
 
+        /* the boot environment will be cloned from this dataset */
 	parent_hdl = zfs_open(lbh->lzh, parentname, ZFS_TYPE_DATASET);
-	err = be_deep_clone(parent_hdl, &sdc);
 
+        /* create the boot environment */
+	err = be_clone_cb(parent_hdl, &ldc);
+
 	free(parentname);
 	return (set_error(lbh, err));
 }
 
+/*
+ * Create a boot environment from pre-existing snapshot, specifying a depth.
+ */
+int be_create_depth(libbe_handle_t *lbh, const char *bename,
+		    const char *snap, int depth)
+{
+	return (be_clone(lbh, bename, snap, depth));
+}
 
 /*
+ * Create the boot environment from pre-existing snapshot
+ */
+int
+be_create_from_existing_snap(libbe_handle_t *lbh, const char *bename,
+    const char *snap)
+{
+	return (be_clone(lbh, bename, snap, -1));
+}
+
+
+/*
  * Create a boot environment from an existing boot environment
  */
 int
-be_create_from_existing(libbe_handle_t *lbh, const char *name, const char *old)
+be_create_from_existing(libbe_handle_t *lbh, const char *bename, const char *old)
 {
 	int err;
-	char buf[BE_MAXPATHLEN];
+	char snap[BE_MAXPATHLEN];
 
-	if ((err = be_snapshot(lbh, old, NULL, true, (char *)&buf)) != 0)
+	if ((err = be_snapshot(lbh, old, NULL, true, snap)) != 0)
 		return (set_error(lbh, err));
 
-	err = be_create_from_existing_snap(lbh, name, (char *)buf);
+        err = be_clone(lbh, bename, snap, -1);
 
 	return (set_error(lbh, err));
 }

Modified: stable/11/lib/libbe/be.h
==============================================================================
--- stable/11/lib/libbe/be.h	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/lib/libbe/be.h	Sun Apr 28 03:49:40 2019	(r346802)
@@ -84,6 +84,7 @@ int be_activate(libbe_handle_t *, const char *, bool);
 
 /* Bootenv creation functions */
 int be_create(libbe_handle_t *, const char *);
+int be_create_depth(libbe_handle_t *, const char *, const char *, int);
 int be_create_from_existing(libbe_handle_t *, const char *, const char *);
 int be_create_from_existing_snap(libbe_handle_t *, const char *, const char *);
 int be_snapshot(libbe_handle_t *, const char *, const char *, bool, char *);

Modified: stable/11/lib/libbe/be_impl.h
==============================================================================
--- stable/11/lib/libbe/be_impl.h	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/lib/libbe/be_impl.h	Sun Apr 28 03:49:40 2019	(r346802)
@@ -50,7 +50,8 @@ struct libbe_deep_clone {
 	libbe_handle_t *lbh;
 	const char *bename;
 	const char *snapname;
-	const char *be_root;
+	int depth;
+	int depth_limit;
 };
 
 struct libbe_dccb {

Modified: stable/11/lib/libbe/libbe.3
==============================================================================
--- stable/11/lib/libbe/libbe.3	Sun Apr 28 02:27:04 2019	(r346801)
+++ stable/11/lib/libbe/libbe.3	Sun Apr 28 03:49:40 2019	(r346802)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 12, 2019
+.Dd April 22, 2019
 .Dt LIBBE 3
 .Os
 .Sh NAME
@@ -63,6 +63,9 @@
 .Fn be_create "libbe_handle_t *hdl" "const char *be_name"
 .Pp
 .Ft int
+.Fn be_create_depth "libbe_handle_t *hdl" "const char *be_name" "const char *snap" "int depth"
+.Pp
+.Ft int
 .Fn be_create_from_existing "libbe_handle_t *hdl" "const char *be_name" "const char *be_origin"
 .Pp
 .Ft int
@@ -213,19 +216,29 @@ function returns the boot environment root path.
 The
 .Fn be_create
 function creates a boot environment with the given name.
-It will be created from a snapshot of the currently booted boot environment.
+The new boot environment will be created from a recursive snapshot of the
+currently booted boot environment.
 .Pp
 The
+.Fn be_create_depth
+function creates a boot environment with the given name from an existing
+snapshot.
+The depth parameter specifies the depth of recursion that will be cloned from
+the existing snapshot.
+A depth of '0' is no recursion and '-1' is unlimited (i.e., a recursive boot
+environment).
+.Pp
+The
 .Fn be_create_from_existing
 function creates a boot environment with the given name from the name of an
 existing boot environment.
-A snapshot will be made of the base boot environment, and the new boot
-environment will be created from that.
+A recursive snapshot will be made of the origin boot environment, and the new
+boot environment will be created from that.
 .Pp
 The
 .Fn be_create_from_existing_snap
-function creates a boot environment with the given name from an existing
-snapshot.
+function creates a recursive boot environment with the given name from an
+existing snapshot.
 .Pp
 The
 .Fn be_rename



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904280349.x3S3nesu010686>