linux-syscall-asmlinkage-20040621
[openafs.git] / src / afs / LINUX / osi_module.c
index adc0599..f864a0c 100644 (file)
@@ -27,6 +27,7 @@ RCSID
 #endif
 
 #include <linux/module.h>
+#include <linux/proc_fs.h>
 #include <linux/slab.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #include <linux/init.h>
@@ -36,22 +37,15 @@ RCSID
 #include <linux/syscall.h>
 #endif
 
-#if defined(AFS_LINUX26_ENV)
-#include <linux/vermagic.h>
-#include <linux/compiler.h>
-
-MODULE_INFO(vermagic, VERMAGIC_STRING);
-
-#endif
-
 #ifdef AFS_SPARC64_LINUX24_ENV
 #define __NR_setgroups32      82       /* This number is not exported for some bizarre reason. */
 #endif
 
+#if !defined(AFS_LINUX24_ENV)
 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv,
                                     struct timezone * tz);
+#endif
 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
-
 #ifdef EXPORTED_SYS_CALL_TABLE
 #ifdef AFS_SPARC64_LINUX20_ENV
 extern unsigned int sys_call_table[];  /* changed to uint because SPARC64 has syscaltable of 32bit items */
@@ -130,6 +124,56 @@ afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
 }
 #endif /* AFS_SPARC64_LINUX20_ENV */
 
+static int afs_ioctl(struct inode *, struct file *, unsigned int,
+                    unsigned long);
+
+static struct file_operations afs_syscall_fops = {
+    .ioctl = afs_ioctl,
+};
+
+static struct proc_dir_entry *openafs_procfs;
+
+static int
+afsproc_init()
+{
+    struct proc_dir_entry *entry1;
+
+    openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
+    entry1 = create_proc_entry(PROC_SYSCALL_NAME, 0666, openafs_procfs);
+
+    entry1->proc_fops = &afs_syscall_fops;
+
+    entry1->owner = THIS_MODULE;
+
+    return 0;
+}
+
+static void
+afsproc_exit()
+{
+    remove_proc_entry(PROC_SYSCALL_NAME, openafs_procfs);
+    remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
+}
+
+extern asmlinkage long
+afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
+
+static int
+afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+         unsigned long arg)
+{
+
+    struct afsprocdata sysargs;
+
+    if (cmd != VIOC_SYSCALL) return -EINVAL;
+
+    if (copy_from_user(&sysargs, (void *)arg, sizeof(struct afsprocdata)))
+       return -EFAULT;
+
+    return afs_syscall(sysargs.syscall, sysargs.param1,
+                      sysargs.param2, sysargs.param3, sysargs.param4);
+}
+
 #ifdef AFS_IA64_LINUX20_ENV
 
 asmlinkage long
@@ -188,9 +232,8 @@ init_module(void)
 {
 #if defined(AFS_IA64_LINUX20_ENV)
     unsigned long kernel_gp = 0;
-    static struct fptr sys_settimeofday, sys_setgroups;
-#endif
-    extern int afs_syscall();
+    static struct fptr sys_setgroups;
+#endif /* defined(AFS_IA64_LINUX20_ENV) */
     extern long afs_xsetgroups();
 #if defined(__NR_setgroups32)
     extern int afs_xsetgroups32();
@@ -199,11 +242,11 @@ init_module(void)
     extern int afs32_xsetgroups();
 #if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV))
     extern int afs32_xsetgroups32();
-#endif
+#endif /* defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV) */
 #if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV))
     extern int afs32_xsetgroups32();
-#endif
-#endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV */
+#endif /* (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV) */
+#endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV || AFS_PPC64_LINUX20_ENV */
 
 #if !defined(EXPORTED_SYS_CALL_TABLE) || (defined(AFS_AMD64_LINUX20_ENV) && !defined(EXPORTED_IA32_SYS_CALL_TABLE))
     unsigned long *ptr;
@@ -234,8 +277,9 @@ init_module(void)
        printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
        return -EIO;
     }
-#endif
-#endif
+#endif /* AFS_S390_LINUX22_ENV */
+#endif /* !defined(AFS_LINUX24_ENV) */
+
 #ifndef EXPORTED_SYS_CALL_TABLE
     sys_call_table = 0;
 
@@ -255,8 +299,7 @@ init_module(void)
     if (ret && sym_start) {
        sys_call_table = sym_start;
     }
