svn commit: r308915 - in stable/10: cddl/contrib/opensolaris/lib/libzfs/common sbin sbin/zfsbootcfg sys/boot/i386/common sys/boot/i386/gptzfsboot sys/boot/i386/zfsboot sys/cddl/contrib/opensolaris/...
Andriy Gapon
avg at FreeBSD.org
Mon Nov 21 10:14:39 UTC 2016
Author: avg
Date: Mon Nov 21 10:14:36 2016
New Revision: 308915
URL: https://svnweb.freebsd.org/changeset/base/308915
Log:
MFC r308089: zfsbootcfg: a simple tool to set next boot (one time)
options for zfsboot
There is a branch-specific change in sbin/zfsbootcfg/Makefile because of
LIBADD vs LDADD/DPADD.
Added:
stable/10/sbin/zfsbootcfg/
- copied from r308089, head/sbin/zfsbootcfg/
Modified:
stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
stable/10/sbin/Makefile
stable/10/sbin/zfsbootcfg/Makefile
stable/10/sys/boot/i386/common/drv.c
stable/10/sys/boot/i386/common/drv.h
stable/10/sys/boot/i386/gptzfsboot/Makefile
stable/10/sys/boot/i386/zfsboot/Makefile
stable/10/sys/boot/i386/zfsboot/zfsboot.c
stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
stable/10/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
==============================================================================
--- stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h Mon Nov 21 10:14:36 2016 (r308915)
@@ -213,6 +213,7 @@ extern int zpool_get_state(zpool_handle_
extern const char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
extern const char *zpool_pool_state_to_name(pool_state_t);
extern void zpool_free_handles(libzfs_handle_t *);
+extern int zpool_nextboot(libzfs_handle_t *, uint64_t, uint64_t, const char *);
/*
* Iterate over all active pools in the system.
Modified: stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
==============================================================================
--- stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c Mon Nov 21 10:14:36 2016 (r308915)
@@ -4126,3 +4126,25 @@ out:
libzfs_fini(hdl);
return (ret);
}
+
+int
+zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
+ const char *command)
+{
+ zfs_cmd_t zc = { 0 };
+ nvlist_t *args;
+ char *packed;
+ size_t size;
+ int error;
+
+ args = fnvlist_alloc();
+ fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
+ fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
+ fnvlist_add_string(args, "command", command);
+ error = zcmd_write_src_nvlist(hdl, &zc, args);
+ if (error == 0)
+ error = ioctl(hdl->libzfs_fd, ZFS_IOC_NEXTBOOT, &zc);
+ zcmd_free_nvlists(&zc);
+ nvlist_free(args);
+ return (error);
+}
Modified: stable/10/sbin/Makefile
==============================================================================
--- stable/10/sbin/Makefile Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sbin/Makefile Mon Nov 21 10:14:36 2016 (r308915)
@@ -73,6 +73,7 @@ SUBDIR=adjkerntz \
.if ${MK_ATM} != "no"
SUBDIR+= atm
.endif
+SUBDIR.${MK_ZFS}+= zfsbootcfg
.if ${MK_CCD} != "no"
SUBDIR+= ccdconfig
Modified: stable/10/sbin/zfsbootcfg/Makefile
==============================================================================
--- head/sbin/zfsbootcfg/Makefile Sat Oct 29 14:09:32 2016 (r308089)
+++ stable/10/sbin/zfsbootcfg/Makefile Mon Nov 21 10:14:36 2016 (r308915)
@@ -5,11 +5,17 @@ PROG= zfsbootcfg
WARNS?= 1
MAN= zfsbootcfg.8
-LIBADD+=zfs
-LIBADD+=nvpair
-LIBADD+=umem
-LIBADD+=uutil
-LIBADD+=geom
+DPADD+=${LIBZFS}
+DPADD+=${LIBNVPAIR}
+DPADD+=${LIBUMEM}
+DPADD+=${LIBUUTIL}
+DPADD+=${LIBGEOM}
+
+LDADD+=-lzfs
+LDADD+=-lnvpair
+LDADD+=-lumem
+LDADD+=-luutil
+LDADD+=-lgeom
CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/include
CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/lib/libumem
Modified: stable/10/sys/boot/i386/common/drv.c
==============================================================================
--- stable/10/sys/boot/i386/common/drv.c Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/boot/i386/common/drv.c Mon Nov 21 10:14:36 2016 (r308915)
@@ -93,7 +93,7 @@ drvread(struct dsk *dskp, void *buf, dad
return (0);
}
-#ifdef GPT
+#if defined(GPT) || defined(ZFS)
int
drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
{
@@ -116,4 +116,4 @@ drvwrite(struct dsk *dskp, void *buf, da
}
return (0);
}
-#endif /* GPT */
+#endif /* GPT || ZFS */
Modified: stable/10/sys/boot/i386/common/drv.h
==============================================================================
--- stable/10/sys/boot/i386/common/drv.h Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/boot/i386/common/drv.h Mon Nov 21 10:14:36 2016 (r308915)
@@ -40,9 +40,9 @@ struct dsk {
};
int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
-#ifdef GPT
+#if defined(GPT) || defined(ZFS)
int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
uint64_t drvsize(struct dsk *dskp);
-#endif /* GPT */
+#endif /* GPT || ZFS */
#endif /* !_DRV_H_ */
Modified: stable/10/sys/boot/i386/gptzfsboot/Makefile
==============================================================================
--- stable/10/sys/boot/i386/gptzfsboot/Makefile Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/boot/i386/gptzfsboot/Makefile Mon Nov 21 10:14:36 2016 (r308915)
@@ -19,7 +19,7 @@ ORG2= 0x0
CFLAGS= -DBOOTPROG=\"gptzfsboot\" \
-O1 \
- -DGPT -DBOOT2 \
+ -DGPT -DZFS -DBOOT2 \
-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
-DSIOFMT=${B2SIOFMT} \
-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
Modified: stable/10/sys/boot/i386/zfsboot/Makefile
==============================================================================
--- stable/10/sys/boot/i386/zfsboot/Makefile Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/boot/i386/zfsboot/Makefile Mon Nov 21 10:14:36 2016 (r308915)
@@ -17,7 +17,7 @@ ORG2= 0x2000
CFLAGS= -DBOOTPROG=\"zfsboot\" \
-O1 \
- -DBOOT2 \
+ -DZFS -DBOOT2 \
-DSIOPRT=${BOOT_COMCONSOLE_PORT} \
-DSIOFMT=${B2SIOFMT} \
-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
Modified: stable/10/sys/boot/i386/zfsboot/zfsboot.c
==============================================================================
--- stable/10/sys/boot/i386/zfsboot/zfsboot.c Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/boot/i386/zfsboot/zfsboot.c Mon Nov 21 10:14:36 2016 (r308915)
@@ -117,6 +117,7 @@ struct dmadat {
static struct dmadat *dmadat;
void exit(int);
+void reboot(void);
static void load(void);
static int parse(void);
static void bios_getmem(void);
@@ -158,7 +159,7 @@ zfs_read(spa_t *spa, const dnode_phys_t
n = size;
if (*offp + n > zp->zp_size)
n = zp->zp_size - *offp;
-
+
rc = dnode_read(spa, dnode, *offp, start, n);
if (rc)
return (-1);
@@ -208,6 +209,35 @@ vdev_read(vdev_t *vdev, void *priv, off_
}
static int
+vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
+{
+ char *p;
+ daddr_t lba;
+ unsigned int nb;
+ struct dsk *dsk = (struct dsk *) priv;
+
+ if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
+ return -1;
+
+ p = buf;
+ lba = off / DEV_BSIZE;
+ lba += dsk->start;
+ while (bytes > 0) {
+ nb = bytes / DEV_BSIZE;
+ if (nb > READ_BUF_SIZE / DEV_BSIZE)
+ nb = READ_BUF_SIZE / DEV_BSIZE;
+ memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE);
+ if (drvwrite(dsk, dmadat->rdbuf, lba, nb))
+ return -1;
+ p += nb * DEV_BSIZE;
+ lba += nb;
+ bytes -= nb * DEV_BSIZE;
+ }
+
+ return 0;
+}
+
+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) {
@@ -217,6 +247,52 @@ xfsread(const dnode_phys_t *dnode, off_t
return 0;
}
+/*
+ * Read Pad2 (formerly "Boot Block Header") area of the first
+ * vdev label of the given vdev.
+ */
+static int
+vdev_read_pad2(vdev_t *vdev, char *buf, size_t size)
+{
+ blkptr_t bp;
+ char *tmp = zap_scratch;
+ off_t off = offsetof(vdev_label_t, vl_pad2);
+
+ if (size > VDEV_PAD_SIZE)
+ size = VDEV_PAD_SIZE;
+
+ BP_ZERO(&bp);
+ BP_SET_LSIZE(&bp, VDEV_PAD_SIZE);
+ BP_SET_PSIZE(&bp, VDEV_PAD_SIZE);
+ BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL);
+ BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF);
+ DVA_SET_OFFSET(BP_IDENTITY(&bp), off);
+ if (vdev_read_phys(vdev, &bp, tmp, off, 0))
+ return (EIO);
+ memcpy(buf, tmp, size);
+ return (0);
+}
+
+static int
+vdev_clear_pad2(vdev_t *vdev)
+{
+ char *zeroes = zap_scratch;
+ uint64_t *end;
+ off_t off = offsetof(vdev_label_t, vl_pad2);
+
+ memset(zeroes, 0, VDEV_PAD_SIZE);
+ end = (uint64_t *)(zeroes + VDEV_PAD_SIZE);
+ /* ZIO_CHECKSUM_LABEL magic and pre-calcualted checksum for all zeros */
+ end[-5] = 0x0210da7ab10c7a11;
+ end[-4] = 0x97f48f807f6e2a3f;
+ end[-3] = 0xaf909f1658aacefc;
+ end[-2] = 0xcbd1ea57ff6db48b;
+ end[-1] = 0x6ec692db0d465fab;
+ if (vdev_write(vdev, vdev->v_read_priv, off, zeroes, VDEV_PAD_SIZE))
+ return (EIO);
+ return (0);
+}
+
static void
bios_getmem(void)
{
@@ -431,10 +507,12 @@ trymbr:
int
main(void)
{
- int autoboot, i;
dnode_phys_t dn;
off_t off;
struct dsk *dsk;
+ int autoboot, i;
+ int nextboot;
+ int rc;
dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
@@ -520,7 +598,39 @@ main(void)
primary_spa = spa;
primary_vdev = spa_get_primary_vdev(spa);
- if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) {
+ nextboot = 0;
+ rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd));
+ if (vdev_clear_pad2(primary_vdev))
+ printf("failed to clear pad2 area of primary vdev\n");
+ if (rc == 0) {
+ if (*cmd) {
+ /*
+ * We could find an old-style ZFS Boot Block header here.
+ * Simply ignore it.
+ */
+ if (*(uint64_t *)cmd != 0x2f5b007b10c) {
+ /*
+ * Note that parse() is destructive to cmd[] and we also want
+ * to honor RBX_QUIET option that could be present in cmd[].
+ */
+ nextboot = 1;
+ memcpy(cmddup, cmd, sizeof(cmd));
+ if (parse()) {
+ printf("failed to parse pad2 area of primary vdev\n");
+ reboot();
+ }
+ if (!OPT_CHECK(RBX_QUIET))
+ printf("zfs nextboot: %s\n", cmddup);
+ }
+ /* Do not process this command twice */
+ *cmd = 0;
+ }
+ } else
+ printf("failed to read pad2 area of primary vdev\n");
+
+ /* Mount ZFS only if it's not already mounted via nextboot parsing. */
+ if (zfsmount.spa == NULL &&
+ (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;
@@ -544,6 +654,10 @@ main(void)
*cmd = 0;
}
+ /* Do not risk waiting at the prompt forever. */
+ if (nextboot && !autoboot)
+ reboot();
+
/*
* Try to exec /boot/loader. If interrupted by a keypress,
* or in case of failure, try to load a kernel directly instead.
@@ -593,6 +707,13 @@ main(void)
void
exit(int x)
{
+ __exit(x);
+}
+
+void
+reboot(void)
+{
+ __exit(0);
}
static void
Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
==============================================================================
--- stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h Mon Nov 21 10:14:36 2016 (r308915)
@@ -162,6 +162,8 @@ typedef enum {
extern int vdev_label_init(vdev_t *vd, uint64_t txg, vdev_labeltype_t reason);
+extern int vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t size);
+
#ifdef __cplusplus
}
#endif
Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
==============================================================================
--- stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c Mon Nov 21 10:14:36 2016 (r308915)
@@ -857,6 +857,44 @@ retry:
return (error);
}
+int
+vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t size)
+{
+ spa_t *spa = vd->vdev_spa;
+ zio_t *zio;
+ char *pad2;
+ int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
+ int error;
+
+ if (size > VDEV_PAD_SIZE)
+ return (EINVAL);
+
+ if (!vd->vdev_ops->vdev_op_leaf)
+ return (ENODEV);
+ if (vdev_is_dead(vd))
+ return (ENXIO);
+
+ ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+ pad2 = zio_buf_alloc(VDEV_PAD_SIZE);
+ bzero(pad2, VDEV_PAD_SIZE);
+ memcpy(pad2, buf, size);
+
+retry:
+ zio = zio_root(spa, NULL, NULL, flags);
+ vdev_label_write(zio, vd, 0, pad2,
+ offsetof(vdev_label_t, vl_pad2),
+ VDEV_PAD_SIZE, NULL, NULL, flags);
+ error = zio_wait(zio);
+ if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) {
+ flags |= ZIO_FLAG_TRYHARD;
+ goto retry;
+ }
+
+ zio_buf_free(pad2, VDEV_PAD_SIZE);
+ return (error);
+}
+
/*
* ==========================================================================
* uberblock load/sync
Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Mon Nov 21 10:14:36 2016 (r308915)
@@ -3471,6 +3471,53 @@ zfs_ioc_log_history(const char *unused,
return (error);
}
+#ifdef __FreeBSD__
+static int
+zfs_ioc_nextboot(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
+{
+ char name[MAXNAMELEN];
+ spa_t *spa;
+ vdev_t *vd;
+ char *command;
+ uint64_t pool_guid;
+ uint64_t vdev_guid;
+ int error;
+
+ if (nvlist_lookup_uint64(innvl,
+ ZPOOL_CONFIG_POOL_GUID, &pool_guid) != 0)
+ return (EINVAL);
+ if (nvlist_lookup_uint64(innvl,
+ ZPOOL_CONFIG_GUID, &vdev_guid) != 0)
+ return (EINVAL);
+ if (nvlist_lookup_string(innvl,
+ "command", &command) != 0)
+ return (EINVAL);
+
+ mutex_enter(&spa_namespace_lock);
+ spa = spa_by_guid(pool_guid, vdev_guid);
+ if (spa != NULL)
+ strcpy(name, spa_name(spa));
+ mutex_exit(&spa_namespace_lock);
+ if (spa == NULL)
+ return (ENOENT);
+
+ if ((error = spa_open(name, &spa, FTAG)) != 0)
+ return (error);
+ spa_vdev_state_enter(spa, SCL_ALL);
+ vd = spa_lookup_by_guid(spa, vdev_guid, B_TRUE);
+ if (vd == NULL) {
+ (void) spa_vdev_state_exit(spa, NULL, ENXIO);
+ spa_close(spa, FTAG);
+ return (ENODEV);
+ }
+ error = vdev_label_write_pad2(vd, command, strlen(command));
+ (void) spa_vdev_state_exit(spa, NULL, 0);
+ txg_wait_synced(spa->spa_dsl_pool, 0);
+ spa_close(spa, FTAG);
+ return (error);
+}
+#endif
+
/*
* The dp_config_rwlock must not be held when calling this, because the
* unmount may need to write out data.
@@ -6033,6 +6080,9 @@ zfs_ioctl_init(void)
zfs_secpolicy_config, POOL_CHECK_NONE);
zfs_ioctl_register_dataset_nolog(ZFS_IOC_UNJAIL, zfs_ioc_unjail,
zfs_secpolicy_config, POOL_CHECK_NONE);
+ zfs_ioctl_register("fbsd_nextboot", ZFS_IOC_NEXTBOOT,
+ zfs_ioc_nextboot, zfs_secpolicy_config, NO_NAME,
+ POOL_CHECK_NONE, B_FALSE, B_FALSE);
#endif
}
Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
==============================================================================
--- stable/10/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h Mon Nov 21 10:13:09 2016 (r308914)
+++ stable/10/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h Mon Nov 21 10:14:36 2016 (r308915)
@@ -888,6 +888,7 @@ typedef enum zfs_ioc {
ZFS_IOC_BOOKMARK,
ZFS_IOC_GET_BOOKMARKS,
ZFS_IOC_DESTROY_BOOKMARKS,
+ ZFS_IOC_NEXTBOOT,
ZFS_IOC_LAST
} zfs_ioc_t;
More information about the svn-src-all
mailing list