linux26-proc-interface-use-long-not-int-20040511
[openafs.git] / src / afs / LINUX / osi_module.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Linux module support routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22 #include "h/unistd.h"           /* For syscall numbers. */
23 #include "h/mm.h"
24
25 #ifdef AFS_AMD64_LINUX20_ENV
26 #include "../asm/ia32_unistd.h"
27 #endif
28
29 #include <linux/module.h>
30 #include <linux/proc_fs.h>
31 #include <linux/slab.h>
32 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
33 #include <linux/init.h>
34 #include <linux/sched.h>
35 #endif
36 #if !defined(EXPORTED_SYS_CALL_TABLE) && defined(HAVE_KERNEL_LINUX_SYSCALL_H)
37 #include <linux/syscall.h>
38 #endif
39
40 #if defined(AFS_LINUX26_ENV)
41 #include <linux/vermagic.h>
42 #include <linux/compiler.h>
43
44 MODULE_INFO(vermagic, VERMAGIC_STRING);
45
46 #endif
47
48 #ifdef AFS_SPARC64_LINUX24_ENV
49 #define __NR_setgroups32      82        /* This number is not exported for some bizarre reason. */
50 #endif
51
52 #if !defined(AFS_LINUX24_ENV)
53 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv,
54                                      struct timezone * tz);
55 #endif
56 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
57 #ifdef EXPORTED_SYS_CALL_TABLE
58 #ifdef AFS_SPARC64_LINUX20_ENV
59 extern unsigned int sys_call_table[];   /* changed to uint because SPARC64 has syscaltable of 32bit items */
60 #else
61 extern void *sys_call_table[];  /* safer for other linuces */
62 #endif
63 #else /* EXPORTED_SYS_CALL_TABLE */
64 #ifdef AFS_SPARC64_LINUX20_ENV
65 static unsigned int *sys_call_table;    /* changed to uint because SPARC64 has syscaltable of 32bit items */
66 #else
67 static void **sys_call_table;   /* safer for other linuces */
68 #endif
69 #endif
70 extern struct file_system_type afs_fs_type;
71
72 static long get_page_offset(void);
73
74 #if defined(AFS_LINUX24_ENV)
75 DECLARE_MUTEX(afs_global_lock);
76 #else
77 struct semaphore afs_global_lock = MUTEX;
78 #endif
79 int afs_global_owner = 0;
80 #if !defined(AFS_LINUX24_ENV)
81 unsigned long afs_linux_page_offset = 0;        /* contains the PAGE_OFFSET value */
82 #endif
83
84 /* Since sys_ni_syscall is not exported, I need to cache it in order to restore
85  * it.
86  */
87 #ifdef AFS_SPARC64_LINUX20_ENV
88 static unsigned int afs_ni_syscall = 0;
89 #else
90 static void *afs_ni_syscall = 0;
91 #endif
92
93 #ifdef AFS_AMD64_LINUX20_ENV
94 #ifdef EXPORTED_IA32_SYS_CALL_TABLE
95 extern void *ia32_sys_call_table[];
96 #else
97 static void **ia32_sys_call_table;
98 #endif
99
100 static void *ia32_ni_syscall = 0;
101 asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
102 #if defined(__NR_ia32_setgroups32)
103 asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
104 #endif /* __NR_ia32_setgroups32 */
105 #endif /* AFS_AMD64_LINUX20_ENV */
106
107 #ifdef AFS_PPC64_LINUX20_ENV
108 asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
109 #endif /* AFS_AMD64_LINUX20_ENV */
110
111 #ifdef AFS_SPARC64_LINUX20_ENV
112 static unsigned int afs_ni_syscall32 = 0;
113 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
114                                     __kernel_gid_t32 * grouplist);
115 #if defined(__NR_setgroups32)
116 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
117                                       __kernel_gid_t32 * grouplist);
118 #endif /* __NR_setgroups32 */
119 #ifdef EXPORTED_SYS_CALL_TABLE
120 extern unsigned int sys_call_table32[];
121 #else /* EXPORTED_SYS_CALL_TABLE */
122 static unsigned int *sys_call_table32;
123 #endif /* EXPORTED_SYS_CALL_TABLE */
124
125 asmlinkage int
126 afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
127               long parm5)
128 {
129     __asm__ __volatile__("srl %o4, 0, %o4\n\t" "mov %o7, %i7\n\t"
130                          "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t"
131                          "ret\n\t" "nop");
132 }
133 #endif /* AFS_SPARC64_LINUX20_ENV */
134
135 static int afs_ioctl(struct inode *, struct file *, unsigned int,
136                      unsigned long);
137
138 static struct file_operations afs_syscall_fops = {
139     .ioctl = afs_ioctl,
140 };
141
142 static struct proc_dir_entry *openafs_procfs;
143
144 static int
145 afsproc_init()
146 {
147     struct proc_dir_entry *entry1;
148
149     openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
150     entry1 = create_proc_entry(PROC_SYSCALL_NAME, 0, openafs_procfs);
151
152     entry1->proc_fops = &afs_syscall_fops;
153
154     entry1->owner = THIS_MODULE;
155
156     return 0;
157 }
158
159 static void
160 afsproc_exit()
161 {
162     remove_proc_entry(PROC_SYSCALL_NAME, openafs_procfs);
163     remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
164 }
165
166 static int
167 afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
168           unsigned long arg)
169 {
170
171     struct afsprocdata sysargs;
172
173     if (cmd != VIOC_SYSCALL) return -EINVAL;
174
175     if (copy_from_user(&sysargs, (void *)arg, sizeof(struct afsprocdata)))
176         return -EFAULT;
177
178     return afs_syscall(sysargs.syscall, sysargs.param1,
179                        sysargs.param2, sysargs.param3, sysargs.param4);
180 }
181
182 #ifdef AFS_IA64_LINUX20_ENV
183
184 asmlinkage long
185 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
186 {
187     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
188                          "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 */
189                          ";;\n" ".L1:    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 */
190                          "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
191                          "data8 @fptr(afs_syscall)");
192 }
193
194 asmlinkage long
195 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
196 {
197     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
198                          "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 */
199                          ";;\n" ".L2:    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 */
200                          "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
201                          "data8 @fptr(afs_xsetgroups)");
202 }
203
204 struct fptr {
205     void *ip;
206     unsigned long gp;
207 };
208
209 #endif /* AFS_IA64_LINUX20_ENV */
210
211 #ifdef AFS_LINUX24_ENV
212 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
213                                     __kernel_gid32_t * grouplist);
214 #endif /* AFS_LINUX24_ENV */
215
216 #ifdef AFS_SPARC64_LINUX20_ENV
217 #define POINTER2SYSCALL (unsigned int)(unsigned long)
218 #define SYSCALL2POINTER (void *)(long)
219 #else
220 #define POINTER2SYSCALL (void *)
221 #define SYSCALL2POINTER (void *)
222 #endif
223
224 #ifdef AFS_PPC64_LINUX20_ENV
225 extern void *set_afs_syscall(void*);
226 extern void *set_afs_xsetgroups_syscall(void*);
227 extern void *set_afs_xsetgroups_syscall32(void*);
228 #endif
229
230 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
231 int __init
232 afs_init(void)
233 #else
234 int
235 init_module(void)
236 #endif
237 {
238 #if defined(AFS_IA64_LINUX20_ENV)
239     unsigned long kernel_gp = 0;
240     static struct fptr sys_setgroups;
241 #endif /* defined(AFS_IA64_LINUX20_ENV) */
242     extern int afs_syscall();
243     extern long afs_xsetgroups();
244 #if defined(__NR_setgroups32)
245     extern int afs_xsetgroups32();
246 #endif /* __NR_setgroups32 */
247 #if defined(AFS_SPARC64_LINUX20_ENV) || defined (AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
248     extern int afs32_xsetgroups();
249 #if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV))
250     extern int afs32_xsetgroups32();
251 #endif /* defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV) */
252 #if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV))
253     extern int afs32_xsetgroups32();
254 #endif /* (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV) */
255 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV || AFS_PPC64_LINUX20_ENV */
256
257 #if !defined(EXPORTED_SYS_CALL_TABLE) || (defined(AFS_AMD64_LINUX20_ENV) && !defined(EXPORTED_IA32_SYS_CALL_TABLE))
258     unsigned long *ptr;
259     unsigned long offset=0;
260     unsigned long datalen=0;
261     int ret;
262     unsigned long token=0;
263     char *mod_name;
264     unsigned long mod_start=0;
265     unsigned long mod_end=0;
266     char *sec_name;
267     unsigned long sec_start=0;
268     unsigned long sec_end=0;
269     char *sym_name;
270     unsigned long sym_start=0;
271     unsigned long sym_end=0;
272 #endif /* EXPORTED_SYS_CALL_TABLE */
273
274     RWLOCK_INIT(&afs_xosi, "afs_xosi");
275
276 #if !defined(AFS_LINUX24_ENV)
277     /* obtain PAGE_OFFSET value */
278     afs_linux_page_offset = get_page_offset();
279
280 #ifndef AFS_S390_LINUX22_ENV
281     if (afs_linux_page_offset == 0) {
282         /* couldn't obtain page offset so can't continue */
283         printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
284         return -EIO;
285     }
286 #endif /* AFS_S390_LINUX22_ENV */
287 #endif /* !defined(AFS_LINUX24_ENV) */
288
289 #ifndef EXPORTED_SYS_CALL_TABLE
290     sys_call_table = 0;
291
292 #ifdef EXPORTED_KALLSYMS_SYMBOL
293     ret = 1;
294     token = 0;
295     while (ret) {
296         sym_start = 0;
297         ret =
298             kallsyms_symbol_to_address("sys_call_table", &token, &mod_name,
299                                        &mod_start, &mod_end, &sec_name,
300                                        &sec_start, &sec_end, &sym_name,
301                                        &sym_start, &sym_end);
302         if (ret && !strcmp(mod_name, "kernel"))
303             break;
304     }
305     if (ret && sym_start) {
306         sys_call_table = sym_start;
307     }
308 #elif defined(EXPORTED_KALLSYMS_ADDRESS)
309     ret =
310         kallsyms_address_to_symbol((unsigned long)&init_mm, &mod_name,
311                                    &mod_start, &mod_end, &sec_name,
312                                    &sec_start, &sec_end, &sym_name,
313                                    &sym_start, &sym_end);
314     ptr = (unsigned long *)sec_start;
315     datalen = (sec_end - sec_start) / sizeof(unsigned long);
316 #elif defined(AFS_IA64_LINUX20_ENV)
317     ptr = (unsigned long *)(&sys_close - 0x180000);
318     datalen = 0x180000 / sizeof(ptr);
319 #elif defined(AFS_AMD64_LINUX20_ENV)
320     ptr = (unsigned long *)&init_mm;
321     datalen = 0x360000 / sizeof(ptr);
322 #else
323     ptr = (unsigned long *)&init_mm;
324     datalen = 16384;
325 #endif
326     for (offset = 0; offset < datalen; ptr++, offset++) {
327 #if defined(AFS_IA64_LINUX20_ENV)
328         unsigned long close_ip =
329             (unsigned long)((struct fptr *)&sys_close)->ip;
330         unsigned long chdir_ip =
331             (unsigned long)((struct fptr *)&sys_chdir)->ip;
332         unsigned long write_ip =
333             (unsigned long)((struct fptr *)&sys_write)->ip;
334         if (ptr[0] == close_ip && ptr[__NR_chdir - __NR_close] == chdir_ip
335             && ptr[__NR_write - __NR_close] == write_ip) {
336             sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]);
337             break;
338         }
339 #elif defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE)
340         if (ptr[0] == (unsigned long)&sys_close
341             && ptr[__NR_wait4 - __NR_close] == (unsigned long)&sys_wait4) {
342             sys_call_table = ptr - __NR_close;
343             break;
344         }
345 #elif defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE)
346         if (ptr[0] == (unsigned long)&sys_close
347             && ptr[__NR_chdir - __NR_close] == (unsigned long)&sys_chdir) {
348             sys_call_table = ptr - __NR_close;
349             break;
350         }
351 #elif defined(EXPORTED_SYS_OPEN)
352         if (ptr[0] == (unsigned long)&sys_exit
353             && ptr[__NR_open - __NR_exit] == (unsigned long)&sys_open) {
354             sys_call_table = ptr - __NR_exit;
355             break;
356         }
357 #else /* EXPORTED_SYS_OPEN */
358         break;
359 #endif /* EXPORTED_KALLSYMS_ADDRESS */
360     }
361 #ifdef EXPORTED_KALLSYMS_ADDRESS
362     ret =
363         kallsyms_address_to_symbol((unsigned long)sys_call_table, &mod_name,
364                                    &mod_start, &mod_end, &sec_name,
365                                    &sec_start, &sec_end, &sym_name,
366                                    &sym_start, &sym_end);
367     if (ret && strcmp(sym_name, "sys_call_table"))
368         sys_call_table = 0;
369 #endif /* EXPORTED_KALLSYMS_ADDRESS */
370     if (!sys_call_table) {
371         printf("Failed to find address of sys_call_table\n");
372         sys_settimeofdayp = 0;
373     } else {
374         printf("Found sys_call_table at %x\n", sys_call_table);
375 #ifdef AFS_SPARC64_LINUX20_ENV
376         error cant support this yet.;
377 #endif /* AFS_SPARC64_LINUX20_ENV */
378 #endif /* EXPORTED_SYS_CALL_TABLE */
379
380 #ifdef AFS_AMD64_LINUX20_ENV
381 #ifndef EXPORTED_IA32_SYS_CALL_TABLE
382         ia32_sys_call_table = 0;
383 #ifdef EXPORTED_KALLSYMS_SYMBOL
384         ret = 1;
385         token = 0;
386         while (ret) {
387             sym_start = 0;
388             ret = kallsyms_symbol_to_address("ia32_sys_call_table", &token,
389                                              &mod_name, &mod_start, &mod_end,
390                                              &sec_name, &sec_start, &sec_end,
391                                              &sym_name, &sym_start, &sym_end);
392             if (ret && !strcmp(mod_name, "kernel"))
393                 break;
394         }
395         if (ret && sym_start) {
396             ia32_sys_call_table = sym_start;
397         }
398 #else /* EXPORTED_KALLSYMS_SYMBOL */
399 #ifdef EXPORTED_KALLSYMS_ADDRESS
400         ret = kallsyms_address_to_symbol((unsigned long)
401                                          &interruptible_sleep_on,
402                                          &mod_name, &mod_start, &mod_end,
403                                          &sec_name, &sec_start, &sec_end,
404                                          &sym_name, &sym_start, &sym_end);
405         ptr = (unsigned long *)sec_start;
406         datalen = (sec_end - sec_start) / sizeof(unsigned long);
407 #else /* EXPORTED_KALLSYMS_ADDRESS */
408 #if defined(AFS_AMD64_LINUX20_ENV)
409         ptr = (unsigned long *)&interruptible_sleep_on;
410         datalen = 0x180000 / sizeof(ptr);
411 #else /* AFS_AMD64_LINUX20_ENV */
412         ptr = (unsigned long *)&interruptible_sleep_on;
413         datalen = 16384;
414 #endif /* AFS_AMD64_LINUX20_ENV */
415 #endif /* EXPORTED_KALLSYMS_ADDRESS */
416         for (offset = 0; offset < datalen; ptr++, offset++) {
417             if (ptr[0] == (unsigned long)&sys_exit
418                 && ptr[__NR_ia32_open - __NR_ia32_exit] ==
419                 (unsigned long)&sys_open) {
420                     ia32_sys_call_table = ptr - __NR_ia32_exit;
421                     break;
422             }
423         }
424 #ifdef EXPORTED_KALLSYMS_ADDRESS
425         ret = kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table,
426                                          &mod_name, &mod_start, &mod_end,
427                                          &sec_name, &sec_start, &sec_end,
428                                          &sym_name, &sym_start, &sym_end);
429         if (ret && strcmp(sym_name, "ia32_sys_call_table"))
430             ia32_sys_call_table = 0;
431 #endif /* EXPORTED_KALLSYMS_ADDRESS */
432 #endif /* EXPORTED_KALLSYMS_SYMBOL */
433         if (!ia32_sys_call_table) {
434             printf("Warning: Failed to find address of ia32_sys_call_table\n");
435         } else {
436             printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
437         }
438 #else
439         printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
440 #endif /* IA32_SYS_CALL_TABLE */
441 #endif
442
443         /* Initialize pointers to kernel syscalls. */
444 #if !defined(AFS_LINUX24_ENV)
445         sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
446 #endif /* AFS_IA64_LINUX20_ENV */
447
448         /* setup AFS entry point. */
449         if (
450 #if defined(AFS_IA64_LINUX20_ENV)
451                 SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
452 #else
453                 SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
454 #endif
455                 == afs_syscall) {
456             printf("AFS syscall entry point already in use!\n");
457             return -EBUSY;
458         }
459 #if defined(AFS_IA64_LINUX20_ENV)
460         afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
461         sys_call_table[__NR_afs_syscall - 1024] =
462                 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
463 #else /* AFS_IA64_LINUX20_ENV */
464         afs_ni_syscall = sys_call_table[__NR_afs_syscall];
465         sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
466 #ifdef AFS_SPARC64_LINUX20_ENV
467         afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
468         sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
469 #endif
470 #endif /* AFS_IA64_LINUX20_ENV */
471 #ifdef AFS_AMD64_LINUX20_ENV
472         if (ia32_sys_call_table) {
473             ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall];
474             ia32_sys_call_table[__NR_ia32_afs_syscall] =
475                     POINTER2SYSCALL afs_syscall;
476         }
477 #endif /* AFS_S390_LINUX22_ENV */
478 #ifndef EXPORTED_SYS_CALL_TABLE
479     }
480 #endif /* EXPORTED_SYS_CALL_TABLE */
481     osi_Init();
482     register_filesystem(&afs_fs_type);
483
484     /* Intercept setgroups calls */
485     if (sys_call_table) {
486 #if defined(AFS_IA64_LINUX20_ENV)
487     sys_setgroupsp = (void *)&sys_setgroups;
488
489     ((struct fptr *)sys_setgroupsp)->ip =
490         SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
491     ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
492
493     sys_call_table[__NR_setgroups - 1024] =
494         POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
495 #else /* AFS_IA64_LINUX20_ENV */
496     sys_setgroupsp = SYSCALL2POINTER sys_call_table[__NR_setgroups];
497     sys_call_table[__NR_setgroups] = POINTER2SYSCALL afs_xsetgroups;
498 #ifdef AFS_SPARC64_LINUX20_ENV
499     sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
500     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
501 #endif /* AFS_SPARC64_LINUX20_ENV */
502 #if defined(__NR_setgroups32)
503     sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
504     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
505 #ifdef AFS_SPARC64_LINUX20_ENV
506         sys32_setgroups32p =
507             SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
508         sys_call_table32[__NR_setgroups32] =
509             POINTER2SYSCALL afs32_xsetgroups32;
510 #endif /* AFS_SPARC64_LINUX20_ENV */
511 #endif /* __NR_setgroups32 */
512 #ifdef AFS_AMD64_LINUX20_ENV
513     if (ia32_sys_call_table) {
514         sys32_setgroupsp =
515             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups];
516         ia32_sys_call_table[__NR_ia32_setgroups] =
517             POINTER2SYSCALL afs32_xsetgroups;
518 #if defined(__NR_ia32_setgroups32)
519         sys32_setgroups32p =
520             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups32];
521         ia32_sys_call_table[__NR_ia32_setgroups32] =
522             POINTER2SYSCALL afs32_xsetgroups32;
523 #endif /* __NR_ia32_setgroups32 */
524     }
525 #endif /* AFS_AMD64_LINUX20_ENV */
526 #endif /* AFS_IA64_LINUX20_ENV */
527
528 #ifdef AFS_PPC64_LINUX20_ENV
529     afs_ni_syscall = set_afs_syscall(afs_syscall);
530     sys_setgroupsp = set_afs_xsetgroups_syscall(afs_xsetgroups);
531     sys32_setgroupsp = set_afs_xsetgroups_syscall32(afs32_xsetgroups);
532 #endif
533     }
534
535     osi_sysctl_init();
536     afsproc_init();
537
538     return 0;
539 }
540
541 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
542 void __exit
543 afs_cleanup(void)
544 #else
545 void
546 cleanup_module(void)
547 #endif
548 {
549     struct task_struct *t;
550
551     osi_sysctl_clean();
552     if (sys_call_table) {
553 #if defined(AFS_IA64_LINUX20_ENV)
554     sys_call_table[__NR_setgroups - 1024] =
555         POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
556     sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
557 #else /* AFS_IA64_LINUX20_ENV */
558     sys_call_table[__NR_setgroups] = POINTER2SYSCALL sys_setgroupsp;
559     sys_call_table[__NR_afs_syscall] = afs_ni_syscall;
560 # ifdef AFS_SPARC64_LINUX20_ENV
561     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
562     sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
563 # endif
564 # if defined(__NR_setgroups32)
565     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
566 # ifdef AFS_SPARC64_LINUX20_ENV
567         sys_call_table32[__NR_setgroups32] =
568             POINTER2SYSCALL sys32_setgroups32p;
569 # endif
570 # endif
571 #endif /* AFS_IA64_LINUX20_ENV */
572 #ifdef AFS_AMD64_LINUX20_ENV
573     if (ia32_sys_call_table) {
574         ia32_sys_call_table[__NR_ia32_setgroups] =
575             POINTER2SYSCALL sys32_setgroupsp;
576         ia32_sys_call_table[__NR_ia32_afs_syscall] =
577             POINTER2SYSCALL ia32_ni_syscall;
578 # if defined(__NR_setgroups32)
579         ia32_sys_call_table[__NR_ia32_setgroups32] =
580             POINTER2SYSCALL sys32_setgroups32p;
581 #endif
582     }
583 #endif
584     }
585 #ifdef AFS_PPC64_LINUX20_ENV
586     set_afs_syscall(afs_ni_syscall);
587     set_afs_xsetgroups_syscall(sys_setgroupsp);
588     set_afs_xsetgroups_syscall32(sys32_setgroupsp);
589 #endif
590     unregister_filesystem(&afs_fs_type);
591
592     osi_linux_free_inode_pages();       /* Invalidate all pages using AFS inodes. */
593     osi_linux_free_afs_memory();
594
595     afsproc_exit();
596     return;
597 }
598
599 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
600 module_init(afs_init);
601 module_exit(afs_cleanup);
602 #endif
603
604
605 #if !defined(AFS_LINUX24_ENV)
606 static long
607 get_page_offset(void)
608 {
609 #if defined(AFS_PPC_LINUX22_ENV) || defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_ALPHA_LINUX20_ENV) || defined(AFS_S390_LINUX22_ENV) || defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PARISC_LINUX24_ENV) || defined(AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
610     return PAGE_OFFSET;
611 #else
612     struct task_struct *p, *q;
613
614     /* search backward thru the circular list */
615 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
616     read_lock(&tasklist_lock);
617 #endif
618     /* search backward thru the circular list */
619 #ifdef DEFINED_PREV_TASK
620     for (q = current; p = q; q = prev_task(p)) {
621 #else
622     for (p = current; p; p = p->prev_task) {
623 #endif
624         if (p->pid == 1) {
625 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
626             read_unlock(&tasklist_lock);
627 #endif
628             return p->addr_limit.seg;
629         }
630     }
631
632 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
633     read_unlock(&tasklist_lock);
634 #endif
635     return 0;
636 #endif
637 }
638 #endif /* !AFS_LINUX24_ENV */