linux-syscall-asmlinkage-20040621
[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 extern asmlinkage long
159 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
160
161 static int
162 afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
163           unsigned long arg)
164 {
165
166     struct afsprocdata sysargs;
167
168     if (cmd != VIOC_SYSCALL) return -EINVAL;
169
170     if (copy_from_user(&sysargs, (void *)arg, sizeof(struct afsprocdata)))
171         return -EFAULT;
172
173     return afs_syscall(sysargs.syscall, sysargs.param1,
174                        sysargs.param2, sysargs.param3, sysargs.param4);
175 }
176
177 #ifdef AFS_IA64_LINUX20_ENV
178
179 asmlinkage long
180 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
181 {
182     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
183                          "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 */
184                          ";;\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 */
185                          "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
186                          "data8 @fptr(afs_syscall)");
187 }
188
189 asmlinkage long
190 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
191 {
192     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t"        /* save rp */
193                          "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 */
194                          ";;\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 */
195                          "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
196                          "data8 @fptr(afs_xsetgroups)");
197 }
198
199 struct fptr {
200     void *ip;
201     unsigned long gp;
202 };
203
204 #endif /* AFS_IA64_LINUX20_ENV */
205
206 #ifdef AFS_LINUX24_ENV
207 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
208                                     __kernel_gid32_t * grouplist);
209 #endif /* AFS_LINUX24_ENV */
210
211 #ifdef AFS_SPARC64_LINUX20_ENV
212 #define POINTER2SYSCALL (unsigned int)(unsigned long)
213 #define SYSCALL2POINTER (void *)(long)
214 #else
215 #define POINTER2SYSCALL (void *)
216 #define SYSCALL2POINTER (void *)
217 #endif
218
219 #ifdef AFS_PPC64_LINUX20_ENV
220 extern void *set_afs_syscall(void*);
221 extern void *set_afs_xsetgroups_syscall(void*);
222 extern void *set_afs_xsetgroups_syscall32(void*);
223 #endif
224
225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
226 int __init
227 afs_init(void)
228 #else
229 int
230 init_module(void)
231 #endif
232 {
233 #if defined(AFS_IA64_LINUX20_ENV)
234     unsigned long kernel_gp = 0;
235     static struct fptr sys_setgroups;
236 #endif /* defined(AFS_IA64_LINUX20_ENV) */
237     extern long afs_xsetgroups();
238 #if defined(__NR_setgroups32)
239     extern int afs_xsetgroups32();
240 #endif /* __NR_setgroups32 */
241 #if defined(AFS_SPARC64_LINUX20_ENV) || defined (AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
242     extern int afs32_xsetgroups();
243 #if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV))
244     extern int afs32_xsetgroups32();
245 #endif /* defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV) */
246 #if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV))
247     extern int afs32_xsetgroups32();
248 #endif /* (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV) */
249 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV || AFS_PPC64_LINUX20_ENV */
250
251 #if !defined(EXPORTED_SYS_CALL_TABLE) || (defined(AFS_AMD64_LINUX20_ENV) && !defined(EXPORTED_IA32_SYS_CALL_TABLE))
252     unsigned long *ptr;
253     unsigned long offset=0;
254     unsigned long datalen=0;
255     int ret;
256     unsigned long token=0;
257     char *mod_name;
258     unsigned long mod_start=0;
259     unsigned long mod_end=0;
260     char *sec_name;
261     unsigned long sec_start=0;
262     unsigned long sec_end=0;
263     char *sym_name;
264     unsigned long sym_start=0;
265     unsigned long sym_end=0;
266 #endif /* EXPORTED_SYS_CALL_TABLE */
267
268     RWLOCK_INIT(&afs_xosi, "afs_xosi");
269
270 #if !defined(AFS_LINUX24_ENV)
271     /* obtain PAGE_OFFSET value */
272     afs_linux_page_offset = get_page_offset();
273
274 #ifndef AFS_S390_LINUX22_ENV
275     if (afs_linux_page_offset == 0) {
276         /* couldn't obtain page offset so can't continue */
277         printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
278         return -EIO;
279     }
280 #endif /* AFS_S390_LINUX22_ENV */
281 #endif /* !defined(AFS_LINUX24_ENV) */
282
283 #ifndef EXPORTED_SYS_CALL_TABLE
284     sys_call_table = 0;
285
286 #ifdef EXPORTED_KALLSYMS_SYMBOL
287     ret = 1;
288     token = 0;
289     while (ret) {
290         sym_start = 0;
291         ret =
292             kallsyms_symbol_to_address("sys_call_table", &token, &mod_name,
293                                        &mod_start, &mod_end, &sec_name,
294                                        &sec_start, &sec_end, &sym_name,
295                                        &sym_start, &sym_end);
296         if (ret && !strcmp(mod_name, "kernel"))
297             break;
298     }
299     if (ret && sym_start) {
300         sys_call_table = sym_start;
301     }
302 #elif defined(EXPORTED_KALLSYMS_ADDRESS)
303     ret =
304         kallsyms_address_to_symbol((unsigned long)&init_mm, &mod_name,
305                                    &mod_start, &mod_end, &sec_name,
306                                    &sec_start, &sec_end, &sym_name,
307                                    &sym_start, &sym_end);
308     ptr = (unsigned long *)sec_start;
309     datalen = (sec_end - sec_start) / sizeof(unsigned long);
310 #elif defined(AFS_IA64_LINUX20_ENV)
311     ptr = (unsigned long *)(&sys_close - 0x180000);
312     datalen = 0x180000 / sizeof(ptr);
313 #elif defined(AFS_AMD64_LINUX20_ENV)
314     ptr = (unsigned long *)&init_mm;
315     datalen = 0x360000 / sizeof(ptr);
316 #else
317     ptr = (unsigned long *)&init_mm;
318     datalen = 16384;
319 #endif
320     for (offset = 0; offset < datalen; ptr++, offset++) {
321 #if defined(AFS_IA64_LINUX20_ENV)
322         unsigned long close_ip =
323             (unsigned long)((struct fptr *)&sys_close)->ip;
324         unsigned long chdir_ip =
325             (unsigned long)((struct fptr *)&sys_chdir)->ip;
326         unsigned long write_ip =
327             (unsigned long)((struct fptr *)&sys_write)->ip;
328         if (ptr[0] == close_ip && ptr[__NR_chdir - __NR_close] == chdir_ip
329             && ptr[__NR_write - __NR_close] == write_ip) {
330             sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]);
331             break;
332         }
333 #elif defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE)
334         if (ptr[0] == (unsigned long)&sys_close
335             && ptr[__NR_wait4 - __NR_close] == (unsigned long)&sys_wait4) {
336             sys_call_table = ptr - __NR_close;
337             break;
338         }
339 #elif defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE)
340         if (ptr[0] == (unsigned long)&sys_close
341             && ptr[__NR_chdir - __NR_close] == (unsigned long)&sys_chdir) {
342             sys_call_table = ptr - __NR_close;
343             break;
344         }
345 #elif defined(EXPORTED_SYS_OPEN)
346         if (ptr[0] == (unsigned long)&sys_exit
347             && ptr[__NR_open - __NR_exit] == (unsigned long)&sys_open) {
348             sys_call_table = ptr - __NR_exit;
349             break;
350         }
351 #else /* EXPORTED_SYS_OPEN */
352         break;
353 #endif /* EXPORTED_KALLSYMS_ADDRESS */
354     }
355 #ifdef EXPORTED_KALLSYMS_ADDRESS
356     ret =
357         kallsyms_address_to_symbol((unsigned long)sys_call_table, &mod_name,
358                                    &mod_start, &mod_end, &sec_name,
359                                    &sec_start, &sec_end, &sym_name,
360                                    &sym_start, &sym_end);
361     if (ret && strcmp(sym_name, "sys_call_table"))
362         sys_call_table = 0;
363 #endif /* EXPORTED_KALLSYMS_ADDRESS */
364     if (!sys_call_table) {
365         printf("Failed to find address of sys_call_table\n");
366     } else {
367         printf("Found sys_call_table at %x\n", sys_call_table);
368 #ifdef AFS_SPARC64_LINUX20_ENV
369         error cant support this yet.;
370 #endif /* AFS_SPARC64_LINUX20_ENV */
371 #endif /* EXPORTED_SYS_CALL_TABLE */
372
373 #ifdef AFS_AMD64_LINUX20_ENV
374 #ifndef EXPORTED_IA32_SYS_CALL_TABLE
375         ia32_sys_call_table = 0;
376 #ifdef EXPORTED_KALLSYMS_SYMBOL
377         ret = 1;
378         token = 0;
379         while (ret) {
380             sym_start = 0;
381             ret = kallsyms_symbol_to_address("ia32_sys_call_table", &token,
382                                              &mod_name, &mod_start, &mod_end,
383                                              &sec_name, &sec_start, &sec_end,
384                                              &sym_name, &sym_start, &sym_end);
385             if (ret && !strcmp(mod_name, "kernel"))
386                 break;
387         }
388         if (ret && sym_start) {
389             ia32_sys_call_table = sym_start;
390         }
391 #else /* EXPORTED_KALLSYMS_SYMBOL */
392 #ifdef EXPORTED_KALLSYMS_ADDRESS
393         ret = kallsyms_address_to_symbol((unsigned long)
394                                          &interruptible_sleep_on,
395                                          &mod_name, &mod_start, &mod_end,
396                                          &sec_name, &sec_start, &sec_end,
397                                          &sym_name, &sym_start, &sym_end);
398         ptr = (unsigned long *)sec_start;
399         datalen = (sec_end - sec_start) / sizeof(unsigned long);
400 #else /* EXPORTED_KALLSYMS_ADDRESS */
401 #if defined(AFS_AMD64_LINUX20_ENV)
402         ptr = (unsigned long *)&interruptible_sleep_on;
403         datalen = 0x180000 / sizeof(ptr);
404 #else /* AFS_AMD64_LINUX20_ENV */
405         ptr = (unsigned long *)&interruptible_sleep_on;
406         datalen = 16384;
407 #endif /* AFS_AMD64_LINUX20_ENV */
408 #endif /* EXPORTED_KALLSYMS_ADDRESS */
409         for (offset = 0; offset < datalen; ptr++, offset++) {
410             if (ptr[0] == (unsigned long)&sys_exit
411                 && ptr[__NR_ia32_open - __NR_ia32_exit] ==
412                 (unsigned long)&sys_open) {
413                     ia32_sys_call_table = ptr - __NR_ia32_exit;
414                     break;
415             }
416         }
417 #ifdef EXPORTED_KALLSYMS_ADDRESS
418         ret = kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table,
419                                          &mod_name, &mod_start, &mod_end,
420                                          &sec_name, &sec_start, &sec_end,
421                                          &sym_name, &sym_start, &sym_end);
422         if (ret && strcmp(sym_name, "ia32_sys_call_table"))
423             ia32_sys_call_table = 0;
424 #endif /* EXPORTED_KALLSYMS_ADDRESS */
425 #endif /* EXPORTED_KALLSYMS_SYMBOL */
426         if (!ia32_sys_call_table) {
427             printf("Warning: Failed to find address of ia32_sys_call_table\n");
428         } else {
429             printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
430         }
431 #else
432         printf("Found ia32_sys_call_table at %x\n", ia32_sys_call_table);
433 #endif /* IA32_SYS_CALL_TABLE */
434 #endif
435
436         /* Initialize pointers to kernel syscalls. */
437 #if !defined(AFS_LINUX24_ENV)
438         sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
439 #endif /* AFS_IA64_LINUX20_ENV */
440
441         /* setup AFS entry point. */
442         if (
443 #if defined(AFS_IA64_LINUX20_ENV)
444                 SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
445 #else
446                 SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
447 #endif
448                 == afs_syscall) {
449             printf("AFS syscall entry point already in use!\n");
450             return -EBUSY;
451         }
452 #if defined(AFS_IA64_LINUX20_ENV)
453         afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
454         sys_call_table[__NR_afs_syscall - 1024] =
455                 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
456 #else /* AFS_IA64_LINUX20_ENV */
457         afs_ni_syscall = sys_call_table[__NR_afs_syscall];
458         sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
459 #ifdef AFS_SPARC64_LINUX20_ENV
460         afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
461         sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
462 #endif
463 #endif /* AFS_IA64_LINUX20_ENV */
464 #ifdef AFS_AMD64_LINUX20_ENV
465         if (ia32_sys_call_table) {
466             ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall];
467             ia32_sys_call_table[__NR_ia32_afs_syscall] =
468                     POINTER2SYSCALL afs_syscall;
469         }
470 #endif /* AFS_S390_LINUX22_ENV */
471 #ifndef EXPORTED_SYS_CALL_TABLE
472     }
473 #endif /* EXPORTED_SYS_CALL_TABLE */
474     osi_Init();
475     register_filesystem(&afs_fs_type);
476
477     /* Intercept setgroups calls */
478     if (sys_call_table) {
479 #if defined(AFS_IA64_LINUX20_ENV)
480     sys_setgroupsp = (void *)&sys_setgroups;
481
482     ((struct fptr *)sys_setgroupsp)->ip =
483         SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
484     ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
485
486     sys_call_table[__NR_setgroups - 1024] =
487         POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
488 #else /* AFS_IA64_LINUX20_ENV */
489     sys_setgroupsp = SYSCALL2POINTER sys_call_table[__NR_setgroups];
490     sys_call_table[__NR_setgroups] = POINTER2SYSCALL afs_xsetgroups;
491 #ifdef AFS_SPARC64_LINUX20_ENV
492     sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
493     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
494 #endif /* AFS_SPARC64_LINUX20_ENV */
495 #if defined(__NR_setgroups32)
496     sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
497     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
498 #ifdef AFS_SPARC64_LINUX20_ENV
499         sys32_setgroups32p =
500             SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
501         sys_call_table32[__NR_setgroups32] =
502             POINTER2SYSCALL afs32_xsetgroups32;
503 #endif /* AFS_SPARC64_LINUX20_ENV */
504 #endif /* __NR_setgroups32 */
505 #ifdef AFS_AMD64_LINUX20_ENV
506     if (ia32_sys_call_table) {
507         sys32_setgroupsp =
508             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups];
509         ia32_sys_call_table[__NR_ia32_setgroups] =
510             POINTER2SYSCALL afs32_xsetgroups;
511 #if defined(__NR_ia32_setgroups32)
512         sys32_setgroups32p =
513             SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups32];
514         ia32_sys_call_table[__NR_ia32_setgroups32] =
515             POINTER2SYSCALL afs32_xsetgroups32;
516 #endif /* __NR_ia32_setgroups32 */
517     }
518 #endif /* AFS_AMD64_LINUX20_ENV */
519 #endif /* AFS_IA64_LINUX20_ENV */
520
521 #ifdef AFS_PPC64_LINUX20_ENV
522     afs_ni_syscall = set_afs_syscall(afs_syscall);
523     sys_setgroupsp = set_afs_xsetgroups_syscall(afs_xsetgroups);
524     sys32_setgroupsp = set_afs_xsetgroups_syscall32(afs32_xsetgroups);
525 #endif
526     }
527
528     osi_sysctl_init();
529     afsproc_init();
530
531     return 0;
532 }
533
534 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
535 void __exit
536 afs_cleanup(void)
537 #else
538 void
539 cleanup_module(void)
540 #endif
541 {
542     struct task_struct *t;
543
544     osi_sysctl_clean();
545     if (sys_call_table) {
546 #if defined(AFS_IA64_LINUX20_ENV)
547     sys_call_table[__NR_setgroups - 1024] =
548         POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
549     sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
550 #else /* AFS_IA64_LINUX20_ENV */
551     sys_call_table[__NR_setgroups] = POINTER2SYSCALL sys_setgroupsp;
552     sys_call_table[__NR_afs_syscall] = afs_ni_syscall;
553 # ifdef AFS_SPARC64_LINUX20_ENV
554     sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
555     sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
556 # endif
557 # if defined(__NR_setgroups32)
558     sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
559 # ifdef AFS_SPARC64_LINUX20_ENV
560         sys_call_table32[__NR_setgroups32] =
561             POINTER2SYSCALL sys32_setgroups32p;
562 # endif
563 # endif
564 #endif /* AFS_IA64_LINUX20_ENV */
565 #ifdef AFS_AMD64_LINUX20_ENV
566     if (ia32_sys_call_table) {
567         ia32_sys_call_table[__NR_ia32_setgroups] =
568             POINTER2SYSCALL sys32_setgroupsp;
569         ia32_sys_call_table[__NR_ia32_afs_syscall] =
570             POINTER2SYSCALL ia32_ni_syscall;
571 # if defined(__NR_setgroups32)
572         ia32_sys_call_table[__NR_ia32_setgroups32] =
573             POINTER2SYSCALL sys32_setgroups32p;
574 #endif
575     }
576 #endif
577     }
578 #ifdef AFS_PPC64_LINUX20_ENV
579     set_afs_syscall(afs_ni_syscall);
580     set_afs_xsetgroups_syscall(sys_setgroupsp);
581     set_afs_xsetgroups_syscall32(sys32_setgroupsp);
582 #endif
583     unregister_filesystem(&afs_fs_type);
584
585     osi_linux_free_inode_pages();       /* Invalidate all pages using AFS inodes. */
586     osi_linux_free_afs_memory();
587
588     afsproc_exit();
589     return;
590 }
591
592 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
593 module_init(afs_init);
594 module_exit(afs_cleanup);
595 #endif
596
597
598 #if !defined(AFS_LINUX24_ENV)
599 static long
600 get_page_offset(void)
601 {
602 #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)
603     return PAGE_OFFSET;
604 #else
605     struct task_struct *p, *q;
606
607     /* search backward thru the circular list */
608 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
609     read_lock(&tasklist_lock);
610 #endif
611     /* search backward thru the circular list */
612 #ifdef DEFINED_PREV_TASK
613     for (q = current; p = q; q = prev_task(p)) {
614 #else
615     for (p = current; p; p = p->prev_task) {
616 #endif
617         if (p->pid == 1) {
618 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
619             read_unlock(&tasklist_lock);
620 #endif
621             return p->addr_limit.seg;
622         }
623     }
624
625 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
626     read_unlock(&tasklist_lock);
627 #endif
628     return 0;
629 #endif
630 }
631 #endif /* !AFS_LINUX24_ENV */