Whamcloud - gitweb
LU-8901 misc: update Intel copyright messages for 2016
[fs/lustre-release.git] / 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, 2016, 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/proc_fs.h>
53 #include <linux/fs.h>
54 #include <linux/poll.h>
55 #include <linux/init.h>
56 #include <linux/list.h>
57 #include <linux/highmem.h>
58 #include <asm/io.h>
59 #include <asm/ioctls.h>
60 #include <asm/poll.h>
61 #include <asm/uaccess.h>
62 #include <linux/miscdevice.h>
63 #include <linux/seq_file.h>
64
65 #include <libcfs/libcfs.h>
66 #include <obd_support.h>
67 #include <obd_class.h>
68 #include <lnet/lnetctl.h>
69 #include <lprocfs_status.h>
70 #include <lustre_ioctl.h>
71 #include <lustre_ver.h>
72
73 int proc_version;
74
75 /* buffer MUST be at least the size of obd_ioctl_hdr */
76 int obd_ioctl_getdata(char **buf, int *len, void __user *arg)
77 {
78         struct obd_ioctl_hdr hdr;
79         struct obd_ioctl_data *data;
80         int offset = 0;
81         ENTRY;
82
83         if (copy_from_user(&hdr, arg, sizeof(hdr)))
84                 RETURN(-EFAULT);
85
86         if (hdr.ioc_version != OBD_IOCTL_VERSION) {
87                 CERROR("Version mismatch kernel (%x) vs application (%x)\n",
88                        OBD_IOCTL_VERSION, hdr.ioc_version);
89                 RETURN(-EINVAL);
90         }
91
92         if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) {
93                 CERROR("User buffer len %d exceeds %d max buffer\n",
94                        hdr.ioc_len, OBD_MAX_IOCTL_BUFFER);
95                 RETURN(-EINVAL);
96         }
97
98         if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) {
99                 CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len);
100                 RETURN(-EINVAL);
101         }
102
103         /* When there are lots of processes calling vmalloc on multi-core
104          * system, the high lock contention will hurt performance badly,
105          * obdfilter-survey is an example, which relies on ioctl. So we'd
106          * better avoid vmalloc on ioctl path. LU-66 */
107         OBD_ALLOC_LARGE(*buf, hdr.ioc_len);
108         if (*buf == NULL) {
109                 CERROR("Cannot allocate control buffer of len %d\n",
110                        hdr.ioc_len);
111                 RETURN(-EINVAL);
112         }
113         *len = hdr.ioc_len;
114         data = (struct obd_ioctl_data *)*buf;
115
116         if (copy_from_user(*buf, arg, hdr.ioc_len)) {
117                 OBD_FREE_LARGE(*buf, hdr.ioc_len);
118                 RETURN(-EFAULT);
119         }
120
121         if (obd_ioctl_is_invalid(data)) {
122                 CERROR("ioctl not correctly formatted\n");
123                 OBD_FREE_LARGE(*buf, hdr.ioc_len);
124                 RETURN(-EINVAL);
125         }
126
127         if (data->ioc_inllen1) {
128                 data->ioc_inlbuf1 = &data->ioc_bulk[0];
129                 offset += cfs_size_round(data->ioc_inllen1);
130         }
131
132         if (data->ioc_inllen2) {
133                 data->ioc_inlbuf2 = &data->ioc_bulk[0] + offset;
134                 offset += cfs_size_round(data->ioc_inllen2);
135         }
136
137         if (data->ioc_inllen3) {
138                 data->ioc_inlbuf3 = &data->ioc_bulk[0] + offset;
139                 offset += cfs_size_round(data->ioc_inllen3);
140         }
141
142         if (data->ioc_inllen4)
143                 data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
144
145         RETURN(0);
146 }
147 EXPORT_SYMBOL(obd_ioctl_getdata);
148
149 int obd_ioctl_popdata(void __user *arg, void *data, int len)
150 {
151         int err;
152         ENTRY;
153
154         err = copy_to_user(arg, data, len) ? -EFAULT : 0;
155         RETURN(err);
156 }
157
158 /*  opening /dev/obd */
159 static int obd_class_open(struct inode * inode, struct file * file)
160 {
161         ENTRY;
162
163         try_module_get(THIS_MODULE);
164         RETURN(0);
165 }
166
167 /*  closing /dev/obd */
168 static int obd_class_release(struct inode * inode, struct file * file)
169 {
170         ENTRY;
171
172         module_put(THIS_MODULE);
173         RETURN(0);
174 }
175
176 /* to control /dev/obd */
177 static long obd_class_ioctl(struct file *filp, unsigned int cmd,
178                             unsigned long arg)
179 {
180         int err = 0;
181         ENTRY;
182
183         /* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
184         if (!cfs_capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
185                 RETURN(err = -EACCES);
186         if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
187                 RETURN(err = -ENOTTY);
188
189         err = class_handle_ioctl(cmd, (unsigned long)arg);
190
191         RETURN(err);
192 }
193
194 /* declare character device */
195 static struct file_operations obd_psdev_fops = {
196         .owner          = THIS_MODULE,
197         .unlocked_ioctl = obd_class_ioctl, /* unlocked_ioctl */
198         .open           = obd_class_open,      /* open */
199         .release        = obd_class_release,   /* release */
200 };
201
202 /* modules setup */
203 struct miscdevice obd_psdev = {
204         .minor = OBD_DEV_MINOR,
205         .name  = OBD_DEV_NAME,
206         .fops  = &obd_psdev_fops,
207 };
208
209
210 #ifdef CONFIG_PROC_FS
211 static int obd_proc_version_seq_show(struct seq_file *m, void *v)
212 {
213         seq_printf(m, "lustre: %s\n", LUSTRE_VERSION_STRING);
214         return 0;
215 }
216 LPROC_SEQ_FOPS_RO(obd_proc_version);
217
218 static int obd_proc_pinger_seq_show(struct seq_file *m, void *v)
219 {
220         seq_printf(m, "%s\n",
221 #ifdef ENABLE_PINGER
222                    "on"
223 #else
224                    "off"
225 #endif
226                  );
227         return 0;
228 }
229 LPROC_SEQ_FOPS_RO(obd_proc_pinger);
230
231 /**
232  * Check all obd devices health
233  *
234  * \param seq_file
235  * \param data [in] unused
236  *
237  * \retval number of characters printed if healthy
238  */
239 static int obd_proc_health_seq_show(struct seq_file *m, void *data)
240 {
241         bool healthy = true;
242         int i;
243
244         if (libcfs_catastrophe) {
245                 seq_printf(m, "LBUG\n");
246                 healthy = false;
247         }
248
249         read_lock(&obd_dev_lock);
250         for (i = 0; i < class_devno_max(); i++) {
251                 struct obd_device *obd;
252
253                 obd = class_num2obd(i);
254                 if (obd == NULL || !obd->obd_attached || !obd->obd_set_up)
255                         continue;
256
257                 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
258                 if (obd->obd_stopping)
259                         continue;
260
261                 class_incref(obd, __FUNCTION__, current);
262                 read_unlock(&obd_dev_lock);
263
264                 if (obd_health_check(NULL, obd)) {
265                         seq_printf(m, "device %s reported unhealthy\n",
266                                    obd->obd_name);
267                         healthy = false;
268                 }
269                 class_decref(obd, __FUNCTION__, current);
270                 read_lock(&obd_dev_lock);
271         }
272         read_unlock(&obd_dev_lock);
273
274         if (healthy)
275                 seq_puts(m, "healthy\n");
276         else
277                 seq_puts(m, "NOT HEALTHY\n");
278         return 0;
279 }
280 LPROC_SEQ_FOPS_RO(obd_proc_health);
281
282 static int obd_proc_jobid_var_seq_show(struct seq_file *m, void *v)
283 {
284         if (strlen(obd_jobid_var) != 0)
285                 seq_printf(m, "%s\n", obd_jobid_var);
286         return 0;
287 }
288
289 static ssize_t
290 obd_proc_jobid_var_seq_write(struct file *file, const char __user *buffer,
291                              size_t count, loff_t *off)
292 {
293         if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN)
294                 return -EINVAL;
295
296         memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1);
297
298         /* This might leave the var invalid on error, which is probably fine.*/
299         if (copy_from_user(obd_jobid_var, buffer, count))
300                 return -EFAULT;
301
302         /* Trim the trailing '\n' if any */
303         if (obd_jobid_var[count - 1] == '\n')
304                 obd_jobid_var[count - 1] = 0;
305
306         return count;
307 }
308 LPROC_SEQ_FOPS(obd_proc_jobid_var);
309
310 static int obd_proc_jobid_name_seq_show(struct seq_file *m, void *v)
311 {
312         if (strlen(obd_jobid_node) != 0)
313                 seq_printf(m, "%s\n", obd_jobid_node);
314         return 0;
315 }
316
317 static ssize_t obd_proc_jobid_name_seq_write(struct file *file,
318                                              const char __user *buffer,
319                                              size_t count, loff_t *off)
320 {
321         if (count == 0 || count > LUSTRE_JOBID_SIZE)
322                 return -EINVAL;
323
324         /* clear previous value */
325         memset(obd_jobid_node, 0, LUSTRE_JOBID_SIZE);
326
327         if (copy_from_user(obd_jobid_node, buffer, count))
328                 return -EFAULT;
329
330         /* Trim the trailing '\n' if any */
331         if (obd_jobid_node[count - 1] == '\n') {
332                 /* Don't echo just a newline */
333                 if (count == 1)
334                         return -EINVAL;
335                 obd_jobid_node[count - 1] = 0;
336         }
337
338         return count;
339 }
340 LPROC_SEQ_FOPS(obd_proc_jobid_name);
341
342 /* Root for /proc/fs/lustre */
343 struct proc_dir_entry *proc_lustre_root = NULL;
344 EXPORT_SYMBOL(proc_lustre_root);
345
346 static struct lprocfs_vars lprocfs_base[] = {
347         { .name =       "version",
348           .fops =       &obd_proc_version_fops  },
349         { .name =       "pinger",
350           .fops =       &obd_proc_pinger_fops   },
351         { .name =       "health_check",
352           .fops =       &obd_proc_health_fops   },
353         { .name =       "jobid_var",
354           .fops =       &obd_proc_jobid_var_fops},
355         { .name =       "jobid_name",
356           .fops =       &obd_proc_jobid_name_fops},
357         { NULL }
358 };
359 #else
360 #define lprocfs_base NULL
361 #endif /* CONFIG_PROC_FS */
362
363 static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos)
364 {
365         if (*pos >= class_devno_max())
366                 return NULL;
367
368         return pos;
369 }
370
371 static void obd_device_list_seq_stop(struct seq_file *p, void *v)
372 {
373 }
374
375 static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos)
376 {
377         ++*pos;
378         if (*pos >= class_devno_max())
379                 return NULL;
380
381         return pos;
382 }
383
384 static int obd_device_list_seq_show(struct seq_file *p, void *v)
385 {
386         loff_t index = *(loff_t *)v;
387         struct obd_device *obd = class_num2obd((int)index);
388         char *status;
389
390         if (obd == NULL)
391                 return 0;
392
393         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
394         if (obd->obd_stopping)
395                 status = "ST";
396         else if (obd->obd_inactive)
397                 status = "IN";
398         else if (obd->obd_set_up)
399                 status = "UP";
400         else if (obd->obd_attached)
401                 status = "AT";
402         else
403                 status = "--";
404
405         seq_printf(p, "%3d %s %s %s %s %d\n",
406                    (int)index, status, obd->obd_type->typ_name,
407                    obd->obd_name, obd->obd_uuid.uuid,
408                    atomic_read(&obd->obd_refcount));
409         return 0;
410 }
411
412 static const struct seq_operations obd_device_list_sops = {
413         .start = obd_device_list_seq_start,
414         .stop = obd_device_list_seq_stop,
415         .next = obd_device_list_seq_next,
416         .show = obd_device_list_seq_show,
417 };
418
419 static int obd_device_list_open(struct inode *inode, struct file *file)
420 {
421         struct seq_file *seq;
422         int rc = seq_open(file, &obd_device_list_sops);
423
424         if (rc)
425                 return rc;
426
427         seq = file->private_data;
428         seq->private = PDE_DATA(inode);
429         return 0;
430 }
431
432 static const struct file_operations obd_device_list_fops = {
433         .owner   = THIS_MODULE,
434         .open    = obd_device_list_open,
435         .read    = seq_read,
436         .llseek  = seq_lseek,
437         .release = seq_release,
438 };
439
440 int class_procfs_init(void)
441 {
442         struct proc_dir_entry *entry;
443         int rc;
444         ENTRY;
445
446         obd_sysctl_init();
447
448         entry = lprocfs_register("fs/lustre", NULL, lprocfs_base, NULL);
449         if (IS_ERR(entry)) {
450                 rc = PTR_ERR(entry);
451                 CERROR("cannot create '/proc/fs/lustre': rc = %d\n", rc);
452                 RETURN(rc);
453         }
454
455         proc_lustre_root = entry;
456
457         rc = lprocfs_seq_create(proc_lustre_root, "devices", 0444,
458                                 &obd_device_list_fops, NULL);
459         if (rc < 0) {
460                 CERROR("cannot create '/proc/fs/lustre/devices': rc = %d\n",
461                        rc);
462                 GOTO(out_proc, rc);
463         }
464
465         RETURN(rc);
466
467 out_proc:
468         lprocfs_remove(&proc_lustre_root);
469
470         RETURN(rc);
471 }
472
473 int class_procfs_clean(void)
474 {
475         ENTRY;
476         if (proc_lustre_root) {
477                 lprocfs_remove(&proc_lustre_root);
478         }
479         RETURN(0);
480 }