Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2012, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | */ | |
36 | ||
37 | #define DEBUG_SUBSYSTEM S_LNET | |
38 | ||
39 | #include <linux/libcfs/libcfs.h> | |
40 | ||
41 | #define LNET_MINOR 240 | |
42 | ||
43 | int libcfs_ioctl_getdata(char *buf, char *end, void *arg) | |
44 | { | |
45 | struct libcfs_ioctl_hdr *hdr; | |
46 | struct libcfs_ioctl_data *data; | |
47 | int err; | |
d7e09d03 PT |
48 | |
49 | hdr = (struct libcfs_ioctl_hdr *)buf; | |
50 | data = (struct libcfs_ioctl_data *)buf; | |
51 | ||
52 | err = copy_from_user(buf, (void *)arg, sizeof(*hdr)); | |
53 | if (err) | |
0a3bdb00 | 54 | return err; |
d7e09d03 PT |
55 | |
56 | if (hdr->ioc_version != LIBCFS_IOCTL_VERSION) { | |
57 | CERROR("PORTALS: version mismatch kernel vs application\n"); | |
0a3bdb00 | 58 | return -EINVAL; |
d7e09d03 PT |
59 | } |
60 | ||
61 | if (hdr->ioc_len + buf >= end) { | |
62 | CERROR("PORTALS: user buffer exceeds kernel buffer\n"); | |
0a3bdb00 | 63 | return -EINVAL; |
d7e09d03 PT |
64 | } |
65 | ||
66 | ||
67 | if (hdr->ioc_len < sizeof(struct libcfs_ioctl_data)) { | |
68 | CERROR("PORTALS: user buffer too small for ioctl\n"); | |
0a3bdb00 | 69 | return -EINVAL; |
d7e09d03 PT |
70 | } |
71 | ||
72 | err = copy_from_user(buf, (void *)arg, hdr->ioc_len); | |
73 | if (err) | |
0a3bdb00 | 74 | return err; |
d7e09d03 PT |
75 | |
76 | if (libcfs_ioctl_is_invalid(data)) { | |
77 | CERROR("PORTALS: ioctl not correctly formatted\n"); | |
0a3bdb00 | 78 | return -EINVAL; |
d7e09d03 PT |
79 | } |
80 | ||
81 | if (data->ioc_inllen1) | |
82 | data->ioc_inlbuf1 = &data->ioc_bulk[0]; | |
83 | ||
84 | if (data->ioc_inllen2) | |
85 | data->ioc_inlbuf2 = &data->ioc_bulk[0] + | |
86 | cfs_size_round(data->ioc_inllen1); | |
87 | ||
0a3bdb00 | 88 | return 0; |
d7e09d03 PT |
89 | } |
90 | ||
91 | int libcfs_ioctl_popdata(void *arg, void *data, int size) | |
92 | { | |
93 | if (copy_to_user((char *)arg, data, size)) | |
94 | return -EFAULT; | |
95 | return 0; | |
96 | } | |
97 | ||
98 | extern struct cfs_psdev_ops libcfs_psdev_ops; | |
99 | ||
100 | static int | |
101 | libcfs_psdev_open(struct inode * inode, struct file * file) | |
102 | { | |
103 | struct libcfs_device_userstate **pdu = NULL; | |
104 | int rc = 0; | |
105 | ||
106 | if (!inode) | |
107 | return (-EINVAL); | |
108 | pdu = (struct libcfs_device_userstate **)&file->private_data; | |
109 | if (libcfs_psdev_ops.p_open != NULL) | |
110 | rc = libcfs_psdev_ops.p_open(0, (void *)pdu); | |
111 | else | |
112 | return (-EPERM); | |
113 | return rc; | |
114 | } | |
115 | ||
116 | /* called when closing /dev/device */ | |
117 | static int | |
118 | libcfs_psdev_release(struct inode * inode, struct file * file) | |
119 | { | |
120 | struct libcfs_device_userstate *pdu; | |
121 | int rc = 0; | |
122 | ||
123 | if (!inode) | |
124 | return (-EINVAL); | |
125 | pdu = file->private_data; | |
126 | if (libcfs_psdev_ops.p_close != NULL) | |
127 | rc = libcfs_psdev_ops.p_close(0, (void *)pdu); | |
128 | else | |
129 | rc = -EPERM; | |
130 | return rc; | |
131 | } | |
132 | ||
133 | static long libcfs_ioctl(struct file *file, | |
134 | unsigned int cmd, unsigned long arg) | |
135 | { | |
136 | struct cfs_psdev_file pfile; | |
137 | int rc = 0; | |
138 | ||
4b1a25f0 | 139 | if (!capable(CAP_SYS_ADMIN)) |
d7e09d03 PT |
140 | return -EACCES; |
141 | ||
142 | if ( _IOC_TYPE(cmd) != IOC_LIBCFS_TYPE || | |
143 | _IOC_NR(cmd) < IOC_LIBCFS_MIN_NR || | |
144 | _IOC_NR(cmd) > IOC_LIBCFS_MAX_NR ) { | |
145 | CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n", | |
146 | _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); | |
147 | return (-EINVAL); | |
148 | } | |
149 | ||
150 | /* Handle platform-dependent IOC requests */ | |
151 | switch (cmd) { | |
152 | case IOC_LIBCFS_PANIC: | |
153 | if (!cfs_capable(CFS_CAP_SYS_BOOT)) | |
154 | return (-EPERM); | |
155 | panic("debugctl-invoked panic"); | |
156 | return (0); | |
157 | case IOC_LIBCFS_MEMHOG: | |
158 | if (!cfs_capable(CFS_CAP_SYS_ADMIN)) | |
159 | return -EPERM; | |
160 | /* go thought */ | |
161 | } | |
162 | ||
163 | pfile.off = 0; | |
164 | pfile.private_data = file->private_data; | |
165 | if (libcfs_psdev_ops.p_ioctl != NULL) | |
166 | rc = libcfs_psdev_ops.p_ioctl(&pfile, cmd, (void *)arg); | |
167 | else | |
168 | rc = -EPERM; | |
169 | return (rc); | |
170 | } | |
171 | ||
172 | static struct file_operations libcfs_fops = { | |
805e517a EG |
173 | .unlocked_ioctl = libcfs_ioctl, |
174 | .open = libcfs_psdev_open, | |
175 | .release = libcfs_psdev_release, | |
d7e09d03 PT |
176 | }; |
177 | ||
c0426cf7 GKH |
178 | struct miscdevice libcfs_dev = { |
179 | .minor = LNET_MINOR, | |
180 | .name = "lnet", | |
181 | .fops = &libcfs_fops, | |
d7e09d03 | 182 | }; |