diff --git a/stand/libsa/zfs/zfs.c b/stand/libsa/zfs/zfs.c --- a/stand/libsa/zfs/zfs.c +++ b/stand/libsa/zfs/zfs.c @@ -827,27 +827,12 @@ int zfs_get_bootonce(void *vdev, const char *key, char *buf, size_t size) { - nvlist_t *benv; - char *result = NULL; - int result_size, rv; - - if ((rv = zfs_get_bootenv(vdev, &benv)) != 0) - return (rv); + spa_t *spa; - if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL, - &result, &result_size)) == 0) { - if (result_size == 0) { - /* ignore empty string */ - rv = ENOENT; - } else { - size = MIN((size_t)result_size + 1, size); - strlcpy(buf, result, size); - } - (void) nvlist_remove(benv, key, DATA_TYPE_STRING); - (void) zfs_set_bootenv(vdev, benv); - } + if ((spa = spa_find_by_dev((struct zfs_devdesc *)vdev)) == NULL) + return (ENXIO); - return (rv); + return (zfs_get_bootonce_spa(spa, key, buf, size)); } /* diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c --- a/stand/libsa/zfs/zfsimpl.c +++ b/stand/libsa/zfs/zfsimpl.c @@ -3899,3 +3899,36 @@ spa->spa_bootenv = benv; return (0); } + +/* + * Get bootonce value by key. The bootonce pair is removed from the + * bootenv nvlist and the remaining nvlist is committed back to disk. This process + * the bootonce flag since we've reached the point in the boot that we've 'used' + * the BE. For chained boot scenarios, we may reach this point multiple times (but + * only remove it and return 0 the first time). + */ +static int +zfs_get_bootonce_spa(spa_t *spa, const char *key, char *buf, size_t size) +{ + nvlist_t *benv; + char *result = NULL; + int result_size, rv; + + if ((rv = zfs_get_bootenv_spa(spa, &benv)) != 0) + return (rv); + + if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL, + &result, &result_size)) == 0) { + if (result_size == 0) { + /* ignore empty string */ + rv = ENOENT; + } else if (buf != NULL) { + size = MIN((size_t)result_size + 1, size); + strlcpy(buf, result, size); + } + (void)nvlist_remove(benv, key, DATA_TYPE_STRING); + (void)zfs_set_bootenv_spa(spa, benv); + } + + return (rv); +}