From owner-svn-src-all@FreeBSD.ORG Tue Jul 1 20:57:40 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 906E134A; Tue, 1 Jul 2014 20:57:40 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2EAB82DA5; Tue, 1 Jul 2014 20:57:40 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s61KvedD094963; Tue, 1 Jul 2014 20:57:40 GMT (envelope-from delphij@svn.freebsd.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s61Kvdbd094960; Tue, 1 Jul 2014 20:57:39 GMT (envelope-from delphij@svn.freebsd.org) Message-Id: <201407012057.s61Kvdbd094960@svn.freebsd.org> From: Xin LI Date: Tue, 1 Jul 2014 20:57:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r268116 - in head: cddl/contrib/opensolaris/lib/libzfs/common sys/cddl/contrib/opensolaris/common/zfs sys/cddl/contrib/opensolaris/uts/common/fs/zfs X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Jul 2014 20:57:40 -0000 Author: delphij Date: Tue Jul 1 20:57:39 2014 New Revision: 268116 URL: http://svnweb.freebsd.org/changeset/base/268116 Log: - Fix handling of "new" style of ioctl in compatiblity mode [1]; - Reorganize code and reduce diff from upstream; - Improve forward compatibility shims for previous kernel; Reported by: sbruno [1] X-MFC-With: r268075 Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c ============================================================================== --- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c Tue Jul 1 20:47:16 2014 (r268115) +++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c Tue Jul 1 20:57:39 2014 (r268116) @@ -72,16 +72,23 @@ zcmd_ioctl(int fd, int request, zfs_cmd_ if (zfs_ioctl_version == ZFS_IOCVER_UNDEF) zfs_ioctl_version = get_zfs_ioctl_version(); - if (zfs_ioctl_version == ZFS_IOCVER_LZC) - cflag = ZFS_CMD_COMPAT_LZC; - else if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN) - cflag = ZFS_CMD_COMPAT_DEADMAN; - - /* - * If vfs.zfs.version.ioctl is not defined, assume we have v28 - * compatible binaries and use vfs.zfs.version.spa to test for v15 - */ - if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) { + if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) { + switch (zfs_ioctl_version) { + case ZFS_IOCVER_ZCMD: + cflag = ZFS_CMD_COMPAT_ZCMD; + break; + case ZFS_IOCVER_LZC: + cflag = ZFS_CMD_COMPAT_LZC; + break; + case ZFS_IOCVER_DEADMAN: + cflag = ZFS_CMD_COMPAT_DEADMAN; + break; + } + } else { + /* + * If vfs.zfs.version.ioctl is not defined, assume we have v28 + * compatible binaries and use vfs.zfs.version.spa to test for v15 + */ cflag = ZFS_CMD_COMPAT_V28; if (zfs_spa_version < 0) Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c Tue Jul 1 20:47:16 2014 (r268115) +++ head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c Tue Jul 1 20:57:39 2014 (r268116) @@ -697,6 +697,12 @@ zcmd_ioctl_compat(int fd, int request, z zp.zfs_cmd_size = sizeof(zfs_cmd_t); zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT; return (ioctl(fd, ncmd, &zp)); + case ZFS_CMD_COMPAT_ZCMD: + ncmd = _IOWR('Z', request, struct zfs_iocparm); + zp.zfs_cmd = (uint64_t)zc; + zp.zfs_cmd_size = sizeof(zfs_cmd_zcmd_t); + zp.zfs_ioctl_version = ZFS_IOCVER_ZCMD; + return (ioctl(fd, ncmd, &zp)); case ZFS_CMD_COMPAT_LZC: ncmd = _IOWR('Z', request, struct zfs_cmd); return (ioctl(fd, ncmd, zc)); @@ -794,7 +800,8 @@ zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nv char *poolname, *snapname; int err; - if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) + if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC || + cflag == ZFS_CMD_COMPAT_ZCMD) goto out; switch (vec) { @@ -945,7 +952,8 @@ zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, n { nvlist_t *tmpnvl; - if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) + if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC || + cflag == ZFS_CMD_COMPAT_ZCMD) return (outnvl); switch (vec) { Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Tue Jul 1 20:47:16 2014 (r268115) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Tue Jul 1 20:57:39 2014 (r268116) @@ -24,6 +24,7 @@ * Copyright (c) 2011-2012 Pawel Jakub Dawidek . * All rights reserved. * Copyright 2013 Martin Matuska . All rights reserved. + * Copyright 2014 Xin Li . All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. @@ -5922,6 +5923,7 @@ zfsdev_ioctl(struct cdev *dev, u_long zc zfs_iocparm_t *zc_iocparm; int cflag, cmd, oldvecnum; boolean_t newioc, compat; + void *compat_zc = NULL; cred_t *cr = td->td_ucred; #endif const zfs_ioc_vec_t *vec; @@ -5930,10 +5932,10 @@ zfsdev_ioctl(struct cdev *dev, u_long zc cflag = ZFS_CMD_COMPAT_NONE; compat = B_FALSE; - newioc = B_TRUE; + newioc = B_TRUE; /* "new" style (zfs_iocparm_t) ioctl */ len = IOCPARM_LEN(zcmd); - cmd = zcmd & 0xff; + vecnum = cmd = zcmd & 0xff; /* * Check if we are talking to supported older binaries @@ -5941,96 +5943,112 @@ zfsdev_ioctl(struct cdev *dev, u_long zc */ if (len != sizeof(zfs_iocparm_t)) { newioc = B_FALSE; - if (len == sizeof(zfs_cmd_t)) { + compat = B_TRUE; + + vecnum = cmd; + + switch (len) { + case sizeof(zfs_cmd_zcmd_t): cflag = ZFS_CMD_COMPAT_LZC; - vecnum = cmd; - } else if (len == sizeof(zfs_cmd_deadman_t)) { + break; + case sizeof(zfs_cmd_deadman_t): cflag = ZFS_CMD_COMPAT_DEADMAN; - compat = B_TRUE; - vecnum = cmd; - } else if (len == sizeof(zfs_cmd_v28_t)) { + break; + case sizeof(zfs_cmd_v28_t): cflag = ZFS_CMD_COMPAT_V28; - compat = B_TRUE; - vecnum = cmd; - } else if (len == sizeof(zfs_cmd_v15_t)) { + break; + case sizeof(zfs_cmd_v15_t): cflag = ZFS_CMD_COMPAT_V15; - compat = B_TRUE; vecnum = zfs_ioctl_v15_to_v28[cmd]; - } else + + /* + * Return without further handling + * if the command is blacklisted. + */ + if (vecnum == ZFS_IOC_COMPAT_PASS) + return (0); + else if (vecnum == ZFS_IOC_COMPAT_FAIL) + return (ENOTSUP); + break; + default: return (EINVAL); - } else - vecnum = cmd; + } + } #ifdef illumos vecnum = cmd - ZFS_IOC_FIRST; ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); #endif - if (compat) { - if (vecnum == ZFS_IOC_COMPAT_PASS) - return (0); - else if (vecnum == ZFS_IOC_COMPAT_FAIL) - return (ENOTSUP); - } - - /* - * Check if we have sufficient kernel memory allocated - * for the zfs_cmd_t request. Bail out if not so we - * will not access undefined memory region. - */ if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) return (SET_ERROR(EINVAL)); vec = &zfs_ioc_vec[vecnum]; -#ifdef illumos zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP); - bzero(zc, sizeof(zfs_cmd_t)); +#ifdef illumos error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag); if (error != 0) { error = SET_ERROR(EFAULT); goto out; } #else /* !illumos */ - /* - * We don't alloc/free zc only if talking to library ioctl version 2 - */ - if (cflag != ZFS_CMD_COMPAT_LZC) { - zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP); - bzero(zc, sizeof(zfs_cmd_t)); - } else { - zc = (void *)arg; - error = 0; - } + bzero(zc, sizeof(zfs_cmd_t)); if (newioc) { zc_iocparm = (void *)arg; - if (zc_iocparm->zfs_cmd_size != sizeof(zfs_cmd_t)) { - error = SET_ERROR(EFAULT); - goto out; - } - error = ddi_copyin((void *)(uintptr_t)zc_iocparm->zfs_cmd, zc, - sizeof(zfs_cmd_t), flag); - if (error != 0) { - error = SET_ERROR(EFAULT); + + switch (zc_iocparm->zfs_ioctl_version) { + case ZFS_IOCVER_CURRENT: + if (zc_iocparm->zfs_cmd_size != sizeof(zfs_cmd_t)) { + error = SET_ERROR(EINVAL); + goto out; + } + break; + case ZFS_IOCVER_ZCMD: + if (zc_iocparm->zfs_cmd_size > sizeof(zfs_cmd_t) || + zc_iocparm->zfs_cmd_size < sizeof(zfs_cmd_zcmd_t)) { + error = SET_ERROR(EFAULT); + goto out; + } + compat = B_TRUE; + cflag = ZFS_CMD_COMPAT_ZCMD; + break; + default: + error = SET_ERROR(EINVAL); goto out; + /* NOTREACHED */ } - if (zc_iocparm->zfs_ioctl_version != ZFS_IOCVER_CURRENT) { - compat = B_TRUE; - switch (zc_iocparm->zfs_ioctl_version) { - case ZFS_IOCVER_ZCMD: - cflag = ZFS_CMD_COMPAT_ZCMD; - break; - default: - error = SET_ERROR(EINVAL); + if (compat) { + ASSERT(sizeof(zfs_cmd_t) >= zc_iocparm->zfs_cmd_size); + compat_zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP); + bzero(compat_zc, sizeof(zfs_cmd_t)); + + error = ddi_copyin((void *)(uintptr_t)zc_iocparm->zfs_cmd, + compat_zc, zc_iocparm->zfs_cmd_size, flag); + if (error != 0) { + error = SET_ERROR(EFAULT); + goto out; + } + } else { + error = ddi_copyin((void *)(uintptr_t)zc_iocparm->zfs_cmd, + zc, zc_iocparm->zfs_cmd_size, flag); + if (error != 0) { + error = SET_ERROR(EFAULT); goto out; } } } if (compat) { - zfs_cmd_compat_get(zc, arg, cflag); + if (newioc) { + ASSERT(compat_zc != NULL); + zfs_cmd_compat_get(zc, compat_zc, cflag); + } else { + ASSERT(compat_zc == NULL); + zfs_cmd_compat_get(zc, arg, cflag); + } oldvecnum = vecnum; error = zfs_ioctl_compat_pre(zc, &vecnum, cflag); if (error != 0) @@ -6126,7 +6144,7 @@ zfsdev_ioctl(struct cdev *dev, u_long zc fnvlist_free(lognv); /* rewrite outnvl for backwards compatibility */ - if (cflag != ZFS_CMD_COMPAT_NONE && cflag != ZFS_CMD_COMPAT_LZC) + if (compat) outnvl = zfs_ioctl_compat_outnvl(zc, outnvl, vecnum, cflag); @@ -6151,17 +6169,30 @@ zfsdev_ioctl(struct cdev *dev, u_long zc out: nvlist_free(innvl); - if (compat) { - zfs_ioctl_compat_post(zc, cmd, cflag); - zfs_cmd_compat_put(zc, arg, vecnum, cflag); - } - #ifdef illumos rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag); if (error == 0 && rc != 0) error = SET_ERROR(EFAULT); #else - if (newioc) { + if (compat) { + zfs_ioctl_compat_post(zc, cmd, cflag); + if (newioc) { + ASSERT(compat_zc != NULL); + ASSERT(sizeof(zfs_cmd_t) >= zc_iocparm->zfs_cmd_size); + + zfs_cmd_compat_put(zc, compat_zc, vecnum, cflag); + rc = ddi_copyout(compat_zc, + (void *)(uintptr_t)zc_iocparm->zfs_cmd, + zc_iocparm->zfs_cmd_size, flag); + if (error == 0 && rc != 0) + error = SET_ERROR(EFAULT); + kmem_free(compat_zc, sizeof (zfs_cmd_t)); + } else { + zfs_cmd_compat_put(zc, arg, vecnum, cflag); + } + } else { + ASSERT(newioc); + rc = ddi_copyout(zc, (void *)(uintptr_t)zc_iocparm->zfs_cmd, sizeof (zfs_cmd_t), flag); if (error == 0 && rc != 0) @@ -6178,15 +6209,7 @@ out: strfree(saved_poolname); } -#ifdef illumos kmem_free(zc, sizeof (zfs_cmd_t)); -#else - /* - * We don't alloc/free zc only if talking to library ioctl version 2 - */ - if (cflag != ZFS_CMD_COMPAT_LZC) - kmem_free(zc, sizeof (zfs_cmd_t)); -#endif return (error); }