commit 40c4901430d1f88812d8faae0f86cf3041dfb356 Author: Andriy Gapon Date: Sat May 5 12:34:42 2012 +0300 sys/boot: add a common CTASSERT definition diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index 7f011c7..4c92ba8 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -327,4 +327,10 @@ void dev_cleanup(void); time_t time(time_t *tloc); +#ifndef CTASSERT /* Allow lint to override */ +#define CTASSERT(x) _CTASSERT(x, __LINE__) +#define _CTASSERT(x, y) __CTASSERT(x, y) +#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] +#endif + #endif /* !_BOOTSTRAP_H_ */ diff --git a/sys/boot/i386/efi/reloc.c b/sys/boot/i386/efi/reloc.c index 24eed0a..96f9241 100644 --- a/sys/boot/i386/efi/reloc.c +++ b/sys/boot/i386/efi/reloc.c @@ -30,16 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include #include - -/* - * XXX: we can't include sys/systm.h. - */ -#ifndef CTASSERT /* Allow lint to override */ -#define CTASSERT(x) _CTASSERT(x, __LINE__) -#define _CTASSERT(x, y) __CTASSERT(x, y) -#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] -#endif - +#include /* * A simple relocator for IA32 EFI binaries. diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c index dbbf08d..cb0dda2 100644 --- a/sys/boot/sparc64/loader/main.c +++ b/sys/boot/sparc64/loader/main.c @@ -74,12 +74,6 @@ __FBSDID("$FreeBSD$"); #include "libofw.h" #include "dev_net.h" -#ifndef CTASSERT -#define CTASSERT(x) _CTASSERT(x, __LINE__) -#define _CTASSERT(x, y) __CTASSERT(x, y) -#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] -#endif - extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; enum { commit 929a8cc2f3d7b0027cd4be1ef3dcf5b6e8f3725a Author: Andriy Gapon Date: Wed Sep 21 12:35:41 2011 +0300 btxldr: future-proof argument passing from boot1/2-ish to loader Place the arguments at a fixed offset of 0x800 withing the argument area (of size 0x1000). Allow variable size extended arguments first of which should be a size of the extended arguments (including the size parameter). Consolidate related definitions in a new i386/common/bootargs.h header. diff --git a/sys/boot/i386/btx/btx/Makefile b/sys/boot/i386/btx/btx/Makefile index 2b4abe6..9784aed 100644 --- a/sys/boot/i386/btx/btx/Makefile +++ b/sys/boot/i386/btx/btx/Makefile @@ -11,7 +11,8 @@ BOOT_BTX_FLAGS=0x1 BOOT_BTX_FLAGS=0x0 .endif -CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} +CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS} -DLOCORE +CFLAGS+=-I${.CURDIR}/../../common .if defined(BTX_SERIAL) BOOT_COMCONSOLE_PORT?= 0x3f8 diff --git a/sys/boot/i386/btx/btx/btx.S b/sys/boot/i386/btx/btx/btx.S index e762e4b..bf4400e 100644 --- a/sys/boot/i386/btx/btx/btx.S +++ b/sys/boot/i386/btx/btx/btx.S @@ -15,6 +15,8 @@ * $FreeBSD$ */ +#include + /* * Memory layout. */ @@ -205,7 +207,7 @@ init.8: xorl %ecx,%ecx # Zero movl $MEM_USR,%edx # User base address movzwl %ss:BDA_MEM,%eax # Get free memory shll $0xa,%eax # To bytes - subl $0x1000,%eax # Less arg space + subl $ARGSPACE,%eax # Less arg space subl %edx,%eax # Less base movb $SEL_UDATA,%cl # User data selector pushl %ecx # Set SS diff --git a/sys/boot/i386/btx/btxldr/Makefile b/sys/boot/i386/btx/btxldr/Makefile index 56333e7..7378e92 100644 --- a/sys/boot/i386/btx/btxldr/Makefile +++ b/sys/boot/i386/btx/btxldr/Makefile @@ -5,7 +5,8 @@ INTERNALPROG= NO_MAN= SRCS= btxldr.S -CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} +CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS} -DLOCORE +CFLAGS+=-I${.CURDIR}/../../common .if defined(BTXLDR_VERBOSE) CFLAGS+=-DBTXLDR_VERBOSE diff --git a/sys/boot/i386/btx/btxldr/btxldr.S b/sys/boot/i386/btx/btxldr/btxldr.S index d4176eb..4d00d61 100644 --- a/sys/boot/i386/btx/btxldr/btxldr.S +++ b/sys/boot/i386/btx/btxldr/btxldr.S @@ -15,6 +15,8 @@ * $FreeBSD$ */ +#include + #define RBX_MUTE 0x10 /* -m */ #define OPT_SET(opt) (1 << (opt)) @@ -31,6 +33,7 @@ .set MEM_TBL,0x5000 # BTX page tables .set MEM_ENTRY,0x9010 # BTX entry point .set MEM_DATA,start+0x1000 # Data segment + /* * Segment selectors. */ @@ -89,7 +92,7 @@ start: cld # String ops inc call hexout # stack call putstr # pointer movl $m_args,%esi # Format string - leal 0x4(%esp,1),%ebx # First argument + leal 0x4(%esp),%ebx # First argument movl $0x6,%ecx # Count start.1: movl (%ebx),%eax # Get argument and addl $0x4,%ebx # bump pointer @@ -97,24 +100,28 @@ start.1: movl (%ebx),%eax # Get argument and loop start.1 # Till done call putstr # End message #endif - movl $0x48,%ecx # Allocate space - subl %ecx,%ebp # for bootinfo - movl 0x18(%esp,1),%esi # Source: bootinfo + movl BI_OFF+4(%esp),%esi # Source: bootinfo cmpl $0x0, %esi # If the bootinfo pointer je start_null_bi # is null, don't copy it + movl $BI_SIZE,%ecx # Allocate space + subl %ecx,%ebp # for bootinfo movl %ebp,%edi # Destination rep # Copy movsb # it - movl %ebp,0x18(%esp,1) # Update pointer + movl %ebp,BI_OFF+4(%esp) # Update pointer + movl %edi,%ebp # Restore base pointer #ifdef BTXLDR_VERBOSE movl $m_rel_bi,%esi # Display movl %ebp,%eax # bootinfo call hexout # relocation call putstr # message #endif -start_null_bi: movl $0x18,%ecx # Allocate space - subl %ecx,%ebp # for arguments - leal 0x4(%esp,1),%esi # Source +start_null_bi: movl $BA_SIZE,%ecx # Fixed size of arguments + testl $KARGS_FLAGS_EXTARG, BF_OFF+4(%esp) # Check for extra data + jz start_fixed # Skip if the flag is not set + addl BA_SIZE+4(%esp),%ecx # Add size of variable args +start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset + leal 0x4(%esp),%esi # Source movl %ebp,%edi # Destination rep # Copy movsb # them diff --git a/sys/boot/i386/btx/lib/Makefile b/sys/boot/i386/btx/lib/Makefile index 8fab66a..08c04d8 100644 --- a/sys/boot/i386/btx/lib/Makefile +++ b/sys/boot/i386/btx/lib/Makefile @@ -3,7 +3,9 @@ PROG= crt0.o INTERNALPROG= NO_MAN= -SRCS= btxcsu.s btxsys.s btxv86.s +SRCS= btxcsu.S btxsys.s btxv86.s +CFLAGS+=-DLOCORE +CFLAGS+=-I${.CURDIR}/../../common LDFLAGS=-Wl,-r .include diff --git a/sys/boot/i386/btx/lib/btxcsu.S b/sys/boot/i386/btx/lib/btxcsu.S new file mode 100644 index 0000000..5441f5b --- /dev/null +++ b/sys/boot/i386/btx/lib/btxcsu.S @@ -0,0 +1,50 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD$ + +#include + +# +# BTX C startup code (ELF). +# + +# +# Globals. +# + .global _start + +# +# Client entry point. +# +_start: cld + pushl %eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi, %ecx + xorb %al, %al + rep + stosb + popl __base + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments diff --git a/sys/boot/i386/btx/lib/btxcsu.s b/sys/boot/i386/btx/lib/btxcsu.s deleted file mode 100644 index 6a00659..0000000 --- a/sys/boot/i386/btx/lib/btxcsu.s +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (c) 1998 Robert Nordier -# All rights reserved. -# -# Redistribution and use in source and binary forms are freely -# permitted provided that the above copyright notice and this -# paragraph and the following disclaimer are duplicated in all -# such forms. -# -# This software is provided "AS IS" and without any express or -# implied warranties, including, without limitation, the implied -# warranties of merchantability and fitness for a particular -# purpose. -# - -# $FreeBSD$ - -# -# BTX C startup code (ELF). -# - -# -# Globals. -# - .global _start -# -# Constants. -# - .set ARGADJ,0xfa0 # Argument adjustment -# -# Client entry point. -# -_start: cld - pushl %eax - movl $_edata,%edi - movl $_end,%ecx - subl %edi, %ecx - xorb %al, %al - rep - stosb - popl __base - movl %esp,%eax # Set - addl $ARGADJ,%eax # argument - movl %eax,__args # pointer - call main # Invoke client main() - call exit # Invoke client exit() -# -# Data. -# - .comm __base,4 # Client base address - .comm __args,4 # Client arguments diff --git a/sys/boot/i386/common/bootargs.h b/sys/boot/i386/common/bootargs.h new file mode 100644 index 0000000..e90e342 --- /dev/null +++ b/sys/boot/i386/common/bootargs.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_I386_ARGS_H_ +#define _BOOT_I386_ARGS_H_ + +#define KARGS_FLAGS_CD 0x1 +#define KARGS_FLAGS_PXE 0x2 +#define KARGS_FLAGS_ZFS 0x4 +#define KARGS_FLAGS_EXTARG 0x8 /* variably sized extended argument */ + +#define BI_SIZE 72 /* struct bootinfo fixed size */ +#define BA_SIZE 24 /* struct bootargs fixed size */ +#define HT_OFF 0 /* offset of howto in bootargs */ +#define BF_OFF 8 /* offset of bootflags in bootargs */ +#define BI_OFF 20 /* offset of bootinfo in bootargs */ + +#define ARGSPACE 0x1000 /* size of the BTX args area */ +#define ARGOFF 0x800 /* args offset within the args area */ +#define ARGADJ (ARGSPACE - ARGOFF) + +#ifndef LOCORE + +struct bootargs +{ + uint32_t howto; + uint32_t bootdev; + uint32_t bootflags; + union { + struct { + uint32_t pxeinfo; + uint32_t reserved; + }; + uint64_t zfspool; + }; + uint32_t bootinfo; + + /* + * If KARGS_FLAGS_EXTARG is set in bootflags, then the above fields + * are followed by a u_int32_t field that specifies a size of the + * extended arguments (including the size field). + */ +}; + +#endif /*LOCORE*/ + +#endif /* !_BOOT_I386_ARGS_H_ */ diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index 75d5dbc..abf6a9e 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -39,28 +39,14 @@ __FBSDID("$FreeBSD$"); #include #include "bootstrap.h" +#include "common/bootargs.h" #include "libi386/libi386.h" #include "btxv86.h" -#define KARGS_FLAGS_CD 0x1 -#define KARGS_FLAGS_PXE 0x2 -#define KARGS_FLAGS_ZFS 0x4 - /* Arguments passed in from the boot1/boot2 loader */ -static struct -{ - u_int32_t howto; - u_int32_t bootdev; - u_int32_t bootflags; - union { - struct { - u_int32_t pxeinfo; - u_int32_t res2; - }; - uint64_t zfspool; - }; - u_int32_t bootinfo; -} *kargs; +static struct bootargs *kargs; +CTASSERT(sizeof(struct bootargs) == BA_SIZE); +/*CTASSERT(sizeof(struct bootinfo) == BI_SIZE);*//*XXX*/ static u_int32_t initial_howto; static u_int32_t initial_bootdev; diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index a6be3ee..17881dd 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -41,9 +41,7 @@ __FBSDID("$FreeBSD$"); #include "drv.h" #include "util.h" #include "cons.h" - -/* Hint to loader that we came from ZFS */ -#define KARGS_FLAGS_ZFS 0x4 +#include "bootargs.h" #define PATH_DOTCONFIG "/boot.config" #define PATH_CONFIG "/boot/config" commit 76adb2bd40f399bd30141217df064eb8aba054aa Author: Andriy Gapon Date: Mon Apr 30 11:10:48 2012 +0300 i386 boot: consolidate MAXBDDEV definition diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c index 5d20cba..ff4056b 100644 --- a/sys/boot/i386/libi386/biosdisk.c +++ b/sys/boot/i386/libi386/biosdisk.c @@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$"); #define BIOS_NUMDRIVES 0x475 #define BIOSDISK_SECSIZE 512 #define BUFSIZE (1 * BIOSDISK_SECSIZE) -#define MAXBDDEV MAXDEV #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ #define WDMAJOR 0 /* major numbers for devices we frontend for */ diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h index b8842ba..0a4621b 100644 --- a/sys/boot/i386/libi386/libi386.h +++ b/sys/boot/i386/libi386/libi386.h @@ -58,7 +58,8 @@ int i386_setcurrdev(struct env_var *ev, int flags, const void *value); extern struct devdesc currdev; /* our current device */ -#define MAXDEV 31 /* maximum number of distinct devices */ +#define MAXDEV 31 /* maximum number of distinct devices */ +#define MAXBDDEV MAXDEV /* exported devices XXX rename? */ extern struct devsw bioscd; diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index 17881dd..452d9ae 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -61,8 +61,6 @@ __FBSDID("$FreeBSD$"); #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 -#define MAXBDDEV 31 - extern uint32_t _end; #ifdef GPT diff --git a/sys/boot/pc98/libpc98/biosdisk.c b/sys/boot/pc98/libpc98/biosdisk.c index c2e7d66..dc98145 100644 --- a/sys/boot/pc98/libpc98/biosdisk.c +++ b/sys/boot/pc98/libpc98/biosdisk.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #define BIOS_NUMDRIVES 0x475 #define BIOSDISK_SECSIZE 512 #define BUFSIZE (1 * BIOSDISK_SECSIZE) -#define MAXBDDEV MAXDEV #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ #define WDMAJOR 0 /* major numbers for devices we frontend for */ commit dcb7de1d27b717e6cee47cc279b6a25c85d2d95c Author: Andriy Gapon Date: Fri May 4 10:48:25 2012 +0300 i386 zfsloader: rename LIBZFS to LIBZFSBOOT to avoid conflict with the other libzfs diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index 9128e62..e2f8892 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -20,9 +20,7 @@ LIBFIREWIRE= ${.OBJDIR}/../libfirewire/libfirewire.a # Set by zfsloader Makefile .if defined(LOADER_ZFS_SUPPORT) CFLAGS+= -DLOADER_ZFS_SUPPORT -LIBZFS= ${.OBJDIR}/../../zfs/libzfsboot.a -.else -LIBZFS= +LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a .endif # Enable PXE TFTP or NFS support, not both. @@ -119,8 +117,8 @@ FILES+= menu.rc # XXX crt0.o needs to be first for pxeboot(8) to work OBJS= ${BTXCRT} -DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND} -LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND} +DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} .include commit 2a93aee8c2d904ffc6d449aafc7ffaac761dcf6b Author: Andriy Gapon Date: Sat May 5 10:47:54 2012 +0300 zfsboot: unstaticize two local variables diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index 452d9ae..2db5ada 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -599,8 +599,8 @@ load(void) struct exec ex; Elf32_Ehdr eh; } hdr; - static Elf32_Phdr ep[2]; - static Elf32_Shdr es[2]; + Elf32_Phdr ep[2]; + Elf32_Shdr es[2]; caddr_t p; dnode_phys_t dn; off_t off; commit 9e267f5350d19b4b26e7a4cdc7064ec1436bfb30 Author: Andriy Gapon Date: Wed Apr 28 23:45:58 2010 +0300 zfsboot/zfsloader: support accessing filesystems within a pool In zfs loader zfs device name format now is "zfs:pool/fs", fully qualified file path is "zfs:pool/fs:/path/to/file" loader allows accessing files from various pools and filesystems as well as changing currdev to a different pool/filesystem. zfsboot accepts kernel/loader name in a format pool:fs:path/to/file or, as before, pool:path/to/file; in the latter case a default filesystem is used (pool root or bootfs). zfsboot passes guids of the selected pool and dataset to zfsloader to be used as its defaults. zfs support should be architecture independent and is provided in a separate library, but architectures wishing to use this zfs support still have to provide some glue code and their devdesc should be compatible with zfs_devdesc. arch_zfs_probe method is used to discover all disk devices that may be part of ZFS pool(s). libi386 unconditionally includes zfs support, but some zfs-specific functions are stubbed out as weak symbols. The strong definitions are provided in libzfsboot. This change mean that the size of i386_devspec becomes larger to match zfs_devspec. TODO: - clear up pool root filesystem vs pool bootfs filesystem distinction - set vfs.root.mountfrom based on currdev (for zfs) Mid-future TODO: - UI for selecting alternative boot environment Distant future TODO: - support accessing snapshots, using a snapshot as readonly root diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index 4c92ba8..f6eab3d 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -317,6 +317,9 @@ struct arch_switch #else void (*arch_loadseg)(void *eh, void *ph, uint64_t delta); #endif + + /* Probe ZFS pool(s), if needed. */ + void (*arch_zfs_probe)(void); }; extern struct arch_switch archsw; diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile index 94a20c8..a3a9e18 100644 --- a/sys/boot/i386/libi386/Makefile +++ b/sys/boot/i386/libi386/Makefile @@ -9,6 +9,7 @@ SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ elf64_freebsd.c \ i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c +SRCS+= ../../zfs/devicename_stubs.c # Enable PXE TFTP or NFS support, not both. .if defined(LOADER_TFTP_SUPPORT) diff --git a/sys/boot/i386/libi386/devicename.c b/sys/boot/i386/libi386/devicename.c index d6f3ac1..534af4c 100644 --- a/sys/boot/i386/libi386/devicename.c +++ b/sys/boot/i386/libi386/devicename.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include "bootstrap.h" #include "libi386.h" +#include "../zfs/libzfs.h" static int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path); @@ -171,7 +172,6 @@ i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) case DEVT_CD: case DEVT_NET: - case DEVT_ZFS: unit = 0; if (*np && (*np != ':')) { @@ -192,7 +192,11 @@ i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; - + case DEVT_ZFS: + err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; default: err = EINVAL; goto fail; @@ -247,9 +251,10 @@ i386_fmtdev(void *vdev) break; case DEVT_NET: - case DEVT_ZFS: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; + case DEVT_ZFS: + return(zfs_fmtdev(vdev)); } return(buf); } diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h index 0a4621b..3edeb92 100644 --- a/sys/boot/i386/libi386/libi386.h +++ b/sys/boot/i386/libi386/libi386.h @@ -30,7 +30,8 @@ /* * i386 fully-qualified device descriptor. * Note, this must match the 'struct devdesc' declaration - * in bootstrap.h. + * in bootstrap.h and also with struct zfs_devdesc for zfs + * support. */ struct i386_devdesc { @@ -49,6 +50,12 @@ struct i386_devdesc { void *data; } bioscd; + struct + { + void *data; + uint64_t pool_guid; + uint64_t root_guid; + } zfs; } d_kind; }; diff --git a/sys/boot/i386/loader/conf.c b/sys/boot/i386/loader/conf.c index bd14f47..09d6a4e 100644 --- a/sys/boot/i386/loader/conf.c +++ b/sys/boot/i386/loader/conf.c @@ -30,6 +30,9 @@ __FBSDID("$FreeBSD$"); #include #include #include "libi386/libi386.h" +#if defined(LOADER_ZFS_SUPPORT) +#include "../zfs/libzfs.h" +#endif /* * We could use linker sets for some or all of these, but @@ -50,10 +53,6 @@ __FBSDID("$FreeBSD$"); extern struct devsw fwohci; #endif -#if defined(LOADER_ZFS_SUPPORT) -extern struct devsw zfs_dev; -#endif - /* Exported for libstand */ struct devsw *devsw[] = { &bioscd, @@ -70,10 +69,6 @@ struct devsw *devsw[] = { NULL }; -#if defined(LOADER_ZFS_SUPPORT) -extern struct fs_ops zfs_fsops; -#endif - struct fs_ops *file_system[] = { &ufs_fsops, &ext2fs_fsops, diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index abf6a9e..bc02f98 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -43,6 +43,10 @@ __FBSDID("$FreeBSD$"); #include "libi386/libi386.h" #include "btxv86.h" +#ifdef LOADER_ZFS_SUPPORT +#include "../zfs/libzfs.h" +#endif + /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; CTASSERT(sizeof(struct bootargs) == BA_SIZE); @@ -58,6 +62,9 @@ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); +#ifdef LOADER_ZFS_SUPPORT +static void i386_zfs_probe(void); +#endif /* from vers.c */ extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; @@ -149,6 +156,9 @@ main(void) archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; +#ifdef LOADER_ZFS_SUPPORT + archsw.arch_zfs_probe = i386_zfs_probe; +#endif /* * March through the device switch probing for things. @@ -192,8 +202,9 @@ main(void) static void extract_currdev(void) { - struct i386_devdesc new_currdev; - int biosdev = -1; + struct i386_devdesc new_currdev; + struct zfs_boot_args *zargs; + int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.d_dev = &biosdisk; @@ -214,6 +225,24 @@ extract_currdev(void) new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } +#ifdef LOADER_ZFS_SUPPORT + } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { + zargs = NULL; + /* check for new style extended argument */ + if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) + zargs = (struct zfs_boot_args *)(kargs + 1); + + if (zargs != NULL && zargs->size >= sizeof(*zargs)) { + /* sufficient data is provided */ + new_currdev.d_kind.zfs.pool_guid = zargs->pool; + new_currdev.d_kind.zfs.root_guid = zargs->root; + } else { + /* old style zfsboot block */ + new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; + new_currdev.d_kind.zfs.root_guid = 0; + } + new_currdev.d_dev = &zfs_dev; +#endif } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; @@ -234,7 +263,7 @@ extract_currdev(void) biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } new_currdev.d_type = new_currdev.d_dev->dv_type; - + /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. @@ -245,33 +274,11 @@ extract_currdev(void) "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.d_unit = 0; } + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); - -#ifdef LOADER_ZFS_SUPPORT - /* - * If we were started from a ZFS-aware boot2, we can work out - * which ZFS pool we are booting from. - */ - if (kargs->bootflags & KARGS_FLAGS_ZFS) { - /* - * Dig out the pool guid and convert it to a 'unit number' - */ - uint64_t guid; - int unit; - char devname[32]; - extern int zfs_guid_to_unit(uint64_t); - - guid = kargs->zfspool; - unit = zfs_guid_to_unit(guid); - if (unit >= 0) { - sprintf(devname, "zfs%d", unit); - setenv("currdev", devname, 1); - } - } -#endif } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); @@ -338,3 +345,30 @@ isa_outb(int port, int value) } } +#ifdef LOADER_ZFS_SUPPORT +static void +i386_zfs_probe(void) +{ + char devname[32]; + int unit, slice; + + /* + * Open all the disks we can find and see if we can reconstruct + * ZFS pools from them. Bogusly assumes that the disks are named + * diskN, diskNpM or diskNsM. + */ + for (unit = 0; unit < MAXBDDEV; unit++) { + sprintf(devname, "disk%d:", unit); + if (zfs_probe_dev(devname, NULL) == ENXIO) + continue; + for (slice = 1; slice <= 128; slice++) { + sprintf(devname, "disk%dp%d:", unit, slice); + zfs_probe_dev(devname, NULL); + } + for (slice = 1; slice <= 4; slice++) { + sprintf(devname, "disk%ds%d:", unit, slice); + zfs_probe_dev(devname, NULL); + } + } +} +#endif diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index 2db5ada..202d0b1 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$"); #include "cons.h" #include "bootargs.h" +#include "libzfs.h" + #define PATH_DOTCONFIG "/boot.config" #define PATH_CONFIG "/boot/config" #define PATH_BOOT3 "/boot/zfsloader" @@ -91,9 +93,12 @@ static const unsigned char dev_maj[NDEV] = {30, 4, 2}; static char cmd[512]; static char cmddup[512]; static char kname[1024]; +static char rootname[256]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint32_t bootdev; +static struct zfs_boot_args zfsargs; +static struct zfsmount zfsmount; vm_offset_t high_heap_base; uint32_t bios_basemem, bios_extmem, high_heap_size; @@ -170,7 +175,7 @@ zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t /* * Current ZFS pool */ -spa_t *spa; +static spa_t *spa; /* * A wrapper for dskread that doesn't have to worry about whether the @@ -209,7 +214,7 @@ static int xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) { if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); + printf("Invalid format\n"); return -1; } return 0; @@ -529,10 +534,12 @@ main(void) } } - zfs_mount_pool(spa); - - if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0 || - zfs_lookup(spa, PATH_DOTCONFIG, &dn) == 0) { + if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) { + printf("%s: failed to mount default pool %s\n", + BOOTPROG, spa->spa_name); + autoboot = 0; + } else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 || + zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) { off = 0; zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); } @@ -567,11 +574,17 @@ main(void) /* Present the user with the boot2 prompt. */ for (;;) { - if (!autoboot || !OPT_CHECK(RBX_QUIET)) - printf("\nFreeBSD/x86 boot\n" - "Default: %s:%s\n" - "boot: ", - spa->spa_name, kname); + if (!autoboot || !OPT_CHECK(RBX_QUIET)) { + printf("\nFreeBSD/x86 boot\n"); + if (zfs_rlookup(spa, zfsmount.rootobj, rootname) != 0) + printf("Default: %s:<0x%llx>:%s\n" + "boot: ", + spa->spa_name, zfsmount.rootobj, kname); + else + printf("Default: %s:%s:%s\n" + "boot: ", + spa->spa_name, rootname, kname); + } if (ioctrl & IO_SERIAL) sio_flush(); if (!autoboot || keyhit(5)) @@ -607,7 +620,8 @@ load(void) uint32_t addr, x; int fmt, i, j; - if (zfs_lookup(spa, kname, &dn)) { + if (zfs_lookup(&zfsmount, kname, &dn)) { + printf("\nCan't find %s\n", kname); return; } off = 0; @@ -681,12 +695,16 @@ load(void) } bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); + zfsargs.size = sizeof(zfsargs); + zfsargs.pool = zfsmount.spa->spa_guid; + zfsargs.root = zfsmount.rootobj; __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), bootdev, - KARGS_FLAGS_ZFS, + KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, (uint32_t) spa->spa_guid, (uint32_t) (spa->spa_guid >> 32), - VTOP(&bootinfo)); + VTOP(&bootinfo), + zfsargs); } static int @@ -738,7 +756,7 @@ parse(void) } if (c == '?') { dnode_phys_t dn; - if (zfs_lookup(spa, arg, &dn) == 0) { + if (zfs_lookup(&zfsmount, arg, &dn) == 0) { zap_list(spa, &dn); } return -1; @@ -760,17 +778,32 @@ parse(void) q = (char *) strchr(arg, ':'); if (q) { spa_t *newspa; + uint64_t newroot; *q++ = 0; newspa = spa_find_by_name(arg); if (newspa) { + arg = q; spa = newspa; - zfs_mount_pool(spa); + newroot = 0; + q = (char *) strchr(arg, ':'); + if (q) { + *q++ = 0; + if (zfs_lookup_dataset(spa, arg, &newroot)) { + printf("\nCan't find dataset %s in ZFS pool %s\n", + arg, spa->spa_name); + return -1; + } + arg = q; + } + if (zfs_mount(spa, newroot, &zfsmount)) { + printf("\nCan't mount ZFS dataset\n"); + return -1; + } } else { printf("\nCan't find ZFS pool %s\n", arg); return -1; } - arg = q; } if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) diff --git a/sys/boot/zfs/devicename_stubs.c b/sys/boot/zfs/devicename_stubs.c new file mode 100644 index 0000000..41bf907 --- /dev/null +++ b/sys/boot/zfs/devicename_stubs.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include "libzfs.h" + +__attribute__((weak)) +int +zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) +{ + return (EINVAL); +} + +__attribute__((weak)) +char * +zfs_fmtdev(void *vdev) +{ + static char buf[128]; + + return (buf); +} diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h new file mode 100644 index 0000000..5c114db --- /dev/null +++ b/sys/boot/zfs/libzfs.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_LIBZFS_H_ +#define _BOOT_LIBZFS_H_ + +#define ZFS_MAXNAMELEN 256 + +/* + * ZFS fully-qualified device descriptor. + * Note, this must match the 'struct devdesc' declaration in bootstrap.h. + * Arch-specific device descriptors should be binary compatible with this + * structure if they are to support ZFS. + */ +struct zfs_devdesc +{ + struct devsw *d_dev; + int d_type; + int d_unit; + void *d_opendata; + uint64_t pool_guid; + uint64_t root_guid; +}; + +struct zfs_boot_args +{ + uint32_t size; + uint32_t reserved; + uint64_t pool; + uint64_t root; +}; + +int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, + const char **path); +char *zfs_fmtdev(void *vdev); +int zfs_probe_dev(const char *devname, uint64_t *pool_guid); + +extern struct devsw zfs_dev; +extern struct fs_ops zfs_fsops; + +#endif /*_BOOT_LIBZFS_H_*/ diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c index 97f924f..35d68d7 100644 --- a/sys/boot/zfs/zfs.c +++ b/sys/boot/zfs/zfs.c @@ -43,9 +43,9 @@ __FBSDID("$FreeBSD$"); #include #include -#include "zfsimpl.c" +#include "libzfs.h" -#define MAXBDDEV 31 +#include "zfsimpl.c" static int zfs_open(const char *path, struct open_file *f); static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); @@ -85,35 +85,20 @@ struct file { static int zfs_open(const char *upath, struct open_file *f) { - spa_t *spa = (spa_t *) f->f_devdata; + struct zfsmount *mount = (struct zfsmount *)f->f_devdata; struct file *fp; int rc; if (f->f_dev != &zfs_dev) return (EINVAL); - rc = zfs_mount_pool(spa); - if (rc) - return (rc); - /* allocate file system specific data structure */ fp = malloc(sizeof(struct file)); bzero(fp, sizeof(struct file)); f->f_fsdata = (void *)fp; - if (spa->spa_root_objset.os_type != DMU_OST_ZFS) { - printf("Unexpected object set type %llu\n", - spa->spa_root_objset.os_type); - rc = EIO; - goto out; - } - - rc = zfs_lookup(spa, upath, &fp->f_dnode); - if (rc) - goto out; - + rc = zfs_lookup(mount, upath, &fp->f_dnode); fp->f_seekp = 0; -out: if (rc) { f->f_fsdata = NULL; free(fp); @@ -142,7 +127,7 @@ zfs_close(struct open_file *f) static int zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) { - spa_t *spa = (spa_t *) f->f_devdata; + spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; struct file *fp = (struct file *)f->f_fsdata; struct stat sb; size_t n; @@ -216,7 +201,7 @@ zfs_seek(struct open_file *f, off_t offset, int where) static int zfs_stat(struct open_file *f, struct stat *sb) { - spa_t *spa = (spa_t *) f->f_devdata; + spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; struct file *fp = (struct file *)f->f_fsdata; return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); @@ -225,7 +210,7 @@ zfs_stat(struct open_file *f, struct stat *sb) static int zfs_readdir(struct open_file *f, struct dirent *d) { - spa_t *spa = (spa_t *) f->f_devdata; + spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; struct file *fp = (struct file *)f->f_fsdata; mzap_ent_phys_t mze; struct stat sb; @@ -381,68 +366,33 @@ vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t size) } } -/* - * Convert a pool guid to a 'unit number' suitable for use with zfs_dev_open. - */ -int -zfs_guid_to_unit(uint64_t guid) +static int +zfs_dev_init(void) { - spa_t *spa; - int unit; - - unit = 0; - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - if (spa->spa_guid == guid) - return unit; - unit++; - } - return (-1); + zfs_init(); + if (archsw.arch_zfs_probe == NULL) + return (ENXIO); + archsw.arch_zfs_probe(); + return (0); } -#if defined(__amd64__) || defined(__i386__) -static int -zfs_dev_init(void) +int +zfs_probe_dev(const char *devname, uint64_t *pool_guid) { - char devname[512]; - int unit, slice; + spa_t *spa; int fd; + int ret; - /* - * Open all the disks we can find and see if we can reconstruct - * ZFS pools from them. Bogusly assumes that the disks are named - * diskN, diskNpM or diskNsM. - */ - zfs_init(); - for (unit = 0; unit < MAXBDDEV; unit++) { - sprintf(devname, "disk%d:", unit); - fd = open(devname, O_RDONLY); - if (fd == -1) - continue; - - /* - * If we find a vdev, the zfs code will eat the fd, otherwise - * we close it. - */ - if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0)) - close(fd); - - for (slice = 1; slice <= 128; slice++) { - sprintf(devname, "disk%dp%d:", unit, slice); - fd = open(devname, O_RDONLY); - if (fd == -1) { - sprintf(devname, "disk%ds%d:", unit, slice); - fd = open(devname, O_RDONLY); - if (fd == -1) - continue; - } - if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0)) - close(fd); - } - } - + fd = open(devname, O_RDONLY); + if (fd == -1) + return (ENXIO); + ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa); + if (ret != 0) + close(fd); + else if (pool_guid != NULL) + *pool_guid = spa->spa_guid; return (0); } -#endif /* * Print information about ZFS pools @@ -452,17 +402,14 @@ zfs_dev_print(int verbose) { spa_t *spa; char line[80]; - int unit; if (verbose) { spa_all_status(); return; } - unit = 0; STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - sprintf(line, " zfs%d: %s\n", unit, spa->spa_name); + sprintf(line, " zfs:%s\n", spa->spa_name); pager_output(line); - unit++; } } @@ -473,33 +420,34 @@ static int zfs_dev_open(struct open_file *f, ...) { va_list args; - struct devdesc *dev; - int unit, i; + struct zfs_devdesc *dev; + struct zfsmount *mount; spa_t *spa; + int rv; va_start(args, f); - dev = va_arg(args, struct devdesc*); + dev = va_arg(args, struct zfs_devdesc *); va_end(args); - /* - * We mostly ignore the stuff that devopen sends us. For now, - * use the unit to find a pool - later we will override the - * devname parsing so that we can name a pool and a fs within - * the pool. - */ - unit = dev->d_unit; - - i = 0; - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - if (i == unit) - break; - i++; - } - if (!spa) { + spa = spa_find_by_guid(dev->pool_guid); + if (!spa) return (ENXIO); + rv = zfs_spa_init(spa); + if (rv != 0) + return (rv); + mount = malloc(sizeof(*mount)); + rv = zfs_mount(spa, dev->root_guid, mount); + if (rv != 0) { + free(mount); + return (rv); } - - f->f_devdata = spa; + if (mount->objset.os_type != DMU_OST_ZFS) { + printf("Unexpected object set type %llu\n", + mount->objset.os_type); + free(mount); + return (EIO); + } + f->f_devdata = mount; free(dev); return (0); } @@ -508,6 +456,7 @@ static int zfs_dev_close(struct open_file *f) { + free(f->f_devdata); f->f_devdata = NULL; return (0); } @@ -530,3 +479,92 @@ struct devsw zfs_dev = { .dv_print = zfs_dev_print, .dv_cleanup = NULL }; + +int +zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char poolname[ZFS_MAXNAMELEN]; + spa_t *spa; + const char *end; + const char *np; + const char *sep; + int rv; + + np = devspec; + if (*np != ':') + return (EINVAL); + np++; + end = strchr(np, ':'); + if (end == NULL) + return (EINVAL); + sep = strchr(np, '/'); + if (sep == NULL || sep >= end) + sep = end; + memcpy(poolname, np, sep - np); + poolname[sep - np] = '\0'; + if (sep < end) { + sep++; + memcpy(rootname, sep, end - sep); + rootname[end - sep] = '\0'; + } + else + rootname[0] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + rv = zfs_spa_init(spa); + if (rv != 0) + return (rv); + dev->pool_guid = spa->spa_guid; + if (rootname[0] != '\0') { + rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); + if (rv != 0) + return (rv); + } else + dev->root_guid = 0; + if (path != NULL) + *path = (*end == '\0') ? end : end + 1; + dev->d_dev = &zfs_dev; + dev->d_type = zfs_dev.dv_type; + return (0); +} + +char * +zfs_fmtdev(void *vdev) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char buf[2 * ZFS_MAXNAMELEN + 8]; + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + + buf[0] = '\0'; + if (dev->d_type != DEVT_ZFS) + return (buf); + + spa = spa_find_by_guid(dev->pool_guid); + if (spa == NULL) { + printf("ZFS: can't find pool by guid\n"); + return (buf); + } + if (zfs_spa_init(spa) != 0) { + printf("ZFS: can't init pool\n"); + return (buf); + } + if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { + printf("ZFS: can't find root filesystem\n"); + return (buf); + } + if (zfs_rlookup(spa, dev->root_guid, rootname)) { + printf("ZFS: can't find filesystem by guid\n"); + return (buf); + } + + if (rootname[0] == '\0') + sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name); + else + sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name, + rootname); + return (buf); +} diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index 3419564..f976a1a 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -36,6 +36,13 @@ __FBSDID("$FreeBSD$"); #include "zfsimpl.h" #include "zfssubr.c" + +struct zfsmount { + spa_t *spa; + objset_phys_t objset; + uint64_t rootobj; +}; + /* * List of all vdevs, chained through v_alllink. */ @@ -626,8 +633,6 @@ spa_find_by_guid(uint64_t guid) return (0); } -#ifdef BOOT2 - static spa_t * spa_find_by_name(const char *name) { @@ -640,8 +645,6 @@ spa_find_by_name(const char *name) return (0); } -#endif - static spa_t * spa_create(uint64_t guid) { @@ -1452,6 +1455,259 @@ objset_get_dnode(spa_t *spa, const objset_phys_t *os, uint64_t objnum, dnode_phy dnode, sizeof(dnode_phys_t)); } +static int +mzap_rlookup(spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + const mzap_phys_t *mz; + const mzap_ent_phys_t *mze; + size_t size; + int chunks, i; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + size = dnode->dn_datablkszsec * 512; + + mz = (const mzap_phys_t *) zap_scratch; + chunks = size / MZAP_ENT_LEN - 1; + + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (value == mze->mze_value) { + strcpy(name, mze->mze_name); + return (0); + } + } + + return (ENOENT); +} + +static void +fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name) +{ + size_t namelen; + const zap_leaf_chunk_t *nc; + char *p; + + namelen = zc->l_entry.le_name_length; + + nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + size_t len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); + } + + *p = '\0'; +} + +static int +fzap_rlookup(spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap_phys_t zh = *(zap_phys_t *) zap_scratch; + fat_zap_t z; + uint64_t *ptrtbl; + uint64_t hash; + int rc; + + if (zh.zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = (zap_phys_t *) zap_scratch; + + /* + * Figure out where the pointer table is and read it in if necessary. + */ + if (zh.zap_ptrtbl.zt_blk) { + rc = dnode_read(spa, dnode, zh.zap_ptrtbl.zt_blk * bsize, + zap_scratch, bsize); + if (rc) + return (rc); + ptrtbl = (uint64_t *) zap_scratch; + } else { + ptrtbl = &ZAP_EMBEDDED_PTRTBL_ENT(&z, 0); + } + + hash = zap_hash(zh.zap_salt, name); + + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + + off_t off = ptrtbl[hash >> (64 - zh.zap_ptrtbl.zt_shift)] << zl.l_bs; + zap_leaf_chunk_t *zc; + + rc = dnode_read(spa, dnode, off, zap_scratch, bsize); + if (rc) + return (rc); + + zl.l_phys = (zap_leaf_phys_t *) zap_scratch; + + /* + * Make sure this chunk matches our hash. + */ + if (zl.l_phys->l_hdr.lh_prefix_len > 0 + && zl.l_phys->l_hdr.lh_prefix + != hash >> (64 - zl.l_phys->l_hdr.lh_prefix_len)) + return (ENOENT); + + /* + * Hash within the chunk to find our entry. + */ + int shift = (64 - ZAP_LEAF_HASH_SHIFT(&zl) - zl.l_phys->l_hdr.lh_prefix_len); + int h = (hash >> shift) & ((1 << ZAP_LEAF_HASH_SHIFT(&zl)) - 1); + h = zl.l_phys->l_hash[h]; + if (h == 0xffff) + return (ENOENT); + zc = &ZAP_LEAF_CHUNK(&zl, h); + while (zc->l_entry.le_hash != hash) { + if (zc->l_entry.le_next == 0xffff) { + zc = 0; + break; + } + zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next); + } + if (fzap_leaf_value(&zl, zc) == value) { + fzap_name_copy(&zl, zc, name); + return (0); + } + + return (ENOENT); +} + +static int +zap_rlookup(spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + int rc; + uint64_t zap_type; + size_t size = dnode->dn_datablkszsec * 512; + + rc = dnode_read(spa, dnode, 0, zap_scratch, size); + if (rc) + return (rc); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_rlookup(spa, dnode, name, value); + else + return fzap_rlookup(spa, dnode, name, value); +} + +static int +zfs_rlookup(spa_t *spa, uint64_t objnum, char *result) +{ + char name[256]; + char component[256]; + uint64_t dir_obj, parent_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dataset, dir, parent; + dsl_dir_phys_t *dd; + dsl_dataset_phys_t *ds; + char *p; + int len; + + p = &name[sizeof(name) - 1]; + *p = '\0'; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %llu\n", objnum); + return (EIO); + } + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + /* Actual loop condition. */ + parent_obj = dd->dd_parent_obj; + if (parent_obj == 0) + break; + + if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, &parent) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&parent.dn_bonus; + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) + return (EIO); + if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) + return (EIO); + + len = strlen(component); + p -= len; + memcpy(p, component, len); + --p; + *p = '/'; + + /* Actual loop iteration. */ + dir_obj = parent_obj; + } + + if (*p != '\0') + ++p; + strcpy(result, p); + + return (0); +} + +static int +zfs_lookup_dataset(spa_t *spa, const char *name, uint64_t *objnum) +{ + char element[256]; + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir; + dsl_dir_phys_t *dd; + const char *p, *q; + + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) + return (EIO); + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &dir_obj)) + return (EIO); + + p = name; + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + while (*p == '/') + p++; + /* Actual loop condition #1. */ + if (*p == '\0') + break; + + q = strchr(p, '/'); + if (q) { + memcpy(element, p, q - p); + element[q - p] = '\0'; + p = q + 1; + } else { + strcpy(element, p); + p += strlen(p); + } + + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) + return (EIO); + + /* Actual loop condition #2. */ + if (zap_lookup(spa, &child_dir_zap, element, &dir_obj) != 0) + return (ENOENT); + } + + *objnum = dd->dd_head_dataset_obj; + return (0); +} + /* * Find the object set given the object number of its dataset object * and return its details in *objset @@ -1481,11 +1737,13 @@ zfs_mount_dataset(spa_t *spa, uint64_t objnum, objset_phys_t *objset) * dataset if there is none and return its details in *objset */ static int -zfs_mount_root(spa_t *spa, objset_phys_t *objset) +zfs_get_root(spa_t *spa, uint64_t *objid) { dnode_phys_t dir, propdir; uint64_t props, bootfs, root; + *objid = 0; + /* * Start with the MOS directory object. */ @@ -1501,8 +1759,10 @@ zfs_mount_root(spa_t *spa, objset_phys_t *objset) && objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0 && bootfs != 0) - return zfs_mount_dataset(spa, bootfs, objset); - + { + *objid = bootfs; + return (0); + } /* * Lookup the root dataset directory */ @@ -1517,29 +1777,45 @@ zfs_mount_root(spa_t *spa, objset_phys_t *objset) * to find the dataset object and from that the object set itself. */ dsl_dir_phys_t *dd = (dsl_dir_phys_t *) &dir.dn_bonus; - return zfs_mount_dataset(spa, dd->dd_head_dataset_obj, objset); + *objid = dd->dd_head_dataset_obj; + return (0); } static int -zfs_mount_pool(spa_t *spa) +zfs_mount(spa_t *spa, uint64_t rootobj, struct zfsmount *mount) { + mount->spa = spa; + /* - * Find the MOS and work our way in from there. + * Find the root object set if not explicitly provided */ - if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { - printf("ZFS: can't read MOS\n"); + if (rootobj == 0 && zfs_get_root(spa, &rootobj)) { + printf("ZFS: can't find root filesystem\n"); return (EIO); } - /* - * Find the root object set - */ - if (zfs_mount_root(spa, &spa->spa_root_objset)) { - printf("Can't find root filesystem - giving up\n"); + if (zfs_mount_dataset(spa, rootobj, &mount->objset)) { + printf("ZFS: can't open root filesystem\n"); return (EIO); } + mount->rootobj = rootobj; + + return (0); +} + +static int +zfs_spa_init(spa_t *spa) +{ + + if (spa->spa_inited) + return (0); + if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { + printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); + return (EIO); + } + spa->spa_inited = 1; return (0); } @@ -1599,10 +1875,11 @@ zfs_dnode_stat(spa_t *spa, dnode_phys_t *dn, struct stat *sb) * Lookup a file and return its dnode. */ static int -zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode) +zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) { int rc; uint64_t objnum, rootnum, parentnum; + spa_t *spa; dnode_phys_t dn; const char *p, *q; char element[256]; @@ -1610,16 +1887,17 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode) int symlinks_followed = 0; struct stat sb; - if (spa->spa_root_objset.os_type != DMU_OST_ZFS) { + spa = mount->spa; + if (mount->objset.os_type != DMU_OST_ZFS) { printf("ZFS: unexpected object set type %llu\n", - spa->spa_root_objset.os_type); + mount->objset.os_type); return (EIO); } /* * Get the root directory dnode. */ - rc = objset_get_dnode(spa, &spa->spa_root_objset, MASTER_NODE_OBJ, &dn); + rc = objset_get_dnode(spa, &mount->objset, MASTER_NODE_OBJ, &dn); if (rc) return (rc); @@ -1627,7 +1905,7 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode) if (rc) return (rc); - rc = objset_get_dnode(spa, &spa->spa_root_objset, rootnum, &dn); + rc = objset_get_dnode(spa, &mount->objset, rootnum, &dn); if (rc) return (rc); @@ -1660,7 +1938,7 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode) return (rc); objnum = ZFS_DIRENT_OBJ(objnum); - rc = objset_get_dnode(spa, &spa->spa_root_objset, objnum, &dn); + rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); if (rc) return (rc); @@ -1702,7 +1980,7 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode) objnum = rootnum; else objnum = parentnum; - objset_get_dnode(spa, &spa->spa_root_objset, objnum, &dn); + objset_get_dnode(spa, &mount->objset, objnum, &dn); } } diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index 9f24cc0..66379a3 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -1327,5 +1327,5 @@ typedef struct spa { struct uberblock spa_uberblock; /* best uberblock so far */ vdev_list_t spa_vdevs; /* list of all toplevel vdevs */ objset_phys_t spa_mos; /* MOS for this pool */ - objset_phys_t spa_root_objset; /* current mounted ZPL objset */ + int spa_inited; /* initialized */ } spa_t; diff --git a/tools/tools/zfsboottest/zfsboottest.c b/tools/tools/zfsboottest/zfsboottest.c index 4b29f94..3058046 100644 --- a/tools/tools/zfsboottest/zfsboottest.c +++ b/tools/tools/zfsboottest/zfsboottest.c @@ -89,7 +89,11 @@ main(int argc, char** argv) char buf[512], hash[33]; MD5_CTX ctx; struct stat sb; + struct zfsmount zfsmnt; dnode_phys_t dn; +#if 0 + uint64_t rootobj; +#endif spa_t *spa; off_t off; ssize_t n; @@ -138,14 +142,28 @@ main(int argc, char** argv) exit(1); } - if (zfs_mount_pool(spa)) { - fprintf(stderr, "can't mount pool\n"); + if (zfs_spa_init(spa)) { + fprintf(stderr, "can't init pool\n"); exit(1); } +#if 0 + if (zfs_get_root(spa, &rootobj)) { + fprintf(stderr, "can't get root\n"); + exit(1); + } + + if (zfs_mount(spa, rootobj, &zfsmnt)) { +#else + if (zfs_mount(spa, 0, &zfsmnt)) { + fprintf(stderr, "can't mount\n"); + exit(1); + } +#endif + printf("\n"); for (++i, failures = 0; i < argc; i++) { - if (zfs_lookup(spa, argv[i], &dn)) { + if (zfs_lookup(&zfsmnt, argv[i], &dn)) { fprintf(stderr, "%s: can't lookup\n", argv[i]); failures++; continue; commit de53a15f9e944bffcdf76992fc659964e36dec61 Author: Andriy Gapon Date: Thu May 3 17:45:40 2012 +0300 zfs boot: update sparc64 support Note: this commit should be squashed into the previous one before going to the main tree. diff --git a/sys/boot/Makefile.sparc64 b/sys/boot/Makefile.sparc64 index 5723629..1064a26 100644 --- a/sys/boot/Makefile.sparc64 +++ b/sys/boot/Makefile.sparc64 @@ -1,3 +1,4 @@ # $FreeBSD$ SUBDIR+= ofw +SUBDIR+= zfs diff --git a/sys/boot/ofw/libofw/Makefile b/sys/boot/ofw/libofw/Makefile index 945d650..e207eca 100644 --- a/sys/boot/ofw/libofw/Makefile +++ b/sys/boot/ofw/libofw/Makefile @@ -6,6 +6,7 @@ INTERNALLIB= SRCS= devicename.c elf_freebsd.c ofw_console.c ofw_copy.c ofw_disk.c \ ofw_memory.c ofw_module.c ofw_net.c ofw_reboot.c \ ofw_time.c openfirm.c +SRCS+= ../../zfs/devicename_stubs.c CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ diff --git a/sys/boot/ofw/libofw/devicename.c b/sys/boot/ofw/libofw/devicename.c index c2d9ef1..bbacb84 100644 --- a/sys/boot/ofw/libofw/devicename.c +++ b/sys/boot/ofw/libofw/devicename.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include "bootstrap.h" #include "libofw.h" +#include "../zfs/libzfs.h" static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **); @@ -81,6 +82,7 @@ ofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path) char *ep; char name[256]; char type[64]; + int err; int len; int i; @@ -114,14 +116,11 @@ found: idev->d_dev = dv; idev->d_type = dv->dv_type; if (idev->d_type == DEVT_ZFS) { - idev->d_unit = 0; - p = name + strlen(dv->dv_name); - if (*p && (*p != ':')) { - idev->d_unit = strtol(p, &ep, 0); - if (ep == p) { - free(idev); - return (EUNIT); - } + p = devspec + strlen(dv->dv_name); + err = zfs_parsedev((struct zfs_devdesc *)idev, p, path); + if (err != 0) { + free(idev); + return (err); } } diff --git a/sys/boot/ofw/libofw/libofw.h b/sys/boot/ofw/libofw/libofw.h index 5f6d7ad..87e9095 100644 --- a/sys/boot/ofw/libofw/libofw.h +++ b/sys/boot/ofw/libofw/libofw.h @@ -33,7 +33,13 @@ struct ofw_devdesc { int d_type; int d_unit; ihandle_t d_handle; - char d_path[256]; + union { + char d_path[256]; + struct { + uint64_t pool_guid; + uint64_t root_guid; + }; + }; }; extern int ofw_getdev(void **vdev, const char *devspec, const char **path); diff --git a/sys/boot/sparc64/loader/Makefile b/sys/boot/sparc64/loader/Makefile index 27359b2..0a3b753 100644 --- a/sys/boot/sparc64/loader/Makefile +++ b/sys/boot/sparc64/loader/Makefile @@ -37,6 +37,7 @@ CFLAGS+= -DLOADER_CD9660_SUPPORT CFLAGS+= -DLOADER_ZFS_SUPPORT CFLAGS+= -I${.CURDIR}/../../zfs CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +LIBZFSBOOT= ${.OBJDIR}/../../zfs/libzfsboot.a .endif .if ${LOADER_GZIP_SUPPORT} == "yes" CFLAGS+= -DLOADER_GZIP_SUPPORT @@ -83,8 +84,8 @@ CFLAGS+= -I${.CURDIR}/../../ofw/libofw/ # where to get libstand from CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ -DPADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} -LDADD= ${LIBFICL} ${LIBOFW} -lstand +DPADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBOFW} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBOFW} -lstand vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version \ diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c index cb0dda2..3da7ea5 100644 --- a/sys/boot/sparc64/loader/main.c +++ b/sys/boot/sparc64/loader/main.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #ifdef LOADER_ZFS_SUPPORT #include +#include "../zfs/libzfs.h" #endif #include @@ -74,6 +75,8 @@ __FBSDID("$FreeBSD$"); #include "libofw.h" #include "dev_net.h" +#define MAXDEV 31 + extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; enum { @@ -140,11 +143,6 @@ static vm_offset_t heapva; static phandle_t root; -#ifdef LOADER_ZFS_SUPPORT -static int zfs_dev_init(void); -#include "zfs.c" -#endif - /* * Machine dependent structures that the machine independent * loader part uses. @@ -731,39 +729,20 @@ tlb_init_sun4u(void) } #ifdef LOADER_ZFS_SUPPORT - -static int -zfs_dev_init(void) +static void +sparc64_zfs_probe(void) { struct vtoc8 vtoc; - char devname[512]; - spa_t *spa; - vdev_t *vdev; + struct zfs_devdesc zfs_currdev; + char devname[32]; uint64_t guid; int fd, part, unit; - zfs_init(); - - guid = 0; /* Get the GUID of the ZFS pool on the boot device. */ - fd = open(getenv("currdev"), O_RDONLY); - if (fd != -1) { - if (vdev_probe(vdev_read, (void *)(uintptr_t) fd, &spa) == 0) - guid = spa->spa_guid; - close(fd); - } - - /* Clean up the environment to let ZFS work. */ - while ((vdev = STAILQ_FIRST(&zfs_vdevs)) != NULL) { - STAILQ_REMOVE_HEAD(&zfs_vdevs, v_alllink); - free(vdev); - } - while ((spa = STAILQ_FIRST(&zfs_pools)) != NULL) { - STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); - free(spa); - } + guid = 0; + zfs_probe_dev(getenv("currdev"), &guid); - for (unit = 0; unit < MAXBDDEV; unit++) { + for (unit = 0; unit < MAXDEV; unit++) { /* Find freebsd-zfs slices in the VTOC. */ sprintf(devname, "disk%d:", unit); fd = open(devname, O_RDONLY); @@ -781,29 +760,23 @@ zfs_dev_init(void) VTOC_TAG_FREEBSD_ZFS) continue; sprintf(devname, "disk%d:%c", unit, part + 'a'); - fd = open(devname, O_RDONLY); - if (fd == -1) + if (zfs_probe_dev(devname, NULL) == ENXIO) break; - - if (vdev_probe(vdev_read, (void*)(uintptr_t) fd, 0)) - close(fd); } } if (guid != 0) { - unit = zfs_guid_to_unit(guid); - if (unit >= 0) { - /* Update the environment for ZFS. */ - sprintf(devname, "zfs%d", unit); - env_setenv("currdev", EV_VOLATILE, devname, - ofw_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, devname, - env_noset, env_nounset); - } + zfs_currdev.pool_guid = guid; + zfs_currdev.root_guid = 0; + zfs_currdev.d_dev = &zfs_dev; + zfs_currdev.d_type = zfs_currdev.d_dev->dv_type; + /* Update the environment for ZFS. */ + env_setenv("currdev", EV_VOLATILE, zfs_fmtdev(&zfs_currdev), + ofw_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, zfs_fmtdev(&zfs_currdev), + env_noset, env_nounset); } - return (0); } - #endif /* LOADER_ZFS_SUPPORT */ int @@ -823,6 +796,9 @@ main(int (*openfirm)(void *)) archsw.arch_copyout = ofw_copyout; archsw.arch_readin = sparc64_readin; archsw.arch_autoload = sparc64_autoload; +#ifdef LOADER_ZFS_SUPPORT + archsw.arch_zfs_probe = sparc64_zfs_probe; +#endif if (init_heap() == (vm_offset_t)-1) OF_exit(); commit 74e4d8f8fe090f38e71f597dc18dceb5a0fb809a Author: Andriy Gapon Date: Thu Jun 10 10:18:19 2010 +0300 zfs boot: try to set vfs.root.mountfrom from currdev as a fallback diff --git a/sys/boot/common/boot.c b/sys/boot/common/boot.c index c6ab681..8ea06dd 100644 --- a/sys/boot/common/boot.c +++ b/sys/boot/common/boot.c @@ -311,12 +311,12 @@ getrootmount(char *rootdev) if (getenv("vfs.root.mountfrom") != NULL) return(0); + error = 1; sprintf(lbuf, "%s/etc/fstab", rootdev); if ((fd = open(lbuf, O_RDONLY)) < 0) - return(1); + goto notfound; /* loop reading lines from /etc/fstab What was that about sscanf again? */ - error = 1; while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) { if ((lbuf[0] == 0) || (lbuf[0] == '#')) continue; @@ -377,6 +377,20 @@ getrootmount(char *rootdev) break; } close(fd); + +notfound: + if (error) { + const char *currdev; + + currdev = getenv("currdev"); + if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { + cp = strdup(currdev); + cp[strlen(cp) - 1] = '\0'; + setenv("vfs.root.mountfrom", cp, 0); + error = 0; + } + } + return(error); }