-#else
-#ifdef EXPORTED_KALLSYMS_ADDRESS
+#elif defined(EXPORTED_KALLSYMS_ADDRESS)
     ret =
        kallsyms_address_to_symbol((unsigned long)&init_mm, &mod_name,
                                   &mod_start, &mod_end, &sec_name,
@@ -264,20 +307,16 @@ init_module(void)
                                   &sym_start, &sym_end);
     ptr = (unsigned long *)sec_start;
     datalen = (sec_end - sec_start) / sizeof(unsigned long);
-#else
-#if defined(AFS_IA64_LINUX20_ENV)
+#elif defined(AFS_IA64_LINUX20_ENV)
     ptr = (unsigned long *)(&sys_close - 0x180000);
     datalen = 0x180000 / sizeof(ptr);
-#else
-#if defined(AFS_AMD64_LINUX20_ENV)
+#elif defined(AFS_AMD64_LINUX20_ENV)
     ptr = (unsigned long *)&init_mm;
     datalen = 0x360000 / sizeof(ptr);
 #else
     ptr = (unsigned long *)&init_mm;
     datalen = 16384;
 #endif
-#endif
-#endif
     for (offset = 0; offset < datalen; ptr++, offset++) {
 #if defined(AFS_IA64_LINUX20_ENV)
        unsigned long close_ip =
@@ -291,29 +330,27 @@ init_module(void)
            sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]);
            break;
        }
-#else
-#if defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE)
+#elif defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE)
        if (ptr[0] == (unsigned long)&sys_close
            && ptr[__NR_wait4 - __NR_close] == (unsigned long)&sys_wait4) {
            sys_call_table = ptr - __NR_close;
            break;
        }
-#else
-#if defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE)
+#elif defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE)
        if (ptr[0] == (unsigned long)&sys_close
            && ptr[__NR_chdir - __NR_close] == (unsigned long)&sys_chdir) {
            sys_call_table = ptr - __NR_close;
            break;
        }
-#else
+#elif defined(EXPORTED_SYS_OPEN)
        if (ptr[0] == (unsigned long)&sys_exit
            && ptr[__NR_open - __NR_exit] == (unsigned long)&sys_open) {
            sys_call_table = ptr - __NR_exit;
            break;
        }
-#endif
-#endif
-#endif
+#else /* EXPORTED_SYS_OPEN */
+       break;
+#endif /* EXPORTED_KALLSYMS_ADDRESS */
     }
 #ifdef EXPORTED_KALLSYMS_ADDRESS
     ret =
@@ -323,131 +360,122 @@ init_module(void)
                                   &sym_start, &sym_end);
     if (ret && strcmp(sym_name, "sys_call_table"))
        sys_call_table = 0;
