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