aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/compat_ioctl.c90
1 files changed, 44 insertions, 46 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 7895bdb0c304..b4873ae84ca1 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -111,6 +111,8 @@
111#include <linux/dvb/frontend.h> 111#include <linux/dvb/frontend.h>
112#include <linux/dvb/video.h> 112#include <linux/dvb/video.h>
113 113
114#include <linux/sort.h>
115
114#ifdef CONFIG_SPARC 116#ifdef CONFIG_SPARC
115#include <asm/fbio.h> 117#include <asm/fbio.h>
116#endif 118#endif
@@ -1048,15 +1050,13 @@ static int compat_ioctl_preallocate(struct file *file, unsigned long arg)
1048} 1050}
1049#endif 1051#endif
1050 1052
1053/*
1054 * simple reversible transform to make our table more evenly
1055 * distributed after sorting.
1056 */
1057#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
1051 1058
1052struct ioctl_trans { 1059#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
1053 unsigned long cmd;
1054 struct ioctl_trans *next;
1055};
1056
1057/* pointer to compatible structure or no argument */
1058#define COMPATIBLE_IOCTL(cmd) { (cmd), },
1059
1060/* ioctl should not be warned about even if it's not implemented. 1060/* ioctl should not be warned about even if it's not implemented.
1061 Valid reasons to use this: 1061 Valid reasons to use this:
1062 - It is implemented with ->compat_ioctl on some device, but programs 1062 - It is implemented with ->compat_ioctl on some device, but programs
@@ -1066,7 +1066,7 @@ struct ioctl_trans {
1066 Most other reasons are not valid. */ 1066 Most other reasons are not valid. */
1067#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd) 1067#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
1068 1068
1069static struct ioctl_trans ioctl_start[] = { 1069static unsigned int ioctl_pointer[] = {
1070/* compatible ioctls first */ 1070/* compatible ioctls first */
1071COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ 1071COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
1072COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ 1072COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
@@ -1710,14 +1710,6 @@ IGNORE_IOCTL(FBIOGCURSOR32)
1710#endif 1710#endif
1711}; 1711};
1712 1712
1713#define IOCTL_HASHSIZE 256
1714static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
1715
1716static inline unsigned long ioctl32_hash(unsigned long cmd)
1717{
1718 return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
1719}
1720
1721/* 1713/*
1722 * Convert common ioctl arguments based on their command number 1714 * Convert common ioctl arguments based on their command number
1723 * 1715 *
@@ -1861,12 +1853,33 @@ static void compat_ioctl_error(struct file *filp, unsigned int fd,
1861 free_page((unsigned long)path); 1853 free_page((unsigned long)path);
1862} 1854}
1863 1855
1856static int compat_ioctl_check_table(unsigned int xcmd)
1857{
1858 int i;
1859 const int max = ARRAY_SIZE(ioctl_pointer) - 1;
1860
1861 BUILD_BUG_ON(max >= (1 << 16));
1862
1863 /* guess initial offset into table, assuming a
1864 normalized distribution */
1865 i = ((xcmd >> 16) * max) >> 16;
1866
1867 /* do linear search up first, until greater or equal */
1868 while (ioctl_pointer[i] < xcmd && i < max)
1869 i++;
1870
1871 /* then do linear search down */
1872 while (ioctl_pointer[i] > xcmd && i > 0)
1873 i--;
1874
1875 return ioctl_pointer[i] == xcmd;
1876}
1877
1864asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, 1878asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
1865 unsigned long arg) 1879 unsigned long arg)
1866{ 1880{
1867 struct file *filp; 1881 struct file *filp;
1868 int error = -EBADF; 1882 int error = -EBADF;
1869 struct ioctl_trans *t;
1870 int fput_needed; 1883 int fput_needed;
1871 1884
1872 filp = fget_light(fd, &fput_needed); 1885 filp = fget_light(fd, &fput_needed);
@@ -1923,10 +1936,8 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
1923 break; 1936 break;
1924 } 1937 }
1925 1938
1926 for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { 1939 if (compat_ioctl_check_table(XFORM(cmd)))
1927 if (t->cmd == cmd) 1940 goto found_handler;
1928 goto found_handler;
1929 }
1930 1941
1931 error = do_ioctl_trans(fd, cmd, arg, filp); 1942 error = do_ioctl_trans(fd, cmd, arg, filp);
1932 if (error == -ENOIOCTLCMD) { 1943 if (error == -ENOIOCTLCMD) {
@@ -1949,35 +1960,22 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
1949 return error; 1960 return error;
1950} 1961}
1951 1962
1952static void ioctl32_insert_translation(struct ioctl_trans *trans) 1963static int __init init_sys32_ioctl_cmp(const void *p, const void *q)
1953{ 1964{
1954 unsigned long hash; 1965 unsigned int a, b;
1955 struct ioctl_trans *t; 1966 a = *(unsigned int *)p;
1956 1967 b = *(unsigned int *)q;
1957 hash = ioctl32_hash (trans->cmd); 1968 if (a > b)
1958 if (!ioctl32_hash_table[hash]) 1969 return 1;
1959 ioctl32_hash_table[hash] = trans; 1970 if (a < b)
1960 else { 1971 return -1;
1961 t = ioctl32_hash_table[hash]; 1972 return 0;
1962 while (t->next)
1963 t = t->next;
1964 trans->next = NULL;
1965 t->next = trans;
1966 }
1967} 1973}
1968 1974
1969static int __init init_sys32_ioctl(void) 1975static int __init init_sys32_ioctl(void)
1970{ 1976{
1971 int i; 1977 sort(ioctl_pointer, ARRAY_SIZE(ioctl_pointer), sizeof(*ioctl_pointer),
1972 1978 init_sys32_ioctl_cmp, NULL);
1973 for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
1974 if (ioctl_start[i].next) {
1975 printk("ioctl translation %d bad\n",i);
1976 return -1;
1977 }
1978
1979 ioctl32_insert_translation(&ioctl_start[i]);
1980 }
1981 return 0; 1979 return 0;
1982} 1980}
1983__initcall(init_sys32_ioctl); 1981__initcall(init_sys32_ioctl);