libbe: handle destroying/renaming temporary/bootonce boot environments

When a temporary/bootonce boot environment is renamed, we need to also
update the bootenv nvlist on-disk to reflect the new name. Additionally,
when a temporary/bootonce boot environment is destroyed, we also need to
clear out the on-disk state.

Reviewed by:	kevans
Approved by:	kp
MFC after:	1 week
Sponsored by:	Rubicon Communications, LLC ("Netgate")
Differential Revision:	https://reviews.freebsd.org/D43591
This commit is contained in:
R. Christian McDonald 2024-01-26 11:39:38 -05:00
parent 31828075e4
commit 5086b6ec32
No known key found for this signature in database
GPG key ID: A2C377A70FBB25ED
4 changed files with 114 additions and 21 deletions

View file

@ -175,6 +175,9 @@ libbe_init(const char *root)
strcmp(altroot, "-") != 0)
lbh->altroot_len = strlen(altroot);
(void) lzbe_get_boot_device(zpool_get_name(lbh->active_phandle),
&lbh->bootonce);
return (lbh);
err:
if (lbh != NULL) {
@ -199,6 +202,8 @@ libbe_close(libbe_handle_t *lbh)
if (lbh->active_phandle != NULL)
zpool_close(lbh->active_phandle);
libzfs_fini(lbh->lzh);
free(lbh->bootonce);
free(lbh);
}
@ -443,6 +448,12 @@ be_destroy_internal(libbe_handle_t *lbh, const char *name, int options,
return (set_error(lbh, BE_ERR_DESTROYMNT));
}
}
/* Handle destroying bootonce */
if (lbh->bootonce != NULL &&
strcmp(path, lbh->bootonce) == 0)
(void) lzbe_set_boot_device(
zpool_get_name(lbh->active_phandle), lzbe_add, NULL);
} else {
/*
* If we're initially destroying a snapshot, origin options do
@ -1021,11 +1032,17 @@ be_rename(libbe_handle_t *lbh, const char *old, const char *new)
.nounmount = 1,
};
err = zfs_rename(zfs_hdl, full_new, flags);
zfs_close(zfs_hdl);
if (err != 0)
return (set_error(lbh, BE_ERR_UNKNOWN));
return (0);
goto error;
/* handle renaming bootonce */
if (lbh->bootonce != NULL &&
strcmp(full_old, lbh->bootonce) == 0)
err = be_activate(lbh, new, true);
error:
zfs_close(zfs_hdl);
return (set_error(lbh, err));
}

View file

@ -36,6 +36,7 @@ struct libbe_handle {
char root[BE_MAXPATHLEN];
char rootfs[BE_MAXPATHLEN];
char bootfs[BE_MAXPATHLEN];
char *bootonce;
size_t altroot_len;
zpool_handle_t *active_phandle;
libzfs_handle_t *lzh;

View file

@ -181,8 +181,8 @@ prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p)
dataset = zfs_get_name(zfs_hdl);
nvlist_add_string(props, "dataset", dataset);
if (data->bootonce != NULL &&
strcmp(dataset, data->bootonce) == 0)
if (data->lbh->bootonce != NULL &&
strcmp(dataset, data->lbh->bootonce) == 0)
nvlist_add_boolean_value(props, "bootonce", true);
name = strrchr(dataset, '/') + 1;
@ -252,9 +252,6 @@ be_proplist_update(prop_data_t *data)
ZFS_TYPE_FILESYSTEM)) == NULL)
return (BE_ERR_ZFSOPEN);
(void) lzbe_get_boot_device(zpool_get_name(data->lbh->active_phandle),
&data->bootonce);
/* XXX TODO: some error checking here */
zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data);

View file

