osi-probe-syscall-20050129
authorJeffrey Hutzelman <jhutz@cmu.edu>
Sat, 29 Jan 2005 05:41:59 +0000 (05:41 +0000)
committerDerrick Brashear <shadow@dementia.org>
Sat, 29 Jan 2005 05:41:59 +0000 (05:41 +0000)
FIXES 17405

add osi_probe

src/afs/LINUX/osi_module.c
src/afs/LINUX/osi_probe.c [new file with mode: 0644]
src/afs/LINUX/osi_prototypes.h
src/afs/LINUX/osi_syscall.c [new file with mode: 0644]
src/libafs/Makefile.common.in
src/libafs/MakefileProto.LINUX.in

index b7e5f2a..f021681 100644 (file)
@@ -33,38 +33,6 @@ RCSID
 #include <linux/init.h>
 #include <linux/sched.h>
 #endif
-#if !defined(EXPORTED_SYS_CALL_TABLE) && defined(HAVE_KERNEL_LINUX_SYSCALL_H)
-#include <linux/syscall.h>
-#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
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
-extern unsigned int sys_call_table[];  /* changed to uint because SPARC64 and S390X have syscalltable of 32bit items */
-#else
-extern void *sys_call_table[]; /* safer for other linuces */
-#endif
-#else /* EXPORTED_SYS_CALL_TABLE */
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
-static unsigned int *sys_call_table;   /* changed to uint because SPARC64 and S390X have syscalltable of 32bit items */
-#else
-static void **sys_call_table;  /* safer for other linuces */
-#endif
-#endif
-
-#if defined(AFS_S390X_LINUX24_ENV)
-#define _S(x) ((x)<<1)
-#else
-#define _S(x) x
-#endif
 
 extern struct file_system_type afs_fs_type;
 
@@ -82,56 +50,6 @@ int afs_global_owner = 0;
 unsigned long afs_linux_page_offset = 0;       /* contains the PAGE_OFFSET value */
 #endif
 
-/* Since sys_ni_syscall is not exported, I need to cache it in order to restore
- * it.
- */
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
-static unsigned int afs_ni_syscall = 0;
-#else
-static void *afs_ni_syscall = 0;
-#endif
-
-#ifdef AFS_AMD64_LINUX20_ENV
-#ifdef EXPORTED_IA32_SYS_CALL_TABLE
-extern void *ia32_sys_call_table[];
-#else
-static void **ia32_sys_call_table;
-#endif
-
-static void *ia32_ni_syscall = 0;
-asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
-#if defined(__NR_ia32_setgroups32)
-asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
-#endif /* __NR_ia32_setgroups32 */
-#endif /* AFS_AMD64_LINUX20_ENV */
-
-#ifdef AFS_PPC64_LINUX20_ENV
-asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
-#endif /* AFS_AMD64_LINUX20_ENV */
-
-#ifdef AFS_SPARC64_LINUX20_ENV
-static unsigned int afs_ni_syscall32 = 0;
-asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
-                                   __kernel_gid_t32 * grouplist);
-#if defined(__NR_setgroups32)
-asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
-                                     __kernel_gid_t32 * grouplist);
-#endif /* __NR_setgroups32 */
-#ifdef EXPORTED_SYS_CALL_TABLE
-extern unsigned int sys_call_table32[];
-#else /* EXPORTED_SYS_CALL_TABLE */
-static unsigned int *sys_call_table32;
-#endif /* EXPORTED_SYS_CALL_TABLE */
-
-asmlinkage int
-afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
-             long parm5)
-{
-    __asm__ __volatile__("srl %o4, 0, %o4\n\t" "mov %o7, %i7\n\t"
-                        "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t"
-                        "ret\n\t" "nop");
-}
-#endif /* AFS_SPARC64_LINUX20_ENV */
 
 static int afs_ioctl(struct inode *, struct file *, unsigned int,
                     unsigned long);
@@ -569,48 +487,6 @@ afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                       sysargs.param2, sysargs.param3, sysargs.param4);
 }
 
