From: Arnd Bergmann <arnd@arndb.de>
To: linux-kernel@vger.kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>
Subject: [RFC 3/4] compat_ioctl: simplify lookup table
Date: Sun, 15 Nov 2009 16:04:09 +0000 [thread overview]
Message-ID: <1258301050-26900-4-git-send-email-arnd@arndb.de> (raw)
In-Reply-To: <1258301050-26900-1-git-send-email-arnd@arndb.de>
The compat_ioctl table now only contains entries for
COMPATIBLE_IOCTL, so we only need to know if a number
is listed in it or now.
As an optimization, we hash the table entries with a
reversible transformation to get a more uniform distribution
over it, sort the table at startup and then guess the
position in the table when an ioctl number gets called
to do a linear search from there.
With the current set of ioctl numbers and the chosen
transformation function, we need an average of four
steps to find if a number is in the set, all of the
accesses within one or two cache lines.
This at least as good as the previous hash table
approach but saves 8.5 kb of kernel memory.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
fs/compat_ioctl.c | 87 +++++++++++++++++++++++++----------------------------
1 files changed, 41 insertions(+), 46 deletions(-)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index d8039c3..61ce31f 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -111,6 +111,8 @@
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
+#include <linux/sort.h>
+
#ifdef CONFIG_SPARC
#include <asm/fbio.h>
#endif
@@ -1048,15 +1050,13 @@ static int compat_ioctl_preallocate(struct file *file, unsigned long arg)
}
#endif
+/*
+ * simple reversible transform to make our table more evenly
+ * distributed after sorting.
+ */
+#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
-struct ioctl_trans {
- unsigned long cmd;
- struct ioctl_trans *next;
-};
-
-/* pointer to compatible structure or no argument */
-#define COMPATIBLE_IOCTL(cmd) { (cmd), },
-
+#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
/* ioctl should not be warned about even if it's not implemented.
Valid reasons to use this:
- It is implemented with ->compat_ioctl on some device, but programs
@@ -1066,7 +1066,7 @@ struct ioctl_trans {
Most other reasons are not valid. */
#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
-static struct ioctl_trans ioctl_start[] = {
+static unsigned int ioctl_pointer[] = {
/* compatible ioctls first */
COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
@@ -1710,14 +1710,6 @@ IGNORE_IOCTL(FBIOGCURSOR32)
#endif
};
-#define IOCTL_HASHSIZE 256
-static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
-
-static inline unsigned long ioctl32_hash(unsigned long cmd)
-{
- return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
-}
-
/*
* Convert common ioctl arguments based on their command number
*
@@ -1861,12 +1853,33 @@ static void compat_ioctl_error(struct file *filp, unsigned int fd,
free_page((unsigned long)path);
}
+static int compat_ioctl_check_table(unsigned int xcmd)
+{
+ int i;
+ const int max = ARRAY_SIZE(ioctl_pointer) - 1;
+
+ BUILD_BUG_ON(max >= (1 << 16));
+
+ /* guess initial offset into table, assuming a
+ normalized distribution */
+ i = ((xcmd >> 16) * max) >> 16;
+
+ /* do linear search up first, until greater or equal */
+ while (ioctl_pointer[i] < xcmd && i < max)
+ i++;
+
+ /* then do linear search down */
+ while (ioctl_pointer[i] > xcmd && i > 0)
+ i--;
+
+ return ioctl_pointer[i] == xcmd;
+}
+
asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
unsigned long arg)
{
struct file *filp;
int error = -EBADF;
- struct ioctl_trans *t;
int fput_needed;
filp = fget_light(fd, &fput_needed);
@@ -1923,10 +1936,8 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
break;
}
- for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
- if (t->cmd == cmd)
- goto found_handler;
- }
+ if (compat_ioctl_check_table(XFORM(cmd)))
+ goto found_handler;
error = do_ioctl_trans(fd, cmd, arg, filp);
if (error == -ENOIOCTLCMD) {
@@ -1949,35 +1960,19 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
return error;
}
-static void ioctl32_insert_translation(struct ioctl_trans *trans)
+static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
{
- unsigned long hash;
- struct ioctl_trans *t;
-
- hash = ioctl32_hash (trans->cmd);
- if (!ioctl32_hash_table[hash])
- ioctl32_hash_table[hash] = trans;
- else {
- t = ioctl32_hash_table[hash];
- while (t->next)
- t = t->next;
- trans->next = NULL;
- t->next = trans;
- }
+ unsigned int a, b;
+ a = *(unsigned int *)p;
+ b = *(unsigned int *)q;
+
+ return a - b;
}
static int __init init_sys32_ioctl(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
- if (ioctl_start[i].next) {
- printk("ioctl translation %d bad\n",i);
- return -1;
- }
-
- ioctl32_insert_translation(&ioctl_start[i]);
- }
+ sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
+ init_sys32_ioctl_cmp, NULL);
return 0;
}
__initcall(init_sys32_ioctl);
--
1.6.3.3
next prev parent reply other threads:[~2009-11-15 16:04 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-11-15 16:04 [RFC 0/4] compat-ioctl.c diet Arnd Bergmann
2009-11-15 16:04 ` [RFC 1/4] compat_ioctl: inline all conversion handlers Arnd Bergmann
2009-11-15 16:04 ` [RFC 2/4] compat_ioctl: simplify calling of handlers Arnd Bergmann
2009-11-15 16:04 ` Arnd Bergmann [this message]
2009-11-15 16:04 ` [RFC 4/4] compat_ioctl: pass compat pointer directly to handlers Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1258301050-26900-4-git-send-email-arnd@arndb.de \
--to=arnd@arndb.de \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®