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