summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_generic.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2014-11-28 19:21:46 +0000
committerhselasky <hselasky@FreeBSD.org>2014-11-28 19:21:46 +0000
commit4c0230ed4dfaa9db76e4fd237df6207f43395e75 (patch)
treeffbba41b7930fcb7af8d196d7e4588d75054e3b6 /sys/kern/sys_generic.c
parentd424575bb703021b51b2d0471522de7f7a7680b5 (diff)
downloadFreeBSD-src-4c0230ed4dfaa9db76e4fd237df6207f43395e75.zip
FreeBSD-src-4c0230ed4dfaa9db76e4fd237df6207f43395e75.tar.gz
MFC r274017, r274088 and r275205:
Provide an on-stack temporary buffer for small IOCTL requests. Avoiding a memory allocation per IOCTL request can give a significant speedup for applications which heavily rely on IOCTLs.
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r--sys/kern/sys_generic.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 0e26642..2358172 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -75,6 +75,20 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
+/*
+ * The following macro defines how many bytes will be allocated from
+ * the stack instead of memory allocated when passing the IOCTL data
+ * structures from userspace and to the kernel. Some IOCTLs having
+ * small data structures are used very frequently and this small
+ * buffer on the stack gives a significant speedup improvement for
+ * those requests. The value of this define should be greater or equal
+ * to 64 bytes and should also be power of two. The data structure is
+ * currently hard-aligned to a 8-byte boundary on the stack. This
+ * should currently be sufficient for all supported platforms.
+ */
+#define SYS_IOCTL_SMALL_SIZE 128 /* bytes */
+#define SYS_IOCTL_SMALL_ALIGN 8 /* bytes */
+
int iosize_max_clamp = 1;
SYSCTL_INT(_debug, OID_AUTO, iosize_max_clamp, CTLFLAG_RW,
&iosize_max_clamp, 0, "Clamp max i/o size to INT_MAX");
@@ -646,6 +660,7 @@ struct ioctl_args {
int
sys_ioctl(struct thread *td, struct ioctl_args *uap)
{
+ u_char smalldata[SYS_IOCTL_SMALL_SIZE] __aligned(SYS_IOCTL_SMALL_ALIGN);
u_long com;
int arg, error;
u_int size;
@@ -680,17 +695,18 @@ sys_ioctl(struct thread *td, struct ioctl_args *uap)
arg = (intptr_t)uap->data;
data = (void *)&arg;
size = 0;
- } else
- data = malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
+ } else {
+ if (size > SYS_IOCTL_SMALL_SIZE)
+ data = malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
+ else
+ data = smalldata;
+ }
} 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);
- }
+ if (error != 0)
+ goto out;
} else if (com & IOC_OUT) {
/*
* Zero the buffer so the user always
@@ -704,7 +720,8 @@ sys_ioctl(struct thread *td, struct ioctl_args *uap)
if (error == 0 && (com & IOC_OUT))
error = copyout(data, uap->data, (u_int)size);
- if (size > 0)
+out:
+ if (size > SYS_IOCTL_SMALL_SIZE)
free(data, M_IOCTLOPS);
return (error);
}
OpenPOWER on IntegriCloud