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