]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/i386/zfsboot/zfsboot.c
Merge llvm-project release/16.x llvmorg-16.0.3-0-gda3cd333bea5
[FreeBSD/FreeBSD.git] / stand / i386 / zfsboot / zfsboot.c
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
18
19 #include <stand.h>
20
21 #include <sys/param.h>
22 #include <sys/errno.h>
23 #include <sys/diskmbr.h>
24 #ifdef GPT
25 #include <sys/gpt.h>
26 #endif
27 #include <sys/reboot.h>
28 #include <sys/queue.h>
29 #ifdef LOADER_ZFS_SUPPORT
30 #include <sys/zfs_bootenv.h>
31 #endif
32
33 #include <machine/bootinfo.h>
34 #include <machine/elf.h>
35 #include <machine/pc/bios.h>
36
37 #include <stdarg.h>
38 #include <stddef.h>
39
40 #include <a.out.h>
41 #include "bootstrap.h"
42 #include "libi386.h"
43 #include <btxv86.h>
44
45 #include "lib.h"
46 #include "rbx.h"
47 #include "cons.h"
48 #include "bootargs.h"
49 #include "disk.h"
50 #include "part.h"
51 #include "paths.h"
52
53 #include "libzfs.h"
54
55 #define ARGS                    0x900
56 #define NOPT                    14
57 #define NDEV                    3
58
59 #define BIOS_NUMDRIVES          0x475
60 #define DRV_HARD                0x80
61 #define DRV_MASK                0x7f
62
63 #define TYPE_AD                 0
64 #define TYPE_DA                 1
65 #define TYPE_MAXHARD            TYPE_DA
66 #define TYPE_FD                 2
67
68 extern uint32_t _end;
69
70 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
71 static const unsigned char flags[NOPT] = {
72     RBX_DUAL,
73     RBX_SERIAL,
74     RBX_ASKNAME,
75     RBX_CDROM,
76     RBX_CONFIG,
77     RBX_KDB,
78     RBX_GDB,
79     RBX_MUTE,
80     RBX_NOINTR,
81     RBX_PAUSE,
82     RBX_QUIET,
83     RBX_DFLTROOT,
84     RBX_SINGLE,
85     RBX_VERBOSE
86 };
87 uint32_t opts;
88
89 /*
90  * Paths to try loading before falling back to the boot2 prompt.
91  *
92  * /boot/zfsloader must be tried before /boot/loader in order to remain
93  * backward compatible with ZFS boot environments where /boot/loader exists
94  * but does not have ZFS support, which was the case before FreeBSD 12.
95  *
96  * If no loader is found, try to load a kernel directly instead.
97  */
98 static const struct string {
99         const char *p;
100         size_t len;
101 } loadpath[] = {
102         { PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS) },
103         { PATH_LOADER, sizeof(PATH_LOADER) },
104         { PATH_KERNEL, sizeof(PATH_KERNEL) },
105 };
106
107 static const unsigned char dev_maj[NDEV] = {30, 4, 2};
108
109 static struct i386_devdesc *bdev;
110 static char cmd[512];
111 static char cmddup[512];
112 static char kname[1024];
113 static int comspeed = SIOSPD;
114 static struct bootinfo bootinfo;
115 static uint32_t bootdev;
116 static struct zfs_boot_args zfsargs;
117 #ifdef LOADER_GELI_SUPPORT
118 static struct geli_boot_args geliargs;
119 #endif
120
121 extern vm_offset_t high_heap_base;
122 extern uint32_t bios_basemem, bios_extmem, high_heap_size;
123
124 static char *heap_top;
125 static char *heap_bottom;
126
127 void exit(int);
128 static void i386_zfs_probe(void);
129 static void load(void);
130 static int parse_cmd(void);
131
132 #ifdef LOADER_GELI_SUPPORT
133 #include "geliboot.h"
134 static char gelipw[GELI_PW_MAXLEN];
135 #endif
136
137 struct arch_switch archsw;      /* MI/MD interface boundary */
138 static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */
139
140 struct devsw *devsw[] = {
141         &bioshd,
142 #if defined(LOADER_ZFS_SUPPORT)
143         &zfs_dev,
144 #endif
145         NULL
146 };
147
148 struct fs_ops *file_system[] = {
149 #if defined(LOADER_ZFS_SUPPORT)
150         &zfs_fsops,
151 #endif
152 #if defined(LOADER_UFS_SUPPORT)
153         &ufs_fsops,
154 #endif
155         NULL
156 };
157
158 caddr_t
159 ptov(uintptr_t x)
160 {
161         return (PTOV(x));
162 }
163
164 int main(void);
165
166 int
167 main(void)
168 {
169         unsigned i;
170         int auto_boot, fd, nextboot = 0;
171         struct disk_devdesc *devdesc;
172
173         bios_getmem();
174
175         if (high_heap_size > 0) {
176                 heap_top = PTOV(high_heap_base + high_heap_size);
177                 heap_bottom = PTOV(high_heap_base);
178         } else {
179                 heap_bottom = (char *)
180                     (roundup2(__base + (int32_t)&_end, 0x10000) - __base);
181                 heap_top = (char *)PTOV(bios_basemem);
182         }
183         setheap(heap_bottom, heap_top);
184
185         /*
186          * Initialise the block cache. Set the upper limit.
187          */
188         bcache_init(32768, 512);
189
190         archsw.arch_autoload = NULL;
191         archsw.arch_getdev = i386_getdev;
192         archsw.arch_copyin = NULL;
193         archsw.arch_copyout = NULL;
194         archsw.arch_readin = NULL;
195         archsw.arch_isainb = NULL;
196         archsw.arch_isaoutb = NULL;
197         archsw.arch_zfs_probe = i386_zfs_probe;
198
199         bootinfo.bi_version = BOOTINFO_VERSION;
200         bootinfo.bi_size = sizeof(bootinfo);
201         bootinfo.bi_basemem = bios_basemem / 1024;
202         bootinfo.bi_extmem = bios_extmem / 1024;
203         bootinfo.bi_memsizes_valid++;
204         bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS);
205
206         /* Set up fall back device name. */
207         snprintf(boot_devname, sizeof (boot_devname), "disk%d:",
208             bd_bios2unit(bootinfo.bi_bios_dev));
209
210         /* Set up currdev variable to have hooks in place. */
211         env_setenv("currdev", EV_VOLATILE, "", gen_setcurrdev,
212             env_nounset);
213
214         devinit();
215
216         /* XXX assumes this will be a disk, but it looks likely give above */
217         disk_parsedev((struct devdesc **)&devdesc, boot_devname, NULL);
218
219         bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc->d_slice + 1,
220             devdesc->dd.d_unit,
221             devdesc->d_partition >= 0 ? devdesc->d_partition : 0xff);
222         free(devdesc);
223
224         /*
225          * devformat() can be called only after dv_init
226          */
227         if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) {
228                 /* set up proper device name string for ZFS */
229                 strncpy(boot_devname, devformat(&bdev->dd), sizeof (boot_devname));
230                 if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd,
231                     sizeof(cmd)) == 0) {
232                         nvlist_t *benv;
233
234                         nextboot = 1;
235                         memcpy(cmddup, cmd, sizeof(cmd));
236                         if (parse_cmd()) {
237                                 if (!OPT_CHECK(RBX_QUIET))
238                                         printf("failed to parse bootonce "
239                                             "command\n");
240                                 exit(0);
241                         }
242                         if (!OPT_CHECK(RBX_QUIET))
243                                 printf("zfs bootonce: %s\n", cmddup);
244
245                         if (zfs_get_bootenv(bdev, &benv) == 0) {
246                                 nvlist_add_string(benv, OS_BOOTONCE_USED,
247                                     cmddup);
248                                 zfs_set_bootenv(bdev, benv);
249                         }
250                         /* Do not process this command twice */
251                         *cmd = 0;
252                 }
253         }
254
255         /* now make sure we have bdev on all cases */
256         free(bdev);
257         i386_getdev((void **)&bdev, boot_devname, NULL);
258
259         env_setenv("currdev", EV_VOLATILE, boot_devname, gen_setcurrdev,
260             env_nounset);
261
262         /* Process configuration file */
263         auto_boot = 1;
264
265         fd = open(PATH_CONFIG, O_RDONLY);
266         if (fd == -1)
267                 fd = open(PATH_DOTCONFIG, O_RDONLY);
268
269         if (fd != -1) {
270                 ssize_t cmdlen;
271
272                 if ((cmdlen = read(fd, cmd, sizeof(cmd))) > 0)
273                         cmd[cmdlen] = '\0';
274                 else
275                         *cmd = '\0';
276                 close(fd);
277         }
278
279         if (*cmd) {
280                 /*
281                  * Note that parse_cmd() is destructive to cmd[] and we also
282                  * want to honor RBX_QUIET option that could be present in
283                  * cmd[].
284                  */
285                 memcpy(cmddup, cmd, sizeof(cmd));
286                 if (parse_cmd())
287                         auto_boot = 0;
288                 if (!OPT_CHECK(RBX_QUIET))
289                         printf("%s: %s\n", PATH_CONFIG, cmddup);
290                 /* Do not process this command twice */
291                 *cmd = 0;
292         }
293
294         /* Do not risk waiting at the prompt forever. */
295         if (nextboot && !auto_boot)
296                 exit(0);
297
298         if (auto_boot && !*kname) {
299                 /*
300                  * Iterate through the list of loader and kernel paths,
301                  * trying to load. If interrupted by a keypress, or in case of
302                  * failure, drop the user to the boot2 prompt.
303                  */
304                 for (i = 0; i < nitems(loadpath); i++) {
305                         memcpy(kname, loadpath[i].p, loadpath[i].len);
306                         if (keyhit(3))
307                                 break;
308                         load();
309                 }
310         }
311
312         /* Present the user with the boot2 prompt. */
313
314         for (;;) {
315                 if (!auto_boot || !OPT_CHECK(RBX_QUIET)) {
316                         printf("\nFreeBSD/x86 boot\n");
317                         printf("Default: %s%s\nboot: ", boot_devname, kname);
318                 }
319                 if (ioctrl & IO_SERIAL)
320                         sio_flush();
321                 if (!auto_boot || keyhit(5))
322                         getstr(cmd, sizeof(cmd));
323                 else if (!auto_boot || !OPT_CHECK(RBX_QUIET))
324                         putchar('\n');
325                 auto_boot = 0;
326                 if (parse_cmd())
327                         putchar('\a');
328                 else
329                         load();
330         }
331 }
332
333 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
334 void
335 exit(int x)
336 {
337         __exit(x);
338 }
339
340 static void
341 load(void)
342 {
343         union {
344                 struct exec ex;
345                 Elf32_Ehdr eh;
346         } hdr;
347         static Elf32_Phdr ep[2];
348         static Elf32_Shdr es[2];
349         caddr_t p;
350         uint32_t addr, x;
351         int fd, fmt, i, j;
352         ssize_t size;
353
354         if ((fd = open(kname, O_RDONLY)) == -1) {
355                 printf("\nCan't find %s\n", kname);
356                 return;
357         }
358
359         size = sizeof(hdr);
360         if (read(fd, &hdr, sizeof (hdr)) != size) {
361                 close(fd);
362                 return;
363         }
364         if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
365                 fmt = 0;
366         } else if (IS_ELF(hdr.eh)) {
367                 fmt = 1;
368         } else {
369                 printf("Invalid %s\n", "format");
370                 close(fd);
371                 return;
372         }
373         if (fmt == 0) {
374                 addr = hdr.ex.a_entry & 0xffffff;
375                 p = PTOV(addr);
376                 lseek(fd, PAGE_SIZE, SEEK_SET);
377                 size = hdr.ex.a_text;
378                 if (read(fd, p, hdr.ex.a_text) != size) {
379                         close(fd);
380                         return;
381                 }
382                 p += roundup2(hdr.ex.a_text, PAGE_SIZE);
383                 size = hdr.ex.a_data;
384                 if (read(fd, p, hdr.ex.a_data) != size) {
385                         close(fd);
386                         return;
387                 }
388                 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
389                 bootinfo.bi_symtab = VTOP(p);
390                 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
391                 p += sizeof(hdr.ex.a_syms);
392                 if (hdr.ex.a_syms) {
393                         size = hdr.ex.a_syms;
394                         if (read(fd, p, hdr.ex.a_syms) != size) {
395                                 close(fd);
396                                 return;
397                         }
398                         p += hdr.ex.a_syms;
399                         size = sizeof (int);
400                         if (read(fd, p, sizeof (int)) != size) {
401                                 close(fd);
402                                 return;
403                         }
404                         x = *(uint32_t *)p;
405                         p += sizeof(int);
406                         x -= sizeof(int);
407                         size = x;
408                         if (read(fd, p, x) != size) {
409                                 close(fd);
410                                 return;
411                         }
412                         p += x;
413                 }
414         } else {
415                 lseek(fd, hdr.eh.e_phoff, SEEK_SET);
416                 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
417                         size = sizeof (ep[0]);
418                         if (read(fd, ep + j, sizeof (ep[0])) != size) {
419                                 close(fd);
420                                 return;
421                         }
422                         if (ep[j].p_type == PT_LOAD)
423                                 j++;
424                 }
425                 for (i = 0; i < 2; i++) {
426                         p = PTOV(ep[i].p_paddr & 0xffffff);
427                         lseek(fd, ep[i].p_offset, SEEK_SET);
428                         size = ep[i].p_filesz;
429                         if (read(fd, p, ep[i].p_filesz) != size) {
430                                 close(fd);
431                                 return;
432                         }
433                 }
434                 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
435                 bootinfo.bi_symtab = VTOP(p);
436                 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
437                         lseek(fd, hdr.eh.e_shoff +
438                             sizeof (es[0]) * (hdr.eh.e_shstrndx + 1),
439                             SEEK_SET);
440                         size = sizeof(es);
441                         if (read(fd, &es, sizeof (es)) != size) {
442                                 close(fd);
443                                 return;
444                         }
445                         for (i = 0; i < 2; i++) {
446                                 memcpy(p, &es[i].sh_size,
447                                     sizeof(es[i].sh_size));
448                                 p += sizeof(es[i].sh_size);
449                                 lseek(fd, es[i].sh_offset, SEEK_SET);
450                                 size = es[i].sh_size;
451                                 if (read(fd, p, es[i].sh_size) != size) {
452                                         close(fd);
453                                         return;
454                                 }
455                                 p += es[i].sh_size;
456                         }
457                 }
458                 addr = hdr.eh.e_entry & 0xffffff;
459         }
460         close(fd);
461
462         bootinfo.bi_esymtab = VTOP(p);
463         bootinfo.bi_kernelname = VTOP(kname);
464 #ifdef LOADER_GELI_SUPPORT
465         explicit_bzero(gelipw, sizeof(gelipw));
466 #endif
467
468         if (bdev->dd.d_dev->dv_type == DEVT_ZFS) {
469                 zfsargs.size = sizeof(zfsargs);
470                 zfsargs.pool = bdev->zfs.pool_guid;
471                 zfsargs.root = bdev->zfs.root_guid;
472 #ifdef LOADER_GELI_SUPPORT
473                 export_geli_boot_data(&zfsargs.gelidata);
474 #endif
475                 /*
476                  * Note that the zfsargs struct is passed by value, not by
477                  * pointer. Code in btxldr.S copies the values from the entry
478                  * stack to a fixed location within loader(8) at startup due
479                  * to the presence of KARGS_FLAGS_EXTARG.
480                  */
481                 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
482                     bootdev,
483                     KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG,
484                     (uint32_t)bdev->zfs.pool_guid,
485                     (uint32_t)(bdev->zfs.pool_guid >> 32),
486                     VTOP(&bootinfo),
487                     zfsargs);
488         } else {
489 #ifdef LOADER_GELI_SUPPORT
490                 geliargs.size = sizeof(geliargs);
491                 export_geli_boot_data(&geliargs.gelidata);
492 #endif
493
494                 /*
495                  * Note that the geliargs struct is passed by value, not by
496                  * pointer. Code in btxldr.S copies the values from the entry
497                  * stack to a fixed location within loader(8) at startup due
498                  * to the presence of the KARGS_FLAGS_EXTARG flag.
499                  */
500                 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
501                     bootdev,
502 #ifdef LOADER_GELI_SUPPORT
503                     KARGS_FLAGS_GELI | KARGS_FLAGS_EXTARG, 0, 0,
504                     VTOP(&bootinfo), geliargs
505 #else
506                     0, 0, 0, VTOP(&bootinfo)
507 #endif
508                     );
509         }
510 }
511
512 static int
513 mount_root(char *arg)
514 {
515         char *root;
516         struct i386_devdesc *ddesc;
517         uint8_t part;
518
519         if (asprintf(&root, "%s:", arg) < 0)
520                 return (1);
521
522         if (i386_getdev((void **)&ddesc, root, NULL)) {
523                 free(root);
524                 return (1);
525         }
526
527         /* we should have new device descriptor, free old and replace it. */
528         free(bdev);
529         bdev = ddesc;
530         if (bdev->dd.d_dev->dv_type == DEVT_DISK) {
531                 if (bdev->disk.d_partition == -1)
532                         part = 0xff;
533                 else
534                         part = bdev->disk.d_partition;
535                 bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type],
536                     bdev->disk.d_slice + 1, bdev->dd.d_unit, part);
537                 bootinfo.bi_bios_dev = bd_unit2bios(bdev);
538         }
539         strncpy(boot_devname, root, sizeof (boot_devname));
540         setenv("currdev", root, 1);
541         free(root);
542         return (0);
543 }
544
545 static void
546 fs_list(char *arg)
547 {
548         int fd;
549         struct dirent *d;
550         char line[80];
551
552         fd = open(arg, O_RDONLY);
553         if (fd < 0)
554                 return;
555         pager_open();
556         while ((d = readdirfd(fd)) != NULL) {
557                 sprintf(line, "%s\n", d->d_name);
558                 if (pager_output(line))
559                         break;
560         }
561         pager_close();
562         close(fd);
563 }
564
565 static int
566 parse_cmd(void)
567 {
568         char *arg = cmd;
569         char *ep, *p, *q;
570         const char *cp;
571         char line[80];
572         int c, i, j;
573
574         while ((c = *arg++)) {
575                 if (c == ' ' || c == '\t' || c == '\n')
576                         continue;
577                 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
578                         ;
579                 ep = p;
580                 if (*p)
581                         *p++ = 0;
582                 if (c == '-') {
583                         while ((c = *arg++)) {
584                                 if (c == 'P') {
585                                         if (*(uint8_t *)PTOV(0x496) & 0x10) {
586                                                 cp = "yes";
587                                         } else {
588                                                 opts |= OPT_SET(RBX_DUAL);
589                                                 opts |= OPT_SET(RBX_SERIAL);
590                                                 cp = "no";
591                                         }
592                                         printf("Keyboard: %s\n", cp);
593                                         continue;
594                                 } else if (c == 'S') {
595                                         j = 0;
596                                         while ((unsigned int)
597                                             (i = *arg++ - '0') <= 9)
598                                                 j = j * 10 + i;
599                                         if (j > 0 && i == -'0') {
600                                                 comspeed = j;
601                                                 break;
602                                         }
603                                         /*
604                                          * Fall through to error below
605                                          * ('S' not in optstr[]).
606                                          */
607                                 }
608                                 for (i = 0; c != optstr[i]; i++)
609                                         if (i == NOPT - 1)
610                                                 return (-1);
611                                 opts ^= OPT_SET(flags[i]);
612                         }
613                         ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
614                             OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
615                         if (ioctrl & IO_SERIAL) {
616                                 if (sio_init(115200 / comspeed) != 0)
617                                         ioctrl &= ~IO_SERIAL;
618                         }
619                 } if (c == '?') {
620                         printf("\n");
621                         if (*arg == '\0')
622                                 arg = (char *)"/";
623                         fs_list(arg);
624                         zfs_list(arg);
625                         return (-1);
626                 } else {
627                         char *ptr;
628                         printf("\n");
629                         arg--;
630
631                         /*
632                          * Report pool status if the comment is 'status'. Lets
633                          * hope no-one wants to load /status as a kernel.
634                          */
635                         if (strcmp(arg, "status") == 0) {
636                                 pager_open();
637                                 for (i = 0; devsw[i] != NULL; i++) {
638                                         if (devsw[i]->dv_print != NULL) {
639                                                 if (devsw[i]->dv_print(1))
640                                                         break;
641                                         } else {
642                                                 snprintf(line, sizeof(line),
643                                                     "%s: (unknown)\n",
644                                                     devsw[i]->dv_name);
645                                                 if (pager_output(line))
646                                                         break;
647                                         }
648                                 }
649                                 pager_close();
650                                 return (-1);
651                         }
652
653                         /*
654                          * If there is "zfs:" prefix simply ignore it.
655                          */
656                         ptr = arg;
657                         if (strncmp(ptr, "zfs:", 4) == 0)
658                                 ptr += 4;
659
660                         /*
661                          * If there is a colon, switch pools.
662                          */
663                         q = strchr(ptr, ':');
664                         if (q) {
665                                 *q++ = '\0';
666                                 if (mount_root(arg) != 0) {
667                                         return (-1);
668                                 }
669                                 arg = q;
670                         }
671                         if ((i = ep - arg)) {
672                                 if ((size_t)i >= sizeof(kname))
673                                         return (-1);
674                                 memcpy(kname, arg, i + 1);
675                         }
676                 }
677                 arg = p;
678         }
679         return (0);
680 }
681
682 /*
683  * Probe all disks to discover ZFS pools. The idea is to walk all possible
684  * disk devices, however, we also need to identify possible boot pool.
685  * For boot pool detection we have boot disk passed us from BIOS, recorded
686  * in bootinfo.bi_bios_dev.
687  */
688 static void
689 i386_zfs_probe(void)
690 {
691         char devname[32];
692         int boot_unit;
693         struct i386_devdesc dev;
694         uint64_t pool_guid = 0;
695
696         dev.dd.d_dev = &bioshd;
697         /* Translate bios dev to our unit number. */
698         boot_unit = bd_bios2unit(bootinfo.bi_bios_dev);
699
700         /*
701          * Open all the disks we can find and see if we can reconstruct
702          * ZFS pools from them.
703          */
704         for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) {
705                 snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name,
706                     dev.dd.d_unit);
707                 /* If this is not boot disk, use generic probe. */
708                 if (dev.dd.d_unit != boot_unit)
709                         zfs_probe_dev(devname, NULL, true);
710                 else
711                         zfs_probe_dev(devname, &pool_guid, true);
712
713                 if (pool_guid != 0 && bdev == NULL) {
714                         bdev = malloc(sizeof (struct i386_devdesc));
715                         bzero(bdev, sizeof (struct i386_devdesc));
716                         bdev->zfs.dd.d_dev = &zfs_dev;
717                         bdev->zfs.pool_guid = pool_guid;
718                 }
719         }
720 }