@ -93,7 +93,6 @@ bectl_cleanup()
atf_test_case bectl_create cleanup
bectl_create_head()
{
atf_set "descr" "Check the various forms of bectl create"
atf_set "require.user" root
}
@ -157,7 +156,6 @@ bectl_create_cleanup()
atf_test_case bectl_destroy cleanup
bectl_destroy_head()
{
atf_set "descr" "Check bectl destroy"
atf_set "require.user" root
}
@ -240,14 +238,12 @@ bectl_destroy_body()
}
bectl_destroy_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_export_import cleanup
bectl_export_import_head()
{
atf_set "descr" "Check bectl export and import"
atf_set "require.user" root
}
@ -278,14 +274,12 @@ bectl_export_import_body()
}
bectl_export_import_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_list cleanup
bectl_list_head()
{
atf_set "descr" "Check bectl list"
atf_set "require.user" root
}
@ -323,14 +317,12 @@ bectl_list_body()
}
bectl_list_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_mount cleanup
bectl_mount_head()
{
atf_set "descr" "Check bectl mount/unmount"
atf_set "require.user" root
}
@ -367,14 +359,12 @@ bectl_mount_body()
}
bectl_mount_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_rename cleanup
bectl_rename_head()
{
atf_set "descr" "Check bectl rename"
atf_set "require.user" root
}
@ -403,14 +393,12 @@ bectl_rename_body()
}
bectl_rename_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_jail cleanup
bectl_jail_head()
{
atf_set "descr" "Check bectl rename"
atf_set "require.user" root
atf_set "require.progs" jail
@ -577,6 +565,94 @@ bectl_promotion_cleanup()
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_destroy_bootonce cleanup
bectl_destroy_bootonce_head()
{
atf_set "descr" "Check bectl destroy (bootonce)"
atf_set "require.user" root
}
bectl_destroy_bootonce_body()
{
if [ "$(atf_config_get ci false)" = "true" ] && \
[ "$(uname -p)" = "i386" ]; then
atf_skip "https://bugs.freebsd.org/249055"
fi
if [ "$(atf_config_get ci false)" = "true" ] && \
[ "$(uname -p)" = "armv7" ]; then
atf_skip "https://bugs.freebsd.org/249229"
fi
cwd=$(realpath .)
zpool=$(make_zpool_name)
disk=${cwd}/disk.img
mount=${cwd}/mnt
root=${mount}/root
be=default2
bectl_create_setup ${zpool} ${disk} ${mount}
atf_check -s exit:0 -o empty bectl -r ${zpool}/ROOT create -e default ${be}
# Create boot environment and bootonce activate it
atf_check -s exit:0 -o ignore bectl -r ${zpool}/ROOT activate -t ${be}
atf_check -s exit:0 -o inline:"zfs:${zpool}/ROOT/${be}:\n" zfsbootcfg -z ${zpool}
# Destroy it
atf_check -s exit:0 -o ignore bectl -r ${zpool}/ROOT destroy ${be}
# Should be empty
atf_check -s exit:0 -o empty zfsbootcfg -z ${zpool}
}
bectl_destroy_bootonce_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_test_case bectl_rename_bootonce cleanup
bectl_rename_bootonce_head()
{
atf_set "descr" "Check bectl destroy (bootonce)"
atf_set "require.user" root
}
bectl_rename_bootonce_body()
{
if [ "$(atf_config_get ci false)" = "true" ] && \
[ "$(uname -p)" = "i386" ]; then
atf_skip "https://bugs.freebsd.org/249055"
fi
if [ "$(atf_config_get ci false)" = "true" ] && \
[ "$(uname -p)" = "armv7" ]; then
atf_skip "https://bugs.freebsd.org/249229"
fi
cwd=$(realpath .)
zpool=$(make_zpool_name)
disk=${cwd}/disk.img
mount=${cwd}/mnt
root=${mount}/root
be=default2
bectl_create_setup ${zpool} ${disk} ${mount}
atf_check -s exit:0 -o empty bectl -r ${zpool}/ROOT create -e default ${be}
# Create boot environment and bootonce activate it
atf_check -s exit:0 -o ignore bectl -r ${zpool}/ROOT activate -t ${be}
atf_check -s exit:0 -o inline:"zfs:${zpool}/ROOT/${be}:\n" zfsbootcfg -z ${zpool}
# Rename it
atf_check -s exit:0 -o ignore bectl -r ${zpool}/ROOT rename ${be} ${be}_renamed
# Should be renamed
atf_check -s exit:0 -o inline:"zfs:${zpool}/ROOT/${be}_renamed:\n" zfsbootcfg -z ${zpool}
}
bectl_rename_bootonce_cleanup()
{
bectl_cleanup $(get_zpool_name)
}
atf_init_test_cases()
{
atf_add_test_case bectl_create
@ -587,4 +663,6 @@ atf_init_test_cases()
atf_add_test_case bectl_rename
atf_add_test_case bectl_jail
atf_add_test_case bectl_promotion
atf_add_test_case bectl_destroy_bootonce
atf_add_test_case bectl_rename_bootonce
}