GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / lustre / lustre / obdclass / linux / linux-module.c
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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2012, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/obdclass/linux/linux-module.c
33  *
34  * Object Devices Class Driver
35  * These are the only exported functions, they provide some generic
36  * infrastructure for managing object devices
37  */
38
39 #define DEBUG_SUBSYSTEM S_CLASS
40
41 #include <linux/module.h>
42 #include <linux/errno.h>
43 #include <linux/kernel.h>
44 #include <linux/major.h>
45 #include <linux/sched.h>
46 #include <linux/lp.h>
47 #include <linux/slab.h>
48 #include <linux/ioport.h>
49 #include <linux/fcntl.h>
50 #include <linux/delay.h>
51 #include <linux/skbuff.h>
52 #include <linux/fs.h>
53 #include <linux/poll.h>
54 #include <linux/list.h>
55 #include <linux/highmem.h>
56 #include <linux/io.h>
57 #include <asm/ioctls.h>
58 #include <linux/uaccess.h>
59 #include <linux/miscdevice.h>
60 #include <linux/seq_file.h>
61 #include <linux/kobject.h>
62
63 #include <linux/libcfs/libcfs.h>
64 #include <uapi/linux/lnet/lnetctl.h>
65 #include <obd_support.h>
66 #include <obd_class.h>
67 #include <lprocfs_status.h>
68 #include <uapi/linux/lustre/lustre_ioctl.h>
69 #include <uapi/linux/lustre/lustre_ver.h>
70
71 #define OBD_MAX_IOCTL_BUFFER    8192
72
73 static int obd_ioctl_is_invalid(struct obd_ioctl_data *data)
74 {
75         if (data->ioc_len > BIT(30)) {
76                 CERROR("OBD ioctl: ioc_len larger than 1<<30\n");
77                 return 1;
78         }
79
80         if (data->ioc_inllen1 > BIT(30)) {
81                 CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n");
82                 return 1;
83         }
84
85         if (data->ioc_inllen2 > BIT(30)) {
86                 CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n");
87                 return 1;
88         }
89
90         if (data->ioc_inllen3 > BIT(30)) {
91                 CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n");
92                 return 1;
93         }
94
95         if (data->ioc_inllen4 > BIT(30)) {
96                 CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n");
97                 return 1;
98         }
99
100         if (data->ioc_inlbuf1 && data->ioc_inllen1 == 0) {
101                 CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n");
102                 return 1;
103         }
104
105         if (data->ioc_inlbuf2 && data->ioc_inllen2 == 0) {
106                 CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n");
107                 return 1;
108         }
109
110         if (data->ioc_inlbuf3 && data->ioc_inllen3 == 0) {
111                 CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n");
112                 return 1;
113         }
114
115         if (data->ioc_inlbuf4 && data->ioc_inllen4 == 0) {
116                 CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n");
117                 return 1;
118         }
119
120         if (data->ioc_pbuf1 && data->ioc_plen1 == 0) {
121                 CERROR("OBD ioctl: pbuf1 pointer but 0 length\n");
122                 return 1;
123         }
124
125         if (data->ioc_pbuf2 && data->ioc_plen2 == 0) {
126                 CERROR("OBD ioctl: pbuf2 pointer but 0 length\n");
127                 return 1;
128         }
129
130         if (!data->ioc_pbuf1 && data->ioc_plen1 != 0) {
131                 CERROR("OBD ioctl: plen1 set but NULL pointer\n");
132                 return 1;
133         }
134
135         if (!data->ioc_pbuf2 && data->ioc_plen2 != 0) {
136                 CERROR("OBD ioctl: plen2 set but NULL pointer\n");
137                 return 1;
138         }
139
140         if (obd_ioctl_packlen(data) > data->ioc_len) {
141                 CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n",
142                 obd_ioctl_packlen(data), data->ioc_len);
143                 return 1;
144         }
145
146         return 0;
147 }
148
149 /* buffer MUST be at least the size of obd_ioctl_hdr */
150 int obd_ioctl_getdata(char **buf, int *len, void __user *arg)
151 {
152         struct obd_ioctl_hdr hdr;
153         struct obd_ioctl_data *data;
154         int err;
155         int offset = 0;
156
157         if (copy_from_user(&hdr, arg, sizeof(hdr)))
158                 return -EFAULT;
159
160         if (hdr.ioc_version != OBD_IOCTL_VERSION) {
161                 CERROR("Version mismatch kernel (%x) vs application (%x)\n",
162                        OBD_IOCTL_VERSION, hdr.ioc_version);
163                 return -EINVAL;
164         }
165
166         if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) {
167                 CERROR("User buffer len %d exceeds %d max buffer\n",
168                        hdr.ioc_len, OBD_MAX_IOCTL_BUFFER);
169                 return -EINVAL;
170         }
171
172         if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) {
173                 CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len);
174                 return -EINVAL;
175         }
176
177         /* When there are lots of processes calling vmalloc on multi-core
178          * system, the high lock contention will hurt performance badly,
179          * obdfilter-survey is an example, which relies on ioctl. So we'd
180          * better avoid vmalloc on ioctl path. LU-66
181          */
182         *buf = libcfs_kvzalloc(hdr.ioc_len, GFP_NOFS);
183         if (!*buf) {
184                 CERROR("Cannot allocate control buffer of len %d\n",
185                        hdr.ioc_len);
186                 return -EINVAL;
187         }
188         *len = hdr.ioc_len;
189         data = (struct obd_ioctl_data *)*buf;
190
191         if (copy_from_user(*buf, arg, hdr.ioc_len)) {
192                 err = -EFAULT;
193                 goto free_buf;
194         }
195         if (hdr.ioc_len != data->ioc_len) {
196                 err = -EINVAL;
197                 goto free_buf;
198         }
199
200         if (obd_ioctl_is_invalid(data)) {
201                 CERROR("ioctl not correctly formatted\n");
202                 err = -EINVAL;
203                 goto free_buf;
204         }
205
206         if (data->ioc_inllen1) {
207                 data->ioc_inlbuf1 = &data->ioc_bulk[0];
208                 offset += cfs_size_round(data->ioc_inllen1);
209         }
210
211         if (data->ioc_inllen2) {
212                 data->ioc_inlbuf2 = &data->ioc_bulk[0] + offset;
213                 offset += cfs_size_round(data->ioc_inllen2);
214         }
215
216         if (data->ioc_inllen3) {
217                 data->ioc_inlbuf3 = &data->ioc_bulk[0] + offset;
218                 offset += cfs_size_round(data->ioc_inllen3);
219         }
220
221         if (data->ioc_inllen4)
222                 data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
223
224         return 0;
225
226 free_buf:
227         kvfree(*buf);
228         return err;
229 }
230 EXPORT_SYMBOL(obd_ioctl_getdata);
231
232 /*  opening /dev/obd */
233 static int obd_class_open(struct inode *inode, struct file *file)
234 {
235         try_module_get(THIS_MODULE);
236         return 0;
237 }
238
239 /*  closing /dev/obd */
240 static int obd_class_release(struct inode *inode, struct file *file)
241 {
242         module_put(THIS_MODULE);
243         return 0;
244 }
245
246 /* to control /dev/obd */
247 static long obd_class_ioctl(struct file *filp, unsigned int cmd,
248                             unsigned long arg)
249 {
250         int err = 0;
251
252         /* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
253         if (!capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
254                 return err = -EACCES;
255         if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
256                 return err = -ENOTTY;
257
258         err = class_handle_ioctl(cmd, (unsigned long)arg);
259
260         return err;
261 }
262
263 /* declare character device */
264 static const struct file_operations obd_psdev_fops = {
265         .owner    = THIS_MODULE,
266         .unlocked_ioctl = obd_class_ioctl, /* unlocked_ioctl */
267         .open      = obd_class_open,      /* open */
268         .release        = obd_class_release,   /* release */
269 };
270
271 /* modules setup */
272 struct miscdevice obd_psdev = {
273         .minor = OBD_DEV_MINOR,
274         .name  = OBD_DEV_NAME,
275         .fops  = &obd_psdev_fops,
276 };
277
278 static ssize_t version_show(struct kobject *kobj, struct attribute *attr,
279                             char *buf)
280 {
281         return sprintf(buf, "%s\n", LUSTRE_VERSION_STRING);
282 }
283
284 static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr,
285                            char *buf)
286 {
287         return sprintf(buf, "%s\n", "on");
288 }
289
290 static ssize_t
291 health_check_show(struct kobject *kobj, struct attribute *attr, char *buf)
292 {
293         bool healthy = true;
294         int i;
295         size_t len = 0;
296
297         if (libcfs_catastrophe)
298                 return sprintf(buf, "LBUG\n");
299
300         read_lock(&obd_dev_lock);
301         for (i = 0; i < class_devno_max(); i++) {
302                 struct obd_device *obd;
303
304                 obd = class_num2obd(i);
305                 if (!obd || !obd->obd_attached || !obd->obd_set_up)
306                         continue;
307
308                 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
309                 if (obd->obd_stopping)
310                         continue;
311
312                 class_incref(obd, __func__, current);
313                 read_unlock(&obd_dev_lock);
314
315                 if (obd_health_check(NULL, obd))
316                         healthy = false;
317                 class_decref(obd, __func__, current);
318                 read_lock(&obd_dev_lock);
319         }
320         read_unlock(&obd_dev_lock);
321
322         if (healthy)
323                 len = sprintf(buf, "healthy\n");
324         else
325                 len = sprintf(buf, "NOT HEALTHY\n");
326
327         return len;
328 }
329
330 static ssize_t jobid_var_show(struct kobject *kobj, struct attribute *attr,
331                               char *buf)
332 {
333         return snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_var);
334 }
335
336 static ssize_t jobid_var_store(struct kobject *kobj, struct attribute *attr,
337                                const char *buffer,
338                                size_t count)
339 {
340         if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN)
341                 return -EINVAL;
342
343         memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1);
344
345         memcpy(obd_jobid_var, buffer, count);
346
347         /* Trim the trailing '\n' if any */
348         if (obd_jobid_var[count - 1] == '\n')
349                 obd_jobid_var[count - 1] = 0;
350
351         return count;
352 }
353
354 static ssize_t jobid_name_show(struct kobject *kobj, struct attribute *attr,
355                                char *buf)
356 {
357         return snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_node);
358 }
359
360 static ssize_t jobid_name_store(struct kobject *kobj, struct attribute *attr,
361                                 const char *buffer,
362                                 size_t count)
363 {
364         if (!count || count > LUSTRE_JOBID_SIZE)
365                 return -EINVAL;
366
367         memcpy(obd_jobid_node, buffer, count);
368
369         obd_jobid_node[count] = 0;
370
371         /* Trim the trailing '\n' if any */
372         if (obd_jobid_node[count - 1] == '\n')
373                 obd_jobid_node[count - 1] = 0;
374
375         return count;
376 }
377
378 /* Root for /sys/kernel/debug/lustre */
379 struct dentry *debugfs_lustre_root;
380 EXPORT_SYMBOL_GPL(debugfs_lustre_root);
381
382 LUSTRE_RO_ATTR(version);
383 LUSTRE_RO_ATTR(pinger);
384 LUSTRE_RO_ATTR(health_check);
385 LUSTRE_RW_ATTR(jobid_var);
386 LUSTRE_RW_ATTR(jobid_name);
387
388 static struct attribute *lustre_attrs[] = {
389         &lustre_attr_version.attr,
390         &lustre_attr_pinger.attr,
391         &lustre_attr_health_check.attr,
392         &lustre_attr_jobid_name.attr,
393         &lustre_attr_jobid_var.attr,
394         NULL,
395 };
396
397 static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos)
398 {
399         if (*pos >= class_devno_max())
400                 return NULL;
401
402         return pos;
403 }
404
405 static void obd_device_list_seq_stop(struct seq_file *p, void *v)
406 {
407 }
408
409 static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos)
410 {
411         ++*pos;
412         if (*pos >= class_devno_max())
413                 return NULL;
414
415         return pos;
416 }
417
418 static int obd_device_list_seq_show(struct seq_file *p, void *v)
419 {
420         loff_t index = *(loff_t *)v;
421         struct obd_device *obd = class_num2obd((int)index);
422         char *status;
423
424         if (!obd)
425                 return 0;
426
427         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
428         if (obd->obd_stopping)
429                 status = "ST";
430         else if (obd->obd_inactive)
431                 status = "IN";
432         else if (obd->obd_set_up)
433                 status = "UP";
434         else if (obd->obd_attached)
435                 status = "AT";
436         else
437                 status = "--";
438
439         seq_printf(p, "%3d %s %s %s %s %d\n",
440                    (int)index, status, obd->obd_type->typ_name,
441                    obd->obd_name, obd->obd_uuid.uuid,
442                    atomic_read(&obd->obd_refcount));
443         return 0;
444 }
445
446 static const struct seq_operations obd_device_list_sops = {
447         .start = obd_device_list_seq_start,
448         .stop = obd_device_list_seq_stop,
449         .next = obd_device_list_seq_next,
450         .show = obd_device_list_seq_show,
451 };
452
453 static int obd_device_list_open(struct inode *inode, struct file *file)
454 {
455         struct seq_file *seq;
456         int rc = seq_open(file, &obd_device_list_sops);
457
458         if (rc)
459                 return rc;
460
461         seq = file->private_data;
462         seq->private = inode->i_private;
463
464         return 0;
465 }
466
467 static const struct file_operations obd_device_list_fops = {
468         .owner   = THIS_MODULE,
469         .open    = obd_device_list_open,
470         .read    = seq_read,
471         .llseek  = seq_lseek,
472         .release = seq_release,
473 };
474
475 struct kobject *lustre_kobj;
476 EXPORT_SYMBOL_GPL(lustre_kobj);
477
478 static const struct attribute_group lustre_attr_group = {
479         .attrs = lustre_attrs,
480 };
481
482 int class_procfs_init(void)
483 {
484         int rc = -ENOMEM;
485         struct dentry *file;
486
487         lustre_kobj = kobject_create_and_add("lustre", fs_kobj);
488         if (!lustre_kobj)
489                 goto out;
490
491         /* Create the files associated with this kobject */
492         rc = sysfs_create_group(lustre_kobj, &lustre_attr_group);
493         if (rc) {
494                 kobject_put(lustre_kobj);
495                 goto out;
496         }
497
498         debugfs_lustre_root = debugfs_create_dir("lustre", NULL);
499         if (IS_ERR_OR_NULL(debugfs_lustre_root)) {
500                 rc = debugfs_lustre_root ? PTR_ERR(debugfs_lustre_root)
501                                          : -ENOMEM;
502                 debugfs_lustre_root = NULL;
503                 kobject_put(lustre_kobj);
504                 goto out;
505         }
506
507         file = debugfs_create_file("devices", 0444, debugfs_lustre_root, NULL,
508                                    &obd_device_list_fops);
509         if (IS_ERR_OR_NULL(file)) {
510                 rc = file ? PTR_ERR(file) : -ENOMEM;
511                 kobject_put(lustre_kobj);
512                 goto out;
513         }
514 out:
515         return rc;
516 }
517
518 int class_procfs_clean(void)
519 {
520         debugfs_remove_recursive(debugfs_lustre_root);
521
522         debugfs_lustre_root = NULL;
523
524         kobject_put(lustre_kobj);
525
526         return 0;
527 }