-#ifdef AFS_IA64_LINUX20_ENV
-
-asmlinkage long
-afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
-{
-    __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"       /* save rp */
-                        "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t"   /* save gp */
-                        ";;\n" ".L1:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_syscall-.L1,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t"    /* restore gp */
-                        "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
-                        "data8 @fptr(afs_syscall)\n\t" ".skip 8");
-}
-
-asmlinkage long
-afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
-{
-    __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"       /* save rp */
-                        "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t"   /* save gp */
-                        ";;\n" ".L2:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t"       /* restore gp */
-                        "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
-                        "data8 @fptr(afs_xsetgroups)\n\t" ".skip 8");
-}
-
-struct fptr {
-    void *ip;
-    unsigned long gp;
-};
-
-#endif /* AFS_IA64_LINUX20_ENV */
-
-#ifdef AFS_LINUX24_ENV
-asmlinkage int (*sys_setgroups32p) (int gidsetsize,
-                                   __kernel_gid32_t * grouplist);
-#endif /* AFS_LINUX24_ENV */
-
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
-#define POINTER2SYSCALL (unsigned int)(unsigned long)
-#define SYSCALL2POINTER (void *)(long)
-#else
-#define POINTER2SYSCALL (void *)
-#define SYSCALL2POINTER (void *)
-#endif
-
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 int __init
@@ -620,45 +496,7 @@ int
 init_module(void)
 #endif
 {
-#if defined(AFS_IA64_LINUX20_ENV)
-    unsigned long kernel_gp = 0;
-    static struct fptr sys_setgroups;
-#endif /* defined(AFS_IA64_LINUX20_ENV) */
-    extern long afs_xsetgroups();
-#if defined(__NR_setgroups32)
-    extern int afs_xsetgroups32();
-#endif /* __NR_setgroups32 */
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined (AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
-    extern int afs32_xsetgroups();
-#if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV))
-    extern int afs32_xsetgroups32();
-#endif /* defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV) */
-#if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV))
-    extern int afs32_xsetgroups32();
-#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;
-    unsigned long offset=0;
-    unsigned long datalen=0;
-#if defined(EXPORTED_KALLSYMS_SYMBOL)
-    unsigned long token=0;
-#endif
-#if defined(EXPORTED_KALLSYMS_SYMBOL) || defined(EXPORTED_KALLSYMS_ADDRESS)
-    int ret;
-    char *mod_name;
-    unsigned long mod_start=0;
-    unsigned long mod_end=0;
-    char *sec_name;
-    unsigned long sec_start=0;
-    unsigned long sec_end=0;
-    char *sym_name;
-    unsigned long sym_start=0;
-    unsigned long sym_end=0;
-#endif
-#endif /* EXPORTED_SYS_CALL_TABLE */
-
+    int e;
     RWLOCK_INIT(&afs_xosi, "afs_xosi");
 
 #if !defined(AFS_LINUX24_ENV)
@@ -674,246 +512,11 @@ init_module(void)
 #endif /* AFS_S390_LINUX22_ENV */
 #endif /* !defined(AFS_LINUX24_ENV) */
 
-#ifndef EXPORTED_SYS_CALL_TABLE
-    sys_call_table = 0;
-
-#ifdef EXPORTED_KALLSYMS_SYMBOL
-    ret = 1;
-    token = 0;
-    while (ret) {
-       sym_start = 0;
-       ret =
-           kallsyms_symbol_to_address("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) {
-       sys_call_table = sym_start;
-    }
-#elif defined(EXPORTED_KALLSYMS_ADDRESS)
-    ret =
-       kallsyms_address_to_symbol((unsigned long)&init_mm, &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);
-#elif defined(AFS_IA64_LINUX20_ENV)
-    ptr = (unsigned long *)(&sys_close - 0x180000);
-    datalen = 0x180000 / sizeof(ptr);
-#elif defined(AFS_AMD64_LINUX20_ENV)
-    ptr = (unsigned long *)&init_mm;
-    datalen = 0x360000 / sizeof(ptr);
-#else
-    ptr = (unsigned long *)&init_mm;
-    datalen = 16384;
-#endif
-    for (offset = 0; offset < datalen; ptr++, offset++) {
-#if defined(AFS_IA64_LINUX20_ENV)
-       unsigned long close_ip =
-           (unsigned long)((struct fptr *)&sys_close)->ip;
-       unsigned long chdir_ip =
-           (unsigned long)((struct fptr *)&sys_chdir)->ip;
-       unsigned long write_ip =
-           (unsigned long)((struct fptr *)&sys_write)->ip;
-       if (ptr[0] == close_ip && ptr[__NR_chdir - __NR_close] == chdir_ip
-           && ptr[__NR_write - __NR_close] == write_ip) {
-           sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]);
-           break;
-       }
-#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;
-       }
-#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;
-       }
-#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;
-       }
-#else /* EXPORTED_SYS_OPEN */
-       break;
-#endif /* EXPORTED_KALLSYMS_ADDRESS */
-    }
-#ifdef EXPORTED_KALLSYMS_ADDRESS
-    ret =
-       kallsyms_address_to_symbol((unsigned long)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, "sys_call_table"))
-       sys_call_table = 0;
-#endif /* EXPORTED_KALLSYMS_ADDRESS */
-    if (!sys_call_table) {
-       printf("Failed to find address of sys_call_table\n");
-    } else {
-       printf("Found sys_call_table at %lx\n", (unsigned long)sys_call_table);
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_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;
-#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;
-       }
-#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);
-#else /* EXPORTED_KALLSYMS_ADDRESS */
-#if defined(AFS_AMD64_LINUX20_ENV)
-       ptr = (unsigned long *)&interruptible_sleep_on;
-       datalen = 0x180000 / sizeof(ptr);
-#else /* AFS_AMD64_LINUX20_ENV */
-       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;
-           }
-       }
-#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;
-#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 %lx\n", (unsigned long)ia32_sys_call_table);
-       }
-#else
-       printf("Found ia32_sys_call_table at %lx\n", (unsigned long)ia32_sys_call_table);
-#endif /* IA32_SYS_CALL_TABLE */
-#endif
-
-       /* Initialize pointers to kernel syscalls. */
-#if !defined(AFS_LINUX24_ENV)
-       sys_settimeofdayp = SYSCALL2POINTER sys_call_table[_S(__NR_settimeofday)];
-#endif /* AFS_IA64_LINUX20_ENV */
-
-       /* setup AFS entry point. */
-       if (
-#if defined(AFS_IA64_LINUX20_ENV)
-               SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
-#else
-               SYSCALL2POINTER sys_call_table[_S(__NR_afs_syscall)]
-#endif
-               == 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;
-#else /* AFS_IA64_LINUX20_ENV */
-       afs_ni_syscall = sys_call_table[_S(__NR_afs_syscall)];
-       sys_call_table[_S(__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;
-       }
-#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;
-
-    ((struct fptr *)sys_setgroupsp)->ip =
-       SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
-    ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
-
-    sys_call_table[__NR_setgroups - 1024] =
-       POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
-#else /* AFS_IA64_LINUX20_ENV */
-    sys_setgroupsp = SYSCALL2POINTER sys_call_table[_S(__NR_setgroups)];
-    sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
-#ifdef AFS_SPARC64_LINUX20_ENV
-    sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
-    sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
-#endif /* AFS_SPARC64_LINUX20_ENV */
-#if defined(__NR_setgroups32)
-    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;
-#endif /* AFS_SPARC64_LINUX20_ENV */
-#endif /* __NR_setgroups32 */
-#ifdef AFS_AMD64_LINUX20_ENV
-    if (ia32_sys_call_table) {
-       sys32_setgroupsp =
-           SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups];
-       ia32_sys_call_table[__NR_ia32_setgroups] =
-           POINTER2SYSCALL afs32_xsetgroups;
-#if defined(__NR_ia32_setgroups32)
-       sys32_setgroups32p =
-           SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups32];
-       ia32_sys_call_table[__NR_ia32_setgroups32] =
-           POINTER2SYSCALL afs32_xsetgroups32;
-#endif /* __NR_ia32_setgroups32 */
-    }
-#endif /* AFS_AMD64_LINUX20_ENV */
-#endif /* AFS_IA64_LINUX20_ENV */
-
-    }
 
+    e = osi_syscall_init();
+    if (e) return e;
+    register_filesystem(&afs_fs_type);
     osi_sysctl_init();
     afsproc_init();
 
@@ -929,39 +532,7 @@ cleanup_module(void)
 #endif
 {
     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;
-    sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
-#else /* AFS_IA64_LINUX20_ENV */
-    sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL sys_setgroupsp;
-    sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
-# ifdef AFS_SPARC64_LINUX20_ENV
-    sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
-    sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
-# endif
-# 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;
-# endif
-# endif
-#endif /* AFS_IA64_LINUX20_ENV */
-#ifdef AFS_AMD64_LINUX20_ENV
-    if (ia32_sys_call_table) {
-       ia32_sys_call_table[__NR_ia32_setgroups] =
-           POINTER2SYSCALL sys32_setgroupsp;
-       ia32_sys_call_table[__NR_ia32_afs_syscall] =
-           POINTER2SYSCALL ia32_ni_syscall;
-# if defined(__NR_setgroups32)
-       ia32_sys_call_table[__NR_ia32_setgroups32] =
-           POINTER2SYSCALL sys32_setgroups32p;
-#endif
-    }
-#endif
-    }
+    osi_syscall_clean();
     unregister_filesystem(&afs_fs_type);
 
     osi_linux_free_inode_pages();      /* Invalidate all pages using AFS inodes. */
