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