From owner-svn-src-head@FreeBSD.ORG Tue Apr 9 22:27:46 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 0C89E6B3; Tue, 9 Apr 2013 22:27:46 +0000 (UTC) (envelope-from mm@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id E2F70247; Tue, 9 Apr 2013 22:27:45 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r39MRjIp071171; Tue, 9 Apr 2013 22:27:45 GMT (envelope-from mm@svn.freebsd.org) Received: (from mm@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r39MRiN1071164; Tue, 9 Apr 2013 22:27:44 GMT (envelope-from mm@svn.freebsd.org) Message-Id: <201304092227.r39MRiN1071164@svn.freebsd.org> From: Martin Matuska Date: Tue, 9 Apr 2013 22:27:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r249319 - 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-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Apr 2013 22:27:46 -0000 Author: mm Date: Tue Apr 9 22:27:44 2013 New Revision: 249319 URL: http://svnweb.freebsd.org/changeset/base/249319 Log: ZFS expects a copyout of zfs_cmd_t on an ioctl error. Our sys_ioctl() doesn't copyout in this case. To solve this issue a new struct zfs_iocparm_t is introduced consisting of: - zfs_ioctl_version (future backwards compatibility purposes) - user space pointer to zfs_cmd_t (copyin and copyout) - size of zfs_cmd_t (verification purposes) The copyin and copyout of zfs_cmd_t is now done the illumos (vendor) way what makes porting of new changes easier and ensures correct behavior if returning an error. MFC after: 10 days 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/common/zfs/zfs_ioctl_compat.h 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 Apr 9 21:02:20 2013 (r249318) +++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c Tue Apr 9 22:27:44 2013 (r249319) @@ -72,7 +72,9 @@ 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_DEADMAN) + 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; /* Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c Tue Apr 9 21:02:20 2013 (r249318) +++ head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c Tue Apr 9 22:27:44 2013 (r249319) @@ -577,12 +577,18 @@ zcmd_ioctl_compat(int fd, int request, z int nc, ret; void *zc_c; unsigned long ncmd; + zfs_iocparm_t zp; switch (cflag) { case ZFS_CMD_COMPAT_NONE: + ncmd = _IOWR('Z', request, struct zfs_iocparm); + zp.zfs_cmd = (uint64_t)zc; + zp.zfs_cmd_size = sizeof(zfs_cmd_t); + zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT; + return (ioctl(fd, ncmd, &zp)); + case ZFS_CMD_COMPAT_LZC: ncmd = _IOWR('Z', request, struct zfs_cmd); - ret = ioctl(fd, ncmd, zc); - return (ret); + return (ioctl(fd, ncmd, zc)); case ZFS_CMD_COMPAT_DEADMAN: zc_c = malloc(sizeof(zfs_cmd_deadman_t)); ncmd = _IOWR('Z', request, struct zfs_cmd_deadman); @@ -677,7 +683,7 @@ zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nv char *poolname, *snapname; int err; - if (cflag == ZFS_CMD_COMPAT_NONE) + if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) goto out; switch (vec) { @@ -828,7 +834,7 @@ zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, n { nvlist_t *tmpnvl; - if (cflag == ZFS_CMD_COMPAT_NONE) + if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) return (outnvl); switch (vec) { Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h ============================================================================== --- head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h Tue Apr 9 21:02:20 2013 (r249318) +++ head/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h Tue Apr 9 22:27:44 2013 (r249319) @@ -49,19 +49,27 @@ extern "C" { #define ZFS_IOCVER_NONE 0 #define ZFS_IOCVER_DEADMAN 1 #define ZFS_IOCVER_LZC 2 -#define ZFS_IOCVER_CURRENT ZFS_IOCVER_LZC +#define ZFS_IOCVER_ZCMD 3 +#define ZFS_IOCVER_CURRENT ZFS_IOCVER_ZCMD /* compatibility conversion flag */ #define ZFS_CMD_COMPAT_NONE 0 #define ZFS_CMD_COMPAT_V15 1 #define ZFS_CMD_COMPAT_V28 2 #define ZFS_CMD_COMPAT_DEADMAN 3 +#define ZFS_CMD_COMPAT_LZC 4 #define ZFS_IOC_COMPAT_PASS 254 #define ZFS_IOC_COMPAT_FAIL 255 #define ZFS_IOCREQ(ioreq) ((ioreq) & 0xff) +typedef struct zfs_iocparm { + uint32_t zfs_ioctl_version; + uint64_t zfs_cmd; + uint64_t zfs_cmd_size; +} zfs_iocparm_t; + typedef struct zinject_record_v15 { uint64_t zi_objset; uint64_t zi_object; 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 Apr 9 21:02:20 2013 (r249318) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Tue Apr 9 22:27:44 2013 (r249319) @@ -5713,11 +5713,13 @@ zfsdev_ioctl(struct cdev *dev, u_long zc { zfs_cmd_t *zc; uint_t vecnum; -#ifdef illumos int error, rc, len; +#ifdef illumos minor_t minor = getminor(dev); #else - int error, len, cflag, cmd, oldvecnum; + zfs_iocparm_t *zc_iocparm; + int cflag, cmd, oldvecnum; + boolean_t newioc, compat; cred_t *cr = td->td_ucred; #endif const zfs_ioc_vec_t *vec; @@ -5725,6 +5727,9 @@ zfsdev_ioctl(struct cdev *dev, u_long zc nvlist_t *innvl = NULL; cflag = ZFS_CMD_COMPAT_NONE; + compat = B_FALSE; + newioc = B_TRUE; + len = IOCPARM_LEN(zcmd); cmd = zcmd & 0xff; @@ -5732,19 +5737,26 @@ zfsdev_ioctl(struct cdev *dev, u_long zc * Check if we are talking to supported older binaries * and translate zfs_cmd if necessary */ - if (len != sizeof(zfs_cmd_t)) - if (len == sizeof(zfs_cmd_deadman_t)) { + if (len != sizeof(zfs_iocparm_t)) { + newioc = B_FALSE; + if (len == sizeof(zfs_cmd_t)) { + cflag = ZFS_CMD_COMPAT_LZC; + vecnum = cmd; + } else if (len == sizeof(zfs_cmd_deadman_t)) { cflag = ZFS_CMD_COMPAT_DEADMAN; + compat = B_TRUE; vecnum = cmd; } else if (len == sizeof(zfs_cmd_v28_t)) { cflag = ZFS_CMD_COMPAT_V28; + compat = B_TRUE; vecnum = cmd; } else if (len == sizeof(zfs_cmd_v15_t)) { cflag = ZFS_CMD_COMPAT_V15; + compat = B_TRUE; vecnum = zfs_ioctl_v15_to_v28[cmd]; } else return (EINVAL); - else + } else vecnum = cmd; #ifdef illumos @@ -5752,7 +5764,7 @@ zfsdev_ioctl(struct cdev *dev, u_long zc ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); #endif - if (cflag != ZFS_CMD_COMPAT_NONE) { + if (compat) { if (vecnum == ZFS_IOC_COMPAT_PASS) return (0); else if (vecnum == ZFS_IOC_COMPAT_FAIL) @@ -5777,13 +5789,33 @@ zfsdev_ioctl(struct cdev *dev, u_long zc error = SET_ERROR(EFAULT); goto out; } -#else - error = 0; -#endif - - if (cflag != ZFS_CMD_COMPAT_NONE) { +#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; + } + + 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 *)zc_iocparm->zfs_cmd, zc, + sizeof(zfs_cmd_t), flag); + if (error != 0) { + error = SET_ERROR(EFAULT); + goto out; + } + } + + if (compat) { zfs_cmd_compat_get(zc, arg, cflag); oldvecnum = vecnum; error = zfs_ioctl_compat_pre(zc, &vecnum, cflag); @@ -5791,8 +5823,8 @@ zfsdev_ioctl(struct cdev *dev, u_long zc goto out; if (oldvecnum != vecnum) vec = &zfs_ioc_vec[vecnum]; - } else - zc = (void *)arg; + } +#endif /* !illumos */ zc->zc_iflags = flag & FKIOCTL; if (zc->zc_nvlist_src_size != 0) { @@ -5803,7 +5835,7 @@ zfsdev_ioctl(struct cdev *dev, u_long zc } /* rewrite innvl for backwards compatibility */ - if (cflag != ZFS_CMD_COMPAT_NONE) + if (compat) innvl = zfs_ioctl_compat_innvl(zc, innvl, vecnum, cflag); /* @@ -5880,7 +5912,7 @@ zfsdev_ioctl(struct cdev *dev, u_long zc fnvlist_free(lognv); /* rewrite outnvl for backwards compatibility */ - if (cflag != ZFS_CMD_COMPAT_NONE) + if (cflag != ZFS_CMD_COMPAT_NONE && cflag != ZFS_CMD_COMPAT_LZC) outnvl = zfs_ioctl_compat_outnvl(zc, outnvl, vecnum, cflag); @@ -5904,10 +5936,23 @@ 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) { + rc = ddi_copyout(zc, (void *)zc_iocparm->zfs_cmd, + sizeof (zfs_cmd_t), flag); + if (error == 0 && rc != 0) + error = SET_ERROR(EFAULT); + } #endif if (error == 0 && vec->zvec_allow_log) { char *s = tsd_get(zfs_allow_log_key); @@ -5919,14 +5964,14 @@ out: strfree(saved_poolname); } - if (cflag != ZFS_CMD_COMPAT_NONE) { - zfs_ioctl_compat_post(zc, cmd, cflag); - zfs_cmd_compat_put(zc, arg, vecnum, cflag); - kmem_free(zc, sizeof (zfs_cmd_t)); - } - #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); }