diff --git a/stand/efi/boot1/zfs_module.c b/stand/efi/boot1/zfs_module.c --- a/stand/efi/boot1/zfs_module.c +++ b/stand/efi/boot1/zfs_module.c @@ -144,6 +144,7 @@ struct zfsmount zmount; dnode_phys_t dn; struct stat st; + uint64_t rootobj; int err; void *buf; @@ -162,20 +163,49 @@ return (EFI_NOT_FOUND); } - if ((err = zfs_mount_impl(spa, 0, &zmount)) != 0) { - DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); - return (EFI_NOT_FOUND); + if (zfs_get_bootonce_spa(spa, OS_BOOTONCE, zfs_bootonce, + sizeof(zfs_bootonce)) == 0) { + /* + * If bootonce attribute is present, use it as root dataset. + * Any attempt to use it should clear the 'once' flag. Prior + * to now, we'd not be able to clear it anyway. We don't care + * if we can't find the files to boot, or if there's a problem + * with it: we've tried to use it once we're able to mount the + * ZFS dataset. + * + * Note: the attribute is prefixed with "zfs:" and suffixed + * with ":". + */ + char *dname, *end; + + if (zfs_bootonce[0] != 'z' || zfs_bootonce[1] != 'f' || + zfs_bootonce[2] != 's' || zfs_bootonce[3] != ':' || + (dname = strchr(&zfs_bootonce[4], '/')) == NULL || + (end = strrchr(&zfs_bootonce[4], ':')) == NULL) { + printf("INVALID zfs bootonce: %s\n", zfs_bootonce); + *zfs_bootonce = '\0'; + rootobj = 0; + } else { + dname += 1; + *end = '\0'; + if (zfs_lookup_dataset(spa, dname, &rootobj) != 0) { + printf("zfs bootonce dataset %s NOT FOUND\n", + dname); + *zfs_bootonce = '\0'; + rootobj = 0; + } else + printf("zfs bootonce: %s\n", zfs_bootonce); + *end = ':'; + } + } else { + *zfs_bootonce = '\0'; + rootobj = 0; } - /* - * OK. We've found a filesystem. Any attempt to use it should clear the - * 'once' flag. Prior to now, we'd not be able to clear it anyway. We - * don't care if we can't find the files to boot, or if there's a - * problem with it: we've tried to use it once we're able to mount the - * ZFS dataset. - */ - *zfs_bootonce = '\0'; - zfs_get_bootonce_spa(spa, OS_BOOTONCE, zfs_bootonce, sizeof(zfs_bootonce)); + if ((err = zfs_mount_impl(spa, rootobj, &zmount)) != 0) { + printf("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); + return (EFI_NOT_FOUND); + } if ((err = zfs_lookup(&zmount, filepath, &dn)) != 0) { if (err == ENOENT) {