linux26-update-20040507
[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/slab.h>
31 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
32 #include <linux/init.h>
33 #include <linux/sched.h>
34 #endif
35 #if !defined(EXPORTED_SYS_CALL_TABLE) && defined(HAVE_KERNEL_LINUX_SYSCALL_H)
36 #include <linux/syscall.h>
37 #endif
38
39 #if defined(AFS_LINUX26_ENV)
40 #include <linux/vermagic.h>
41 #include <linux/compiler.h>
42
43 MODULE_INFO(vermagic, VERMAGIC_STRING);
44
45 #endif
46
47 #ifdef AFS_SPARC64_LINUX24_ENV
48 #define __NR_setgroups32      82        /* This number is not exported for some bizarre reason. */
49 #endif
50
51 #if !defined(AFS_LINUX24_ENV)
52 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv,
53                                      struct timezone * tz);
54 #endif
55 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
56
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 #ifdef AFS_IA64_LINUX20_ENV
136
137 asmlinkage long
138 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
139 {
140     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
141                          "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 */
142                          ";;\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 */
143                          "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
144                          "data8 @fptr(afs_syscall)");
145 }
146
147 asmlinkage long
148 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
149 {
150     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
151                          "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 */
152                          ";;\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 */
153                          "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
154                          "data8 @fptr(afs_xsetgroups)");
155 }
156
157 struct fptr {
158     void *ip;
159     unsigned long gp;
160 };
161
162 #endif /* AFS_IA64_LINUX20_ENV */
163
164 #ifdef AFS_LINUX24_ENV
165 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
166                                     __kernel_gid32_t * grouplist);
167 #endif /* AFS_LINUX24_ENV */
168
169 #ifdef AFS_SPARC64_LINUX20_ENV
170 #define POINTER2SYSCALL (unsigned int)(unsigned long)
171 #define SYSCALL2POINTER (void *)(long)
172 #else
173 #define POINTER2SYSCALL (void *)
174 #define SYSCALL2POINTER (void *)
175 #endif
176
177 #ifdef AFS_PPC64_LINUX20_ENV
178 extern void *set_afs_syscall(void*);
179 extern void *set_afs_xsetgroups_syscall(void*);
180 extern void *set_afs_xsetgroups_syscall32(void*);
181 #endif
182
183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
184 int __init
185 afs_init(void)
186 #else
187 int
188 init_module(void)
189 #endif
190 {
191 #if defined(AFS_IA64_LINUX20_ENV)
192     unsigned long kernel_gp = 0;
193     static struct fptr sys_setgroups;
194 #endif
195     extern int afs_syscall();
196     extern long afs_xsetgroups();
197 #if defined(__NR_setgroups32)
198     extern int afs_xsetgroups32();
199 #endif /* __NR_setgroups32 */
200 #if defined(AFS_SPARC64_LINUX20_ENV) || defined (AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
201     extern int afs32_xsetgroups();
202 #if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV))
203     extern int afs32_xsetgroups32();
204 #endif
205 #if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV))
206     extern int afs32_xsetgroups32();
207 #endif
208 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV */
209
210 #if !defined(EXPORTED_SYS_CALL_TABLE) || (defined(AFS_AMD64_LINUX20_ENV) && !defined(EXPORTED_IA32_SYS_CALL_TABLE))
211     unsigned long *ptr;
212     unsigned long offset=0;
213     unsigned long datalen=0;
214     int ret;
215     unsigned long token=0;
216     char *mod_name;
217     unsigned long mod_start=0;
218     unsigned long mod_end=0;
219     char *sec_name;
220     unsigned long sec_start=0;
221     unsigned long sec_end=0;
222     char *sym_name;
223     unsigned long sym_start=0;
224     unsigned long sym_end=0;
225 #endif /* EXPORTED_SYS_CALL_TABLE */
226
227     RWLOCK_INIT(&afs_xosi, "afs_xosi");
228
229 #if !defined(AFS_LINUX24_ENV)
230     /* obtain PAGE_OFFSET value */
231     afs_linux_page_offset = get_page_offset();
232
233 #ifndef AFS_S390_LINUX22_ENV
234     if (afs_linux_page_offset == 0) {
235         /* couldn't obtain page offset so can't continue */
236         printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
237         return -EIO;
238     }
239 #endif
240 #endif
241 #ifndef EXPORTED_SYS_CALL_TABLE
242     sys_call_table = 0;
243
244 #ifdef EXPORTED_KALLSYMS_SYMBOL
245     ret = 1;
246     token = 0;
247     while (ret) {
248         sym_start = 0;
249         ret =
250             kallsyms_symbol_to_address("sys_call_table", &token, &mod_name,
251                                        &mod_start, &mod_end, &sec_name,
252                                        &sec_start, &sec_end, &sym_name,
253                                        &sym_start, &sym_end);
254         if (ret && !strcmp(mod_name, "kernel"))
255             break;
256     }
257     if (ret && sym_start) {
258         sys_call_table = sym_start;
259     }
260 #else
261 #ifdef EXPORTED_KALLSYMS_ADDRESS
262     ret =
263         kallsyms_address_to_symbol((unsigned long)&init_mm, &mod_name,
264                                    &mod_start, &mod_end, &sec_name,
265                                    &sec_start, &sec_end, &sym_name,
266                                    &sym_start, &sym_end);
267     ptr = (unsigned long *)sec_start;
268     datalen = (sec_end - sec_start) / sizeof(unsigned long);
269 #else
270 #if defined(AFS_IA64_LINUX20_ENV)
271     ptr = (unsigned long *)(&sys_close - 0x180000);
272     datalen = 0x180000 / sizeof(ptr);
273 #else
274 #if defined(AFS_AMD64_LINUX20_ENV)
275     ptr = (unsigned long *)&init_mm;
276     datalen = 0x360000 / sizeof(ptr);
277 #else
278     ptr = (unsigned long *)&init_mm;
279     datalen = 16384;
280 #endif
281 #endif
282 #endif
283     for (offset = 0; offset < datalen; ptr++, offset++) {
284 #if defined(AFS_IA64_LINUX20_ENV)
285         unsigned long close_ip =
286             (unsigned long)((struct fptr *)&sys_close)->ip;
287         unsigned long chdir_ip =
288             (unsigned long)((struct fptr *)&sys_chdir)->ip;
289         unsigned long write_ip =
290             (unsigned long)((struct fptr *)&sys_write)->ip;
291         if (ptr[0] == close_ip && ptr[__NR_chdir - __NR_close] == chdir_ip
292             && ptr[__NR_write - __NR_close] == write_ip) {
293             sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]);
294             break;
295         }
296 #else
297 #if defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE)
298         if (ptr[0] == (unsigned long)&sys_close
299             && ptr[__NR_wait4 - __NR_close] == (unsigned long)&sys_wait4) {
300             sys_call_table = ptr - __NR_close;
301             break;
302         }
303 #else
304 #if defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE)
305         if (ptr[0] == (unsigned long)&sys_close
306             && ptr[__NR_chdir - __NR_close] == (unsigned long)&sys_chdir) {
307             sys_call_table = ptr - __NR_close;
308             break;
309         }
310 #else
311         if (ptr[0] == (unsigned long)&sys_exit
312             && ptr[__NR_open - __NR_exit] == (unsigned long)&sys_open) {
313             sys_call_table = ptr - __NR_exit;
314             break;
315         }
316 #endif
317 #endif
318 #endif
319     }
320 #ifdef EXPORTED_KALLSYMS_ADDRESS
321     ret =
322         kallsyms_address_to_symbol((unsigned long)sys_call_table, &mod_name,
323                                    &mod_start, &mod_end, &sec_name,
324                                    &sec_start, &sec_end, &sym_name,
325                                    &sym_start, &sym_end);
326     if (ret && strcmp(sym_name, "sys_call_table"))
327         sys_call_table = 0;
328 #endif
329 #endif
330     if (!sys_call_table) {
331         printf("Failed to find address of sys_call_table\n");
332         return -EIO;
333     }
334     printf("Found sys_call_table at %x\n", sys_call_table);
335 # ifdef AFS_SPARC64_LINUX20_ENV
336     error cant support this yet.
337 #endif
338 #endif                          /* EXPORTED_SYS_CALL_TABLE */
339 #ifdef AFS_AMD64_LINUX20_ENV
340 #ifndef EXPORTED_IA32_SYS_CALL_TABLE
341       ia32_sys_call_table = 0;
342 #ifdef EXPORTED_KALLSYMS_SYMBOL
343     ret = 1;
344     token = 0;
345     while (ret) {
346         sym_start = 0;
347         ret =
348             kallsyms_symbol_to_address("ia32_sys_call_table", &token,
349                                        &mod_name, &mod_start, &mod_end,
350                                        &sec_name, &sec_start, &sec_end,
351                                        &sym_name, &sym_start, &sym_end);
352         if (ret && !strcmp(mod_name, "kernel"))
353             break;
354     }
355     if (ret && sym_start) {
356         ia32_sys_call_table = sym_start;
357     }
358 #else /* EXPORTED_KALLSYMS_SYMBOL */
359 #ifdef EXPORTED_KALLSYMS_ADDRESS
360     ret =
361         kallsyms_address_to_symbol((unsigned long)&interruptible_sleep_on,
362                                    &mod_name, &mod_start, &mod_end, &sec_name,
363                                    &sec_start, &sec_end, &sym_name,
364                                    &sym_start, &sym_end);
365     ptr = (unsigned long *)sec_start;
366     datalen = (sec_end - sec_start) / sizeof(unsigned long);
367 #else /* EXPORTED_KALLSYMS_ADDRESS */
368 #if defined(AFS_AMD64_LINUX20_ENV)
369     ptr = (unsigned long *)&interruptible_sleep_on;
370     datalen = 0x180000 / sizeof(ptr);
371 #else /* AFS_AMD64_LINUX20_ENV */
372     ptr = (unsigned long *)&interruptible_sleep_on;
373     datalen = 16384;
374 #endif /* AFS_AMD64_LINUX20_ENV */
375 #endif /* EXPORTED_KALLSYMS_ADDRESS */
376     for (offset = 0; offset < datalen; ptr++, offset++) {
377         if (ptr[0] == (unsigned long)&sys_exit
378             && ptr[__NR_ia32_open - __NR_ia32_exit] ==
379             (unsigned long)&sys_open) {
380             ia32_sys_call_table = ptr - __NR_ia32_exit;
381             break;
382         }
383     }
384 #ifdef EXPORTED_KALLSYMS_ADDRESS
385     ret =
386         kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table,
387                                    &mod_name, &mod_start, &mod_end, &sec_name,
388                                    &sec_start, &sec_end, &sym_name,
389                                    &sym_start, &sym_end);
390     if (ret && strcmp(sym_name, "ia32_sys_call_table"))
391         ia32_sys_call_table = 0;
392 #endif /* EXPORTED_KALLSYMS_ADDRESS */
393 #endif /* EXPORTED_KALLSYMS_SYMBOL */
394     if (!ia32_sys_call_table) {
395         printf("Warning: Failed to find address of ia32_sys_call_table\n");
396     } else {
397         printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
398     }
399 #else
400     printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
401 #endif /* IA32_SYS_CALL_TABLE */
402 #endif
403
404     /* Initialize pointers to kernel syscalls. */
405 #if !defined(AFS_LINUX24_ENV)
406     sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
407 #endif /* AFS_IA64_LINUX20_ENV */
408
409     /* setup AFS entry point. */
410     if (
411 #if defined(AFS_IA64_LINUX20_ENV)
412            SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
413 #else
414            SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
415 #endif
416            == afs_syscall) {
417         printf("AFS syscall entry point already in use!\n");
418         return -EBUSY;
419     }
420 #if defined(AFS_IA64_LINUX20_ENV)
421     afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
422     sys_call_table[__NR_afs_syscall - 1024] =
423         POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
424 #else /* AFS_IA64_LINUX20_ENV */
425     afs_ni_syscall = sys_call_table[__NR_afs_syscall];
426     sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
427 # ifdef AFS_SPARC64_LINUX20_ENV
428     afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
429     sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
430 # endif
431 #endif /* AFS_IA64_LINUX20_ENV */
432 #ifdef AFS_AMD64_LINUX20_ENV
433     if (ia32_sys_call_table) {
434         ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall];
435         ia32_sys_call_table[__NR_ia32_afs_syscall] =
436             POINTER2SYSCALL afs_syscall;
437     }
438 #endif /* AFS_S390_LINUX22_ENV */
439
440     osi_Init();
441     register_filesystem(&afs_fs_type);
442
443     /* Intercept setgroups calls */
444 #if defined(AFS_IA64_LINUX20_ENV)
445     sys_setgroupsp = (void *)&sys_setgroups;
446
447     ((struct fptr *)sys_setgroupsp)->ip =
448         SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
449     ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
450
451     sys_call_table[__NR_setgroups - 1024] =
452         POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
453 #else /* AFS_IA64_LINUX20_ENV */
454     sys_setgroupsp = SYSCALL2POINTER sys_call_table[__NR_setgroups];
455     sys_call_table[__NR_setgroups] = POINTER2SYSCALL afs_xsetgroups;
456 #ifdef AFS_SPARC64_LINUX20_ENV
457     sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
458     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
459 #endif /* AFS_SPARC64_LINUX20_ENV */
460 #if defined(__NR_setgroups32)
461     sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
462     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
463 #ifdef AFS_SPARC64_LINUX20_ENV
464     sys32_setgroups32p = SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
465     sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL afs32_xsetgroups32;
466 #endif /* AFS_SPARC64_LINUX20_ENV */
467 #endif /* __NR_setgroups32 */
468 #ifdef AFS_AMD64_LINUX20_ENV
469     if (ia32_sys_call_table) {
470         sys32_setgroupsp =
471             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups];
472         ia32_sys_call_table[__NR_ia32_setgroups] =
473             POINTER2SYSCALL afs32_xsetgroups;
474 #if defined(__NR_ia32_setgroups32)
475         sys32_setgroups32p =
476             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups32];
477         ia32_sys_call_table[__NR_ia32_setgroups32] =
478             POINTER2SYSCALL afs32_xsetgroups32;
479 #endif /* __NR_ia32_setgroups32 */
480     }
481 #endif /* AFS_AMD64_LINUX20_ENV */
482 #endif /* AFS_IA64_LINUX20_ENV */
483
484 #ifdef AFS_PPC64_LINUX20_ENV
485     afs_ni_syscall = set_afs_syscall(afs_syscall);
486     sys_setgroupsp = set_afs_xsetgroups_syscall(afs_xsetgroups);
487     sys32_setgroupsp = set_afs_xsetgroups_syscall32(afs32_xsetgroups);
488 #endif
489
490     osi_sysctl_init();
491
492     return 0;
493 }
494
495 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
496 void __exit
497 afs_cleanup(void)
498 #else
499 void
500 cleanup_module(void)
501 #endif
502 {
503     struct task_struct *t;
504
505     osi_sysctl_clean();
506
507 #if defined(AFS_IA64_LINUX20_ENV)
508     sys_call_table[__NR_setgroups - 1024] =
509         POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
510     sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
511 #else /* AFS_IA64_LINUX20_ENV */
512     sys_call_table[__NR_setgroups] = POINTER2SYSCALL sys_setgroupsp;
513     sys_call_table[__NR_afs_syscall] = afs_ni_syscall;
514 # ifdef AFS_SPARC64_LINUX20_ENV
515     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
516     sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
517 # endif
518 # if defined(__NR_setgroups32)
519     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
520 # ifdef AFS_SPARC64_LINUX20_ENV
521     sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL sys32_setgroups32p;
522 # endif
523 # endif
524 #endif /* AFS_IA64_LINUX20_ENV */
525 #ifdef AFS_AMD64_LINUX20_ENV
526     if (ia32_sys_call_table) {
527         ia32_sys_call_table[__NR_ia32_setgroups] =
528             POINTER2SYSCALL sys32_setgroupsp;
529         ia32_sys_call_table[__NR_ia32_afs_syscall] =
530             POINTER2SYSCALL ia32_ni_syscall;
531 # if defined(__NR_setgroups32)
532         ia32_sys_call_table[__NR_ia32_setgroups32] =
533             POINTER2SYSCALL sys32_setgroups32p;
534 #endif
535     }
536 #endif
537 #ifdef AFS_PPC64_LINUX20_ENV
538     set_afs_syscall(afs_ni_syscall);
539     set_afs_xsetgroups_syscall(sys_setgroupsp);
540     set_afs_xsetgroups_syscall32(sys32_setgroupsp);
541 #endif
542     unregister_filesystem(&afs_fs_type);
543
544     osi_linux_free_inode_pages();       /* Invalidate all pages using AFS inodes. */
545     osi_linux_free_afs_memory();
546
547     return;
548 }
549
550 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
551 module_init(afs_init);
552 module_exit(afs_cleanup);
553 #endif
554
555
556 #if !defined(AFS_LINUX24_ENV)
557 static long
558 get_page_offset(void)
559 {
560 #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)
561     return PAGE_OFFSET;
562 #else
563     struct task_struct *p, *q;
564
565     /* search backward thru the circular list */
566 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
567     read_lock(&tasklist_lock);
568 #endif
569     /* search backward thru the circular list */
570 #ifdef DEFINED_PREV_TASK
571     for (q = current; p = q; q = prev_task(p)) {
572 #else
573     for (p = current; p; p = p->prev_task) {
574 #endif
575         if (p->pid == 1) {
576 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
577             read_unlock(&tasklist_lock);
578 #endif
579             return p->addr_limit.seg;
580         }
581     }
582
583 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
584     read_unlock(&tasklist_lock);
585 #endif
586     return 0;
587 #endif
588 }
589 #endif /* !AFS_LINUX24_ENV */