-#endif
-#endif
+#endif /* EXPORTED_KALLSYMS_ADDRESS */
     if (!sys_call_table) {
        printf("Failed to find address of sys_call_table\n");
-       return -EIO;
-    }
-    printf("Found sys_call_table at %x\n", sys_call_table);
-# ifdef AFS_SPARC64_LINUX20_ENV
-    error cant support this yet.
-#endif
-#endif                         /* EXPORTED_SYS_CALL_TABLE */
+    } else {
+       printf("Found sys_call_table at %x\n", sys_call_table);
+#ifdef AFS_SPARC64_LINUX20_ENV
+       error cant support this yet.;
+#endif /* AFS_SPARC64_LINUX20_ENV */
+#endif /* EXPORTED_SYS_CALL_TABLE */
+
 #ifdef AFS_AMD64_LINUX20_ENV
 #ifndef EXPORTED_IA32_SYS_CALL_TABLE
-      ia32_sys_call_table = 0;
+       ia32_sys_call_table = 0;
 #ifdef EXPORTED_KALLSYMS_SYMBOL
-    ret = 1;
-    token = 0;
-    while (ret) {
-       sym_start = 0;
-       ret =
-           kallsyms_symbol_to_address("ia32_sys_call_table", &token,
-                                      &mod_name, &mod_start, &mod_end,
-                                      &sec_name, &sec_start, &sec_end,
-                                      &sym_name, &sym_start, &sym_end);
-       if (ret && !strcmp(mod_name, "kernel"))
-           break;
-    }
-    if (ret && sym_start) {
-       ia32_sys_call_table = sym_start;
-    }
+       ret = 1;
+       token = 0;
+       while (ret) {
+           sym_start = 0;
+           ret = kallsyms_symbol_to_address("ia32_sys_call_table", &token,
+                                            &mod_name, &mod_start, &mod_end,
+                                            &sec_name, &sec_start, &sec_end,
+                                            &sym_name, &sym_start, &sym_end);
+           if (ret && !strcmp(mod_name, "kernel"))
+               break;
+       }
+       if (ret && sym_start) {
+           ia32_sys_call_table = sym_start;
+       }
 #else /* EXPORTED_KALLSYMS_SYMBOL */
 #ifdef EXPORTED_KALLSYMS_ADDRESS
-    ret =
-       kallsyms_address_to_symbol((unsigned long)&interruptible_sleep_on,
-                                  &mod_name, &mod_start, &mod_end, &sec_name,
-                                  &sec_start, &sec_end, &sym_name,
-                                  &sym_start, &sym_end);
-    ptr = (unsigned long *)sec_start;
-    datalen = (sec_end - sec_start) / sizeof(unsigned long);
+       ret = kallsyms_address_to_symbol((unsigned long)
+                                        &interruptible_sleep_on,
+                                        &mod_name, &mod_start, &mod_end,
+                                        &sec_name, &sec_start, &sec_end,
+                                        &sym_name, &sym_start, &sym_end);
+       ptr = (unsigned long *)sec_start;
+       datalen = (sec_end - sec_start) / sizeof(unsigned long);
 #else /* EXPORTED_KALLSYMS_ADDRESS */
 #if defined(AFS_AMD64_LINUX20_ENV)
-    ptr = (unsigned long *)&interruptible_sleep_on;
-    datalen = 0x180000 / sizeof(ptr);
+       ptr = (unsigned long *)&interruptible_sleep_on;
+       datalen = 0x180000 / sizeof(ptr);
 #else /* AFS_AMD64_LINUX20_ENV */
-    ptr = (unsigned long *)&interruptible_sleep_on;
-    datalen = 16384;
+       ptr = (unsigned long *)&interruptible_sleep_on;
+       datalen = 16384;
 #endif /* AFS_AMD64_LINUX20_ENV */
 #endif /* EXPORTED_KALLSYMS_ADDRESS */
-    for (offset = 0; offset < datalen; ptr++, offset++) {
-       if (ptr[0] == (unsigned long)&sys_exit
-           && ptr[__NR_ia32_open - __NR_ia32_exit] ==
-           (unsigned long)&sys_open) {
-           ia32_sys_call_table = ptr - __NR_ia32_exit;
-           break;
+       for (offset = 0; offset < datalen; ptr++, offset++) {
+           if (ptr[0] == (unsigned long)&sys_exit
+               && ptr[__NR_ia32_open - __NR_ia32_exit] ==
+               (unsigned long)&sys_open) {
+                   ia32_sys_call_table = ptr - __NR_ia32_exit;
+                   break;
+           }
        }
-    }
 #ifdef EXPORTED_KALLSYMS_ADDRESS
-    ret =
-       kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table,
-                                  &mod_name, &mod_start, &mod_end, &sec_name,
-                                  &sec_start, &sec_end, &sym_name,
-                                  &sym_start, &sym_end);
-    if (ret && strcmp(sym_name, "ia32_sys_call_table"))
-       ia32_sys_call_table = 0;
+       ret = kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table,
+                                        &mod_name, &mod_start, &mod_end,
+                                        &sec_name, &sec_start, &sec_end,
+                                        &sym_name, &sym_start, &sym_end);
+       if (ret && strcmp(sym_name, "ia32_sys_call_table"))
+           ia32_sys_call_table = 0;
 #endif /* EXPORTED_KALLSYMS_ADDRESS */
 #endif /* EXPORTED_KALLSYMS_SYMBOL */
-    if (!ia32_sys_call_table) {
-       printf("Warning: Failed to find address of ia32_sys_call_table\n");
-    } else {
-       printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
-    }
+       if (!ia32_sys_call_table) {
+           printf("Warning: Failed to find address of ia32_sys_call_table\n");
+       } else {
+           printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
+       }
 #else
-    printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
+       printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
 #endif /* IA32_SYS_CALL_TABLE */
 #endif
 
-    /* Initialize pointers to kernel syscalls. */
-#if defined(AFS_IA64_LINUX20_ENV)
-    kernel_gp = ((struct fptr *)printk)->gp;
-
-    sys_settimeofdayp = (void *)&sys_settimeofday;
-
-    ((struct fptr *)sys_settimeofdayp)->ip =
-       SYSCALL2POINTER sys_call_table[__NR_settimeofday - 1024];
-    ((struct fptr *)sys_settimeofdayp)->gp = kernel_gp;
-
-#else /* !AFS_IA64_LINUX20_ENV */
-    sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
+       /* Initialize pointers to kernel syscalls. */
+#if !defined(AFS_LINUX24_ENV)
+       sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
 #endif /* AFS_IA64_LINUX20_ENV */
 
