Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-module.c
1 #define DEBUG_SUBSYSTEM S_LNET
2
3 #include <libcfs/libcfs.h>
4
5 #define LNET_MINOR 240
6
7 int libcfs_ioctl_getdata(char *buf, char *end, void *arg)
8 {
9         struct libcfs_ioctl_hdr   *hdr;
10         struct libcfs_ioctl_data  *data;
11         int err;
12         ENTRY;
13
14         hdr = (struct libcfs_ioctl_hdr *)buf;
15         data = (struct libcfs_ioctl_data *)buf;
16
17         err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
18         if (err)
19                 RETURN(err);
20
21         if (hdr->ioc_version != LIBCFS_IOCTL_VERSION) {
22                 CERROR("PORTALS: version mismatch kernel vs application\n");
23                 RETURN(-EINVAL);
24         }
25
26         if (hdr->ioc_len + buf >= end) {
27                 CERROR("PORTALS: user buffer exceeds kernel buffer\n");
28                 RETURN(-EINVAL);
29         }
30
31
32         if (hdr->ioc_len < sizeof(struct libcfs_ioctl_data)) {
33                 CERROR("PORTALS: user buffer too small for ioctl\n");
34                 RETURN(-EINVAL);
35         }
36
37         err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
38         if (err)
39                 RETURN(err);
40
41         if (libcfs_ioctl_is_invalid(data)) {
42                 CERROR("PORTALS: ioctl not correctly formatted\n");
43                 RETURN(-EINVAL);
44         }
45
46         if (data->ioc_inllen1)
47                 data->ioc_inlbuf1 = &data->ioc_bulk[0];
48
49         if (data->ioc_inllen2)
50                 data->ioc_inlbuf2 = &data->ioc_bulk[0] +
51                         size_round(data->ioc_inllen1);
52
53         RETURN(0);
54 }
55
56 int libcfs_ioctl_popdata(void *arg, void *data, int size)
57 {
58         if (copy_to_user((char *)arg, data, size))
59                 return -EFAULT;
60         return 0;
61 }
62
63 extern struct cfs_psdev_ops          libcfs_psdev_ops;
64
65 static int
66 libcfs_psdev_open(struct inode * inode, struct file * file)
67 {
68         struct libcfs_device_userstate **pdu = NULL;
69         int    rc = 0;
70
71         if (!inode)
72                 return (-EINVAL);
73         pdu = (struct libcfs_device_userstate **)&file->private_data;
74         if (libcfs_psdev_ops.p_open != NULL)
75                 rc = libcfs_psdev_ops.p_open(0, (void *)pdu);
76         else
77                 return (-EPERM);
78         return rc;
79 }
80
81 /* called when closing /dev/device */
82 static int
83 libcfs_psdev_release(struct inode * inode, struct file * file)
84 {
85         struct libcfs_device_userstate *pdu;
86         int    rc = 0;
87
88         if (!inode)
89                 return (-EINVAL);
90         pdu = file->private_data;
91         if (libcfs_psdev_ops.p_close != NULL)
92                 rc = libcfs_psdev_ops.p_close(0, (void *)pdu);
93         else
94                 rc = -EPERM;
95         return rc;
96 }
97
98 static int
99 libcfs_ioctl(struct inode *inode, struct file *file,
100              unsigned int cmd, unsigned long arg)
101 {
102         struct cfs_psdev_file    pfile;
103         int    rc = 0;
104
105         if (current->fsuid != 0)
106                 return -EACCES;
107
108         if ( _IOC_TYPE(cmd) != IOC_LIBCFS_TYPE ||
109              _IOC_NR(cmd) < IOC_LIBCFS_MIN_NR  ||
110              _IOC_NR(cmd) > IOC_LIBCFS_MAX_NR ) {
111                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
112                        _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
113                 return (-EINVAL);
114         }
115
116         /* Handle platform-dependent IOC requests */
117         switch (cmd) {
118         case IOC_LIBCFS_PANIC:
119                 if (!capable (CAP_SYS_BOOT))
120                         return (-EPERM);
121                 panic("debugctl-invoked panic");
122                 return (0);
123         case IOC_LIBCFS_MEMHOG:
124                 if (!capable (CAP_SYS_ADMIN))
125                         return -EPERM;
126                 /* go thought */
127         }
128
129         pfile.off = 0;
130         pfile.private_data = file->private_data;
131         if (libcfs_psdev_ops.p_ioctl != NULL)
132                 rc = libcfs_psdev_ops.p_ioctl(&pfile, cmd, (void *)arg);
133         else
134                 rc = -EPERM;
135         return (rc);
136 }
137
138 static struct file_operations libcfs_fops = {
139         ioctl:   libcfs_ioctl,
140         open:    libcfs_psdev_open,
141         release: libcfs_psdev_release
142 };
143
144 cfs_psdev_t libcfs_dev = {
145         LNET_MINOR,
146         "lnet",
147         &libcfs_fops
148 };
149
150