diff --git a/src/afs/LINUX/osi_probe.c b/src/afs/LINUX/osi_probe.c
new file mode 100644 (file)
index 0000000..fc9c394
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+ * vi:set cin noet sw=4 tw=70:
+ * Copyright 2004, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions of this code borrowed from arla under the following terms:
+ * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Code to find the Linux syscall table */
+
+#ifdef OSI_PROBE_STANDALONE
+#define OSI_PROBE_DEBUG
+#endif
+#ifndef OSI_PROBE_STANDALONE
+#include <afsconfig.h>
+#include "afs/param.h"
+#endif
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#ifndef OSI_PROBE_STANDALONE
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#endif
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+
+#ifdef AFS_AMD64_LINUX20_ENV
+#include <asm/ia32_unistd.h>
+#endif
+
+#ifdef HAVE_KERNEL_LINUX_SYSCALL_H
+#include <linux/syscall.h>
+#endif
+
+/* number of syscalls */
+/* NB: on MIPS we care about the 4xxx range */
+#ifndef NR_syscalls
+#define NR_syscalls 222
+#endif
+
+/* lower bound of valid kernel text pointers */
+//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define ktxt_lower_bound (((unsigned long)&kernel_thread )  & ~0xfffffL)
+//#else
+//#define ktxt_lower_bound (((unsigned long)&empty_zero_page) & ~0xfffffL)
+//#endif
+
+/* On SPARC64 and S390X, sys_call_table contains 32-bit entries
+ * even though pointers are 64 bit quantities.
+ */
+#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
+#define SYSCALLTYPE unsigned int
+#define PROBETYPE int
+#else
+#define SYSCALLTYPE void *
+#define PROBETYPE long
+#endif
+
+
+/* Allow the user to specify sys_call_table addresses */
+static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
+MODULE_PARM(sys_call_table_addr, "1-4l");
+MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
+
+/* If this is set, we are more careful about avoiding duplicate matches */
+static int probe_carefully = 1;
+MODULE_PARM(probe_carefully, "i");
+MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
+
+static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+MODULE_PARM(probe_ignore_syscalls, "1-8i");
+MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
+
+#ifdef OSI_PROBE_DEBUG
+/* 
+ * Debugging flags:
+ * 0x0001 - General debugging
+ * 0x0002 - detail - try
+ * 0x0004 - detail - try_harder
+ * 0x0008 - detail - check_table
+ * 0x0010 - detail - check_harder
+ * 0x0020 - detail - check_harder/zapped
+ * 0x0040 - automatically ignore setgroups and afs_syscall
+ */
+static int probe_debug = 0x41;
+MODULE_PARM(probe_debug, "i");
+MODULE_PARM_DESC(probe_debug, "Debugging level");
+
+static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
+MODULE_PARM(probe_debug_addr, "1-4l");
+MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
+
+static unsigned long probe_debug_range = 0;
+MODULE_PARM(probe_debug_range, "l");
+MODULE_PARM_DESC(probe_debug_range, "Debug range length");
+
+static unsigned long probe_debug_tag = 0;
+MODULE_PARM(probe_debug_tag, "l");
+MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
+#endif
+
+
+/* Weak references are our friends.  They are supported by the in-kernel
+ * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
+ * A weak reference not satisified by the kernel will have value zero.
+ */
+extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
+                                     char **mod_name,
+                                     unsigned long *mod_start,
+                                     unsigned long *mod_end,
+                                     char **sec_name,
+                                     unsigned long *sec_start,
+                                     unsigned long *sec_end,
+                                     char **sym_name,
+                                     unsigned long *sym_start,
+                                     unsigned long *sym_end
+                                    ) __attribute__((weak));
+
+extern int kallsyms_address_to_symbol(unsigned long address,
+                                     char **mod_name,
+                                     unsigned long *mod_start,
+                                     unsigned long *mod_end,
+                                     char **sec_name,
+                                     unsigned long *sec_start,
+                                     unsigned long *sec_end,
+                                     char **sym_name,
+                                     unsigned long *sym_start,
+                                     unsigned long *sym_end
+                                    ) __attribute__((weak));
+
+extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
+extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
+extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
+
+extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
+extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
+extern asmlinkage int  sys_write(unsigned int, const char *, size_t) __attribute__((weak));
+#ifdef AFS_LINUX26_ENV
+extern asmlinkage long sys_wait4(pid_t, int *, int, struct rusage *) __attribute__((weak));
+#else
+extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
+#endif
+extern asmlinkage int  sys_exit (int) __attribute__((weak));
+extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
+extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
+
+
+/* Structures used to control probing.  We put all the details of which
+ * symbols we're interested in, what syscall functions to look for, etc
+ * into tables, so we can then have a single copy of the functions that
+ * actually do the work.
+ */
+typedef struct {
+    char *name;
+    int NR1;
+    void *fn1;
+    int NR2;
+    void *fn2;
+    int NR3;
+    void *fn3;
+} tryctl;
+
+typedef struct {
+    char *symbol;                   /* symbol name */
+    char *desc;                     /* description for messages */
+    int offset;                     /* first syscall number in table */
+
+    void *weak_answer;              /* weak symbol ref */
+    void *parm_answer;              /* module parameter answer */
+    void *debug_answer;             /* module parameter answer */
+    unsigned long given_answer;     /* compiled-in answer, if any */
+
+    tryctl *trylist;                /* array of combinations to try */
+
+    unsigned long try_sect_sym;     /* symbol in section to try scanning */
+    unsigned long try_base;         /* default base address for scan */
+    unsigned long try_base_mask;    /* base address bits to force to zero */
+    unsigned long try_length;       /* default length for scan */
+
+    int n_zapped_syscalls;          /* number of unimplemented system calls */
+    int *zapped_syscalls;           /* list of unimplemented system calls */
+
+    int n_unique_syscalls;          /* number of unique system calls */
+    int *unique_syscalls;           /* list of unimplemented system calls */
+
+    int verifyNR;                   /* syscall number to verify match */
+    void *verify_fn;                /* syscall pointer to verify match */
+
+    int debug_ignore_NR[4];         /* syscalls to ignore for debugging */
+} probectl;
+
+
+
+/********** Probing Configuration: sys_call_table **********/
+
+/* syscall pairs/triplets to probe */
+/* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
+static tryctl main_try[] = {
+#if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
+    { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
+#endif
+    { "scan: close+wait4",       __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1,         0          },
+#if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
+    { "scan: close+chdir",       __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1,         0          },
+#endif
+    { "scan: close+ioctl",       __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1,         0          },
+    { "scan: exit+open",         __NR_exit,  &sys_exit,  __NR_open,  &sys_open,  -1,         0          },
+    { 0 }
+};
+
+/* zapped syscalls for try_harder */
+/* this list is based on the table in 'zapped_syscalls' */
+
+static int main_zapped_syscalls[] = {
+/* 
+ * SPARC-Linux uses syscall number mappings chosen to be compatible
+ * with SunOS.  So, it doesn't have any of the traditional calls or
+ * the new STREAMS ones.  However, there are a number of syscalls
+ * which are SunOS-specific (not implemented on Linux), i386-specific
+ * (not implemented on SPARC-Linux), or implemented only on one of
+ * sparc32 or sparc64.  Of course, there are no __NR macros for most
+ * of these.
+ * 
+ * Note that the calls we list here are implemented by sys_nis_syscall,
+ * not by sys_ni_syscall.  That means we have to exclude all of the
+ * other entries, or we might get a sys_ni_syscall into the list and
+ * the test would no longer work.
+ */
+#if defined(AFS_SPARC64_LINUX20_ENV)
+    /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
+    56, 63, 151, 152, 218,
+#elif defined(AFS_SPARC_LINUX20_ENV)
+    /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
+    52, 151, 152, 164, 218,
+#else /* !AFS_SPARC_LINUX20_ENV */
+
+/* 
+ * These 7 syscalls are present in the syscall table on most "older"
+ * platforms that use the traditional syscall number mappings.  They
+ * are not implemented on any platform.
+ */
+#ifdef __NR_break
+    __NR_break,
+#endif
+#ifdef __NR_stty
+    __NR_stty,
+#endif
+#ifdef __NR_gtty
+    __NR_gtty,
+#endif
+#ifdef __NR_ftime
+    __NR_ftime,
+#endif
+#ifdef __NR_prof
+    __NR_prof,
+#endif
+#ifdef __NR_lock
+    __NR_lock,
+#endif
+#ifdef __NR_mpx
+    __NR_mpx,
+#endif
+/* 
+ * On s390 and arm (but not arm26), the seven traditional unimplemented
+ * system calls are indeed present and unimplemented.  However, the
+ * corresponding __NR macros are not defined, so the tests above fail.
+ * Instead, we just have to know the numbers for these.
+ */
+#ifdef AFS_S390_LINUX20_ENV
+    /* break, stty, gtty, ftime, prof, lock, mpx */
+    17, 31, 32, 35, 44, 53, 56,
+#endif
+
+/* 
+ * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
+ * the traditional numbers, so the list above are not helpful.  They
+ * do have entries for getpmsg/putpmsg, which are always unimplemented.
+ */
+#ifdef __NR_getpmsg
+    __NR_getpmsg,
+#endif
+#ifdef __NR_putpmsg
+    __NR_putpmsg,
+#endif
+
+/* 
+ * The module-loading mechanism changed in Linux 2.6, and insmod's
+ * loss is our gain: three new unimplemented system calls! 
+ */
+#if defined(AFS_LINUX26_ENV)
+#ifdef __NR_
+    __NR_create_module,
+#endif
+#ifdef __NR_query_module
+    __NR_query_module,
+#endif
+#ifdef __NR_get_kernel_syms
+    __NR_get_kernel_syms,
+#endif
+#endif /* AFS_LINUX26_ENV */
+
+/* 
+ * On IA64, the old module-loading calls are indeed present and
+ * unimplemented, but the __NR macros are not defined.  Again,
+ * we simply have to know their numbers.
+ */
+#ifdef AFS_IA64_LINUX26_ENV
+    /* create_module, query_module, get_kernel_sysms */
+    1132, 1136, 1135,
+#endif
+
+/* And the same deal for arm (not arm26), if we ever support that. */
+#if 0
+    /* create_module, query_module, get_kernel_sysms */
+    127, 167, 130,
+#endif
+
+/*
+ * Alpha-Linux uses syscall number mappings chosen to be compatible
+ * with OSF/1.  So, it doesn't have any of the traditional calls or
+ * the new STREAMS ones, but it does have several OSF/1-specific
+ * syscalls which are not implemented on Linux.  These don't exist on
+ * any other platform.
+ */
+#ifdef __NR_osf_syscall
+    __NR_osf_syscall,
+#endif
+#ifdef __NR_osf_profil
+    __NR_osf_profil,
+#endif
+#ifdef __NR_osf_reboot
+    __NR_osf_reboot,
+#endif
+#ifdef __NR_osf_kmodcall
+    __NR_osf_kmodcall,
+#endif
+#ifdef __NR_osf_old_vtrace
+    __NR_osf_old_vtrace,
+#endif
+
+/*
+ * On PPC64, we need a couple more entries to distinguish the two
+ * tables, since the system call numbers are the same and the sets of
+ * unimplemented calls are very similar.
+ * mmap2 and fstat64 are implemented only for 32-bit calls
+ */
+#ifdef AFS_PPC64_LINUX20_ENV
+    __NR_mmap2,
+    __NR_fstat64,
+#endif /* AFS_PPC64_LINUX20_ENV */
+
+/* Similarly for S390X, with lcown16 and fstat64 */
+#ifdef AFS_S390X_LINUX20_ENV
+    /* lchown16, fstat64 */
+    16, 197,
+#endif
+#endif /* !AFS_SPARC_LINUX20_ENV */
+    0
+};
+
+/* unique syscalls for try_harder */
+static int main_unique_syscalls[] = {
+    __NR_exit, __NR_mount, __NR_read, __NR_write,
+    __NR_open, __NR_close, __NR_unlink
+};
+
+/* probe control structure */
+static probectl main_probe = {
+    /* symbol name and description */
+    "sys_call_table",
+    "system call table",
+
+    /* syscall number of first entry in table */
+#ifdef AFS_IA64_LINUX20_ENV
+    1024,
+#else
+    0,
+#endif
+
+    sys_call_table,               /* weak symbol ref */
+    0, 0,                         /* module parameter answers */
+#ifdef AFS_LINUX_sys_call_table
+    AFS_LINUX_sys_call_table,     /* compiled-in answer, if any */
+#else
+    0,
+#endif
+
+    main_try,                     /* array of combinations to try */
+
+    /* symbol in section to try scanning */
+#if defined(AFS_SPARC64_LINUX20_ENV)
+    (unsigned long)&sys_close,
+#elif defined(AFS_AMD64_LINUX20_ENV)
+    /* On this platform, it's in a different section! */
+    (unsigned long)&tasklist_lock,
+#else
+    (unsigned long)&init_mm,
+#endif
+
+    /* default base address for scan */
+    /* base address bits to force to zero */
+    /* default length for scan */
+#if   defined(AFS_SPARC64_LINUX20_ENV)
+    (unsigned long)(&sys_close),
+    0xfffff,
+    0x10000,
+#elif   defined(AFS_IA64_LINUX20_ENV)
+    (unsigned long)(&sys_close - 0x180000),
+    0,
+    (0x180000 / sizeof(unsigned long *)),
+#elif defined(AFS_AMD64_LINUX20_ENV)
+    (unsigned long)(&tasklist_lock - 0x1000),
+    0,
+    16384,
+#else
+    (unsigned long)&init_mm,
+    0,
+    16384,
+#endif
+
+    /* number and list of unimplemented system calls */
+    ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
+    main_zapped_syscalls,
+
+    /* number and list of unique system calls */
+    (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
+    main_unique_syscalls,
+
+    /* syscall number and pointer to verify match */
+    __NR_close, &sys_close,
+
+    /* syscalls to ignore for debugging */
+    {
+#if   defined(AFS_ALPHA_LINUX20_ENV)
+       338,
+#elif defined(AFS_AMD64_LINUX20_ENV)
+       183,
+#elif defined(AFS_IA64_LINUX20_ENV)
+       1141,
+#elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+       227,
+#else
+       137,
+#endif
+       __NR_setgroups,
+#ifdef __NR_setgroups32
+       __NR_setgroups32,
+#else
+       -1,
+#endif
+       -1,
+    }
+};
+
+
+/********** Probing Configuration: amd64 ia32_sys_call_table **********/
+#if defined(AFS_AMD64_LINUX20_ENV)
+
+/* syscall pairs/triplets to probe */
+static tryctl ia32_try[] = {
+    { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        __NR_ia32_write, &sys_write },
+    { "scan: close+chdir",       __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        -1,              0          },
+    { 0 }
+};
+
+/* zapped syscalls for try_harder */
+static int ia32_zapped_syscalls[] = {
+    __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
+    __NR_ia32_prof,  __NR_ia32_lock, __NR_ia32_mpx,
+    0
+};
+
+/* unique syscalls for try_harder */
+static int ia32_unique_syscalls[] = {
+    __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
+    __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
+};
+
+/* probe control structure */
+static probectl ia32_probe = {
+    /* symbol name and description */
+    "ia32_sys_call_table",
+    "32-bit system call table",
+
+    /* syscall number of first entry in table */
+    0,
+
+    ia32_sys_call_table,          /* weak symbol ref */
+    0, 0,                         /* module parameter answers */
+#ifdef AFS_LINUX_ia32_sys_call_table
+    AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
+#else
+    0,
+#endif
+
+    ia32_try,                     /* array of combinations to try */
+
+    /* symbol in section to try scanning */
+    (unsigned long)&init_mm,
+
+    /* default base address for scan */
+    /* base address bits to force to zero */
+    /* default length for scan */
+    (unsigned long)&init_mm,
+    0,
+    (0x180000 / sizeof(unsigned long *)),
+
+    /* number and list of unimplemented system calls */
+    ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
+    ia32_zapped_syscalls,
+
+    /* number and list of unique system calls */
+    (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
+    ia32_unique_syscalls,
+
+    /* syscall number and pointer to verify match */
+    __NR_ia32_close, &sys_close,
+
+    /* syscalls to ignore for debugging */
+    {
+       137,
+       __NR_ia32_setgroups,
+       __NR_ia32_setgroups32,
+       -1,
+    }
+};
+
+static probectl *probe_list[] = {
+    &main_probe, &ia32_probe
+};
+
+
+/********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
+#elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+
+/* 
+ * syscall pairs/triplets to probe
+ * This has to be empty, because anything that would work will
+ * also match the main table, and that's no good.
+ */
+static tryctl sct32_try[] = {
+    { 0 }
+};
+
+/* zapped syscalls for try_harder */
+static int sct32_zapped_syscalls[] = {
+#ifdef AFS_PPC64_LINUX20_ENV
+    /* These should be sufficient */
+    __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
+    __NR_prof, __NR_lock, __NR_mpx,
+#endif
+#ifdef AFS_SPARC64_LINUX20_ENV
+    /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
+    52, 151, 152, 164, 218,
+#endif
+    0
+};
+
+/* unique syscalls for try_harder */
+/* mmap2 and fstat64 are implemented only for 32-bit calls */
+static int sct32_unique_syscalls[] = {
+#ifdef AFS_PPC64_LINUX20_ENV
+    __NR_mmap2, __NR_fstat64,
+#endif
+    __NR_exit, __NR_mount, __NR_read, __NR_write,
+    __NR_open, __NR_close, __NR_unlink
+};
+
+/* probe control structure */
+static probectl sct32_probe = {
+    /* symbol name and description */
+    "sys_call_table32",
+    "32-bit system call table",
+
+    /* syscall number of first entry in table */
+    0,
+
+    sys_call_table32,             /* weak symbol ref */
+    0, 0,                         /* module parameter answers */
+#ifdef AFS_LINUX_sys_call_table32
+    AFS_LINUX_sys_call_table32,   /* compiled-in answer, if any */
+#else
+    0,
+#endif
+
+    sct32_try,                   /* array of combinations to try */
+
+    /* symbol in section to try scanning */
+#if defined(AFS_SPARC64_LINUX20_ENV)
+    (unsigned long)&sys_close,
+#else
+    (unsigned long)&init_mm,
+#endif
+
+    /* default base address for scan */
+    /* base address bits to force to zero */
+    /* default length for scan */
+#if   defined(AFS_SPARC64_LINUX20_ENV)
+    (unsigned long)(&sys_close),
+    0xfffff,
+    0x10000,
+#else
+    (unsigned long)&init_mm,
+    0,
+    16384,
+#endif
+
+    /* number and list of unimplemented system calls */
+    ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
+    sct32_zapped_syscalls,
+
+    /* number and list of unique system calls */
+    (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
+    sct32_unique_syscalls,
+
+    /* syscall number and pointer to verify match */
+    __NR_close, &sys_close,
+
+    /* syscalls to ignore for debugging */
+    {
+#if defined(AFS_SPARC64_LINUX20_ENV)
+       227,
+#else
+       137,
+#endif
+       __NR_setgroups,
+       -1,
+       -1,
+    }
+};
+
+static probectl *probe_list[] = {
+    &main_probe, &sct32_probe
+};
+
+
+/********** Probing Configuration: s390x sys_call_table_emu **********/
+#elif defined(AFS_S390X_LINUX20_ENV)
+
+/* syscall pairs/triplets to probe */
+/* nothing worthwhile is exported, so this is empty */
+static tryctl emu_try[] = {
+    { 0 }
+};
+
+/* zapped syscalls for try_harder */
+static int emu_zapped_syscalls[] = {
+    /* break, stty, gtty, ftime, prof, lock, mpx */
+    17, 31, 32, 35, 44, 53, 56,
+    0
+};
+
+/* unique syscalls for try_harder */
+static int emu_unique_syscalls[] = {
+    /* lchown16, fstat64 */
+    16, 197,
+    __NR_exit, __NR_mount, __NR_read, __NR_write,
+    __NR_open, __NR_close, __NR_unlink
+};
+
+/* probe control structure */
+static probectl emu_probe = {
+    /* symbol name and description */
+    "sys_call_table_emu",
+    "32-bit system call table",
+
+    /* syscall number of first entry in table */
+    0,
+
+    sys_call_table_emu,           /* weak symbol ref */
+    0, 0,                         /* module parameter answers */
+#ifdef AFS_LINUX_sys_call_table_emu
+    AFS_LINUX_sys_call_table_emu, /* compiled-in answer, if any */
+#else
+    0,
+#endif
+
+    emu_try,                      /* array of combinations to try */
+
+    /* symbol in section to try scanning */
+    (unsigned long)&init_mm,
+
+    /* default base address for scan */
+    /* base address bits to force to zero */
+    /* default length for scan */
+    (unsigned long)&init_mm,
+    0,
+    16384,
+
+    /* number and list of unimplemented system calls */
+    ((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
+    emu_zapped_syscalls,
+
+    /* number and list of unique system calls */
+    (sizeof(emu_unique_syscalls)/sizeof(emu_unique_syscalls[0])),
+    emu_unique_syscalls,
+
+    /* syscall number and pointer to verify match */
+    __NR_close, &sys_close,
+
+    /* syscalls to ignore for debugging */
+    {
+       137,
+       __NR_setgroups,
+       -1,
+       -1,
+    }
+};
+
+static probectl *probe_list[] = {
+    &main_probe, &emu_probe
+};
+
+
+/********** End of Probing Configuration **********/
+
+#else /* no per-platform probe control, so use the default list */
+static probectl *probe_list[] = {
+    &main_probe
+};
+#endif
+
+#define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
+#define DEBUG_IN_RANGE(P,x) (!probe_debug_range ||                             \
+  (P->debug_answer &&                                                          \
+   (unsigned long)(x) >= (unsigned long)P->debug_answer &&                     \
+   (unsigned long)(x) <  (unsigned long)P->debug_answer + probe_debug_range))
+
+
+
+static int check_table(probectl *P, PROBETYPE *ptr)
+{
+    PROBETYPE *x;
+    int i, j;
+
+    for (x = ptr, i = 0; i < NR_syscalls; i++, x++) {
+#ifdef OSI_PROBE_DEBUG
+       if (probe_debug & 0x0040) {
+           for (j = 0; j < 4; j++) {
+               if (P->debug_ignore_NR[j] == i) break;
+           }
+           if (j < 4) continue;
+       }
+#endif
+       for (j = 0; j < 8; j++) {
+           if (probe_ignore_syscalls[j] == i) break;
+       }
+       if (j < 8) continue;
+       if (*x <= ktxt_lower_bound) {
+#ifdef OSI_PROBE_DEBUG
+           if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
+               printk("<7>check 0x%lx -> %d [0x%lx]\n",
+                      (unsigned long)ptr, i, (unsigned long)*x);
+#endif
+           return i;
+       }
+    }
+#ifdef OSI_PROBE_DEBUG
+    if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
+       printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
+#endif
+    return -1;
+}
+
+static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
+                unsigned long datalen)
+{
+    char *mod_name, *sec_name, *sym_name;
+    unsigned long mod_start, mod_end;
+    unsigned long sec_start, sec_end;
+    unsigned long sym_start, sym_end;
+    unsigned long offset, ip1, ip2, ip3;
+    int ret;
+
+#ifdef AFS_IA64_LINUX20_ENV
+    ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
+    ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
+    ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
+#else
+    ip1 = (unsigned long)T->fn1;
+    ip2 = (unsigned long)T->fn2;
+    ip3 = (unsigned long)T->fn3;
+#endif
+
+#ifdef OSI_PROBE_DEBUG
+    if (probe_debug & 0x0001)
+       printk("<7>osi_probe: %s                      %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
+              P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
+#endif
+
+    if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
+       return 0;
+
+    for (offset = 0; offset < datalen; offset++, ptr++) {
+       ret = check_table(P, ptr);
+       if (ret >= 0) {
+           /* return value is number of entries to skip */
+           ptr    += ret;
+           offset += ret;
+           continue;
+       }
+
+#ifdef OSI_PROBE_DEBUG
+       if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
+           printk("<7>try 0x%lx\n", (unsigned long)ptr);
+#endif
+       if (ptr[T->NR1 - P->offset] != ip1)                    continue;
+       if (ptr[T->NR2 - P->offset] != ip2)        continue;
+       if (ip3 && ptr[T->NR3 - P->offset] != ip3) continue;
+
+#ifdef OSI_PROBE_DEBUG
+       if (probe_debug & 0x0002)
+           printk("<7>try found 0x%lx\n", (unsigned long)ptr);
+#endif
+       if (kallsyms_address_to_symbol) {
+           ret = kallsyms_address_to_symbol((unsigned long)ptr,
+                                            &mod_name, &mod_start, &mod_end,
+                                            &sec_name, &sec_start, &sec_end,
+                                            &sym_name, &sym_start, &sym_end);
+           if (!ret || strcmp(sym_name, P->symbol)) continue;
+       }
+       /* XXX should we make sure there is only one match? */
+       return (void *)ptr;
+    }
+    return 0;
+}
+
+
+static int check_harder(probectl *P, PROBETYPE *p)
+{
+    unsigned long ip1;
+    int i, s;
+
+    /* Check zapped syscalls */
+    for (i = 1; i < P->n_zapped_syscalls; i++) {
+       if (p[P->zapped_syscalls[i]] != p[P->zapped_syscalls[0]]) {
+#ifdef OSI_PROBE_DEBUG
+           if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
+               printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
+#endif
+           return 0;
+       }
+    }
+
+    /* Check unique syscalls */
+    for (i = 0; i < P->n_unique_syscalls; i++) {
+       for (s = 0; s < NR_syscalls; s++) {
+           if (p[s] == p[P->unique_syscalls[i]] && s != P->unique_syscalls[i]) {
+#ifdef OSI_PROBE_DEBUG
+               if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
+                   printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
+#endif
+               return 0;
+           }
+       }
+    }
+
+#ifdef AFS_IA64_LINUX20_ENV
+    ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
+#else
+    ip1 = (unsigned long)(P->verify_fn);
+#endif
+
+    if (ip1 && p[P->verifyNR - P->offset] != ip1) {
+#ifdef OSI_PROBE_DEBUG
+       if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
+           printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
+#endif
+       return 0;
+    }
+
+#ifdef OSI_PROBE_DEBUG
+    if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
+       printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
+#endif
+    return 1;
+}
+
+static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
+{
+    char *mod_name, *sec_name, *sym_name;
+    unsigned long mod_start, mod_end;
+    unsigned long sec_start, sec_end;
+    unsigned long sym_start, sym_end;
+    unsigned long offset;
+    void *match = 0;
+    int ret;
+
+#ifdef OSI_PROBE_DEBUG
+    if (probe_debug & 0x0001)
+       printk("<7>osi_probe: %s                      try_harder\n", P->symbol);
+#endif
+    for (offset = 0; offset < datalen; offset++, ptr++) {
+       ret = check_table(P, ptr);
+        if (ret >= 0) {
+            /* return value is number of entries to skip */
+           ptr    += ret;
+           offset += ret;
+           continue;
+       }
+
+#ifdef OSI_PROBE_DEBUG
+       if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
+           printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
+#endif
+       if (!check_harder(P, ptr))
+           continue;
+
+#ifdef OSI_PROBE_DEBUG
+       if (probe_debug & 0x0004)
+           printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
+#endif
+
+       if (kallsyms_address_to_symbol) {
+           ret = kallsyms_address_to_symbol((unsigned long)ptr,
+                                            &mod_name, &mod_start, &mod_end,
+                                            &sec_name, &sec_start, &sec_end,
+                                            &sym_name, &sym_start, &sym_end);
+           if (!ret || strcmp(sym_name, P->symbol)) continue;
+       }
+
+       if (match) {
+#ifdef OSI_PROBE_DEBUG
+           if (probe_debug & 0x0005)
+               printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
+#endif
+           return 0;
+       }
+
+       match = (void *)ptr;
+       if (!probe_carefully)
+           break;
+    }
+    return match;
+}
+
+
+#ifdef OSI_PROBE_DEBUG
+#define check_result(x,m) do {                                                             \
+    if (probe_debug & 0x0001) {                                                              \
+       printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
+    }                                                                                      \
+    if ((x)) {                                                                             \
+       *method = (m);                                                                     \
+        final_answer = (void *)(x);                                                        \
+    }                                                                                      \
+} while (0)
+#else
+#define check_result(x,m) do {  \
+    if ((x)) {                  \
+        *method = (m);          \
+        return (void *)(x);     \
+    }                           \
+} while (0)
+#endif
+static void *do_find_syscall_table(probectl *P, char **method)
+{
+    char *mod_name, *sec_name, *sym_name;
+    unsigned long mod_start, mod_end;
+    unsigned long sec_start, sec_end;
+    unsigned long sym_start, sym_end;
+    PROBETYPE *B;
+    unsigned long token, L;
+    tryctl *T;
+    void *answer;
+#ifdef OSI_PROBE_DEBUG
+    void *final_answer = 0;
+#endif
+    int ret;
+
+    *method = "not found";
+
+    /* if it's exported, there's nothing to do */
+    check_result(P->weak_answer, "exported");
+
+    /* ask the kernel to do the name lookup, if it's willing */
+    if (kallsyms_symbol_to_address) {
+       token = 0;
+        sym_start = 0;
+       do {
+           ret = kallsyms_symbol_to_address(P->symbol, &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") && sym_start)
+               break;
+           sym_start = 0;
+       } while (ret);
+        check_result(sym_start, "kallsyms_symbol_to_address");
+    }
+
+    /* Maybe a little birdie told us */
+    check_result(P->parm_answer,  "module parameter");
+    check_result(P->given_answer, "compiled-in");
+
+    /* OK, so we have to scan. */
+    B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
+    L = P->try_length;
+    /* Now, see if the kernel will tell us something better than the default */
+    if (kallsyms_address_to_symbol) {
+       ret = kallsyms_address_to_symbol(P->try_sect_sym,
+                                        &mod_name, &mod_start, &mod_end,
+                                        &sec_name, &sec_start, &sec_end,
+                                        &sym_name, &sym_start, &sym_end);
+       if (ret) {
+           B = (PROBETYPE *)sec_start;
+           L = (sec_end - sec_start) / sizeof(unsigned long);
+       }
+    }
+
+#ifdef OSI_PROBE_DEBUG
+    if (probe_debug & 0x0007)
+       printk("<7>osi_probe: %s                      base=0x%lx, len=0x%lx\n",
+              P->symbol, (unsigned long)B, L);
+    if (probe_debug & 0x0009) {
+       printk("<7>osi_probe: %s                      ktxt_lower_bound=0x%lx\n",
+              P->symbol, ktxt_lower_bound);
+       printk("<7>osi_probe: %s                      NR_syscalls=%d\n",
+              P->symbol, NR_syscalls);
+    }
+#endif
+
+    for (T = P->trylist; T->name; T++) {
+       answer = try(P, T, B, L);
+        check_result(answer, T->name);
+    }
+
+    /* XXX more checks here */
+
+    answer = try_harder(P, B, L);
+    check_result(answer, "pattern scan");
+
+#ifdef OSI_PROBE_DEBUG
+    return final_answer;
+#else
+    return 0;
+#endif
+}
+
+void *osi_find_syscall_table(int which)
+{
+    probectl *P;
+    void *answer;
+    char *method;
+
+    if (which < 0 || which >= N_PROBE_LIST) {
+       printk("error - afs_find_syscall_table called with invalid index!\n");
+       return 0;
+    }
+    P = probe_list[which];
+    if (which < 4) {
+       P->parm_answer = (void *)sys_call_table_addr[which];
+#ifdef OSI_PROBE_DEBUG
+       P->debug_answer = (void *)probe_debug_addr[which];
+#endif
+    }
+    answer = do_find_syscall_table(P, &method);
+    if (!answer) {
+       printk("Warning: failed to find address of %s\n", P->desc);
+       printk("System call hooks will not be installed; proceeding anyway\n");
+       return 0;
+    }
+    printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
+    return answer;
+}
+
+
+#ifdef OSI_PROBE_STANDALONE
+int __init osi_probe_init(void)
+{
+    int i;
+
+    if (!probe_debug_tag) probe_debug_tag = jiffies;
+    printk("*** osi_probe %ld debug = 0x%04x ***\n",
+          probe_debug_tag, probe_debug);
+    for (i = 0; i < N_PROBE_LIST; i++)
+       (void)osi_find_syscall_table(i);
+    return 0;
+}
+
+void osi_probe_exit(void) { }
+
+module_init(osi_probe_init);
+module_exit(osi_probe_exit);
+#endif
index 3174826..05effc3 100644 (file)
@@ -41,6 +41,13 @@ extern void afs_osi_SetTime(osi_timeval_t * tvp);
 extern void osi_linux_free_inode_pages(void);
 extern void check_bad_parent(struct dentry *dp);
 
+/* osi_probe.c */
+extern void *osi_find_syscall_table(int which);
+
+/* osi_syscall.c */
+extern int osi_syscall_init(void);
+extern void osi_syscall_clean(void);
+
 /* osi_sysctl.c */
 extern int osi_sysctl_init(void);
 extern void osi_sysctl_clean(void);
diff --git a/src/afs/LINUX/osi_syscall.c b/src/afs/LINUX/osi_syscall.c
new file mode 100644 (file)
index 0000000..f4ddebf
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * Linux module support routines.
+ *
+ */
+#include <afsconfig.h>
+#include "afs/param.h"
+
+RCSID
+    ("$Header$");
+
+#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "h/unistd.h"          /* For syscall numbers. */
+#include "h/mm.h"
+
+#ifdef AFS_AMD64_LINUX20_ENV
+#include "../asm/ia32_unistd.h"
+#endif
+
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/init.h>
+#include <linux/sched.h>
+#endif
+
+
+/* On SPARC64 and S390X, sys_call_table contains 32-bit entries
+ * even though pointers are 64 bit quantities.
+ * XXX unify this with osi_probe.c
+ */
+#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
+#define SYSCALLTYPE unsigned int
+#define POINTER2SYSCALL (unsigned int)(unsigned long)
+#define SYSCALL2POINTER (void *)(long)
+#else
+#define SYSCALLTYPE void *
+#define POINTER2SYSCALL (void *)
+#define SYSCALL2POINTER (void *)
+#endif
+
+#if defined(AFS_S390X_LINUX24_ENV)
+#define _S(x) ((x)<<1)
+#elif defined(AFS_IA64_LINUX20_ENV)
+#define _S(x) ((x)-1024)
+#else
+#define _S(x) x
+#endif
+
+
+/***** ALL PLATFORMS *****/
+extern asmlinkage long
+afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
+
+static SYSCALLTYPE *afs_sys_call_table;
+static SYSCALLTYPE afs_ni_syscall = 0;
+
+extern long afs_xsetgroups();
+asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
+
+#ifdef AFS_LINUX24_ENV
+extern int afs_xsetgroups32();
+asmlinkage int (*sys_setgroups32p) (int gidsetsize,
+                                   __kernel_gid32_t * grouplist);
+#endif
+
+#if !defined(AFS_LINUX24_ENV)
+asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
+#endif
+
+
+/***** AMD64 *****/
+#ifdef AFS_AMD64_LINUX20_ENV
+static SYSCALLTYPE *afs_ia32_sys_call_table;
+static SYSCALLTYPE ia32_ni_syscall = 0;
+
+extern int afs32_xsetgroups();
+asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
+#ifdef AFS_LINUX24_ENV
+extern int afs32_xsetgroups32();
+asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
+#endif /* __NR_ia32_setgroups32 */
+#endif /* AFS_AMD64_LINUX20_ENV */
+
+
+/***** PPC64 *****/
+#ifdef AFS_PPC64_LINUX20_ENV
+extern SYSCALLTYPE *afs_sys_call_table32;
+static SYSCALLTYPE afs_ni_syscall32 = 0;
+
+extern int afs32_xsetgroups();
+asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
+#endif /* AFS_AMD64_LINUX20_ENV */
+
+
+/***** SPARC64 *****/
+#ifdef AFS_SPARC64_LINUX20_ENV
+extern SYSCALLTYPE *afs_sys_call_table32;
+static SYSCALLTYPE afs_ni_syscall32 = 0;
+
+extern int afs32_xsetgroups();
+asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
+                                   __kernel_gid_t32 * grouplist);
+#ifdef AFS_LINUX24_ENV
+/* This number is not exported for some bizarre reason. */
+#define __NR_setgroups32      82
+extern int afs32_xsetgroups32();
+asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
+                                     __kernel_gid_t32 * grouplist);
+#endif
+
+asmlinkage int
+afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
+             long parm5)
+{
+    __asm__ __volatile__("srl %o4, 0, %o4\n\t" "mov %o7, %i7\n\t"
+                        "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t"
+                        "ret\n\t" "nop");
+}
+#endif /* AFS_SPARC64_LINUX20_ENV */
+
+
+/***** IA64 *****/
+#ifdef AFS_IA64_LINUX20_ENV
+
+asmlinkage long
+afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
+{
+    __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"       /* save rp */
+                        "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t"   /* save gp */
+                        ";;\n" ".L1:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_syscall-.L1,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t"    /* restore gp */
+                        "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
+                        "data8 @fptr(afs_syscall)\n\t" ".skip 8");
+}
+
+asmlinkage long
+afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
+{
+    __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"       /* save rp */
+                        "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t"   /* save gp */
+                        ";;\n" ".L2:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t"       /* restore gp */
+                        "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
+                        "data8 @fptr(afs_xsetgroups)\n\t" ".skip 8");
+}
+
+struct fptr {
+    void *ip;
+    unsigned long gp;
+};
+
+#endif /* AFS_IA64_LINUX20_ENV */
+
+
+
+/**********************************************************************/
+/********************* System Call Initialization *********************/
+/**********************************************************************/
+
+int osi_syscall_init(void)
+{
+/***** IA64 *****/
+#ifdef AFS_IA64_LINUX20_ENV
+    /* This needs to be first because we are declaring variables, and
+     * also because the handling of syscall pointers is bizarre enough
+     * that we want to special-case even the "common" part.
+     */
+    unsigned long kernel_gp = 0;
+    static struct fptr sys_setgroups;
+
+    afs_sys_call_table = osi_find_syscall_table(0);
+    if (afs_sys_call_table) {
+
+#if !defined(AFS_LINUX24_ENV)
+       /* XXX no sys_settimeofday on IA64? */
+#endif
+
+       /* check we aren't already loaded */
+       /* XXX this can't be right */
+       if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
+           == afs_syscall) {
+           printf("AFS syscall entry point already in use!\n");
+           return -EBUSY;
+       }
+
+       /* setup AFS entry point */
+       afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
+       afs_sys_call_table[_S(__NR_afs_syscall)] =
+               POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
+
+       /* setup setgroups */
+       sys_setgroupsp = (void *)&sys_setgroups;
+
+       ((struct fptr *)sys_setgroupsp)->ip =
+           SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
+       ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
+
+       afs_sys_call_table[__S(_NR_setgroups)] =
+           POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
+    }
+
+    /* XXX no 32-bit syscalls on IA64? */
+
+
+/***** COMMON (except IA64) *****/
+#else /* !AFS_IA64_LINUX20_ENV */
+
+    afs_sys_call_table = osi_find_syscall_table(0);
+    if (afs_sys_call_table) {
+#if !defined(AFS_LINUX24_ENV)
+       sys_settimeofdayp =
+           SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
+#endif /* AFS_LINUX24_ENV */
+
+       /* check we aren't already loaded */
+       if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
+           == afs_syscall) {
+           printf("AFS syscall entry point already in use!\n");
+           return -EBUSY;
+       }
+
+       /* setup AFS entry point */
+       afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
+       afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
+
+       /* setup setgroups */
+       sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
+       afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
+
+#if defined(__NR_setgroups32)
+       /* setup setgroups32 */
+       sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
+       afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
+#endif
+    }
+#endif /* !AFS_IA64_LINUX20_ENV */
+
+
+/***** AMD64 *****/
+#ifdef AFS_AMD64_LINUX20_ENV
+    afs_ia32_sys_call_table = osi_find_syscall_table(1);
+    if (afs_ia32_sys_call_table) {
+       /* setup AFS entry point for IA32 */
+       ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
+       afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
+           POINTER2SYSCALL afs_syscall;
+
+       /* setup setgroups for IA32 */
+       sys32_setgroupsp =
+           SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
+       afs_ia32_sys_call_table[__NR_ia32_setgroups] =
+           POINTER2SYSCALL afs32_xsetgroups;
+
+#if AFS_LINUX24_ENV
+       /* setup setgroups32 for IA32 */
+       sys32_setgroups32p =
+           SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
+       afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
+           POINTER2SYSCALL afs32_xsetgroups32;
+#endif /* __NR_ia32_setgroups32 */
+    }
+#endif /* AFS_AMD64_LINUX20_ENV */
+
+
+/***** PPC64 *****/
+#ifdef AFS_PPC64_LINUX20_ENV
+    /* XXX no 32-bit syscalls on PPC64? */
+#endif
+
+
+/***** SPARC64 *****/
+#ifdef AFS_SPARC64_LINUX20_ENV
+    afs_sys_call_table32 = osi_find_syscall_table(1);
+    if (afs_sys_call_table32) {
+       /* setup AFS entry point for 32-bit SPARC */
+       afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
+       afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
+
+       /* setup setgroups for 32-bit SPARC */
+       sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
+       afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
+
+#ifdef AFS_LINUX24_ENV
+       /* setup setgroups32 for 32-bit SPARC */
+       sys32_setgroups32p =
+           SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
+       afs_sys_call_table32[__NR_setgroups32] =
+           POINTER2SYSCALL afs32_xsetgroups32;
+#endif
+    }
+#endif /* AFS_SPARC64_LINUX20_ENV */
+    return 0;
+}
+
+
+
+/**********************************************************************/
+/************************ System Call Cleanup *************************/
+/**********************************************************************/
+
+void osi_syscall_clean(void)
+{
+/***** COMMON *****/
+    if (afs_sys_call_table) {
+       /* put back the AFS entry point */
+       afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
+
+       /* put back setgroups */
+#if defined(AFS_IA64_LINUX20_ENV)
+       afs_sys_call_table[_S(__NR_setgroups)] =
+           POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
+#else /* AFS_IA64_LINUX20_ENV */
+       afs_sys_call_table[_S(__NR_setgroups)] =
+           POINTER2SYSCALL sys_setgroupsp;
+#endif
+
+#if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
+       /* put back setgroups32 */
+       afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
+#endif
+    }
+
+
+/***** IA64 *****/
+#ifdef AFS_IA64_LINUX20_ENV
+    /* XXX no 32-bit syscalls on IA64? */
+#endif
+
+
+/***** AMD64 *****/
+#ifdef AFS_AMD64_LINUX20_ENV
+    if (afs_ia32_sys_call_table) {
+       /* put back AFS entry point for IA32 */
+       afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
+           POINTER2SYSCALL ia32_ni_syscall;
+
+       /* put back setgroups for IA32 */
+       afs_ia32_sys_call_table[__NR_ia32_setgroups] =
+           POINTER2SYSCALL sys32_setgroupsp;
+
+#ifdef AFS_LINUX24_ENV
+       /* put back setgroups32 for IA32 */
+       afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
+           POINTER2SYSCALL sys32_setgroups32p;
+#endif
+    }
+#endif
+
+
+/***** PPC64 *****/
+#ifdef AFS_PPC64_LINUX20_ENV
+    /* XXX no 32-bit syscalls on PPC64? */
+#endif
+
+
+/***** SPARC64 *****/
+#ifdef AFS_SPARC64_LINUX20_ENV
+    if (afs_sys_call_table32) {
+       /* put back AFS entry point for 32-bit SPARC */
+       afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
+
+       /* put back setgroups for IA32 */
+       afs_sys_call_table32[__NR_setgroups] =
+           POINTER2SYSCALL sys32_setgroupsp;
+
+#ifdef AFS_LINUX24_ENV
+       /* put back setgroups32 for IA32 */
+       afs_sys_call_table32[__NR_setgroups32] =
+           POINTER2SYSCALL sys32_setgroups32p;
+#endif
+    }
+#endif
+}
index 8be95e2..9ee7e74 100644 (file)
@@ -387,6 +387,10 @@ osi_debug.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_debug.c
        $(CRULE_OPT)
 osi_module.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_module.c
        $(CRULE_NOOPT)
+osi_probe.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_probe.c
+       $(CRULE_NOOPT)
+osi_syscall.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_syscall.c
+       $(CRULE_NOOPT)
 osi_sysctl.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_sysctl.c
        $(CRULE_NOOPT)
 osi_alloc.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_alloc.c
index 211dd10..e834f7c 100644 (file)
@@ -18,7 +18,9 @@ AFS_OS_OBJS = \
        osi_file.o \
        osi_misc.o \
        osi_module.o \
+       osi_probe.o \
        osi_sleep.o \
+       osi_syscall.o \
        osi_sysctl.o \
        osi_vfsops.o \
        osi_vm.o \