Date: Mon, 21 Nov 2016 10:14:36 +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-10@freebsd.org Subject: 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/... Message-ID: <201611211014.uALAEavQ090123@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611211014.uALAEavQ090123>