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