From owner-freebsd-current@FreeBSD.ORG Sat Apr 23 01:27:20 2011 Return-Path: Delivered-To: current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B222C106566B for ; Sat, 23 Apr 2011 01:27:20 +0000 (UTC) (envelope-from julian@freebsd.org) Received: from vps1.elischer.org (vps1.elischer.org [204.109.63.16]) by mx1.freebsd.org (Postfix) with ESMTP id 463D68FC0C for ; Sat, 23 Apr 2011 01:27:20 +0000 (UTC) Received: from julian-mac.elischer.org (home-nat.elischer.org [67.100.89.137]) (authenticated bits=0) by vps1.elischer.org (8.14.4/8.14.4) with ESMTP id p3N1RHFR054743 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO) for ; Fri, 22 Apr 2011 18:27:19 -0700 (PDT) (envelope-from julian@freebsd.org) Message-ID: <4DB22B26.3040603@freebsd.org> Date: Fri, 22 Apr 2011 18:28:06 -0700 From: Julian Elischer User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.2.15) Gecko/20110303 Thunderbird/3.1.9 MIME-Version: 1.0 To: FreeBSD Current Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Subject: bsd/linux ioctl. X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Apr 2011 01:27:20 -0000 So at work (fusion-io) we have a driver that runs on lots of OS, including FreeBSD (hint: ask your fio sales rep, it's not on the website!). But as usual the BSD way of doing the copy in and out of user space caused lots of grief. Then suddenly I heard it was solved and I thought nothing more of it.. The following comment comes from the FreeBSD 'wrapper' in the driver, talking about the ioctl code.. /* Define dir as void in FreeBSD to prevent */ /* kernel from copying ioctl arguments in and */ /* out automatically. The driver expects to */ /* deal with copying itself. We also need to */ /* specify zero as a argument size to force */ /* generic IOCL code in kernel pointer to give */ /* us the raw userland pointer unchanged. */ So I never actually read this code before so my first reaction was "hmm that's neat, a cool workaround for people who want linux or SysV compat ioctl behavior" So my first question is "is this hack commonly known?" and secondly "should we clean it up and put it in an ioctl(9) man page?" We should probably have such a page. Do we have a driver porter's handbook? a quick look failed to find any mention of this in any documentation. Looking at ioctl we can see how this works: Also see that because we force the size to be 0 or sizeof(int), the driver has to know the size and can not do a size based version check as is sometimes done. It seems a pity to force the size and direction information to be lost. is it really necessary? It seems to me that we could still allow current behaviour but allow this information through by testing for IOC_VOID in a few more places and switching some of the tests around a bit.. from ioctl() size = IOCPARM_LEN(com); if ((size > IOCPARM_MAX) || ((com & (IOC_VOID | IOC_IN | IOC_OUT)) == 0) || #if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) ((com & IOC_OUT) && size == 0) || #else ((com & (IOC_IN | IOC_OUT)) && size == 0) || #endif ((com & IOC_VOID) && size > 0 && size != sizeof(int))) return (ENOTTY); if (size > 0) { if (com & IOC_VOID) { /* Integer argument. */ arg = (intptr_t)uap->data; data = (void *)&arg; size = 0; } else data = malloc((u_long)size, M_IOCTLOPS, M_WAITOK); } else data = (void *)&uap->data; if (com & IOC_IN) { error = copyin(uap->data, data, (u_int)size); if (error) { if (size > 0) free(data, M_IOCTLOPS); return (error); } } else if (com & IOC_OUT) { /* * Zero the buffer so the user always * gets back something deterministic. */ bzero(data, size); } [...]