2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Linux module support routines.
14 #include <afsconfig.h>
15 #include "afs/param.h"
19 #include "afs/sysincludes.h"
20 #include "afsincludes.h"
21 #include "h/unistd.h" /* For syscall numbers. */
24 #include <linux/module.h>
25 #include <linux/slab.h>
26 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
27 #include <linux/init.h>
32 #ifdef AFS_SPARC64_LINUX24_ENV
33 #define __NR_setgroups32 82 /* This number is not exported for some bizarre reason. */
36 asmlinkage int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
37 asmlinkage int (*sys_killp)(int pid, int signal);
38 asmlinkage long (*sys_setgroupsp)(int gidsetsize, gid_t *grouplist);
40 #ifdef AFS_SPARC64_LINUX20_ENV
41 extern unsigned int sys_call_table[]; /* changed to uint because SPARC64 has syscaltable of 32bit items */
43 extern void * sys_call_table[]; /* safer for other linuces */
45 extern struct file_system_type afs_file_system;
47 static long get_page_offset(void);
49 #if defined(AFS_LINUX24_ENV)
50 DECLARE_MUTEX(afs_global_lock);
52 struct semaphore afs_global_lock = MUTEX;
54 int afs_global_owner = 0;
55 unsigned long afs_linux_page_offset = 0; /* contains the PAGE_OFFSET value */
57 /* Since sys_ni_syscall is not exported, I need to cache it in order to restore
60 #ifdef AFS_SPARC64_LINUX20_ENV
61 static unsigned int afs_ni_syscall = 0;
63 static void* afs_ni_syscall = 0;
66 #ifdef AFS_SPARC64_LINUX20_ENV
67 static unsigned int afs_ni_syscall32 = 0;
68 asmlinkage int (*sys32_setgroupsp)(int gidsetsize, __kernel_gid_t32 *grouplist);
69 #if defined(__NR_setgroups32)
70 asmlinkage int (*sys32_setgroups32p)(int gidsetsize, __kernel_gid_t32 *grouplist);
72 extern unsigned int sys_call_table32[];
74 asmlinkage int afs_syscall32(long syscall, long parm1, long parm2, long parm3,
75 long parm4, long parm5)
77 __asm__ __volatile__ ("
88 #ifdef AFS_IA64_LINUX20_ENV
91 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
93 __asm__ __volatile__ ("
94 alloc r42 = ar.pfs, 8, 3, 6, 0
95 mov r41 = b0 /* save rp */
101 mov out5 = gp /* save gp */
105 addl r15=.fptr_afs_syscall-.L1,r3
113 br.call.sptk.many b0 = b6
117 mov gp = r48 /* restore gp */
120 data8 @fptr(afs_syscall)
125 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
127 __asm__ __volatile__ ("
128 alloc r42 = ar.pfs, 8, 3, 6, 0
129 mov r41 = b0 /* save rp */
135 mov out5 = gp /* save gp */
139 addl r15=.fptr_afs_xsetgroups - .L2,r3
147 br.call.sptk.many b0 = b6
151 mov gp = r48 /* restore gp */
153 .fptr_afs_xsetgroups:
154 data8 @fptr(afs_xsetgroups)
164 #endif /* AFS_IA64_LINUX20_ENV */
166 #ifdef AFS_LINUX24_ENV
167 asmlinkage int (*sys_setgroups32p)(int gidsetsize, __kernel_gid32_t *grouplist);
170 #ifdef AFS_SPARC64_LINUX20_ENV
171 #define POINTER2SYSCALL (unsigned int)(unsigned long)
172 #define SYSCALL2POINTER (void *)(long)
174 #define POINTER2SYSCALL (void *)
175 #define SYSCALL2POINTER (void *)
178 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
179 int __init afs_init(void)
181 int init_module(void)
184 #if defined(AFS_IA64_LINUX20_ENV)
185 unsigned long kernel_gp;
186 static struct fptr sys_kill, sys_settimeofday, sys_setgroups;
188 extern int afs_syscall();
189 extern long afs_xsetgroups();
190 #if defined(__NR_setgroups32)
191 extern int afs_xsetgroups32();
193 #ifdef AFS_SPARC64_LINUX20_ENV
194 extern int afs32_xsetgroups();
195 #if defined(__NR_setgroups32)
196 extern int afs32_xsetgroups32();
200 RWLOCK_INIT(&afs_xosi, "afs_xosi");
202 /* obtain PAGE_OFFSET value */
203 afs_linux_page_offset = get_page_offset();
205 #ifndef AFS_S390_LINUX22_ENV
206 if (afs_linux_page_offset == 0) {
207 /* couldn't obtain page offset so can't continue */
208 printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
213 /* Initialize pointers to kernel syscalls. */
214 #if defined(AFS_IA64_LINUX20_ENV)
215 kernel_gp = ((struct fptr *)printk)->gp;
217 sys_settimeofdayp = (void *) &sys_settimeofday;
218 sys_killp = (void *) &sys_kill;
220 ((struct fptr *)sys_settimeofdayp)->ip =
221 SYSCALL2POINTER sys_call_table[__NR_settimeofday - 1024];
222 ((struct fptr *)sys_settimeofdayp)->gp = kernel_gp;
224 ((struct fptr *)sys_killp)->ip =
225 SYSCALL2POINTER sys_call_table[__NR_kill - 1024];
226 ((struct fptr *)sys_killp)->gp = kernel_gp;
227 #else /* !AFS_IA64_LINUX20_ENV */
228 sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
229 sys_killp = SYSCALL2POINTER sys_call_table[__NR_kill];
230 #endif /* AFS_IA64_LINUX20_ENV */
232 /* setup AFS entry point. */
234 #if defined(AFS_IA64_LINUX20_ENV)
235 SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
237 SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
240 printf("AFS syscall entry point already in use!\n");
245 #if defined(AFS_IA64_LINUX20_ENV)
246 afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
247 sys_call_table[__NR_afs_syscall - 1024] = POINTER2SYSCALL ((struct fptr *)afs_syscall_stub)->ip;
248 #else /* AFS_IA64_LINUX20_ENV */
249 afs_ni_syscall = sys_call_table[__NR_afs_syscall];
250 sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
251 # ifdef AFS_SPARC64_LINUX20_ENV
252 afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
253 sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
255 #endif /* AFS_IA64_LINUX20_ENV */
258 register_filesystem(&afs_file_system);
260 /* Intercept setgroups calls */
261 #if defined(AFS_IA64_LINUX20_ENV)
262 sys_setgroupsp = (void *) &sys_setgroups;
264 ((struct fptr *)sys_setgroupsp)->ip =
265 SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
266 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
268 sys_call_table[__NR_setgroups - 1024] = POINTER2SYSCALL ((struct fptr *)afs_xsetgroups_stub)->ip;
269 #else /* AFS_IA64_LINUX20_ENV */
270 sys_setgroupsp = SYSCALL2POINTER sys_call_table[__NR_setgroups];
271 sys_call_table[__NR_setgroups] = POINTER2SYSCALL afs_xsetgroups;
272 # ifdef AFS_SPARC64_LINUX20_ENV
273 sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
274 sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
276 # if defined(__NR_setgroups32)
277 sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
278 sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
279 # ifdef AFS_SPARC64_LINUX20_ENV
280 sys32_setgroups32p = SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
281 sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL afs32_xsetgroups32;
284 #endif /* AFS_IA64_LINUX20_ENV */
291 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
292 void __exit afs_cleanup(void)
294 void cleanup_module(void)
297 struct task_struct *t;
301 #if defined(AFS_IA64_LINUX20_ENV)
302 sys_call_table[__NR_setgroups - 1024] = POINTER2SYSCALL ((struct fptr *) sys_setgroupsp)->ip;
303 sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
304 #else /* AFS_IA64_LINUX20_ENV */
305 sys_call_table[__NR_setgroups] = POINTER2SYSCALL sys_setgroupsp;
306 sys_call_table[__NR_afs_syscall] = afs_ni_syscall;
307 # ifdef AFS_SPARC64_LINUX20_ENV
308 sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
309 sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
311 # if defined(__NR_setgroups32)
312 sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
313 # ifdef AFS_SPARC64_LINUX20_ENV
314 sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL sys32_setgroups32p;
317 #endif /* AFS_IA64_LINUX20_ENV */
318 unregister_filesystem(&afs_file_system);
320 osi_linux_free_inode_pages(); /* Invalidate all pages using AFS inodes. */
321 osi_linux_free_afs_memory();
326 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
327 module_init(afs_init);
328 module_exit(afs_cleanup);
332 static long get_page_offset(void)
334 #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)
337 struct task_struct *p;
339 /* search backward thru the circular list */
340 for(p = current; p; p = p->prev_task)
342 return p->addr_limit.seg;