aboutsummaryrefslogtreecommitdiff
path: root/stand
diff options
context:
space:
mode:
authorMariusz Zaborski <oshogbo@FreeBSD.org>2020-08-18 19:48:04 +0000
committerMariusz Zaborski <oshogbo@FreeBSD.org>2020-08-18 19:48:04 +0000
commit277f38abffc6a8160b5044128b5b2c620fbb970c (patch)
tree3bab41fe37fb14ef05b8dfb2b0b1235a2a47ffce /stand
parentad7a0eb189e2aba52f2dcc6b47642a84365b90dd (diff)
downloadsrc-277f38abffc6a8160b5044128b5b2c620fbb970c.tar.gz
src-277f38abffc6a8160b5044128b5b2c620fbb970c.zip
Notes
Diffstat (limited to 'stand')
-rw-r--r--stand/efi/loader/main.c2
-rw-r--r--stand/i386/loader/main.c2
-rw-r--r--stand/libsa/zfs/libzfs.h2
-rw-r--r--stand/libsa/zfs/zfs.c138
-rw-r--r--stand/libsa/zfs/zfsimpl.c72
-rw-r--r--stand/lua/core.lua47
-rw-r--r--stand/lua/menu.lua30
7 files changed, 212 insertions, 81 deletions
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index 8ba03141c95b..e81a01de8b1e 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -269,7 +269,7 @@ probe_zfs_currdev(uint64_t guid)
currdev.root_guid = 0;
set_currdev_devdesc((struct devdesc *)&currdev);
devname = efi_fmtdev(&currdev);
- init_zfs_bootenv(devname);
+ init_zfs_boot_options(devname);
rv = sanity_check_currdev();
if (rv) {
diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c
index 377075f100ee..d7c23ba807ad 100644
--- a/stand/i386/loader/main.c
+++ b/stand/i386/loader/main.c
@@ -363,7 +363,7 @@ extract_currdev(void)
#ifdef LOADER_ZFS_SUPPORT
if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS)
- init_zfs_bootenv(zfs_fmtdev(&new_currdev));
+ init_zfs_boot_options(zfs_fmtdev(&new_currdev));
#endif
env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
diff --git a/stand/libsa/zfs/libzfs.h b/stand/libsa/zfs/libzfs.h
index a5df0c1b8255..e9eb717f0cb0 100644
--- a/stand/libsa/zfs/libzfs.h
+++ b/stand/libsa/zfs/libzfs.h
@@ -123,7 +123,7 @@ int zfs_nextboot(void *vdev, char *buf, size_t size);
int zfs_probe_dev(const char *devname, uint64_t *pool_guid);
int zfs_list(const char *name);
uint64_t ldi_get_size(void *);
-void init_zfs_bootenv(const char *currdev);
+void init_zfs_boot_options(const char *currdev);
int zfs_bootenv(const char *name);
int zfs_belist_add(const char *name, uint64_t __unused);
int zfs_set_env(void);
diff --git a/stand/libsa/zfs/zfs.c b/stand/libsa/zfs/zfs.c
index fd7b6cbfdeba..6bceb1ee5270 100644
--- a/stand/libsa/zfs/zfs.c
+++ b/stand/libsa/zfs/zfs.c
@@ -60,7 +60,10 @@ static off_t zfs_seek(struct open_file *f, off_t offset, int where);
static int zfs_stat(struct open_file *f, struct stat *sb);
static int zfs_readdir(struct open_file *f, struct dirent *d);
-static void zfs_bootenv_initial(const char *);
+static void zfs_bootenv_initial(const char *envname, spa_t *spa,
+ const char *name, const char *dsname, int checkpoint);
+static void zfs_checkpoints_initial(spa_t *spa, const char *name,
+ const char *dsname);
struct devsw zfs_dev;
@@ -1077,15 +1080,15 @@ zfs_fmtdev(void *vdev)
return (buf);
}
-int
-zfs_list(const char *name)
+static int
+split_devname(const char *name, char *poolname, size_t size,
+ const char **dsnamep)
{
- static char poolname[ZFS_MAXNAMELEN];
- uint64_t objid;
- spa_t *spa;
- const char *dsname;
- int len;
- int rv;
+ const char *dsname;
+ size_t len;
+
+ ASSERT(name != NULL);
+ ASSERT(poolname != NULL);
len = strlen(name);
dsname = strchr(name, '/');
@@ -1094,8 +1097,29 @@ zfs_list(const char *name)
dsname++;
} else
dsname = "";
- memcpy(poolname, name, len);
- poolname[len] = '\0';
+
+ if (len + 1 > size)
+ return (EINVAL);
+
+ strlcpy(poolname, name, len + 1);
+
+ if (dsnamep != NULL)
+ *dsnamep = dsname;
+
+ return (0);
+}
+
+int
+zfs_list(const char *name)
+{
+ static char poolname[ZFS_MAXNAMELEN];
+ uint64_t objid;
+ spa_t *spa;
+ const char *dsname;
+ int rv;
+
+ if (split_devname(name, poolname, sizeof(poolname), &dsname) != 0)
+ return (EINVAL);
spa = spa_find_by_name(poolname);
if (!spa)
@@ -1108,10 +1132,13 @@ zfs_list(const char *name)
}
void
-init_zfs_bootenv(const char *currdev_in)
+init_zfs_boot_options(const char *currdev_in)
{
+ char poolname[ZFS_MAXNAMELEN];
char *beroot, *currdev;
+ spa_t *spa;
int currdev_len;
+ const char *dsname;
currdev = NULL;
currdev_len = strlen(currdev_in);
@@ -1124,6 +1151,7 @@ init_zfs_bootenv(const char *currdev_in)
return;
/* Remove the trailing : */
currdev[currdev_len - 1] = '\0';
+
setenv("zfs_be_active", currdev, 1);
setenv("zfs_be_currpage", "1", 1);
/* Remove the last element (current bootenv) */
@@ -1132,49 +1160,71 @@ init_zfs_bootenv(const char *currdev_in)
beroot[0] = '\0';
beroot = strchr(currdev, ':') + 1;
setenv("zfs_be_root", beroot, 1);
- zfs_bootenv_initial(beroot);
+
+ if (split_devname(beroot, poolname, sizeof(poolname), &dsname) != 0)
+ return;
+
+ spa = spa_find_by_name(poolname);
+ if (spa == NULL)
+ return;
+
+ zfs_bootenv_initial("bootenvs", spa, beroot, dsname, 0);
+ zfs_checkpoints_initial(spa, beroot, dsname);
+
free(currdev);
}
static void
-zfs_bootenv_initial(const char *name)
+zfs_checkpoints_initial(spa_t *spa, const char *name, const char *dsname)
{
- char poolname[ZFS_MAXNAMELEN], *dsname;
- char envname[32], envval[256];
+ char envname[32];
+
+ if (spa->spa_uberblock_checkpoint.ub_checkpoint_txg != 0) {
+ snprintf(envname, sizeof(envname), "zpool_checkpoint");
+ setenv(envname, name, 1);
+
+ spa->spa_uberblock = &spa->spa_uberblock_checkpoint;
+ spa->spa_mos = &spa->spa_mos_checkpoint;
+
+ zfs_bootenv_initial("bootenvs_check", spa, name, dsname, 1);
+
+ spa->spa_uberblock = &spa->spa_uberblock_master;
+ spa->spa_mos = &spa->spa_mos_master;
+ }
+}
+
+static void
+zfs_bootenv_initial(const char *envprefix, spa_t *spa, const char *rootname,
+ const char *dsname, int checkpoint)
+{
+ char envname[32], envval[256];
uint64_t objid;
- spa_t *spa;
- int bootenvs_idx, len, rv;
+ int bootenvs_idx, rv;
SLIST_INIT(&zfs_be_head);
zfs_env_count = 0;
- len = strlen(name);
- dsname = strchr(name, '/');
- if (dsname != NULL) {
- len = dsname - name;
- dsname++;
- } else
- dsname = "";
- strlcpy(poolname, name, len + 1);
- spa = spa_find_by_name(poolname);
- if (spa == NULL)
- return;
+
rv = zfs_lookup_dataset(spa, dsname, &objid);
if (rv != 0)
return;
+
rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
bootenvs_idx = 0;
/* Populate the initial environment variables */
SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
/* Enumerate all bootenvs for general usage */
- snprintf(envname, sizeof(envname), "bootenvs[%d]", bootenvs_idx);
- snprintf(envval, sizeof(envval), "zfs:%s/%s", name, zfs_be->name);
+ snprintf(envname, sizeof(envname), "%s[%d]",
+ envprefix, bootenvs_idx);
+ snprintf(envval, sizeof(envval), "zfs:%s%s/%s",
+ checkpoint ? "!" : "", rootname, zfs_be->name);
rv = setenv(envname, envval, 1);
if (rv != 0)
break;
bootenvs_idx++;
}
+ snprintf(envname, sizeof(envname), "%s_count", envprefix);
snprintf(envval, sizeof(envval), "%d", bootenvs_idx);
- setenv("bootenvs_count", envval, 1);
+ setenv(envname, envval, 1);
/* Clean up the SLIST of ZFS BEs */
while (!SLIST_EMPTY(&zfs_be_head)) {
@@ -1183,19 +1233,17 @@ zfs_bootenv_initial(const char *name)
free(zfs_be->name);
free(zfs_be);
}
-
- return;
-
}
int
zfs_bootenv(const char *name)
{
- static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
+ char poolname[ZFS_MAXNAMELEN], *root;
+ const char *dsname;
char becount[4];
uint64_t objid;
spa_t *spa;
- int len, rv, pages, perpage, currpage;
+ int rv, pages, perpage, currpage;
if (name == NULL)
return (EINVAL);
@@ -1209,15 +1257,9 @@ zfs_bootenv(const char *name)
SLIST_INIT(&zfs_be_head);
zfs_env_count = 0;
- len = strlen(name);
- dsname = strchr(name, '/');
- if (dsname != NULL) {
- len = dsname - name;
- dsname++;
- } else
- dsname = "";
- memcpy(poolname, name, len);
- poolname[len] = '\0';
+
+ if (split_devname(name, poolname, sizeof(poolname), &dsname) != 0)
+ return (EINVAL);
spa = spa_find_by_name(poolname);
if (!spa)
@@ -1307,7 +1349,7 @@ zfs_set_env(void)
ctr++;
continue;
}
-
+
snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
snprintf(envval, sizeof(envval), "%s", zfs_be->name);
rv = setenv(envname, envval, 1);
@@ -1340,7 +1382,7 @@ zfs_set_env(void)
}
}
-
+
for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) {
snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
(void)unsetenv(envname);
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index 0e97e06245b3..152c0459c2be 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -699,7 +699,7 @@ vdev_indirect_read(vdev_t *vdev, const blkptr_t *bp, void *buf,
vic = &vdev->vdev_indirect_config;
vdev->v_mapping = vdev_indirect_mapping_open(spa,
- &spa->spa_mos, vic->vic_mapping_object);
+ spa->spa_mos, vic->vic_mapping_object);
}
vdev_indirect_remap(vdev, offset, bytes, &zio);
@@ -1347,6 +1347,8 @@ spa_create(uint64_t guid, const char *name)
free(spa);
return (NULL);
}
+ spa->spa_uberblock = &spa->spa_uberblock_master;
+ spa->spa_mos = &spa->spa_mos_master;
spa->spa_guid = guid;
spa->spa_root_vdev = vdev_create(guid, NULL);
if (spa->spa_root_vdev == NULL) {
@@ -1883,7 +1885,7 @@ vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap)
* the best uberblock and then we can actually access
* the contents of the pool.
*/
- vdev_uberblock_load(vdev, &spa->spa_uberblock);
+ vdev_uberblock_load(vdev, spa->spa_uberblock);
if (spap != NULL)
*spap = spa;
@@ -2409,8 +2411,9 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh,
if (zh->zap_magic != ZAP_MAGIC)
return (EIO);
- if ((rc = fzap_check_size(integer_size, num_integers)) != 0)
+ if ((rc = fzap_check_size(integer_size, num_integers)) != 0) {
return (rc);
+ }
z.zap_block_shift = ilog2(bsize);
z.zap_phys = zh;
@@ -2766,7 +2769,7 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
p = &name[sizeof(name) - 1];
*p = '\0';
- if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
+ if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) {
printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
return (EIO);
}
@@ -2774,7 +2777,7 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
dir_obj = ds->ds_dir_obj;
for (;;) {
- if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0)
+ if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir) != 0)
return (EIO);
dd = (dsl_dir_phys_t *)&dir.dn_bonus;
@@ -2783,12 +2786,12 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
if (parent_obj == 0)
break;
- if (objset_get_dnode(spa, &spa->spa_mos, parent_obj,
+ if (objset_get_dnode(spa, spa->spa_mos, parent_obj,
&parent) != 0)
return (EIO);
dd = (dsl_dir_phys_t *)&parent.dn_bonus;
child_dir_zapobj = dd->dd_child_dir_zapobj;
- if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj,
+ if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap) != 0)
return (EIO);
if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0)
@@ -2820,7 +2823,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
dsl_dir_phys_t *dd;
const char *p, *q;
- if (objset_get_dnode(spa, &spa->spa_mos,
+ if (objset_get_dnode(spa, spa->spa_mos,
DMU_POOL_DIRECTORY_OBJECT, &dir))
return (EIO);
if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj),
@@ -2829,7 +2832,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
p = name;
for (;;) {
- if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir))
+ if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir))
return (EIO);
dd = (dsl_dir_phys_t *)&dir.dn_bonus;
@@ -2850,7 +2853,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
}
child_dir_zapobj = dd->dd_child_dir_zapobj;
- if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj,
+ if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap) != 0)
return (EIO);
@@ -2873,21 +2876,21 @@ zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/)
dsl_dataset_phys_t *ds;
dsl_dir_phys_t *dd;
- if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
+ if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) {
printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
return (EIO);
}
ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
dir_obj = ds->ds_dir_obj;
- if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) {
+ if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir)) {
printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj);
return (EIO);
}
dd = (dsl_dir_phys_t *)&dir.dn_bonus;
child_dir_zapobj = dd->dd_child_dir_zapobj;
- if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj,
+ if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap) != 0) {
printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj);
return (EIO);
@@ -2908,7 +2911,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum,
size_t size;
int err;
- err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset);
+ err = objset_get_dnode(spa, spa->spa_mos, objnum, &dataset);
if (err != 0) {
printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
return (err);
@@ -2916,7 +2919,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum,
ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
dir_obj = ds->ds_dir_obj;
- err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir);
+ err = objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir);
if (err != 0) {
printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj);
return (err);
@@ -2924,7 +2927,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum,
dd = (dsl_dir_phys_t *)&dir.dn_bonus;
child_dir_zapobj = dd->dd_child_dir_zapobj;
- err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj,
+ err = objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap);
if (err != 0) {
printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj);
@@ -2962,7 +2965,7 @@ zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset)
dnode_phys_t dataset;
dsl_dataset_phys_t *ds;
- if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
+ if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) {
printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
return (EIO);
}
@@ -2992,7 +2995,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid)
/*
* Start with the MOS directory object.
*/
- if (objset_get_dnode(spa, &spa->spa_mos,
+ if (objset_get_dnode(spa, spa->spa_mos,
DMU_POOL_DIRECTORY_OBJECT, &dir)) {
printf("ZFS: can't read MOS object directory\n");
return (EIO);
@@ -3003,7 +3006,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid)
*/
if (zap_lookup(spa, &dir, DMU_POOL_PROPS,
sizeof(props), 1, &props) == 0 &&
- objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 &&
+ objset_get_dnode(spa, spa->spa_mos, props, &propdir) == 0 &&
zap_lookup(spa, &propdir, "bootfs",
sizeof(bootfs), 1, &bootfs) == 0 && bootfs != 0) {
*objid = bootfs;
@@ -3014,7 +3017,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid)
*/
if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET,
sizeof(root), 1, &root) ||
- objset_get_dnode(spa, &spa->spa_mos, root, &dir)) {
+ objset_get_dnode(spa, spa->spa_mos, root, &dir)) {
printf("ZFS: can't find root dsl_dir\n");
return (EIO);
}
@@ -3085,7 +3088,7 @@ check_mos_features(const spa_t *spa)
size_t size;
int rc;
- if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY,
+ if ((rc = objset_get_dnode(spa, spa->spa_mos, DMU_OT_OBJECT_DIRECTORY,
&dir)) != 0)
return (rc);
if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ,
@@ -3097,7 +3100,7 @@ check_mos_features(const spa_t *spa)
return (0);
}
- if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0)
+ if ((rc = objset_get_dnode(spa, spa->spa_mos, objnum, &dir)) != 0)
return (rc);
if (dir.dn_type != DMU_OTN_ZAP_METADATA)
@@ -3131,7 +3134,7 @@ load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value)
unsigned char *nv;
*value = NULL;
- if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0)
+ if ((rc = objset_get_dnode(spa, spa->spa_mos, obj, &dir)) != 0)
return (rc);
if (dir.dn_type != DMU_OT_PACKED_NVLIST &&
dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) {
@@ -3160,22 +3163,23 @@ load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value)
static int
zfs_spa_init(spa_t *spa)
{
+ struct uberblock checkpoint;
dnode_phys_t dir;
uint64_t config_object;
nvlist_t *nvlist;
int rc;
- if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) {
+ if (zio_read(spa, &spa->spa_uberblock->ub_rootbp, spa->spa_mos)) {
printf("ZFS: can't read MOS of pool %s\n", spa->spa_name);
return (EIO);
}
- if (spa->spa_mos.os_type != DMU_OST_META) {
+ if (spa->spa_mos->os_type != DMU_OST_META) {
printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name);
return (EIO);
}
- if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT,
- &dir)) {
+ if (objset_get_dnode(spa, &spa->spa_mos_master,
+ DMU_POOL_DIRECTORY_OBJECT, &dir)) {
printf("ZFS: failed to read pool %s directory object\n",
spa->spa_name);
return (EIO);
@@ -3200,6 +3204,20 @@ zfs_spa_init(spa_t *spa)
rc = load_nvlist(spa, config_object, &nvlist);
if (rc != 0)
return (rc);
+
+ rc = zap_lookup(spa, &dir, DMU_POOL_ZPOOL_CHECKPOINT,
+ sizeof(uint64_t), sizeof(checkpoint) / sizeof(uint64_t),
+ &checkpoint);
+ if (rc == 0 && checkpoint.ub_checkpoint_txg != 0) {
+ memcpy(&spa->spa_uberblock_checkpoint, &checkpoint,
+ sizeof(checkpoint));
+ if (zio_read(spa, &spa->spa_uberblock_checkpoint.ub_rootbp,
+ &spa->spa_mos_checkpoint)) {
+ printf("ZFS: can not read checkpoint data.\n");
+ return (EIO);
+ }
+ }
+
/*
* Update vdevs from MOS config. Note, we do skip encoding bytes
* here. See also vdev_label_read_config().
diff --git a/stand/lua/core.lua b/stand/lua/core.lua
index 448215d97d03..c56443e98733 100644
--- a/stand/lua/core.lua
+++ b/stand/lua/core.lua
@@ -38,6 +38,8 @@ local default_safe_mode = false
local default_single_user = false
local default_verbose = false
+local bootenv_list = "bootenvs"
+
local function composeLoaderCmd(cmd_name, argstr)
if argstr ~= nil then
cmd_name = cmd_name .. " " .. argstr
@@ -270,7 +272,7 @@ function core.bootenvDefault()
end
function core.bootenvList()
- local bootenv_count = tonumber(loader.getenv("bootenvs_count"))
+ local bootenv_count = tonumber(loader.getenv(bootenv_list .. "_count"))
local bootenvs = {}
local curenv
local envcount = 0
@@ -281,7 +283,12 @@ function core.bootenvList()
end
-- Currently selected bootenv is always first/default
- curenv = core.bootenvDefault()
+ -- On the rewinded list the bootenv may not exists
+ if core.isRewinded() then
+ curenv = core.bootenvDefaultRewinded()
+ else
+ curenv = core.bootenvDefault()
+ end
if curenv ~= nil then
envcount = envcount + 1
bootenvs[envcount] = curenv
@@ -289,7 +296,7 @@ function core.bootenvList()
end
for curenv_idx = 0, bootenv_count - 1 do
- curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]")
+ curenv = loader.getenv(bootenv_list .. "[" .. curenv_idx .. "]")
if curenv ~= nil and unique[curenv] == nil then
envcount = envcount + 1
bootenvs[envcount] = curenv
@@ -299,6 +306,40 @@ function core.bootenvList()
return bootenvs
end
+function core.isCheckpointed()
+ return loader.getenv("zpool_checkpoint") ~= nil
+end
+
+function core.bootenvDefaultRewinded()
+ local defname = "zfs:!" .. string.sub(core.bootenvDefault(), 5)
+ local bootenv_count = tonumber("bootenvs_check_count")
+
+ if bootenv_count == nil or bootenv_count <= 0 then
+ return defname
+ end
+
+ for curenv_idx = 0, bootenv_count - 1 do
+ curenv = loader.getenv("bootenvs_check[" .. curenv_idx .. "]")
+ if curenv == defname then
+ return defname
+ end
+ end
+
+ return loader.getenv("bootenvs_check[0]")
+end
+
+function core.isRewinded()
+ return bootenv_list == "bootenvs_check"
+end
+
+function core.changeRewindCheckpoint()
+ if core.isRewinded() then
+ bootenv_list = "bootenvs"
+ else
+ bootenv_list = "bootenvs_check"
+ end
+end
+
function core.setDefaults()
core.setACPI(core.getACPIPresent(true))
core.setSafeMode(default_safe_mode)
diff --git a/stand/lua/menu.lua b/stand/lua/menu.lua
index 32f414f7fbfa..103ec9c00050 100644
--- a/stand/lua/menu.lua
+++ b/stand/lua/menu.lua
@@ -132,6 +132,9 @@ menu.boot_environments = {
},
{
entry_type = core.MENU_ENTRY,
+ visible = function()
+ return core.isRewinded() == false
+ end,
name = function()
return color.highlight("b") .. "ootfs: " ..
core.bootenvDefault()
@@ -250,6 +253,7 @@ menu.welcome = {
},
menu_entries.kernel_options,
menu_entries.boot_options,
+ menu_entries.zpool_checkpoints,
menu_entries.boot_envs,
menu_entries.chainload,
}
@@ -334,6 +338,32 @@ menu.welcome = {
submenu = menu.boot_options,
alias = {"o", "O"},
},
+ zpool_checkpoints = {
+ entry_type = core.MENU_ENTRY,
+ name = function()
+ rewind = "No"
+ if core.isRewinded() then
+ rewind = "Yes"
+ end
+ return "Rewind ZFS " .. color.highlight("C") ..
+ "heckpoint: " .. rewind
+ end,
+ func = function()
+ core.changeRewindCheckpoint()
+ if core.isRewinded() then
+ bootenvSet(
+ core.bootenvDefaultRewinded())
+ else
+ bootenvSet(core.bootenvDefault())
+ end
+ config.setCarouselIndex("be_active", 1)
+ end,
+ visible = function()
+ return core.isZFSBoot() and
+ core.isCheckpointed()
+ end,
+ alias = {"c", "C"},
+ },
boot_envs = {
entry_type = core.MENU_SUBMENU,
visible = function()