Index: stand/i386/zfsboot/zfsboot.c =================================================================== --- stand/i386/zfsboot/zfsboot.c +++ stand/i386/zfsboot/zfsboot.c @@ -166,9 +166,10 @@ int main(void) { - unsigned i; - int auto_boot, fd, nextboot = 0; struct disk_devdesc devdesc; + uint64_t pool_guid; + unsigned int i; + int auto_boot, fd, nextboot = 0; bios_getmem(); @@ -215,8 +216,14 @@ if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); - disk_parsedev(&devdesc, boot_devname + 4, NULL); + if (zfs_get_bootguid(&pool_guid) == 0) { + bdev = malloc(sizeof (struct i386_devdesc)); + bzero(bdev, sizeof (struct i386_devdesc)); + bdev->dd.d_dev = &zfs_dev; + bdev->d_kind.zfs.pool_guid = pool_guid; + } + disk_parsedev(&devdesc, boot_devname + 4, NULL); bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1, devdesc.dd.d_unit, devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff); @@ -681,41 +688,31 @@ } /* - * Probe all disks to discover ZFS pools. The idea is to walk all possible - * disk devices, however, we also need to identify possible boot pool. - * For boot pool detection we have boot disk passed us from BIOS, recorded - * in bootinfo.bi_bios_dev. + * Probe all disks to discover ZFS pools. */ static void i386_zfs_probe(void) { char devname[32]; - int boot_unit; struct i386_devdesc dev; - uint64_t pool_guid = 0; + int boot_unit; dev.dd.d_dev = &bioshd; + /* Translate bios dev to our unit number. */ boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); /* * Open all the disks we can find and see if we can reconstruct - * ZFS pools from them. + * ZFS pools from them. Start with the boot disk. */ + snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, boot_unit); + zfs_probe_dev(devname, NULL); for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { - snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, - dev.dd.d_unit); - /* If this is not boot disk, use generic probe. */ - if (dev.dd.d_unit != boot_unit) + if (dev.dd.d_unit != boot_unit) { + snprintf(devname, sizeof (devname), "%s%d:", + bioshd.dv_name, dev.dd.d_unit); zfs_probe_dev(devname, NULL); - else - zfs_probe_dev(devname, &pool_guid); - - if (pool_guid != 0 && bdev == NULL) { - bdev = malloc(sizeof (struct i386_devdesc)); - bzero(bdev, sizeof (struct i386_devdesc)); - bdev->dd.d_dev = &zfs_dev; - bdev->d_kind.zfs.pool_guid = pool_guid; } } } Index: stand/libsa/zfs/libzfs.h =================================================================== --- stand/libsa/zfs/libzfs.h +++ stand/libsa/zfs/libzfs.h @@ -53,6 +53,7 @@ char *zfs_fmtdev(void *vdev); int zfs_probe_dev(const char *devname, uint64_t *pool_guid); int zfs_list(const char *name); +int zfs_get_bootguid(uint64_t *pool_guid); int zfs_get_bootonce(void *, const char *, char *, size_t); int zfs_get_bootenv(void *, nvlist_t **); int zfs_set_bootenv(void *, nvlist_t *); Index: stand/libsa/zfs/zfs.c =================================================================== --- stand/libsa/zfs/zfs.c +++ stand/libsa/zfs/zfs.c @@ -767,6 +767,20 @@ return (0); } +int +zfs_get_bootguid(uint64_t *pool_guid) +{ + spa_t *spa; + + *pool_guid = 0; + spa = spa_first_bootable(); + if (spa != NULL) { + *pool_guid = spa->spa_guid; + return (0); + } + return (ENXIO); +} + /* * Return bootenv nvlist from pool label. */ Index: stand/libsa/zfs/zfsimpl.c =================================================================== --- stand/libsa/zfs/zfsimpl.c +++ stand/libsa/zfs/zfsimpl.c @@ -1342,6 +1342,21 @@ return (rc); } +static spa_t * +spa_first_bootable(void) +{ + spa_t *spa; + + /* Pick the first pool with "bootfs" property explicitly set, if any. */ + STAILQ_FOREACH(spa, &zfs_pools, spa_link) { + if (spa->spa_bootfs != 0) + return (spa); + } + + /* Fall back to the first pool if there is one. */ + return (STAILQ_FIRST(&zfs_pools)); +} + static spa_t * spa_find_by_guid(uint64_t guid) { @@ -1374,7 +1389,7 @@ return (NULL); if (dev->pool_guid == 0) - return (STAILQ_FIRST(&zfs_pools)); + return (spa_first_bootable()); return (spa_find_by_guid(dev->pool_guid)); } @@ -3294,40 +3309,35 @@ static int zfs_get_root(const spa_t *spa, uint64_t *objid) { - dnode_phys_t dir, propdir; - uint64_t props, bootfs, root; + dnode_phys_t dir; + uint64_t root; *objid = 0; - /* - * Start with the MOS directory object. - */ - if (objset_get_dnode(spa, spa->spa_mos, - DMU_POOL_DIRECTORY_OBJECT, &dir)) { - printf("ZFS: can't read MOS object directory\n"); - return (EIO); - } - - /* - * Lookup the pool_props and see if we can find a bootfs. - */ - if (zap_lookup(spa, &dir, DMU_POOL_PROPS, - sizeof(props), 1, &props) == 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; + /* See if the pool has bootfs set. */ + if (spa->spa_bootfs != 0) { + *objid = spa->spa_bootfs; return (0); } + /* * Lookup the root dataset directory */ + if (objset_get_dnode(spa, spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, + &dir)) { + printf("ZFS: failed to read pool %s directory object\n", + spa->spa_name); + return (EIO); + } if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, - sizeof(root), 1, &root) || - objset_get_dnode(spa, spa->spa_mos, root, &dir)) { + sizeof(root), 1, &root) != 0) { printf("ZFS: can't find root dsl_dir\n"); return (EIO); } + if (objset_get_dnode(spa, spa->spa_mos, root, &dir) != 0) { + printf("ZFS: can't read root dsl_dir\n"); + return (EIO); + } /* * Use the information from the dataset directory's bonus buffer @@ -3471,8 +3481,8 @@ zfs_spa_init(spa_t *spa) { struct uberblock checkpoint; - dnode_phys_t dir; - uint64_t config_object; + dnode_phys_t dir, propdir; + uint64_t config_object, props; nvlist_t *nvlist; int rc; @@ -3502,6 +3512,22 @@ return (rc); } + /* + * Lookup the pool_props and see if we can find a bootfs. + */ + if (zap_lookup(spa, &dir, DMU_POOL_PROPS, + sizeof(props), 1, &props) == 0) { + rc = objset_get_dnode(spa, spa->spa_mos, props, &propdir); + if (rc != 0) { + printf("ZFS: failed to read pool %s properties object\n", + spa->spa_name); + return (rc); + } + spa->spa_bootfs = 0; + (void)zap_lookup(spa, &propdir, "bootfs", + sizeof(spa->spa_bootfs), 1, &spa->spa_bootfs); + } + rc = zap_lookup(spa, &dir, DMU_POOL_CONFIG, sizeof (config_object), 1, &config_object); if (rc != 0) { Index: sys/cddl/boot/zfs/zfsimpl.h =================================================================== --- sys/cddl/boot/zfs/zfsimpl.h +++ sys/cddl/boot/zfs/zfsimpl.h @@ -2030,6 +2030,7 @@ char *spa_name; /* pool name */ uint64_t spa_guid; /* pool guid */ uint64_t spa_txg; /* most recent transaction */ + uint64_t spa_bootfs; /* bootfs object id */ struct uberblock *spa_uberblock; /* best uberblock so far */ vdev_t *spa_root_vdev; /* toplevel vdev container */ objset_phys_t *spa_mos; /* MOS for this pool */