Move zfs_cmd_t copyin/copyout to platform code

FreeBSD needs to cope with multiple version of the zfs_cmd_t
structure. Allowing the platform code to pre and post
process the cmd structure makes it possible to work with
legacy tooling.

Reviewed-by: Jorgen Lundman <lundman@lundman.net>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Matt Macy <mmacy@FreeBSD.org>
Closes #9624
This commit is contained in:
Matthew Macy 2019-12-02 10:08:27 -08:00 committed by Brian Behlendorf
parent 42a826eed3
commit 5142032106
3 changed files with 25 additions and 22 deletions

View File

@ -84,7 +84,7 @@ void zfs_ioctl_init_os(void);
int zfs_vfs_ref(zfsvfs_t **); int zfs_vfs_ref(zfsvfs_t **);
long zfsdev_ioctl_common(uint_t, unsigned long); long zfsdev_ioctl_common(uint_t, zfs_cmd_t *);
int zfsdev_attach(void); int zfsdev_attach(void);
void zfsdev_detach(void); void zfsdev_detach(void);
int zfs_kmod_init(void); int zfs_kmod_init(void);

View File

@ -168,9 +168,25 @@ static long
zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg) zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{ {
uint_t vecnum; uint_t vecnum;
zfs_cmd_t *zc;
int error, rc;
vecnum = cmd - ZFS_IOC_FIRST; vecnum = cmd - ZFS_IOC_FIRST;
return (zfsdev_ioctl_common(vecnum, arg));
zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
if (ddi_copyin((void *)(uintptr_t)arg, zc, sizeof (zfs_cmd_t), 0)) {
error = -SET_ERROR(EFAULT);
goto out;
}
error = -zfsdev_ioctl_common(vecnum, zc);
rc = ddi_copyout(zc, (void *)(uintptr_t)arg, sizeof (zfs_cmd_t), 0);
if (error == 0 && rc != 0)
error = -SET_ERROR(EFAULT);
out:
kmem_free(zc, sizeof (zfs_cmd_t));
return (error);
} }
int int

View File

@ -7215,18 +7215,19 @@ zfsdev_minor_alloc(void)
} }
long long
zfsdev_ioctl_common(uint_t vecnum, unsigned long arg) zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc)
{ {
zfs_cmd_t *zc; int error, cmd, flag = 0;
int error, cmd, rc, flag = 0;
const zfs_ioc_vec_t *vec; const zfs_ioc_vec_t *vec;
char *saved_poolname = NULL; char *saved_poolname = NULL;
nvlist_t *innvl = NULL; nvlist_t *innvl = NULL;
fstrans_cookie_t cookie; fstrans_cookie_t cookie;
cmd = vecnum; cmd = vecnum;
error = 0;
if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); return (SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
vec = &zfs_ioc_vec[vecnum]; vec = &zfs_ioc_vec[vecnum];
/* /*
@ -7234,16 +7235,7 @@ zfsdev_ioctl_common(uint_t vecnum, unsigned long arg)
* a normal or legacy handler are registered. * a normal or legacy handler are registered.
*/ */
if (vec->zvec_func == NULL && vec->zvec_legacy_func == NULL) if (vec->zvec_func == NULL && vec->zvec_legacy_func == NULL)
return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); return (SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
error = ddi_copyin((void *)(uintptr_t)arg, zc, sizeof (zfs_cmd_t),
flag);
if (error != 0) {
error = SET_ERROR(EFAULT);
goto out;
}
zc->zc_iflags = flag & FKIOCTL; zc->zc_iflags = flag & FKIOCTL;
if (zc->zc_nvlist_src_size > MAX_NVLIST_SRC_SIZE) { if (zc->zc_nvlist_src_size > MAX_NVLIST_SRC_SIZE) {
@ -7406,9 +7398,6 @@ zfsdev_ioctl_common(uint_t vecnum, unsigned long arg)
out: out:
nvlist_free(innvl); nvlist_free(innvl);
rc = ddi_copyout(zc, (void *)(uintptr_t)arg, sizeof (zfs_cmd_t), flag);
if (error == 0 && rc != 0)
error = SET_ERROR(EFAULT);
if (error == 0 && vec->zvec_allow_log) { if (error == 0 && vec->zvec_allow_log) {
char *s = tsd_get(zfs_allow_log_key); char *s = tsd_get(zfs_allow_log_key);
if (s != NULL) if (s != NULL)
@ -7418,9 +7407,7 @@ out:
if (saved_poolname != NULL) if (saved_poolname != NULL)
kmem_strfree(saved_poolname); kmem_strfree(saved_poolname);
} }
return (error);
kmem_free(zc, sizeof (zfs_cmd_t));
return (-error);
} }
int int