diff options
Diffstat (limited to 'sys/boot')
-rw-r--r-- | sys/boot/Makefile | 6 | ||||
-rw-r--r-- | sys/boot/Makefile.amd64 | 2 | ||||
-rw-r--r-- | sys/boot/common/part.c | 6 | ||||
-rw-r--r-- | sys/boot/efi/Makefile.inc | 14 | ||||
-rw-r--r-- | sys/boot/efi/boot1/Makefile | 20 | ||||
-rw-r--r-- | sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu (renamed from sys/boot/efi/boot1/fat.tmpl.bz2.uu) | 2 | ||||
-rw-r--r-- | sys/boot/efi/libefi/Makefile | 2 | ||||
-rw-r--r-- | sys/boot/efi/loader/Makefile | 14 | ||||
-rw-r--r-- | sys/boot/forth/loader.conf | 1 | ||||
-rw-r--r-- | sys/boot/forth/menu-commands.4th | 64 | ||||
-rw-r--r-- | sys/boot/forth/menu.rc | 53 | ||||
-rw-r--r-- | sys/boot/forth/support.4th | 24 | ||||
-rw-r--r-- | sys/boot/i386/loader/main.c | 68 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/main.c | 60 | ||||
-rw-r--r-- | sys/boot/zfs/libzfs.h | 3 | ||||
-rw-r--r-- | sys/boot/zfs/zfs.c | 171 | ||||
-rw-r--r-- | sys/boot/zfs/zfsimpl.c | 62 |
17 files changed, 543 insertions, 29 deletions
diff --git a/sys/boot/Makefile b/sys/boot/Makefile index 3b098e9..4b30df4 100644 --- a/sys/boot/Makefile +++ b/sys/boot/Makefile @@ -1,7 +1,6 @@ # $FreeBSD$ .include <bsd.own.mk> -.include <bsd.arch.inc.mk> .if ${MK_FORTH} != "no" # Build the add-in FORTH interpreter. @@ -9,13 +8,12 @@ SUBDIR+= ficl SUBDIR+= forth .endif +.include <bsd.arch.inc.mk> + # Pick the machine-dependent subdir based on the target architecture. ADIR= ${MACHINE:S/powerpc64/powerpc/} .if exists(${.CURDIR}/${ADIR}/.) SUBDIR+= ${ADIR} .endif -.if ${MACHINE} == "amd64" -SUBDIR+= i386 -.endif .include <bsd.subdir.mk> diff --git a/sys/boot/Makefile.amd64 b/sys/boot/Makefile.amd64 index 2b85283..384cf7a 100644 --- a/sys/boot/Makefile.amd64 +++ b/sys/boot/Makefile.amd64 @@ -8,3 +8,5 @@ SUBDIR+= userboot .if ${MK_FORTH} != "no" SUBDIR+= ficl32 .endif + +SUBDIR+= i386 diff --git a/sys/boot/common/part.c b/sys/boot/common/part.c index 4457619..518df1a 100644 --- a/sys/boot/common/part.c +++ b/sys/boot/common/part.c @@ -306,6 +306,7 @@ ptable_gptread(struct ptable *table, void *dev, diskread_t dread) table->type = PTABLE_NONE; goto out; } + DEBUG("GPT detected"); size = MIN(hdr.hdr_entries * hdr.hdr_entsz, MAXTBLSZ * table->sectorsize); for (i = 0; i < size / hdr.hdr_entsz; i++) { @@ -631,6 +632,11 @@ ptable_open(void *dev, off_t sectors, uint16_t sectorsize, if (buf[DOSMAGICOFFSET] != 0x55 || buf[DOSMAGICOFFSET + 1] != 0xaa) { DEBUG("magic sequence not found"); +#if defined(LOADER_GPT_SUPPORT) + /* There is no PMBR, check that we have backup GPT */ + table->type = PTABLE_GPT; + table = ptable_gptread(table, dev, dread); +#endif goto out; } /* Check that we have PMBR. Also do some validation. */ diff --git a/sys/boot/efi/Makefile.inc b/sys/boot/efi/Makefile.inc index 58c4726..83db76a 100644 --- a/sys/boot/efi/Makefile.inc +++ b/sys/boot/efi/Makefile.inc @@ -4,13 +4,21 @@ BINDIR?= /boot .if ${MACHINE_CPUARCH} == "i386" CFLAGS+= -march=i386 +CFLAGS+= -msoft-float .endif # Options used when building app-specific efi components # See conf/kern.mk for the correct set of these -CFLAGS+= -ffreestanding -fshort-wchar -Wformat -CFLAGS+= -mno-red-zone -CFLAGS+= -mno-mmx -mno-sse -mno-aes -mno-avx -msoft-float +CFLAGS+= -ffreestanding -Wformat LDFLAGS+= -nostdlib +.if ${MACHINE_CPUARCH} == "amd64" +CFLAGS+= -fshort-wchar +CFLAGS+= -mno-red-zone +CFLAGS+= -mno-mmx -mno-sse +CFLAGS.clang+= -mno-aes -mno-avx +CFLAGS+= -msoft-float +.endif + + .include "../Makefile.inc" diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile index 554df39..ddf3147 100644 --- a/sys/boot/efi/boot1/Makefile +++ b/sys/boot/efi/boot1/Makefile @@ -18,19 +18,25 @@ SRCS= boot1.c reloc.c start.S CFLAGS+= -fPIC CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../include -CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. # Always add MI sources and REGULAR efi loader bits -.PATH: ${.CURDIR}/../loader/arch/amd64 ${.CURDIR}/../../common +.PATH: ${.CURDIR}/../loader/arch/${MACHINE} +.PATH: ${.CURDIR}/../loader +.PATH: ${.CURDIR}/../../common CFLAGS+= -I${.CURDIR}/../../common FILES= boot1.efi boot1.efifat FILESMODE_boot1.efi= ${BINMODE} -LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE_CPUARCH}/ldscript.${MACHINE_CPUARCH} -LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared -Wl,-znocombreloc +LDSCRIPT= ${.CURDIR}/../loader/arch/${MACHINE}/ldscript.${MACHINE} +LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared + +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" +LDFLAGS+= -Wl,-znocombreloc +.endif ${PROG}: ${LDSCRIPT} @@ -62,8 +68,8 @@ boot1.o: ${.CURDIR}/../../common/ufsread.c boot1.efifat: boot1.efi echo ${.OBJDIR} - uudecode ${.CURDIR}/fat.tmpl.bz2.uu - mv fat.tmpl.bz2 ${.TARGET}.bz2 + uudecode ${.CURDIR}/fat-${MACHINE}.tmpl.bz2.uu + mv fat-${MACHINE}.tmpl.bz2 ${.TARGET}.bz2 bzip2 -f -d ${.TARGET}.bz2 dd if=boot1.efi of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc @@ -73,6 +79,7 @@ CLEANFILES= boot1.efifat .include <bsd.prog.mk> +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" beforedepend ${OBJS}: machine x86 CLEANFILES+= machine x86 boot1.efi @@ -82,3 +89,4 @@ machine: x86: ln -sf ${.CURDIR}/../../../x86/include x86 +.endif diff --git a/sys/boot/efi/boot1/fat.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu index c9044ee..d8a44b7 100644 --- a/sys/boot/efi/boot1/fat.tmpl.bz2.uu +++ b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu @@ -1,7 +1,7 @@ FAT template boot filesystem created by generate-fat.sh DO NOT EDIT $FreeBSD$ -begin 644 fat.tmpl.bz2 +begin 644 fat-amd64.tmpl.bz2 M0EIH.3%!629362AK*D(`&I+____[ZZKJZ_^N_ZO^Z_Z_OJ[L`4`!7I0$#&$" M0$!$3&(<P`(;J*C:0E0E#30&AH`T````9#0```9````#)ZF0:,-3U/409,`) M@`"8`C3",````$R:8F@P`C`````"24U,D>I-DTU,)ZAZ0VA-!M0T'J`>H#"9 diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile index 99c2e9b..8180d9e 100644 --- a/sys/boot/efi/libefi/Makefile +++ b/sys/boot/efi/libefi/Makefile @@ -10,7 +10,7 @@ SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \ CFLAGS+= -fPIC -mno-red-zone .endif CFLAGS+= -I${.CURDIR}/../include -CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../../lib/libstand # Pick up the bootstrap header for some interface items diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile index 26fd8a0..8d3fe87 100644 --- a/sys/boot/efi/loader/Makefile +++ b/sys/boot/efi/loader/Makefile @@ -23,16 +23,16 @@ SRCS= autoload.c \ smbios.c \ vers.c -.PATH: ${.CURDIR}/arch/${MACHINE_CPUARCH} +.PATH: ${.CURDIR}/arch/${MACHINE} # For smbios.c .PATH: ${.CURDIR}/../../i386/libi386 -.include "${.CURDIR}/arch/${MACHINE_CPUARCH}/Makefile.inc" +.include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" CFLAGS+= -fPIC CFLAGS+= -I${.CURDIR} -CFLAGS+= -I${.CURDIR}/arch/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/arch/${MACHINE} CFLAGS+= -I${.CURDIR}/../include -CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/../include/${MACHINE} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../i386/libi386 @@ -42,7 +42,7 @@ CFLAGS+= -DNO_PCI -DEFI BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH CFLAGS+= -I${.CURDIR}/../../ficl -CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE} LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif @@ -61,12 +61,12 @@ CFLAGS+= -I${.CURDIR}/../../common FILES= loader.efi FILESMODE_loader.efi= ${BINMODE} -LDSCRIPT= ${.CURDIR}/arch/${MACHINE_CPUARCH}/ldscript.${MACHINE_CPUARCH} +LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared -Wl,-znocombreloc CLEANFILES= vers.c loader.efi -NEWVERSWHAT= "EFI loader" ${MACHINE_CPUARCH} +NEWVERSWHAT= "EFI loader" ${MACHINE} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../../efi/loader/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index 88f5411..141b862 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -73,6 +73,7 @@ entropy_cache_type="/boot/entropy" #password="" # Prevent changes to boot options #bootlock_password="" # Prevent booting (see check-password.4th(8)) #geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root +bootenv_autolist="YES" # Auto populate the list of ZFS Boot Environments #beastie_disable="NO" # Turn the beastie boot menu on and off #kernels="kernel kernel.old" # Kernels to display in the boot menu #loader_logo="orbbw" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none diff --git a/sys/boot/forth/menu-commands.4th b/sys/boot/forth/menu-commands.4th index 797c7e6..5c6350a 100644 --- a/sys/boot/forth/menu-commands.4th +++ b/sys/boot/forth/menu-commands.4th @@ -351,4 +351,68 @@ also menu-namespace also menu-command-helpers 2 goto_menu ; +\ +\ Set boot environment defaults +\ + +: init_bootenv ( -- ) + s" set menu_caption[1]=${bemenu_current}${vfs.root.mountfrom}" evaluate + s" set ansi_caption[1]=${beansi_current}${vfs.root.mountfrom}" evaluate + s" set menu_caption[2]=${bemenu_bootfs}${zfs_be_active}" evaluate + s" set ansi_caption[2]=${beansi_bootfs}${zfs_be_active}" evaluate + s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate + s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate +; + +\ +\ Redraw the entire screen. A long BE name can corrupt the menu +\ + +: be_draw_screen + clear \ Clear the screen (in screen.4th) + print_version \ print version string (bottom-right; see version.4th) + draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) + draw-brand \ Draw brand.4th logo at top (in brand.4th) + menu-init \ Initialize menu and draw bounding box (in menu.4th) +; + +\ +\ Select a boot environment +\ + +: set_bootenv ( N -- N TRUE ) + dup s" set vfs.root.mountfrom=${bootenv_root[E]}" 38 +c! evaluate + s" set currdev=${vfs.root.mountfrom}:" evaluate + s" unload" evaluate + free-module-options + s" /boot/defaults/loader.conf" read-conf + s" /boot/loader.conf" read-conf + s" /boot/loader.conf.local" read-conf + init_bootenv + be_draw_screen + menu-redraw + TRUE +; + +\ +\ Switch to the next page of boot environments +\ + +: set_be_page ( N -- N TRUE ) + s" zfs_be_currpage" getenv dup -1 = if + drop s" 1" + else + 0 s>d 2swap + >number ( ud caddr/u -- ud' caddr'/u' ) \ convert string to numbers + 2drop \ drop the string + 1 um/mod ( ud u1 -- u2 u3 ) \ convert double ud' to single u3' and remainder u2 + swap drop ( ud2 u3 -- u3 ) \ drop the remainder u2 + 1+ \ increment the page number + s>d <# #s #> \ convert back to a string + then + s" zfs_be_currpage" setenv + s" reloadbe" evaluate + 3 goto_menu +; + only forth definitions diff --git a/sys/boot/forth/menu.rc b/sys/boot/forth/menu.rc index 7ffeef4..3c7de71 100644 --- a/sys/boot/forth/menu.rc +++ b/sys/boot/forth/menu.rc @@ -68,6 +68,13 @@ set mainmenu_command[6]="2 goto_menu" set mainmenu_keycode[6]=111 set mainansi_caption[6]="Configure Boot ^[1mO^[mptions..." +s" currdev" getenv dup 0> [if] drop 4 s" zfs:" compare 0= [if] + set mainmenu_caption[7]="Select Boot [E]nvironment..." + set mainmenu_command[7]="3 goto_menu" + set mainmenu_keycode[7]=101 + set mainansi_caption[7]="Select Boot ^[1mE^[37mnvironment..." +[then] [else] drop [then] + \ \ BOOT OPTIONS MENU \ @@ -119,6 +126,37 @@ set optionsmenu_keycode[6]=118 set optionsansi_caption[6]="^[1mV^[merbose..... ^[34;1mOff^[m" set optionstoggled_ansi[6]="^[1mV^[merbose..... ^[32;7mOn^[m" +\ +\ BOOT ENVIRONMENT MENU +\ + +set menuset_name3="bootenv" + +set bemenu_current="Active: " +set beansi_current="^[1m${bemenu_current}^[m" +set bemenu_bootfs="bootfs: " +set beansi_bootfs="^[1m${bemenu_bootfs}^[m" +set bemenu_page="[P]age: " +set beansi_page="^[1mP^[mage: " +set bemenu_pageof=" of " +set beansi_pageof="${bemenu_pageof}" +set zfs_be_currpage=1 + +set bootenvmenu_init="init_bootenv" + +set bootenvmenu_command[1]="be_draw_screen 1 goto_menu" +set bootenvmenu_keycode[1]=8 + +set bootenvmenu_command[2]="set_bootenv" +set bootenvmenu_keycode[2]=97 +set bootenv_root[2]="${zfs_be_active}" + +set bootenvmenu_command[3]="set_be_page" +set bootenvmenu_keycode[3]=112 + +set bootenvmenu_options=4 +set bootenvmenu_optionstext="Boot Environments:" + \ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to \ customize the timeout; default is 10-seconds) \ @@ -128,6 +166,21 @@ set menu_timeout_command="boot" \ try-include /boot/menu.rc.local +\ Initialize boot environment variables +\ +s" reloadbe" sfind ( xt|0 bool ) [if] + s" bootenv_autolist" getenv dup -1 = [if] + drop s" execute" evaluate \ Use evaluate to avoid passing + \ reloadbe an optional parameter + [else] + s" YES" compare-insensitive 0= [if] + s" execute" evaluate + [then] + [then] +[else] + drop ( xt=0 ) +[then] + \ Display the main menu (see `menu.4th') set menuset_initial=1 menuset-loadinitial diff --git a/sys/boot/forth/support.4th b/sys/boot/forth/support.4th index 6db232b..1acef70 100644 --- a/sys/boot/forth/support.4th +++ b/sys/boot/forth/support.4th @@ -930,6 +930,30 @@ only forth definitions also support-functions repeat ; +: free-one-module { addr -- addr } + addr module.name strfree + addr module.loadname strfree + addr module.type strfree + addr module.args strfree + addr module.beforeload strfree + addr module.afterload strfree + addr module.loaderror strfree + addr +; + +: free-module-options + module_options @ + begin + ?dup + while + free-one-module + dup module.next @ + swap free-memory + repeat + 0 module_options ! + 0 last_module_option ! +; + only forth also support-functions definitions \ Variables used for processing multiple conf files diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index c1a3ca4..be08271 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -69,6 +69,7 @@ static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_ZFS_SUPPORT +static void init_zfs_bootenv(char *currdev); static void i386_zfs_probe(void); #endif @@ -291,12 +292,45 @@ extract_currdev(void) new_currdev.d_unit = 0; } +#ifdef LOADER_ZFS_SUPPORT + if (new_currdev.d_type == DEVT_ZFS) + init_zfs_bootenv(zfs_fmtdev(&new_currdev)); +#endif + 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 +static void +init_zfs_bootenv(char *currdev) +{ + char *beroot; + + if (strlen(currdev) == 0) + return; + if(strncmp(currdev, "zfs:", 4) != 0) + return; + /* Remove the trailing : */ + currdev[strlen(currdev) - 1] = '\0'; + setenv("zfs_be_active", currdev, 1); + setenv("zfs_be_currpage", "1", 1); + /* Do not overwrite if already set */ + setenv("vfs.root.mountfrom", currdev, 0); + /* Forward past zfs: */ + currdev = strchr(currdev, ':'); + currdev++; + /* Remove the last element (current bootenv) */ + beroot = strrchr(currdev, '/'); + if (beroot != NULL) + beroot[0] = '\0'; + beroot = currdev; + setenv("zfs_be_root", beroot, 1); +} +#endif + COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int @@ -350,6 +384,40 @@ command_lszfs(int argc, char *argv[]) command_errmsg = strerror(err); return (CMD_ERROR); } + + return (CMD_OK); +} + +COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", + command_reloadbe); + +static int +command_reloadbe(int argc, char *argv[]) +{ + int err; + char *root; + + if (argc > 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + if (argc == 2) { + err = zfs_bootenv(argv[1]); + } else { + root = getenv("zfs_be_root"); + if (root == NULL) { + /* There does not appear to be a ZFS pool here, exit without error */ + return (CMD_OK); + } + err = zfs_bootenv(getenv("zfs_be_root")); + } + + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); } #endif diff --git a/sys/boot/userboot/userboot/main.c b/sys/boot/userboot/userboot/main.c index c9353ab..e4d546a 100644 --- a/sys/boot/userboot/userboot/main.c +++ b/sys/boot/userboot/userboot/main.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); static void userboot_zfs_probe(void); static int userboot_zfs_found; +static void init_zfs_bootenv(char *currdev); #endif #define USERBOOT_VERSION USERBOOT_VERSION_3 @@ -167,6 +168,7 @@ extract_currdev(void) zdev.d_type = zdev.d_dev->dv_type; dev = *(struct disk_devdesc *)&zdev; + init_zfs_bootenv(zfs_fmtdev(&dev)); } else #endif @@ -198,6 +200,32 @@ extract_currdev(void) #if defined(USERBOOT_ZFS_SUPPORT) static void +init_zfs_bootenv(char *currdev) +{ + char *beroot; + + if (strlen(currdev) == 0) + return; + if(strncmp(currdev, "zfs:", 4) != 0) + return; + /* Remove the trailing : */ + currdev[strlen(currdev) - 1] = '\0'; + setenv("zfs_be_active", currdev, 1); + setenv("zfs_be_currpage", "1", 1); + /* Do not overwrite if already set */ + setenv("vfs.root.mountfrom", currdev, 0); + /* Forward past zfs: */ + currdev = strchr(currdev, ':'); + currdev++; + /* Remove the last element (current bootenv) */ + beroot = strrchr(currdev, '/'); + if (beroot != NULL) + beroot[0] = '\0'; + beroot = currdev; + setenv("zfs_be_root", beroot, 1); +} + +static void userboot_zfs_probe(void) { char devname[32]; @@ -237,6 +265,38 @@ command_lszfs(int argc, char *argv[]) } return (CMD_OK); } + +COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", + command_reloadbe); + +static int +command_reloadbe(int argc, char *argv[]) +{ + int err; + char *root; + + if (argc > 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + if (argc == 2) { + err = zfs_bootenv(argv[1]); + } else { + root = getenv("zfs_be_root"); + if (root == NULL) { + return (CMD_OK); + } + err = zfs_bootenv(root); + } + + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + + return (CMD_OK); +} #endif /* USERBOOT_ZFS_SUPPORT */ COMMAND_SET(quit, "quit", "exit the loader", command_quit); diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h index 6834f8b..b289849 100644 --- a/sys/boot/zfs/libzfs.h +++ b/sys/boot/zfs/libzfs.h @@ -62,6 +62,9 @@ int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, char *zfs_fmtdev(void *vdev); int zfs_probe_dev(const char *devname, uint64_t *pool_guid); int zfs_list(const char *name); +int zfs_bootenv(const char *name); +int zfs_belist_add(const char *name); +int zfs_set_env(void); extern struct devsw zfs_dev; extern struct fs_ops zfs_fsops; diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c index 64c738d..0679a57 100644 --- a/sys/boot/zfs/zfs.c +++ b/sys/boot/zfs/zfs.c @@ -48,6 +48,10 @@ __FBSDID("$FreeBSD$"); #include "zfsimpl.c" +/* Define the range of indexes to be populated with ZFS Boot Environments */ +#define ZFS_BE_FIRST 4 +#define ZFS_BE_LAST 8 + 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); static int zfs_close(struct open_file *f); @@ -80,6 +84,16 @@ struct file { zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ }; +static int zfs_env_index; +static int zfs_env_count; + +SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head); +struct zfs_be_list *zfs_be_headp; +struct zfs_be_entry { + const char *name; + SLIST_ENTRY(zfs_be_entry) entries; +} *zfs_be, *zfs_be_tmp; + /* * Open a file. */ @@ -691,6 +705,161 @@ zfs_list(const char *name) rv = zfs_lookup_dataset(spa, dsname, &objid); if (rv != 0) return (rv); - rv = zfs_list_dataset(spa, objid); + + return (zfs_list_dataset(spa, objid)); +} + +int +zfs_bootenv(const char *name) +{ + static char poolname[ZFS_MAXNAMELEN], *dsname, *root; + char becount[4]; + uint64_t objid; + spa_t *spa; + int len, rv, pages, perpage, currpage; + + if (name == NULL) + return (EINVAL); + if ((root = getenv("zfs_be_root")) == NULL) + return (EINVAL); + + if (strcmp(name, root) != 0) { + if (setenv("zfs_be_root", name, 1) != 0) + return (ENOMEM); + } + + SLIST_INIT(&zfs_be_head); + zfs_env_count = 0; + len = strlen(name); + dsname = strchr(name, '/'); + if (dsname != NULL) { + len = dsname - name; + dsname++; + } else + dsname = ""; + memcpy(poolname, name, len); + poolname[len] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + rv = zfs_lookup_dataset(spa, dsname, &objid); + if (rv != 0) + return (rv); + rv = zfs_callback_dataset(spa, objid, zfs_belist_add); + + /* Calculate and store the number of pages of BEs */ + perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1); + pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0); + snprintf(becount, 4, "%d", pages); + if (setenv("zfs_be_pages", becount, 1) != 0) + return (ENOMEM); + + /* Roll over the page counter if it has exceeded the maximum */ + currpage = strtol(getenv("zfs_be_currpage"), NULL, 10); + if (currpage > pages) { + if (setenv("zfs_be_currpage", "1", 1) != 0) + return (ENOMEM); + } + + /* Populate the menu environment variables */ + zfs_set_env(); + + /* Clean up the SLIST of ZFS BEs */ + while (!SLIST_EMPTY(&zfs_be_head)) { + zfs_be = SLIST_FIRST(&zfs_be_head); + SLIST_REMOVE_HEAD(&zfs_be_head, entries); + free(zfs_be); + } + return (rv); } + +int +zfs_belist_add(const char *name) +{ + + /* Add the boot environment to the head of the SLIST */ + zfs_be = malloc(sizeof(struct zfs_be_entry)); + zfs_be->name = name; + SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries); + zfs_env_count++; + + return (0); +} + +int +zfs_set_env(void) +{ + char envname[32], envval[256]; + char *beroot, *pagenum; + int rv, page, ctr; + + beroot = getenv("zfs_be_root"); + if (beroot == NULL) { + return (1); + } + + pagenum = getenv("zfs_be_currpage"); + if (pagenum != NULL) { + page = strtol(pagenum, NULL, 10); + } else { + page = 1; + } + + ctr = 1; + rv = 0; + zfs_env_index = ZFS_BE_FIRST; + SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { + /* Skip to the requested page number */ + if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) { + ctr++; + continue; + } + + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); + snprintf(envval, sizeof(envval), "%s", zfs_be->name); + rv = setenv(envname, envval, 1); + if (rv != 0) { + break; + } + + snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); + rv = setenv(envname, envval, 1); + if (rv != 0){ + break; + } + + snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); + rv = setenv(envname, "set_bootenv", 1); + if (rv != 0){ + break; + } + + snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); + snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name); + rv = setenv(envname, envval, 1); + if (rv != 0){ + break; + } + + zfs_env_index++; + if (zfs_env_index > ZFS_BE_LAST) { + break; + } + + } + + for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); + (void)unsetenv(envname); + } + + return (rv); +}
\ No newline at end of file diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index d889047..927fbad 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -1473,7 +1473,7 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64 * the directory contents. */ static int -mzap_list(const dnode_phys_t *dnode) +mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *)) { const mzap_phys_t *mz; const mzap_ent_phys_t *mze; @@ -1492,7 +1492,7 @@ mzap_list(const dnode_phys_t *dnode) mze = &mz->mz_chunk[i]; if (mze->mze_name[0]) //printf("%-32s 0x%jx\n", mze->mze_name, (uintmax_t)mze->mze_value); - printf("%s\n", mze->mze_name); + callback(mze->mze_name); } return (0); @@ -1503,7 +1503,7 @@ mzap_list(const dnode_phys_t *dnode) * the directory header. */ static int -fzap_list(const spa_t *spa, const dnode_phys_t *dnode) +fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *)) { int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; zap_phys_t zh = *(zap_phys_t *) zap_scratch; @@ -1566,13 +1566,21 @@ fzap_list(const spa_t *spa, const dnode_phys_t *dnode) value = fzap_leaf_value(&zl, zc); //printf("%s 0x%jx\n", name, (uintmax_t)value); - printf("%s\n", name); + callback((const char *)name); } } return (0); } +static int zfs_printf(const char *name) +{ + + printf("%s\n", name); + + return (0); +} + /* * List a zap directory. */ @@ -1587,9 +1595,9 @@ zap_list(const spa_t *spa, const dnode_phys_t *dnode) zap_type = *(uint64_t *) zap_scratch; if (zap_type == ZBT_MICRO) - return mzap_list(dnode); + return mzap_list(dnode, zfs_printf); else - return fzap_list(spa, dnode); + return fzap_list(spa, dnode, zfs_printf); } static int @@ -1858,6 +1866,48 @@ zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/) return (zap_list(spa, &child_dir_zap) != 0); } + +int +zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *name)) +{ + uint64_t dir_obj, child_dir_zapobj, zap_type; + dnode_phys_t child_dir_zap, dir, dataset; + dsl_dataset_phys_t *ds; + dsl_dir_phys_t *dd; + int err; + + err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); + if (err != 0) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (err); + } + ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); + if (err != 0) { + printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); + return (err); + } + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + child_dir_zapobj = dd->dd_child_dir_zapobj; + err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap); + if (err != 0) { + printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); + return (err); + } + + err = dnode_read(spa, &child_dir_zap, 0, zap_scratch, child_dir_zap.dn_datablkszsec * 512); + if (err != 0) + return (err); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_list(&child_dir_zap, callback); + else + return fzap_list(spa, &child_dir_zap, callback); +} #endif /* |