summaryrefslogtreecommitdiffstats
path: root/sys/boot/i386
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2012-05-12 09:03:30 +0000
committeravg <avg@FreeBSD.org>2012-05-12 09:03:30 +0000
commita1cf7817fdc316198beb7e881a16684b20ea9ab8 (patch)
treedf061398b6750e42dc38884e817fdece2299ea9e /sys/boot/i386
parent8f2a8ac2b1384a6b3dd4d5d11d4522ea728f9882 (diff)
downloadFreeBSD-src-a1cf7817fdc316198beb7e881a16684b20ea9ab8.zip
FreeBSD-src-a1cf7817fdc316198beb7e881a16684b20ea9ab8.tar.gz
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. Backward-compatibility shims are provided for recently added sparc64 zfs boot support. Currently that architecture still works the old way and does not support the new features. TODO: - clear up pool root filesystem vs pool bootfs filesystem distinction - update sparc64 support - set vfs.root.mountfrom based on currdev (for zfs) Mid-future TODO: - loader sub-menu for selecting alternative boot environment Distant future TODO: - support accessing snapshots, using a snapshot as readonly root Reviewed by: marius (sparc64), Gavin Mu <gavin.mu@gmail.com> (sparc64) Tested by: Florian Wagner <florian@wagner-flo.net> (x86), marius (sparc64) No objections: fs@, hackers@ MFC after: 1 month
Diffstat (limited to 'sys/boot/i386')
-rw-r--r--sys/boot/i386/libi386/Makefile2
-rw-r--r--sys/boot/i386/libi386/devicename.c11
-rw-r--r--sys/boot/i386/libi386/libi386.h9
-rw-r--r--sys/boot/i386/loader/conf.c11
-rw-r--r--sys/boot/i386/loader/main.c88
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c67
6 files changed, 133 insertions, 55 deletions
diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile
index 94a20c8..c968746 100644
--- a/sys/boot/i386/libi386/Makefile
+++ b/sys/boot/i386/libi386/Makefile
@@ -9,6 +9,8 @@ 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
+.PATH: ${.CURDIR}/../../zfs
+SRCS+= 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 <sys/disklabel.h>
#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 <stand.h>
#include <bootstrap.h>
#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 df11a2e..08cf16b 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$");
#include "libi386/libi386.h"
#include "btxv86.h"
+#ifdef LOADER_ZFS_SUPPORT
+#include "../zfs/libzfs.h"
+#endif
+
CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE);
CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO);
CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS);
@@ -62,6 +66,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[];
@@ -153,6 +160,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.
@@ -196,8 +206,11 @@ main(void)
static void
extract_currdev(void)
{
- struct i386_devdesc new_currdev;
- int biosdev = -1;
+ struct i386_devdesc new_currdev;
+#ifdef LOADER_ZFS_SUPPORT
+ struct zfs_boot_args *zargs;
+#endif
+ int biosdev = -1;
/* Assume we are booting from a BIOS disk by default */
new_currdev.d_dev = &biosdisk;
@@ -218,6 +231,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;
@@ -238,7 +269,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.
@@ -249,33 +280,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);
@@ -342,3 +351,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 452d9ae..c92b11e 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))
OpenPOWER on IntegriCloud