Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Nov 2016 10:13:09 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r308914 - in stable/11: 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/...
Message-ID:  <201611211013.uALAD98b090023@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Mon Nov 21 10:13:09 2016
New Revision: 308914
URL: https://svnweb.freebsd.org/changeset/base/308914

Log:
  MFC r308089: zfsbootcfg: a simple tool to set next boot (one time)
  options for zfsboot

Added:
  stable/11/sbin/zfsbootcfg/
     - copied from r308089, head/sbin/zfsbootcfg/
Modified:
  stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
  stable/11/sbin/Makefile
  stable/11/sys/boot/i386/common/drv.c
  stable/11/sys/boot/i386/common/drv.h
  stable/11/sys/boot/i386/gptzfsboot/Makefile
  stable/11/sys/boot/i386/zfsboot/Makefile
  stable/11/sys/boot/i386/zfsboot/zfsboot.c
  stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
  stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
  stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  stable/11/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
==============================================================================
--- stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
==============================================================================
--- stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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/11/sbin/Makefile
==============================================================================
--- stable/11/sbin/Makefile	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sbin/Makefile	Mon Nov 21 10:13:09 2016	(r308914)
@@ -87,6 +87,7 @@ SUBDIR.${MK_PF}+=	pfctl
 SUBDIR.${MK_PF}+=	pflogd
 SUBDIR.${MK_QUOTAS}+=	quotacheck
 SUBDIR.${MK_ROUTED}+=	routed
+SUBDIR.${MK_ZFS}+=	zfsbootcfg
 
 SUBDIR.${MK_TESTS}+=	tests
 

Modified: stable/11/sys/boot/i386/common/drv.c
==============================================================================
--- stable/11/sys/boot/i386/common/drv.c	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/boot/i386/common/drv.c	Mon Nov 21 10:13:09 2016	(r308914)
@@ -91,7 +91,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)
 {
@@ -114,4 +114,4 @@ drvwrite(struct dsk *dskp, void *buf, da
 	}
 	return (0);
 }
-#endif	/* GPT */
+#endif	/* GPT || ZFS */

Modified: stable/11/sys/boot/i386/common/drv.h
==============================================================================
--- stable/11/sys/boot/i386/common/drv.h	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/boot/i386/common/drv.h	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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);
-#endif	/* GPT */
+#endif	/* GPT || ZFS */
 uint64_t drvsize(struct dsk *dskp);
 
 #endif	/* !_DRV_H_ */

Modified: stable/11/sys/boot/i386/gptzfsboot/Makefile
==============================================================================
--- stable/11/sys/boot/i386/gptzfsboot/Makefile	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/boot/i386/gptzfsboot/Makefile	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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/11/sys/boot/i386/zfsboot/Makefile
==============================================================================
--- stable/11/sys/boot/i386/zfsboot/Makefile	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/boot/i386/zfsboot/Makefile	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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/11/sys/boot/i386/zfsboot/zfsboot.c
==============================================================================
--- stable/11/sys/boot/i386/zfsboot/zfsboot.c	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/boot/i386/zfsboot/zfsboot.c	Mon Nov 21 10:13:09 2016	(r308914)
@@ -119,6 +119,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);
@@ -175,7 +176,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);
@@ -260,6 +261,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) {
@@ -269,6 +299,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)
 {
@@ -542,10 +618,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);
 
@@ -634,7 +712,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;
@@ -658,6 +768,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.
@@ -707,6 +821,13 @@ main(void)
 void
 exit(int x)
 {
+    __exit(x);
+}
+
+void
+reboot(void)
+{
+    __exit(0);
 }
 
 static void

Modified: stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
==============================================================================
--- stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h	Mon Nov 21 10:13:09 2016	(r308914)
@@ -167,6 +167,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/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
==============================================================================
--- stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c	Mon Nov 21 10:13:09 2016	(r308914)
@@ -871,6 +871,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/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Mon Nov 21 10:13:09 2016	(r308914)
@@ -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/11/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
==============================================================================
--- stable/11/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h	Mon Nov 21 09:23:42 2016	(r308913)
+++ stable/11/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h	Mon Nov 21 10:13:09 2016	(r308914)
@@ -891,6 +891,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;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611211013.uALAD98b090023>