Author: mjg
Date: Sat Jul  4 06:25:41 2020
New Revision: 362922
URL: https://svnweb.freebsd.org/changeset/base/362922

Log:
  linux: fix ioctl performance for termios
  
  TCGETS et al are frequently issued by Linux binaries while the previous code
  avoidably ping-pongs a global sx lock and serializes on Giant.
  
  Note that even with the fix the common case will serialize on a per-tty lock.

Modified:
  head/sys/compat/linux/linux_ioctl.c

Modified: head/sys/compat/linux/linux_ioctl.c
==============================================================================
--- head/sys/compat/linux/linux_ioctl.c Sat Jul  4 06:22:05 2020        
(r362921)
+++ head/sys/compat/linux/linux_ioctl.c Sat Jul  4 06:25:41 2020        
(r362922)
@@ -132,8 +132,6 @@ static struct linux_ioctl_handler socket_handler =
 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
 static struct linux_ioctl_handler sound_handler =
 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
-static struct linux_ioctl_handler termio_handler =
-{ linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
 static struct linux_ioctl_handler private_handler =
 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
 static struct linux_ioctl_handler drm_handler =
@@ -156,7 +154,6 @@ DATA_SET(linux_ioctl_handler_set, hdio_handler);
 DATA_SET(linux_ioctl_handler_set, disk_handler);
 DATA_SET(linux_ioctl_handler_set, socket_handler);
 DATA_SET(linux_ioctl_handler_set, sound_handler);
-DATA_SET(linux_ioctl_handler_set, termio_handler);
 DATA_SET(linux_ioctl_handler_set, private_handler);
 DATA_SET(linux_ioctl_handler_set, drm_handler);
 DATA_SET(linux_ioctl_handler_set, sg_handler);
@@ -165,6 +162,14 @@ DATA_SET(linux_ioctl_handler_set, video2_handler);
 DATA_SET(linux_ioctl_handler_set, fbsd_usb);
 DATA_SET(linux_ioctl_handler_set, evdev_handler);
 
+/*
+ * Keep sorted by low.
+ */
+static struct linux_ioctl_handler linux_ioctls[] = {
+       { .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN,
+           .high = LINUX_IOCTL_TERMIO_MAX },
+};
+
 #ifdef __i386__
 static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
     TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
@@ -3558,8 +3563,8 @@ linux_ioctl_evdev(struct thread *td, struct linux_ioct
  * main ioctl syscall function
  */
 
-int
-linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
+static int
+linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args)
 {
        struct file *fp;
        struct linux_ioctl_handler_element *he;
@@ -3618,6 +3623,35 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args
        }
 
        return (EINVAL);
+}
+
+int
+linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
+{
+       struct linux_ioctl_handler *handler;
+       int error, cmd, i;
+
+       cmd = args->cmd & 0xffff;
+
+       /*
+        * array of ioctls known at compilation time. Elides a lot of work on
+        * each call compared to the list variant. Everything frequently used
+        * should be moved here.
+        *
+        * Arguably the magic creating the list should create an array instead.
+        *
+        * For now just a linear scan.
+        */
+       for (i = 0; i < nitems(linux_ioctls); i++) {
+               handler = &linux_ioctls[i];
+               if (cmd >= handler->low && cmd <= handler->high) {
+                       error = (*handler->func)(td, args);
+                       if (error != ENOIOCTL) {
+                               return (error);
+                       }
+               }
+       }
+       return (linux_ioctl_fallback(td, args));
 }
 
 int
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to