[RFC PATCH 1/2] Shrink compat_ioctl.c

Matt Mackall
2008-09-29T23:29:51Z

I'm throwing this out untested as I don't have a mixed 64/32 system
handy at the moment.

compat_ioctl: shrink structures

Initially, compat_ioctl.c has a ~18k table of translated ioctls.
Each table entry is 24 bytes but we can shrink this to 16:

- use short table indexes rather than a pointer for .next values
- use unsigned ints for cmd numbers (they're 32-bit ioctls, after all)

In addition, there's a 2k hash table that we can do away with simply
by hashifying the main table in place at init time.

This saves about 6k data and 2k BSS.

diff -r f6d1daaf90b2 -r b055e64aea17 fs/compat_ioctl.c
--- a/fs/compat_ioctl.c Mon Sep 29 17:28:28 2008 -0500
+++ b/fs/compat_ioctl.c Mon Sep 29 17:28:41 2008 -0500
@@ -1825,21 +1825,21 @@
unsigned long, struct file *);

struct ioctl_trans {
- unsigned long cmd;
ioctl_trans_handler_t handler;
- struct ioctl_trans *next;
+ unsigned int cmd;
+ unsigned short next;
};

#define HANDLE_IOCTL(cmd,handler) \
- { (cmd), (ioctl_trans_handler_t)(handler) },
+ { (ioctl_trans_handler_t)(handler), (cmd)},

/* pointer to compatible structure or no argument */
#define COMPATIBLE_IOCTL(cmd) \
- { (cmd), do_ioctl32_pointer },
+ { do_ioctl32_pointer, (cmd) },

/* argument is an unsigned long integer, not a pointer */
#define ULONG_IOCTL(cmd) \
- { (cmd), (ioctl_trans_handler_t)sys_ioctl },
+ { (ioctl_trans_handler_t)sys_ioctl, (cmd) },

/* ioctl should not be warned about even if it's not implemented.
Valid reasons to use this:
@@ -1850,7 +1850,7 @@
Most other reasons are not valid. */
#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)

-static struct ioctl_trans ioctl_start[] = {
+static struct ioctl_trans ioctl_table[] = {
/* 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 */
@@ -2728,10 +2728,9 @@
#endif
};

-#define IOCTL_HASHSIZE 256
-static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
+#define IOCTL_HASHSIZE 256 /* must be less than table size */

-static inline unsigned long ioctl32_hash(unsigned long cmd)
+static inline unsigned int ioctl32_hash(unsigned int cmd)
{
return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
}
@@ -2770,7 +2769,7 @@
{
struct file *filp;
int error = -EBADF;
- struct ioctl_trans *t;
+ int t;
int fput_needed;

filp = fget_light(fd, &fput_needed);
@@ -2815,8 +2814,8 @@
break;
}

- for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
- if (t->cmd == cmd)
+ for (t = ioctl32_hash(cmd); t >= 0; t = ioctl_table[t].next) {
+ if (ioctl_table[t].cmd == cmd)
goto found_handler;
}

@@ -2837,9 +2836,9 @@
goto out_fput;

found_handler:
- if (t->handler) {
+ if (ioctl_table[t].handler) {
lock_kernel();
- error = t->handler(fd, cmd, arg, filp);
+ error = ioctl_table[t].handler(fd, cmd, arg, filp);
unlock_kernel();
goto out_fput;
}
@@ -2852,34 +2851,25 @@
return error;
}

-static void ioctl32_insert_translation(struct ioctl_trans *trans)
-{
- 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;
- }
-}
-
static int __init init_sys32_ioctl(void)
{
int i;
+ unsigned long hash;
+ struct ioctl_trans t;

- for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
- if (ioctl_start[i].next) {
- printk("ioctl translation %d bad\n",i);
- return -1;
- }
+ /* hash-order table in-place */
+ for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
+ hash = ioctl32_hash(ioctl_table[i].cmd);
+ t = ioctl_table[hash];
+ ioctl_table[hash] = ioctl_table[i];
+ ioctl_table[i] = t;
+ }

- ioctl32_insert_translation(&ioctl_start[i]);
+ /* link entries outside of hash area */
+ for (i = IOCTL_HASHSIZE; i < ARRAY_SIZE(ioctl_table); i++) {
+ hash = ioctl32_hash(ioctl_table[i].cmd);
+ ioctl_table[i].next = ioctl_table[hash].next;
+ ioctl_table[hash].next = i;
}
return 0;
}