Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144322252
D18564.id54216.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D18564.id54216.diff
View Options
Index: lib/libbe/Makefile
===================================================================
--- lib/libbe/Makefile
+++ lib/libbe/Makefile
@@ -1,8 +1,10 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PACKAGE= lib${LIB}
LIB= be
-SHLIBDIR?= /lib
+SHLIBDIR= /lib
SHLIB_MAJOR= 1
SHLIB_MINOR= 0
@@ -28,4 +30,7 @@
CFLAGS+= -DNEED_SOLARIS_BOOLEAN
+HAS_TESTS= YES
+SUBDIR.${MK_TESTS}+= tests
+
.include <bsd.lib.mk>
Index: lib/libbe/be.h
===================================================================
--- lib/libbe/be.h
+++ lib/libbe/be.h
@@ -84,6 +84,7 @@
/* Bootenv creation functions */
int be_create(libbe_handle_t *, const char *);
+int be_create_shallow(libbe_handle_t *, const char *, const char *);
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 *);
Index: lib/libbe/be.c
===================================================================
--- lib/libbe/be.c
+++ lib/libbe/be.c
@@ -352,7 +352,6 @@
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:
@@ -426,43 +425,78 @@
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_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_deep_clone(zfs_handle_t *ds, void *data)
+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);
+
+ /* 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));
- snprintf(snap_path, sizeof(snap_path), "%s@%s", dspath, isdc->snapname);
+ /* 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));
- if (zfs_dataset_exists(isdc->lbh->lzh, be_path, ZFS_TYPE_DATASET))
- return (set_error(isdc->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,
@@ -470,58 +504,53 @@
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));
-
- sdc.lbh = isdc->lbh;
- sdc.bename = NULL;
- sdc.snapname = isdc->snapname;
- sdc.be_root = (char *)&be_path;
+ /* create recursive boot environment */
+ if (ldc->recursive)
+ err = zfs_iter_filesystems(ds, be_clone_cb, ldc);
- 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, bool recursive)
{
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)
- return (set_error(lbh, err));
- if ((err = be_root_concat(lbh, snap, snap_path)) != 0)
- return (set_error(lbh, err));
- if ((err = be_validate_snap(lbh, snap_path)) != 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, name, be_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));
- if ((bename = strrchr(name, '/')) == NULL)
- bename = name;
- else
- bename++;
+ /* ensure the snapshot exists */
+ if ((err = be_validate_snap(lbh, snap_path)) != 0)
+ return (set_error(lbh, err));
+ /* 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);
@@ -530,32 +559,62 @@
*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.recursive = recursive;
+ /* 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 non-recursive boot environment from pre-existing snapshot
+ */
+int
+be_create_shallow(libbe_handle_t *lbh, const char *bename,
+ const char *snap)
+{
+ int err;
+
+ err = be_clone(lbh, bename, snap, false);
+ return (set_error(lbh, err));
+}
+
+/*
+ * Create the boot environment from pre-existing snapshot
+ */
+int
+be_create_from_existing_snap(libbe_handle_t *lbh, const char *bename,
+ const char *snap)
+{
+ int err;
+
+ err = be_clone(lbh, bename, snap, true);
+ return (set_error(lbh, err));
+}
+
/*
* 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, true);
return (set_error(lbh, err));
}
Index: lib/libbe/be_impl.h
===================================================================
--- lib/libbe/be_impl.h
+++ lib/libbe/be_impl.h
@@ -50,7 +50,7 @@
libbe_handle_t *lbh;
const char *bename;
const char *snapname;
- const char *be_root;
+ boolean_t recursive;
};
struct libbe_dccb {
Index: lib/libbe/tests/Makefile
===================================================================
--- /dev/null
+++ lib/libbe/tests/Makefile
@@ -0,0 +1,18 @@
+PACKAGE= tests
+
+ATF_TESTS_SH+= be_create
+
+PROGS= target_prog
+SRCS_target_prog= target_prog.c
+BINDIR_target_prog= ${TESTSDIR}
+
+LIBADD+= zfs
+LIBADD+= nvpair
+LIBADD+= be
+
+CFLAGS+= -I${SRCTOP}/sys/cddl/compat/opensolaris
+CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common
+
+CFLAGS+= -DNEED_SOLARIS_BOOLEAN
+
+.include <bsd.test.mk>
Index: lib/libbe/tests/be_create.sh
===================================================================
--- /dev/null
+++ lib/libbe/tests/be_create.sh
@@ -0,0 +1,119 @@
+# The code for the following tests was copied from the
+# bectl tests found in src/sbin/bectl/tests, modified as needed.
+
+# Establishes a libbe zpool that can be used for some light testing; contains
+# a 'default' BE and not much else.
+libbe_create_setup()
+{
+ zpool=$1
+ disk=$2
+ mnt=$3
+
+ kldload -n -q zfs || atf_skip "ZFS module not loaded on the current system"
+ atf_check mkdir -p ${mnt}
+ atf_check truncate -s 1G ${disk}
+ atf_check zpool create -o altroot=${mnt} ${zpool} ${disk}
+ atf_check zfs create -o mountpoint=none ${zpool}/ROOT
+ atf_check zfs create -o mountpoint=/ -o canmount=noauto \
+ ${zpool}/ROOT/default
+ atf_check zfs create -o mountpoint=/usr -o canmount=noauto \
+ ${zpool}/ROOT/default/usr
+ atf_check zfs create -o mountpoint=/usr/obj -o canmount=noauto \
+ ${zpool}/ROOT/default/usr/obj
+}
+
+libbe_cleanup()
+{
+ zpool=$1
+ cwd=$(atf_get_srcdir)
+
+ if zpool get health ${zpool} >/dev/null 2>&1; then
+ zpool destroy ${zpool}
+ fi
+
+ if [ -f "${cwd}/disk.img" ]; then
+ rm ${cwd}/disk.img
+ fi
+
+}
+
+atf_test_case libbe_create cleanup
+libbe_create_head()
+{
+ atf_set "descr" "check _be_create from libbe"
+ atf_set "require.user" root
+}
+libbe_create_body()
+{
+ cwd=$(atf_get_srcdir)
+ zpool=libbe_test
+ disk=${cwd}/disk.img
+ mount=${cwd}/mnt
+ prog=${cwd}/./target_prog
+
+ # preliminary setup/checks
+ atf_require_prog $prog
+ libbe_create_setup ${zpool} ${disk} ${mount}
+
+ # a recursive and non-recursive snapshot to test against
+ atf_check zfs snapshot ${zpool}/ROOT/default@non-recursive
+ atf_check zfs snapshot -r ${zpool}/ROOT/default@recursive
+
+ # create a dataset after snapshots were taken
+ atf_check zfs create -o mountpoint=/usr/src -o canmount=noauto \
+ ${zpool}/ROOT/default/usr/src
+
+ # create a non-recursive boot environment named 'nonrecursive'
+ atf_check -o empty -s exit:0 $prog "${zpool}/ROOT" \
+ nonrecursive \
+ "${zpool}/ROOT/default@non-recursive" \
+ false
+ # the dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/nonrecursive"
+ # the child dataset should not exist.
+ atf_check -e not-empty -s not-exit:0 \
+ zfs list "${zpool}/ROOT/nonrecursive/usr"
+
+ # create a recursive boot environment named 'recursive'.
+ atf_check -o empty -s exit:0 $prog "${zpool}/ROOT" \
+ recursive \
+ "${zpool}/ROOT/default@recursive" \
+ true
+ # the dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/recursive"
+ # the child dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/recursive/usr"
+ # the child dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/recursive/usr/obj"
+ # the child dataset should not exist.
+ atf_check -e not-empty -s not-exit:0 \
+ zfs list "${zpool}/ROOT/recursive/usr/src"
+
+ # create a recursive boot environment named 'relative-snap'.
+ # This test is to ensure that a relative snapshot label can be used,
+ # (i.e. the format: 'bootenvironment@snapshot')
+ atf_check -o empty -s exit:0 $prog "${zpool}/ROOT" \
+ relative-snap \
+ default@recursive \
+ true
+ # the dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/relative-snap"
+ # the child dataset should exist
+ atf_check -o not-empty -s exit:0 \
+ zfs list "${zpool}/ROOT/relative-snap/usr"
+}
+
+libbe_create_cleanup()
+{
+ libbe_cleanup libbe_test
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case libbe_create
+}
Index: lib/libbe/tests/target_prog.c
===================================================================
--- /dev/null
+++ lib/libbe/tests/target_prog.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <be.h>
+
+/*
+ * argv[1] = root boot environment (e.g. zroot/ROOT),
+ * argv[2] = name of boot environment to create
+ * argv[3] = snapshot to create boot environment from
+ * argv[4] = create boot environment recursively (true/false)
+ */
+int main(int argc, char *argv[]) {
+
+ libbe_handle_t *lbh;
+
+ if (argc != 5)
+ return -1;
+
+ if ((lbh = libbe_init(argv[1])) == NULL)
+ return -1;
+
+ libbe_print_on_error(lbh, true);
+
+ /* create recursive boot environment */
+ if (strcmp(argv[4], "true") == 0)
+ return (be_create_from_existing_snap(lbh, argv[2], argv[3]));
+
+ /* create non-recursive boot environment */
+ return (be_create_shallow(lbh, argv[2], argv[3]));
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 8, 8:26 PM (13 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28494408
Default Alt Text
D18564.id54216.diff (13 KB)
Attached To
Mode
D18564: allow creation of non-recursive boot environments (libbe)
Attached
Detach File
Event Timeline
Log In to Comment