LINUX: Avoid duplicate mntget in afs_linux_raw_open
[openafs.git] / src / afs / LINUX / osi_ioctl.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
18 #include <linux/module.h> /* early to avoid printf->printk mapping */
19 #include "afs/sysincludes.h"
20 #include "afsincludes.h"
21 #include <linux/unistd.h>               /* For syscall numbers. */
22 #include <linux/mm.h>
23
24 #ifdef AFS_AMD64_LINUX20_ENV
25 #include <asm/ia32_unistd.h>
26 #endif
27
28 #if defined(AFS_SPARC64_LINUX26_ENV) && defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
29 #include <linux/ioctl32.h>
30 #endif
31
32 #include <linux/proc_fs.h>
33 #include <linux/slab.h>
34 #include <linux/init.h>
35 #include <linux/sched.h>
36 #include <linux/kernel.h>
37
38 extern struct proc_dir_entry *openafs_procfs;
39 #if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
40 static int ioctl32_done;
41 #endif
42
43 extern asmlinkage long
44 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
45
46 static int
47 afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
48           unsigned long arg)
49 {
50
51     struct afsprocdata sysargs;
52 #ifdef NEED_IOCTL32
53     struct afsprocdata32 sysargs32;
54 #endif
55
56     if (cmd != VIOC_SYSCALL && cmd != VIOC_SYSCALL32) return -EINVAL;
57
58 #ifdef NEED_IOCTL32
59 # if defined(AFS_S390X_LINUX26_ENV)
60     if (test_thread_flag(TIF_31BIT))
61 # elif defined(AFS_AMD64_LINUX20_ENV)
62     if (test_thread_flag(TIF_IA32))
63 # else
64     if (test_thread_flag(TIF_32BIT))
65 # endif /* AFS_S390X_LINUX26_ENV */
66     {
67         if (copy_from_user(&sysargs32, (void *)arg,
68                            sizeof(struct afsprocdata32)))
69             return -EFAULT;
70
71         return afs_syscall((unsigned long)sysargs32.syscall,
72                            (unsigned long)sysargs32.param1,
73                            (unsigned long)sysargs32.param2,
74                            (unsigned long)sysargs32.param3,
75                            (unsigned long)sysargs32.param4);
76     } else
77 #endif /* NEED_IOCTL32 */
78     {
79         if (copy_from_user(&sysargs, (void *)arg, sizeof(struct afsprocdata)))
80             return -EFAULT;
81
82         return afs_syscall(sysargs.syscall, sysargs.param1,
83                            sysargs.param2, sysargs.param3, sysargs.param4);
84     }
85 }
86
87 #if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COMPAT_IOCTL)
88 static long afs_unlocked_ioctl(struct file *file, unsigned int cmd,
89                                unsigned long arg) {
90     return afs_ioctl(FILE_INODE(file), file, cmd, arg);
91 }
92 #endif
93
94 static struct file_operations afs_syscall_fops = {
95 #ifdef HAVE_UNLOCKED_IOCTL
96     .unlocked_ioctl = afs_unlocked_ioctl,
97 #else
98     .ioctl = afs_ioctl,
99 #endif
100 #ifdef HAVE_COMPAT_IOCTL
101     .compat_ioctl = afs_unlocked_ioctl,
102 #endif
103 };
104
105 void
106 osi_ioctl_init(void)
107 {
108     struct proc_dir_entry *entry;
109
110     entry = create_proc_entry(PROC_SYSCALL_NAME, 0666, openafs_procfs);
111     entry->proc_fops = &afs_syscall_fops;
112 #if defined(STRUCT_PROC_DIR_ENTRY_HAS_OWNER)
113     entry->owner = THIS_MODULE;
114 #endif
115
116 #if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
117     if (register_ioctl32_conversion(VIOC_SYSCALL32, NULL) == 0) 
118         ioctl32_done = 1;
119 #endif
120 }
121
122 void
123 osi_ioctl_clean(void)
124 {
125     remove_proc_entry(PROC_SYSCALL_NAME, openafs_procfs);
126 #if defined(NEED_IOCTL32) && !defined(HAVE_COMPAT_IOCTL)
127     if (ioctl32_done)
128             unregister_ioctl32_conversion(VIOC_SYSCALL32);
129 #endif
130 }