path: root/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
diff options
authorToomas Soome <tsoome@FreeBSD.org>2020-08-05 14:32:20 +0000
committerToomas Soome <tsoome@FreeBSD.org>2020-08-05 14:32:20 +0000
commit722c2b4acaa88c0e6f41c30c5d5c355260b2a4b2 (patch)
treee4a776f807f5a082f86ca25e3d2afa8e5618e041 /cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
parent491ceb65ec22261b9060b42edeb910881d4fe347 (diff)
MFOpenZFS: Add support for boot environment data to be stored in the label
We are building new bootonce mechanism (previously zfs bootnext) and it is based on this OpenZFS change. Since this patch is nicely self contained, I am commiting it as is, and we can stack our changes. Original patch description follows: Modern bootloaders leverage data stored in the root filesystem to enable some of their powerful features. GRUB specifically has a grubenv file which can store large amounts of configuration data that can be read and written at boot time and during normal operation. This allows sysadmins to configure useful features like automated failover after failed boot attempts. Unfortunately, due to the Copy-on-Write nature of ZFS, the standard behavior of these tools cannot handle writing to ZFS files safely at boot time. We need an alternative way to store data that allows the bootloader to make changes to the data. This work is very similar to work that was done on Illumos to enable similar functionality in the FreeBSD bootloader. This patch is different in that the data being stored is a raw grubenv file; this file can store arbitrary variables and values, and the scripting provided by grub is powerful enough that special structures are not required to implement advanced behavior. We repurpose the second padding area in each label to store the grubenv file, protected by an embedded checksum. We add two ioctls to get and set this data, and libzfs_core and libzfs functions to access them more easily. There are no direct command line interfaces to these functions; these will be added directly to the bootloader utilities. Reviewed-by: Pavel Zakharov <pavel.zakharov@delphix.com> Reviewed-by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Paul Dagnelie <pcd@delphix.com> Closes #10009 Obtained from: OpenZFS Sponsored by: Netflix, Klara Inc.
Notes: svn path=/head/; revision=363911
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c')
1 files changed, 38 insertions, 2 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
index 39b6c35f6fbd..434f77e27da9 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
@@ -21,7 +21,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
@@ -395,7 +395,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
* Assuming bootfs is a valid dataset name.
static boolean_t
-bootfs_name_valid(const char *pool, char *bootfs)
+bootfs_name_valid(const char *pool, const char *bootfs)
int len = strlen(pool);
@@ -4233,6 +4233,42 @@ zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
+zpool_set_bootenv(zpool_handle_t *zhp, const char *envmap)
+ int error = lzc_set_bootenv(zhp->zpool_name, envmap);
+ if (error != 0) {
+ (void) zpool_standard_error_fmt(zhp->zpool_hdl, error,
+ dgettext(TEXT_DOMAIN,
+ "error setting bootenv in pool '%s'"), zhp->zpool_name);
+ }
+ return (error);
+zpool_get_bootenv(zpool_handle_t *zhp, char *outbuf, size_t size, off_t offset)
+ nvlist_t *nvl;
+ int error = lzc_get_bootenv(zhp->zpool_name, &nvl);;
+ if (error != 0) {
+ (void) zpool_standard_error_fmt(zhp->zpool_hdl, error,
+ dgettext(TEXT_DOMAIN,
+ "error getting bootenv in pool '%s'"), zhp->zpool_name);
+ return (-1);
+ }
+ char *envmap = fnvlist_lookup_string(nvl, "envmap");
+ if (offset >= strlen(envmap)) {
+ fnvlist_free(nvl);
+ return (0);
+ }
+ strlcpy(outbuf, envmap + offset, size);
+ int bytes = MIN(strlen(envmap + offset), size);
+ fnvlist_free(nvl);
+ return (bytes);
#ifdef illumos
* Read the EFI label from the config, if a label does not exist then