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;
 
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to