kboot: Add ZFS support to hostdisk

Add helper function to walk through the disk drives we've found to look
for zpools. main.c will still need to call this because the loader
hasn't implemented a good way to 'taste' drives for zpools and/or GELI
partitions (mostly because there's no generic list of candidate
devices).

Sponsored by:		Netflix
Reviewed by:		kevans
Differential Revision:	https://reviews.freebsd.org/D38007
This commit is contained in:
Warner Losh 2023-01-13 14:20:30 -07:00
parent 1a13008e98
commit cc82c650a7
2 changed files with 127 additions and 2 deletions

View File

@ -30,8 +30,14 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/disk.h>
#include <stdarg.h>
#include <paths.h>
#include "host_syscall.h"
#include "kboot.h"
#include "bootstrap.h"
#ifdef LOADER_ZFS_SUPPORT
#include "libzfs.h"
#include <sys/zfs_bootenv.h>
#endif
static int hostdisk_init(void);
static int hostdisk_strategy(void *devdata, int flag, daddr_t dblk,
@ -75,6 +81,8 @@ typedef struct hdinfo {
uint64_t hd_sectors;
uint64_t hd_sectorsize;
int hd_flags;
#define HDF_HAS_ZPOOL 1 /* We found a zpool here and uuid valid */
uint64_t hd_zfs_uuid;
} hdinfo_t;
#define dev2hd(d) ((hdinfo_t *)d->d_opendata)
@ -416,3 +424,117 @@ hostdisk_parsedev(struct devdesc **idev, const char *devspec, const char **path)
*idev = dev;
return (0);
}
#ifdef LOADER_ZFS_SUPPORT
static bool
hostdisk_zfs_check_one(hdinfo_t *hd)
{
char *fn;
bool found = false;
uint64_t pool_uuid;
if (asprintf(&fn, "%s:", hd->hd_dev) == -1)
return (false);
pool_uuid = 0;
zfs_probe_dev(fn, &pool_uuid, false);
if (pool_uuid != 0) {
found = true;
hd->hd_flags |= HDF_HAS_ZPOOL;
hd->hd_zfs_uuid = pool_uuid;
}
free(fn);
return (found);
}
void
hostdisk_zfs_probe(void)
{
hdinfo_t *hd, *md;
STAILQ_FOREACH(hd, &hdinfo, hd_link) {
if (hostdisk_zfs_check_one(hd))
continue;
STAILQ_FOREACH(md, &hd->hd_children, hd_link) {
hostdisk_zfs_check_one(md);
}
}
}
/* XXX refactor */
static bool
sanity_check_currdev(void)
{
struct stat st;
return (stat(PATH_DEFAULTS_LOADER_CONF, &st) == 0 ||
#ifdef PATH_BOOTABLE_TOKEN
stat(PATH_BOOTABLE_TOKEN, &st) == 0 || /* non-standard layout */
#endif
stat(PATH_KERNEL, &st) == 0);
}
/* This likely shoud move to libsa/zfs/zfs.c and be used by at least EFI booting */
static bool
probe_zfs_currdev(uint64_t pool_guid, uint64_t root_guid, bool setcurrdev)
{
char *devname;
struct zfs_devdesc currdev;
char *buf = NULL;
bool bootable;
currdev.dd.d_dev = &zfs_dev;
currdev.dd.d_unit = 0;
currdev.pool_guid = pool_guid;
currdev.root_guid = root_guid;
devname = devformat(&currdev.dd);
if (setcurrdev)
set_currdev(devname);
bootable = sanity_check_currdev();
if (bootable) {
buf = malloc(VDEV_PAD_SIZE);
if (buf != NULL) {
if (zfs_get_bootonce(&currdev, OS_BOOTONCE, buf,
VDEV_PAD_SIZE) == 0) {
printf("zfs bootonce: %s\n", buf);
if (setcurrdev)
set_currdev(buf);
setenv("zfs-bootonce", buf, 1);
}
free(buf);
(void)zfs_attach_nvstore(&currdev);
}
init_zfs_boot_options(devname);
}
return (bootable);
}
static bool
hostdisk_zfs_try_default(hdinfo_t *hd)
{
return (probe_zfs_currdev(hd->hd_zfs_uuid, 0, true));
}
bool
hostdisk_zfs_find_default(void)
{
hdinfo_t *hd, *md;
STAILQ_FOREACH(hd, &hdinfo, hd_link) {
if (hd->hd_flags & HDF_HAS_ZPOOL) {
if (hostdisk_zfs_try_default(hd))
return (true);
continue;
}
STAILQ_FOREACH(md, &hd->hd_children, hd_link) {
if (md->hd_flags & HDF_HAS_ZPOOL) {
if (hostdisk_zfs_try_default(md))
return (true);
}
}
}
return (false);
}
#endif

View File

@ -14,14 +14,17 @@ vm_offset_t acpi_rsdp(void);
void do_init(void);
extern const char *hostfs_root;
/* Per-platform fdt fixup */
void fdt_arch_fixups(void *fdtp);
uint64_t kboot_get_phys_load_segment(void);
uint8_t kboot_get_kernel_machine_bits(void);
/* hostdisk.c */
extern const char *hostfs_root;
void hostdisk_zfs_probe(void);
bool hostdisk_zfs_find_default(void);
/* util.c */
bool file2str(const char *fn, char *buffer, size_t buflen);
bool file2u64(const char *fn, uint64_t *val);