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 #include <linux/module.h>
37 #include <linux/kernel.h>
38 #include <linux/mm.h>
39 #include <linux/string.h>
40 #include <linux/stat.h>
41 #include <linux/errno.h>
42 #include <linux/unistd.h>
43 #include <net/sock.h>
44 #include <linux/uio.h>
45 
46 #include <linux/uaccess.h>
47 
48 #include <linux/fs.h>
49 #include <linux/file.h>
50 #include <linux/list.h>
51 
52 #include <linux/proc_fs.h>
53 #include <linux/sysctl.h>
54 
55 # define DEBUG_SUBSYSTEM S_LNET
56 
57 #include "../../include/linux/libcfs/libcfs.h"
58 #include <asm/div64.h>
59 
60 #include "../../include/linux/libcfs/libcfs_crypto.h"
61 #include "../../include/linux/lnet/lib-lnet.h"
62 #include "../../include/linux/lnet/lnet.h"
63 #include "tracefile.h"
64 
65 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
66 MODULE_DESCRIPTION("Portals v3.1");
67 MODULE_LICENSE("GPL");
68 
69 extern struct miscdevice libcfs_dev;
70 extern struct rw_semaphore cfs_tracefile_sem;
71 extern struct mutex cfs_trace_thread_mutex;
72 extern struct cfs_wi_sched *cfs_sched_rehash;
73 extern void libcfs_init_nidstrings(void);
74 
75 static int insert_proc(void);
76 static void remove_proc(void);
77 
78 static struct ctl_table_header *lnet_table_header;
79 extern char lnet_upcall[1024];
80 /**
81  * The path of debug log dump upcall script.
82  */
83 extern char lnet_debug_log_upcall[1024];
84 
85 #define CTL_LNET	(0x100)
86 
87 enum {
88 	PSDEV_DEBUG = 1,	  /* control debugging */
89 	PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
90 	PSDEV_PRINTK,	     /* force all messages to console */
91 	PSDEV_CONSOLE_RATELIMIT,  /* ratelimit console messages */
92 	PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
93 	PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
94 	PSDEV_CONSOLE_BACKOFF,    /* delay increase factor */
95 	PSDEV_DEBUG_PATH,	 /* crashdump log location */
96 	PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
97 	PSDEV_CPT_TABLE,	  /* information about cpu partitions */
98 	PSDEV_LNET_UPCALL,	/* User mode upcall script  */
99 	PSDEV_LNET_MEMUSED,       /* bytes currently PORTAL_ALLOCated */
100 	PSDEV_LNET_CATASTROPHE,   /* if we have LBUGged or panic'd */
101 	PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
102 	PSDEV_LNET_DUMP_KERNEL,   /* snapshot kernel debug buffer to file */
103 	PSDEV_LNET_DAEMON_FILE,   /* spool kernel debug buffer to file */
104 	PSDEV_LNET_DEBUG_MB,      /* size of debug buffer */
105 	PSDEV_LNET_DEBUG_LOG_UPCALL, /* debug log upcall script */
106 	PSDEV_LNET_WATCHDOG_RATELIMIT,  /* ratelimit watchdog messages  */
107 	PSDEV_LNET_FORCE_LBUG,    /* hook to force an LBUG */
108 	PSDEV_LNET_FAIL_LOC,      /* control test failures instrumentation */
109 	PSDEV_LNET_FAIL_VAL,      /* userdata for fail loc */
110 };
111 
kportal_memhog_free(struct libcfs_device_userstate * ldu)112 static void kportal_memhog_free (struct libcfs_device_userstate *ldu)
113 {
114 	struct page **level0p = &ldu->ldu_memhog_root_page;
115 	struct page **level1p;
116 	struct page **level2p;
117 	int	   count1;
118 	int	   count2;
119 
120 	if (*level0p != NULL) {
121 
122 		level1p = (struct page **)page_address(*level0p);
123 		count1 = 0;
124 
125 		while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
126 		       *level1p != NULL) {
127 
128 			level2p = (struct page **)page_address(*level1p);
129 			count2 = 0;
130 
131 			while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
132 			       *level2p != NULL) {
133 
134 				__free_page(*level2p);
135 				ldu->ldu_memhog_pages--;
136 				level2p++;
137 				count2++;
138 			}
139 
140 			__free_page(*level1p);
141 			ldu->ldu_memhog_pages--;
142 			level1p++;
143 			count1++;
144 		}
145 
146 		__free_page(*level0p);
147 		ldu->ldu_memhog_pages--;
148 
149 		*level0p = NULL;
150 	}
151 
152 	LASSERT (ldu->ldu_memhog_pages == 0);
153 }
154 
kportal_memhog_alloc(struct libcfs_device_userstate * ldu,int npages,gfp_t flags)155 static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
156 		     gfp_t flags)
157 {
158 	struct page **level0p;
159 	struct page **level1p;
160 	struct page **level2p;
161 	int	   count1;
162 	int	   count2;
163 
164 	LASSERT (ldu->ldu_memhog_pages == 0);
165 	LASSERT (ldu->ldu_memhog_root_page == NULL);
166 
167 	if (npages < 0)
168 		return -EINVAL;
169 
170 	if (npages == 0)
171 		return 0;
172 
173 	level0p = &ldu->ldu_memhog_root_page;
174 	*level0p = alloc_page(flags);
175 	if (*level0p == NULL)
176 		return -ENOMEM;
177 	ldu->ldu_memhog_pages++;
178 
179 	level1p = (struct page **)page_address(*level0p);
180 	count1 = 0;
181 	memset(level1p, 0, PAGE_CACHE_SIZE);
182 
183 	while (ldu->ldu_memhog_pages < npages &&
184 	       count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
185 
186 		if (cfs_signal_pending())
187 			return -EINTR;
188 
189 		*level1p = alloc_page(flags);
190 		if (*level1p == NULL)
191 			return -ENOMEM;
192 		ldu->ldu_memhog_pages++;
193 
194 		level2p = (struct page **)page_address(*level1p);
195 		count2 = 0;
196 		memset(level2p, 0, PAGE_CACHE_SIZE);
197 
198 		while (ldu->ldu_memhog_pages < npages &&
199 		       count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
200 
201 			if (cfs_signal_pending())
202 				return -EINTR;
203 
204 			*level2p = alloc_page(flags);
205 			if (*level2p == NULL)
206 				return -ENOMEM;
207 			ldu->ldu_memhog_pages++;
208 
209 			level2p++;
210 			count2++;
211 		}
212 
213 		level1p++;
214 		count1++;
215 	}
216 
217 	return 0;
218 }
219 
220 /* called when opening /dev/device */
libcfs_psdev_open(unsigned long flags,void * args)221 static int libcfs_psdev_open(unsigned long flags, void *args)
222 {
223 	struct libcfs_device_userstate *ldu;
224 
225 	try_module_get(THIS_MODULE);
226 
227 	LIBCFS_ALLOC(ldu, sizeof(*ldu));
228 	if (ldu != NULL) {
229 		ldu->ldu_memhog_pages = 0;
230 		ldu->ldu_memhog_root_page = NULL;
231 	}
232 	*(struct libcfs_device_userstate **)args = ldu;
233 
234 	return 0;
235 }
236 
237 /* called when closing /dev/device */
libcfs_psdev_release(unsigned long flags,void * args)238 static int libcfs_psdev_release(unsigned long flags, void *args)
239 {
240 	struct libcfs_device_userstate *ldu;
241 
242 	ldu = (struct libcfs_device_userstate *)args;
243 	if (ldu != NULL) {
244 		kportal_memhog_free(ldu);
245 		LIBCFS_FREE(ldu, sizeof(*ldu));
246 	}
247 
248 	module_put(THIS_MODULE);
249 	return 0;
250 }
251 
252 static struct rw_semaphore ioctl_list_sem;
253 static struct list_head ioctl_list;
254 
libcfs_register_ioctl(struct libcfs_ioctl_handler * hand)255 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
256 {
257 	int rc = 0;
258 
259 	down_write(&ioctl_list_sem);
260 	if (!list_empty(&hand->item))
261 		rc = -EBUSY;
262 	else
263 		list_add_tail(&hand->item, &ioctl_list);
264 	up_write(&ioctl_list_sem);
265 
266 	return rc;
267 }
268 EXPORT_SYMBOL(libcfs_register_ioctl);
269 
libcfs_deregister_ioctl(struct libcfs_ioctl_handler * hand)270 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
271 {
272 	int rc = 0;
273 
274 	down_write(&ioctl_list_sem);
275 	if (list_empty(&hand->item))
276 		rc = -ENOENT;
277 	else
278 		list_del_init(&hand->item);
279 	up_write(&ioctl_list_sem);
280 
281 	return rc;
282 }
283 EXPORT_SYMBOL(libcfs_deregister_ioctl);
284 
libcfs_ioctl_int(struct cfs_psdev_file * pfile,unsigned long cmd,void * arg,struct libcfs_ioctl_data * data)285 static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
286 			    void *arg, struct libcfs_ioctl_data *data)
287 {
288 	int err = -EINVAL;
289 
290 	switch (cmd) {
291 	case IOC_LIBCFS_CLEAR_DEBUG:
292 		libcfs_debug_clear_buffer();
293 		return 0;
294 	/*
295 	 * case IOC_LIBCFS_PANIC:
296 	 * Handled in arch/cfs_module.c
297 	 */
298 	case IOC_LIBCFS_MARK_DEBUG:
299 		if (data->ioc_inlbuf1 == NULL ||
300 		    data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
301 			return -EINVAL;
302 		libcfs_debug_mark_buffer(data->ioc_inlbuf1);
303 		return 0;
304 	case IOC_LIBCFS_MEMHOG:
305 		if (pfile->private_data == NULL) {
306 			err = -EINVAL;
307 		} else {
308 			kportal_memhog_free(pfile->private_data);
309 			/* XXX The ioc_flags is not GFP flags now, need to be fixed */
310 			err = kportal_memhog_alloc(pfile->private_data,
311 						   data->ioc_count,
312 						   data->ioc_flags);
313 			if (err != 0)
314 				kportal_memhog_free(pfile->private_data);
315 		}
316 		break;
317 
318 	case IOC_LIBCFS_PING_TEST: {
319 		extern void (kping_client)(struct libcfs_ioctl_data *);
320 		void (*ping)(struct libcfs_ioctl_data *);
321 
322 		CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
323 		       data->ioc_count, libcfs_nid2str(data->ioc_nid),
324 		       libcfs_nid2str(data->ioc_nid));
325 		ping = symbol_get(kping_client);
326 		if (!ping)
327 			CERROR("symbol_get failed\n");
328 		else {
329 			ping(data);
330 			symbol_put(kping_client);
331 		}
332 		return 0;
333 	}
334 
335 	default: {
336 		struct libcfs_ioctl_handler *hand;
337 		err = -EINVAL;
338 		down_read(&ioctl_list_sem);
339 		list_for_each_entry(hand, &ioctl_list, item) {
340 			err = hand->handle_ioctl(cmd, data);
341 			if (err != -EINVAL) {
342 				if (err == 0)
343 					err = libcfs_ioctl_popdata(arg,
344 							data, sizeof (*data));
345 				break;
346 			}
347 		}
348 		up_read(&ioctl_list_sem);
349 		break;
350 	}
351 	}
352 
353 	return err;
354 }
355 
libcfs_ioctl(struct cfs_psdev_file * pfile,unsigned long cmd,void * arg)356 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
357 {
358 	char    *buf;
359 	struct libcfs_ioctl_data *data;
360 	int err = 0;
361 
362 	LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
363 	if (buf == NULL)
364 		return -ENOMEM;
365 
366 	/* 'cmd' and permissions get checked in our arch-specific caller */
367 	if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
368 		CERROR("PORTALS ioctl: data error\n");
369 		err = -EINVAL;
370 		goto out;
371 	}
372 	data = (struct libcfs_ioctl_data *)buf;
373 
374 	err = libcfs_ioctl_int(pfile, cmd, arg, data);
375 
376 out:
377 	LIBCFS_FREE(buf, 1024);
378 	return err;
379 }
380 
381 
382 struct cfs_psdev_ops libcfs_psdev_ops = {
383 	libcfs_psdev_open,
384 	libcfs_psdev_release,
385 	NULL,
386 	NULL,
387 	libcfs_ioctl
388 };
389 
init_libcfs_module(void)390 static int init_libcfs_module(void)
391 {
392 	int rc;
393 
394 	libcfs_arch_init();
395 	libcfs_init_nidstrings();
396 	init_rwsem(&cfs_tracefile_sem);
397 	mutex_init(&cfs_trace_thread_mutex);
398 	init_rwsem(&ioctl_list_sem);
399 	INIT_LIST_HEAD(&ioctl_list);
400 	init_waitqueue_head(&cfs_race_waitq);
401 
402 	rc = libcfs_debug_init(5 * 1024 * 1024);
403 	if (rc < 0) {
404 		pr_err("LustreError: libcfs_debug_init: %d\n", rc);
405 		return rc;
406 	}
407 
408 	rc = cfs_cpu_init();
409 	if (rc != 0)
410 		goto cleanup_debug;
411 
412 	rc = misc_register(&libcfs_dev);
413 	if (rc) {
414 		CERROR("misc_register: error %d\n", rc);
415 		goto cleanup_cpu;
416 	}
417 
418 	rc = cfs_wi_startup();
419 	if (rc) {
420 		CERROR("initialize workitem: error %d\n", rc);
421 		goto cleanup_deregister;
422 	}
423 
424 	/* max to 4 threads, should be enough for rehash */
425 	rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
426 	rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
427 				 rc, &cfs_sched_rehash);
428 	if (rc != 0) {
429 		CERROR("Startup workitem scheduler: error: %d\n", rc);
430 		goto cleanup_deregister;
431 	}
432 
433 	rc = cfs_crypto_register();
434 	if (rc) {
435 		CERROR("cfs_crypto_register: error %d\n", rc);
436 		goto cleanup_wi;
437 	}
438 
439 
440 	rc = insert_proc();
441 	if (rc) {
442 		CERROR("insert_proc: error %d\n", rc);
443 		goto cleanup_crypto;
444 	}
445 
446 	CDEBUG (D_OTHER, "portals setup OK\n");
447 	return 0;
448  cleanup_crypto:
449 	cfs_crypto_unregister();
450  cleanup_wi:
451 	cfs_wi_shutdown();
452  cleanup_deregister:
453 	misc_deregister(&libcfs_dev);
454 cleanup_cpu:
455 	cfs_cpu_fini();
456  cleanup_debug:
457 	libcfs_debug_cleanup();
458 	return rc;
459 }
460 
exit_libcfs_module(void)461 static void exit_libcfs_module(void)
462 {
463 	int rc;
464 
465 	remove_proc();
466 
467 	CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
468 	       atomic_read(&libcfs_kmemory));
469 
470 	if (cfs_sched_rehash != NULL) {
471 		cfs_wi_sched_destroy(cfs_sched_rehash);
472 		cfs_sched_rehash = NULL;
473 	}
474 
475 	cfs_crypto_unregister();
476 	cfs_wi_shutdown();
477 
478 	rc = misc_deregister(&libcfs_dev);
479 	if (rc)
480 		CERROR("misc_deregister error %d\n", rc);
481 
482 	cfs_cpu_fini();
483 
484 	if (atomic_read(&libcfs_kmemory) != 0)
485 		CERROR("Portals memory leaked: %d bytes\n",
486 		       atomic_read(&libcfs_kmemory));
487 
488 	rc = libcfs_debug_cleanup();
489 	if (rc)
490 		pr_err("LustreError: libcfs_debug_cleanup: %d\n", rc);
491 
492 	libcfs_arch_cleanup();
493 }
494 
proc_call_handler(void * data,int write,loff_t * ppos,void __user * buffer,size_t * lenp,int (* handler)(void * data,int write,loff_t pos,void __user * buffer,int len))495 static int proc_call_handler(void *data, int write, loff_t *ppos,
496 		void __user *buffer, size_t *lenp,
497 		int (*handler)(void *data, int write,
498 		loff_t pos, void __user *buffer, int len))
499 {
500 	int rc = handler(data, write, *ppos, buffer, *lenp);
501 
502 	if (rc < 0)
503 		return rc;
504 
505 	if (write) {
506 		*ppos += *lenp;
507 	} else {
508 		*lenp = rc;
509 		*ppos += rc;
510 	}
511 	return 0;
512 }
513 
__proc_dobitmasks(void * data,int write,loff_t pos,void __user * buffer,int nob)514 static int __proc_dobitmasks(void *data, int write,
515 			     loff_t pos, void __user *buffer, int nob)
516 {
517 	const int     tmpstrlen = 512;
518 	char	 *tmpstr;
519 	int	   rc;
520 	unsigned int *mask = data;
521 	int	   is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
522 	int	   is_printk = (mask == &libcfs_printk) ? 1 : 0;
523 
524 	rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
525 	if (rc < 0)
526 		return rc;
527 
528 	if (!write) {
529 		libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
530 		rc = strlen(tmpstr);
531 
532 		if (pos >= rc) {
533 			rc = 0;
534 		} else {
535 			rc = cfs_trace_copyout_string(buffer, nob,
536 						      tmpstr + pos, "\n");
537 		}
538 	} else {
539 		rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
540 		if (rc < 0) {
541 			cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
542 			return rc;
543 		}
544 
545 		rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
546 		/* Always print LBUG/LASSERT to console, so keep this mask */
547 		if (is_printk)
548 			*mask |= D_EMERG;
549 	}
550 
551 	cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
552 	return rc;
553 }
554 
proc_dobitmasks(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)555 static int proc_dobitmasks(struct ctl_table *table, int write,
556 			   void __user *buffer, size_t *lenp, loff_t *ppos)
557 {
558 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
559 				 __proc_dobitmasks);
560 }
561 
562 static int min_watchdog_ratelimit;	  /* disable ratelimiting */
563 static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */
564 
__proc_dump_kernel(void * data,int write,loff_t pos,void __user * buffer,int nob)565 static int __proc_dump_kernel(void *data, int write,
566 			      loff_t pos, void __user *buffer, int nob)
567 {
568 	if (!write)
569 		return 0;
570 
571 	return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
572 }
573 
proc_dump_kernel(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)574 static int proc_dump_kernel(struct ctl_table *table, int write,
575 			    void __user *buffer, size_t *lenp, loff_t *ppos)
576 {
577 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
578 				 __proc_dump_kernel);
579 }
580 
__proc_daemon_file(void * data,int write,loff_t pos,void __user * buffer,int nob)581 static int __proc_daemon_file(void *data, int write,
582 			      loff_t pos, void __user *buffer, int nob)
583 {
584 	if (!write) {
585 		int len = strlen(cfs_tracefile);
586 
587 		if (pos >= len)
588 			return 0;
589 
590 		return cfs_trace_copyout_string(buffer, nob,
591 						cfs_tracefile + pos, "\n");
592 	}
593 
594 	return cfs_trace_daemon_command_usrstr(buffer, nob);
595 }
596 
proc_daemon_file(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)597 static int proc_daemon_file(struct ctl_table *table, int write,
598 			    void __user *buffer, size_t *lenp, loff_t *ppos)
599 {
600 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
601 				 __proc_daemon_file);
602 }
603 
__proc_debug_mb(void * data,int write,loff_t pos,void __user * buffer,int nob)604 static int __proc_debug_mb(void *data, int write,
605 			   loff_t pos, void __user *buffer, int nob)
606 {
607 	if (!write) {
608 		char tmpstr[32];
609 		int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
610 				    cfs_trace_get_debug_mb());
611 
612 		if (pos >= len)
613 			return 0;
614 
615 		return cfs_trace_copyout_string(buffer, nob, tmpstr + pos,
616 		       "\n");
617 	}
618 
619 	return cfs_trace_set_debug_mb_usrstr(buffer, nob);
620 }
621 
proc_debug_mb(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)622 static int proc_debug_mb(struct ctl_table *table, int write,
623 			 void __user *buffer, size_t *lenp, loff_t *ppos)
624 {
625 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
626 				 __proc_debug_mb);
627 }
628 
proc_console_max_delay_cs(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)629 static int proc_console_max_delay_cs(struct ctl_table *table, int write,
630 				     void __user *buffer, size_t *lenp,
631 				     loff_t *ppos)
632 {
633 	int rc, max_delay_cs;
634 	struct ctl_table dummy = *table;
635 	long d;
636 
637 	dummy.data = &max_delay_cs;
638 	dummy.proc_handler = &proc_dointvec;
639 
640 	if (!write) { /* read */
641 		max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
642 		rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
643 		return rc;
644 	}
645 
646 	/* write */
647 	max_delay_cs = 0;
648 	rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
649 	if (rc < 0)
650 		return rc;
651 	if (max_delay_cs <= 0)
652 		return -EINVAL;
653 
654 	d = cfs_time_seconds(max_delay_cs) / 100;
655 	if (d == 0 || d < libcfs_console_min_delay)
656 		return -EINVAL;
657 	libcfs_console_max_delay = d;
658 
659 	return rc;
660 }
661 
proc_console_min_delay_cs(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)662 static int proc_console_min_delay_cs(struct ctl_table *table, int write,
663 				     void __user *buffer, size_t *lenp,
664 				     loff_t *ppos)
665 {
666 	int rc, min_delay_cs;
667 	struct ctl_table dummy = *table;
668 	long d;
669 
670 	dummy.data = &min_delay_cs;
671 	dummy.proc_handler = &proc_dointvec;
672 
673 	if (!write) { /* read */
674 		min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
675 		rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
676 		return rc;
677 	}
678 
679 	/* write */
680 	min_delay_cs = 0;
681 	rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
682 	if (rc < 0)
683 		return rc;
684 	if (min_delay_cs <= 0)
685 		return -EINVAL;
686 
687 	d = cfs_time_seconds(min_delay_cs) / 100;
688 	if (d == 0 || d > libcfs_console_max_delay)
689 		return -EINVAL;
690 	libcfs_console_min_delay = d;
691 
692 	return rc;
693 }
694 
proc_console_backoff(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)695 static int proc_console_backoff(struct ctl_table *table, int write,
696 				void __user *buffer, size_t *lenp, loff_t *ppos)
697 {
698 	int rc, backoff;
699 	struct ctl_table dummy = *table;
700 
701 	dummy.data = &backoff;
702 	dummy.proc_handler = &proc_dointvec;
703 
704 	if (!write) { /* read */
705 		backoff = libcfs_console_backoff;
706 		rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
707 		return rc;
708 	}
709 
710 	/* write */
711 	backoff = 0;
712 	rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
713 	if (rc < 0)
714 		return rc;
715 	if (backoff <= 0)
716 		return -EINVAL;
717 
718 	libcfs_console_backoff = backoff;
719 
720 	return rc;
721 }
722 
libcfs_force_lbug(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)723 static int libcfs_force_lbug(struct ctl_table *table, int write,
724 			     void __user *buffer,
725 			     size_t *lenp, loff_t *ppos)
726 {
727 	if (write)
728 		LBUG();
729 	return 0;
730 }
731 
proc_fail_loc(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)732 static int proc_fail_loc(struct ctl_table *table, int write,
733 			 void __user *buffer,
734 			 size_t *lenp, loff_t *ppos)
735 {
736 	int rc;
737 	long old_fail_loc = cfs_fail_loc;
738 
739 	rc = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
740 	if (old_fail_loc != cfs_fail_loc)
741 		wake_up(&cfs_race_waitq);
742 	return rc;
743 }
744 
__proc_cpt_table(void * data,int write,loff_t pos,void __user * buffer,int nob)745 static int __proc_cpt_table(void *data, int write,
746 			    loff_t pos, void __user *buffer, int nob)
747 {
748 	char *buf = NULL;
749 	int   len = 4096;
750 	int   rc  = 0;
751 
752 	if (write)
753 		return -EPERM;
754 
755 	LASSERT(cfs_cpt_table != NULL);
756 
757 	while (1) {
758 		LIBCFS_ALLOC(buf, len);
759 		if (buf == NULL)
760 			return -ENOMEM;
761 
762 		rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
763 		if (rc >= 0)
764 			break;
765 
766 		if (rc == -EFBIG) {
767 			LIBCFS_FREE(buf, len);
768 			len <<= 1;
769 			continue;
770 		}
771 		goto out;
772 	}
773 
774 	if (pos >= rc) {
775 		rc = 0;
776 		goto out;
777 	}
778 
779 	rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
780  out:
781 	if (buf != NULL)
782 		LIBCFS_FREE(buf, len);
783 	return rc;
784 }
785 
proc_cpt_table(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)786 static int proc_cpt_table(struct ctl_table *table, int write,
787 			   void __user *buffer, size_t *lenp, loff_t *ppos)
788 {
789 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
790 				 __proc_cpt_table);
791 }
792 
793 static struct ctl_table lnet_table[] = {
794 	/*
795 	 * NB No .strategy entries have been provided since sysctl(8) prefers
796 	 * to go via /proc for portability.
797 	 */
798 	{
799 		.procname = "debug",
800 		.data     = &libcfs_debug,
801 		.maxlen   = sizeof(int),
802 		.mode     = 0644,
803 		.proc_handler = &proc_dobitmasks,
804 	},
805 	{
806 		.procname = "subsystem_debug",
807 		.data     = &libcfs_subsystem_debug,
808 		.maxlen   = sizeof(int),
809 		.mode     = 0644,
810 		.proc_handler = &proc_dobitmasks,
811 	},
812 	{
813 		.procname = "printk",
814 		.data     = &libcfs_printk,
815 		.maxlen   = sizeof(int),
816 		.mode     = 0644,
817 		.proc_handler = &proc_dobitmasks,
818 	},
819 	{
820 		.procname = "console_ratelimit",
821 		.data     = &libcfs_console_ratelimit,
822 		.maxlen   = sizeof(int),
823 		.mode     = 0644,
824 		.proc_handler = &proc_dointvec
825 	},
826 	{
827 		.procname = "console_max_delay_centisecs",
828 		.maxlen   = sizeof(int),
829 		.mode     = 0644,
830 		.proc_handler = &proc_console_max_delay_cs
831 	},
832 	{
833 		.procname = "console_min_delay_centisecs",
834 		.maxlen   = sizeof(int),
835 		.mode     = 0644,
836 		.proc_handler = &proc_console_min_delay_cs
837 	},
838 	{
839 		.procname = "console_backoff",
840 		.maxlen   = sizeof(int),
841 		.mode     = 0644,
842 		.proc_handler = &proc_console_backoff
843 	},
844 
845 	{
846 		.procname = "debug_path",
847 		.data     = libcfs_debug_file_path_arr,
848 		.maxlen   = sizeof(libcfs_debug_file_path_arr),
849 		.mode     = 0644,
850 		.proc_handler = &proc_dostring,
851 	},
852 
853 	{
854 		.procname = "cpu_partition_table",
855 		.maxlen   = 128,
856 		.mode     = 0444,
857 		.proc_handler = &proc_cpt_table,
858 	},
859 
860 	{
861 		.procname = "upcall",
862 		.data     = lnet_upcall,
863 		.maxlen   = sizeof(lnet_upcall),
864 		.mode     = 0644,
865 		.proc_handler = &proc_dostring,
866 	},
867 	{
868 		.procname = "debug_log_upcall",
869 		.data     = lnet_debug_log_upcall,
870 		.maxlen   = sizeof(lnet_debug_log_upcall),
871 		.mode     = 0644,
872 		.proc_handler = &proc_dostring,
873 	},
874 	{
875 		.procname = "lnet_memused",
876 		.data     = (int *)&libcfs_kmemory.counter,
877 		.maxlen   = sizeof(int),
878 		.mode     = 0444,
879 		.proc_handler = &proc_dointvec,
880 	},
881 	{
882 		.procname = "catastrophe",
883 		.data     = &libcfs_catastrophe,
884 		.maxlen   = sizeof(int),
885 		.mode     = 0444,
886 		.proc_handler = &proc_dointvec,
887 	},
888 	{
889 		.procname = "panic_on_lbug",
890 		.data     = &libcfs_panic_on_lbug,
891 		.maxlen   = sizeof(int),
892 		.mode     = 0644,
893 		.proc_handler = &proc_dointvec,
894 	},
895 	{
896 		.procname = "dump_kernel",
897 		.maxlen   = 256,
898 		.mode     = 0200,
899 		.proc_handler = &proc_dump_kernel,
900 	},
901 	{
902 		.procname = "daemon_file",
903 		.mode     = 0644,
904 		.maxlen   = 256,
905 		.proc_handler = &proc_daemon_file,
906 	},
907 	{
908 		.procname = "debug_mb",
909 		.mode     = 0644,
910 		.proc_handler = &proc_debug_mb,
911 	},
912 	{
913 		.procname = "watchdog_ratelimit",
914 		.data     = &libcfs_watchdog_ratelimit,
915 		.maxlen   = sizeof(int),
916 		.mode     = 0644,
917 		.proc_handler = &proc_dointvec_minmax,
918 		.extra1   = &min_watchdog_ratelimit,
919 		.extra2   = &max_watchdog_ratelimit,
920 	},
921 	{
922 		.procname = "force_lbug",
923 		.data     = NULL,
924 		.maxlen   = 0,
925 		.mode     = 0200,
926 		.proc_handler = &libcfs_force_lbug
927 	},
928 	{
929 		.procname = "fail_loc",
930 		.data     = &cfs_fail_loc,
931 		.maxlen   = sizeof(cfs_fail_loc),
932 		.mode     = 0644,
933 		.proc_handler = &proc_fail_loc
934 	},
935 	{
936 		.procname = "fail_val",
937 		.data     = &cfs_fail_val,
938 		.maxlen   = sizeof(int),
939 		.mode     = 0644,
940 		.proc_handler = &proc_dointvec
941 	},
942 	{
943 	}
944 };
945 
946 static struct ctl_table top_table[] = {
947 	{
948 		.procname = "lnet",
949 		.mode     = 0555,
950 		.data     = NULL,
951 		.maxlen   = 0,
952 		.child    = lnet_table,
953 	},
954 	{
955 	}
956 };
957 
insert_proc(void)958 static int insert_proc(void)
959 {
960 	if (lnet_table_header == NULL)
961 		lnet_table_header = register_sysctl_table(top_table);
962 	return 0;
963 }
964 
remove_proc(void)965 static void remove_proc(void)
966 {
967 	if (lnet_table_header != NULL)
968 		unregister_sysctl_table(lnet_table_header);
969 
970 	lnet_table_header = NULL;
971 }
972 
973 MODULE_VERSION("1.0.0");
974 
975 module_init(init_libcfs_module);
976 module_exit(exit_libcfs_module);
977