-    /* setup AFS entry point. */
-    if (
+       /* setup AFS entry point. */
+       if (
 #if defined(AFS_IA64_LINUX20_ENV)
-          SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
+               SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
 #else
-          SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
+               SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
 #endif
-          == afs_syscall) {
-       printf("AFS syscall entry point already in use!\n");
-       return -EBUSY;
-    }
+               == afs_syscall) {
+           printf("AFS syscall entry point already in use!\n");
+           return -EBUSY;
+       }
 #if defined(AFS_IA64_LINUX20_ENV)
-    afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
-    sys_call_table[__NR_afs_syscall - 1024] =
-       POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
+       afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
+       sys_call_table[__NR_afs_syscall - 1024] =
+               POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
 #else /* AFS_IA64_LINUX20_ENV */
-    afs_ni_syscall = sys_call_table[__NR_afs_syscall];
-    sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
-# ifdef AFS_SPARC64_LINUX20_ENV
-    afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
-    sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
-# endif
+       afs_ni_syscall = sys_call_table[__NR_afs_syscall];
+       sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
+#ifdef AFS_SPARC64_LINUX20_ENV
+       afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
+       sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
+#endif
 #endif /* AFS_IA64_LINUX20_ENV */
 #ifdef AFS_AMD64_LINUX20_ENV
-    if (ia32_sys_call_table) {
-       ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall];
-       ia32_sys_call_table[__NR_ia32_afs_syscall] =
-           POINTER2SYSCALL afs_syscall;
-    }
+       if (ia32_sys_call_table) {
+           ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall];
+           ia32_sys_call_table[__NR_ia32_afs_syscall] =
+                   POINTER2SYSCALL afs_syscall;
+       }
 #endif /* AFS_S390_LINUX22_ENV */
-
+#ifndef EXPORTED_SYS_CALL_TABLE
+    }
+#endif /* EXPORTED_SYS_CALL_TABLE */
     osi_Init();
     register_filesystem(&afs_fs_type);
 
     /* Intercept setgroups calls */
+    if (sys_call_table) {
 #if defined(AFS_IA64_LINUX20_ENV)
     sys_setgroupsp = (void *)&sys_setgroups;
 
@@ -468,8 +496,10 @@ init_module(void)
     sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
 #ifdef AFS_SPARC64_LINUX20_ENV
-    sys32_setgroups32p = SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
-    sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL afs32_xsetgroups32;
+       sys32_setgroups32p =
+           SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
+       sys_call_table32[__NR_setgroups32] =
+           POINTER2SYSCALL afs32_xsetgroups32;
 #endif /* AFS_SPARC64_LINUX20_ENV */
 #endif /* __NR_setgroups32 */
 #ifdef AFS_AMD64_LINUX20_ENV
@@ -493,8 +523,10 @@ init_module(void)
     sys_setgroupsp = set_afs_xsetgroups_syscall(afs_xsetgroups);
     sys32_setgroupsp = set_afs_xsetgroups_syscall32(afs32_xsetgroups);
 #endif
+    }
 
     osi_sysctl_init();
+    afsproc_init();
 
     return 0;
 }
@@ -510,7 +542,7 @@ cleanup_module(void)
     struct task_struct *t;
 
     osi_sysctl_clean();
-
+    if (sys_call_table) {
 #if defined(AFS_IA64_LINUX20_ENV)
     sys_call_table[__NR_setgroups - 1024] =
        POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
@@ -525,7 +557,8 @@ cleanup_module(void)
 # if defined(__NR_setgroups32)
     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
 # ifdef AFS_SPARC64_LINUX20_ENV
-    sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL sys32_setgroups32p;
+       sys_call_table32[__NR_setgroups32] =
+           POINTER2SYSCALL sys32_setgroups32p;
 # endif
 # endif
 #endif /* AFS_IA64_LINUX20_ENV */
@@ -541,6 +574,7 @@ cleanup_module(void)
 #endif
     }
 #endif
+    }
 #ifdef AFS_PPC64_LINUX20_ENV
     set_afs_syscall(afs_ni_syscall);
     set_afs_xsetgroups_syscall(sys_setgroupsp);
@@ -551,6 +585,7 @@ cleanup_module(void)
     osi_linux_free_inode_pages();      /* Invalidate all pages using AFS inodes. */
     osi_linux_free_afs_memory();
 
+    afsproc_exit();
     return;
 }