1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Copyright (c) 2011, 2012, Intel Corporation.
5  *
6  *   This file is part of Portals
7  *   http://sourceforge.net/projects/sandiaportals/
8  *
9  *   Portals is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Portals is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Portals; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #define DEBUG_SUBSYSTEM S_LNET
25 #include "../../include/linux/libcfs/libcfs.h"
26 #include "../../include/linux/lnet/lib-lnet.h"
27 
28 /* This is really lnet_proc.c. You might need to update sanity test 215
29  * if any file format is changed. */
30 
31 #define LNET_LOFFT_BITS		(sizeof(loff_t) * 8)
32 /*
33  * NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system
34  */
35 #define LNET_PROC_CPT_BITS	(LNET_CPT_BITS + 1)
36 /* change version, 16 bits or 8 bits */
37 #define LNET_PROC_VER_BITS	max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
38 
39 #define LNET_PROC_HASH_BITS	LNET_PEER_HASH_BITS
40 /*
41  * bits for peer hash offset
42  * NB: we don't use the highest bit of *ppos because it's signed
43  */
44 #define LNET_PROC_HOFF_BITS	(LNET_LOFFT_BITS -       \
45 				 LNET_PROC_CPT_BITS -    \
46 				 LNET_PROC_VER_BITS -    \
47 				 LNET_PROC_HASH_BITS - 1)
48 /* bits for hash index + position */
49 #define LNET_PROC_HPOS_BITS	(LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
50 /* bits for peer hash table + hash version */
51 #define LNET_PROC_VPOS_BITS	(LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
52 
53 #define LNET_PROC_CPT_MASK	((1ULL << LNET_PROC_CPT_BITS) - 1)
54 #define LNET_PROC_VER_MASK	((1ULL << LNET_PROC_VER_BITS) - 1)
55 #define LNET_PROC_HASH_MASK	((1ULL << LNET_PROC_HASH_BITS) - 1)
56 #define LNET_PROC_HOFF_MASK	((1ULL << LNET_PROC_HOFF_BITS) - 1)
57 
58 #define LNET_PROC_CPT_GET(pos)				\
59 	(int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
60 
61 #define LNET_PROC_VER_GET(pos)				\
62 	(int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
63 
64 #define LNET_PROC_HASH_GET(pos)				\
65 	(int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
66 
67 #define LNET_PROC_HOFF_GET(pos)				\
68 	(int)((pos) & LNET_PROC_HOFF_MASK)
69 
70 #define LNET_PROC_POS_MAKE(cpt, ver, hash, off)		\
71 	(((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) |   \
72 	((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) |   \
73 	((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
74 	((off) & LNET_PROC_HOFF_MASK))
75 
76 #define LNET_PROC_VERSION(v)	((unsigned int)((v) & LNET_PROC_VER_MASK))
77 
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))78 static int proc_call_handler(void *data, int write, loff_t *ppos,
79 		void __user *buffer, size_t *lenp,
80 		int (*handler)(void *data, int write,
81 		loff_t pos, void __user *buffer, int len))
82 {
83 	int rc = handler(data, write, *ppos, buffer, *lenp);
84 
85 	if (rc < 0)
86 		return rc;
87 
88 	if (write) {
89 		*ppos += *lenp;
90 	} else {
91 		*lenp = rc;
92 		*ppos += rc;
93 	}
94 	return 0;
95 }
96 
__proc_lnet_stats(void * data,int write,loff_t pos,void __user * buffer,int nob)97 static int __proc_lnet_stats(void *data, int write,
98 			     loff_t pos, void __user *buffer, int nob)
99 {
100 	int rc;
101 	lnet_counters_t *ctrs;
102 	int len;
103 	char *tmpstr;
104 	const int tmpsiz = 256; /* 7 %u and 4 %llu */
105 
106 	if (write) {
107 		lnet_counters_reset();
108 		return 0;
109 	}
110 
111 	/* read */
112 
113 	LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
114 	if (ctrs == NULL)
115 		return -ENOMEM;
116 
117 	LIBCFS_ALLOC(tmpstr, tmpsiz);
118 	if (tmpstr == NULL) {
119 		LIBCFS_FREE(ctrs, sizeof(*ctrs));
120 		return -ENOMEM;
121 	}
122 
123 	lnet_counters_get(ctrs);
124 
125 	len = snprintf(tmpstr, tmpsiz,
126 		       "%u %u %u %u %u %u %u %llu %llu %llu %llu",
127 		       ctrs->msgs_alloc, ctrs->msgs_max,
128 		       ctrs->errors,
129 		       ctrs->send_count, ctrs->recv_count,
130 		       ctrs->route_count, ctrs->drop_count,
131 		       ctrs->send_length, ctrs->recv_length,
132 		       ctrs->route_length, ctrs->drop_length);
133 
134 	if (pos >= min_t(int, len, strlen(tmpstr)))
135 		rc = 0;
136 	else
137 		rc = cfs_trace_copyout_string(buffer, nob,
138 					      tmpstr + pos, "\n");
139 
140 	LIBCFS_FREE(tmpstr, tmpsiz);
141 	LIBCFS_FREE(ctrs, sizeof(*ctrs));
142 	return rc;
143 }
144 
proc_lnet_stats(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)145 static int proc_lnet_stats(struct ctl_table *table, int write,
146 			   void __user *buffer, size_t *lenp, loff_t *ppos)
147 {
148 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
149 				 __proc_lnet_stats);
150 }
151 
proc_lnet_routes(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)152 static int proc_lnet_routes(struct ctl_table *table, int write,
153 			    void __user *buffer, size_t *lenp, loff_t *ppos)
154 {
155 	const int tmpsiz = 256;
156 	char *tmpstr;
157 	char *s;
158 	int rc = 0;
159 	int len;
160 	int ver;
161 	int off;
162 
163 	CLASSERT(sizeof(loff_t) >= 4);
164 
165 	off = LNET_PROC_HOFF_GET(*ppos);
166 	ver = LNET_PROC_VER_GET(*ppos);
167 
168 	LASSERT(!write);
169 
170 	if (*lenp == 0)
171 		return 0;
172 
173 	LIBCFS_ALLOC(tmpstr, tmpsiz);
174 	if (tmpstr == NULL)
175 		return -ENOMEM;
176 
177 	s = tmpstr; /* points to current position in tmpstr[] */
178 
179 	if (*ppos == 0) {
180 		s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
181 			      the_lnet.ln_routing ? "enabled" : "disabled");
182 		LASSERT(tmpstr + tmpsiz - s > 0);
183 
184 		s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %8s %7s %s\n",
185 			      "net", "hops", "priority", "state", "router");
186 		LASSERT(tmpstr + tmpsiz - s > 0);
187 
188 		lnet_net_lock(0);
189 		ver = (unsigned int)the_lnet.ln_remote_nets_version;
190 		lnet_net_unlock(0);
191 		*ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
192 	} else {
193 		struct list_head *n;
194 		struct list_head *r;
195 		lnet_route_t *route = NULL;
196 		lnet_remotenet_t *rnet  = NULL;
197 		int skip  = off - 1;
198 		struct list_head *rn_list;
199 		int i;
200 
201 		lnet_net_lock(0);
202 
203 		if (ver != LNET_PROC_VERSION(the_lnet.ln_remote_nets_version)) {
204 			lnet_net_unlock(0);
205 			LIBCFS_FREE(tmpstr, tmpsiz);
206 			return -ESTALE;
207 		}
208 
209 		for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE && route == NULL;
210 		     i++) {
211 			rn_list = &the_lnet.ln_remote_nets_hash[i];
212 
213 			n = rn_list->next;
214 
215 			while (n != rn_list && route == NULL) {
216 				rnet = list_entry(n, lnet_remotenet_t,
217 						      lrn_list);
218 
219 				r = rnet->lrn_routes.next;
220 
221 				while (r != &rnet->lrn_routes) {
222 					lnet_route_t *re =
223 						list_entry(r, lnet_route_t,
224 							       lr_list);
225 					if (skip == 0) {
226 						route = re;
227 						break;
228 					}
229 
230 					skip--;
231 					r = r->next;
232 				}
233 
234 				n = n->next;
235 			}
236 		}
237 
238 		if (route != NULL) {
239 			__u32 net = rnet->lrn_net;
240 			unsigned int hops = route->lr_hops;
241 			unsigned int priority = route->lr_priority;
242 			lnet_nid_t nid = route->lr_gateway->lp_nid;
243 			int alive = route->lr_gateway->lp_alive;
244 
245 			s += snprintf(s, tmpstr + tmpsiz - s,
246 				      "%-8s %4u %8u %7s %s\n",
247 				      libcfs_net2str(net), hops,
248 				      priority,
249 				      alive ? "up" : "down",
250 				      libcfs_nid2str(nid));
251 			LASSERT(tmpstr + tmpsiz - s > 0);
252 		}
253 
254 		lnet_net_unlock(0);
255 	}
256 
257 	len = s - tmpstr;     /* how many bytes was written */
258 
259 	if (len > *lenp) {    /* linux-supplied buffer is too small */
260 		rc = -EINVAL;
261 	} else if (len > 0) { /* wrote something */
262 		if (copy_to_user(buffer, tmpstr, len))
263 			rc = -EFAULT;
264 		else {
265 			off += 1;
266 			*ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
267 		}
268 	}
269 
270 	LIBCFS_FREE(tmpstr, tmpsiz);
271 
272 	if (rc == 0)
273 		*lenp = len;
274 
275 	return rc;
276 }
277 
proc_lnet_routers(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)278 static int proc_lnet_routers(struct ctl_table *table, int write,
279 			     void __user *buffer, size_t *lenp, loff_t *ppos)
280 {
281 	int rc = 0;
282 	char *tmpstr;
283 	char *s;
284 	const int tmpsiz = 256;
285 	int len;
286 	int ver;
287 	int off;
288 
289 	off = LNET_PROC_HOFF_GET(*ppos);
290 	ver = LNET_PROC_VER_GET(*ppos);
291 
292 	LASSERT(!write);
293 
294 	if (*lenp == 0)
295 		return 0;
296 
297 	LIBCFS_ALLOC(tmpstr, tmpsiz);
298 	if (tmpstr == NULL)
299 		return -ENOMEM;
300 
301 	s = tmpstr; /* points to current position in tmpstr[] */
302 
303 	if (*ppos == 0) {
304 		s += snprintf(s, tmpstr + tmpsiz - s,
305 			      "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
306 			      "ref", "rtr_ref", "alive_cnt", "state",
307 			      "last_ping", "ping_sent", "deadline",
308 			      "down_ni", "router");
309 		LASSERT(tmpstr + tmpsiz - s > 0);
310 
311 		lnet_net_lock(0);
312 		ver = (unsigned int)the_lnet.ln_routers_version;
313 		lnet_net_unlock(0);
314 		*ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
315 	} else {
316 		struct list_head *r;
317 		struct lnet_peer *peer = NULL;
318 		int skip = off - 1;
319 
320 		lnet_net_lock(0);
321 
322 		if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
323 			lnet_net_unlock(0);
324 
325 			LIBCFS_FREE(tmpstr, tmpsiz);
326 			return -ESTALE;
327 		}
328 
329 		r = the_lnet.ln_routers.next;
330 
331 		while (r != &the_lnet.ln_routers) {
332 			lnet_peer_t *lp = list_entry(r, lnet_peer_t,
333 							 lp_rtr_list);
334 
335 			if (skip == 0) {
336 				peer = lp;
337 				break;
338 			}
339 
340 			skip--;
341 			r = r->next;
342 		}
343 
344 		if (peer != NULL) {
345 			lnet_nid_t nid = peer->lp_nid;
346 			unsigned long now = cfs_time_current();
347 			unsigned long deadline = peer->lp_ping_deadline;
348 			int nrefs = peer->lp_refcount;
349 			int nrtrrefs = peer->lp_rtr_refcount;
350 			int alive_cnt = peer->lp_alive_count;
351 			int alive = peer->lp_alive;
352 			int pingsent = !peer->lp_ping_notsent;
353 			int last_ping = cfs_duration_sec(cfs_time_sub(now,
354 						     peer->lp_ping_timestamp));
355 			int down_ni = 0;
356 			lnet_route_t *rtr;
357 
358 			if ((peer->lp_ping_feats &
359 			     LNET_PING_FEAT_NI_STATUS) != 0) {
360 				list_for_each_entry(rtr, &peer->lp_routes,
361 							lr_gwlist) {
362 					/* downis on any route should be the
363 					 * number of downis on the gateway */
364 					if (rtr->lr_downis != 0) {
365 						down_ni = rtr->lr_downis;
366 						break;
367 					}
368 				}
369 			}
370 
371 			if (deadline == 0)
372 				s += snprintf(s, tmpstr + tmpsiz - s,
373 					      "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
374 					      nrefs, nrtrrefs, alive_cnt,
375 					      alive ? "up" : "down", last_ping,
376 					      pingsent, "NA", down_ni,
377 					      libcfs_nid2str(nid));
378 			else
379 				s += snprintf(s, tmpstr + tmpsiz - s,
380 					      "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
381 					      nrefs, nrtrrefs, alive_cnt,
382 					      alive ? "up" : "down", last_ping,
383 					      pingsent,
384 					      cfs_duration_sec(cfs_time_sub(deadline, now)),
385 					      down_ni, libcfs_nid2str(nid));
386 			LASSERT(tmpstr + tmpsiz - s > 0);
387 		}
388 
389 		lnet_net_unlock(0);
390 	}
391 
392 	len = s - tmpstr;     /* how many bytes was written */
393 
394 	if (len > *lenp) {    /* linux-supplied buffer is too small */
395 		rc = -EINVAL;
396 	} else if (len > 0) { /* wrote something */
397 		if (copy_to_user(buffer, tmpstr, len))
398 			rc = -EFAULT;
399 		else {
400 			off += 1;
401 			*ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
402 		}
403 	}
404 
405 	LIBCFS_FREE(tmpstr, tmpsiz);
406 
407 	if (rc == 0)
408 		*lenp = len;
409 
410 	return rc;
411 }
412 
proc_lnet_peers(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)413 static int proc_lnet_peers(struct ctl_table *table, int write,
414 			   void __user *buffer, size_t *lenp, loff_t *ppos)
415 {
416 	const int tmpsiz  = 256;
417 	struct lnet_peer_table *ptable;
418 	char *tmpstr;
419 	char *s;
420 	int cpt  = LNET_PROC_CPT_GET(*ppos);
421 	int ver  = LNET_PROC_VER_GET(*ppos);
422 	int hash = LNET_PROC_HASH_GET(*ppos);
423 	int hoff = LNET_PROC_HOFF_GET(*ppos);
424 	int rc = 0;
425 	int len;
426 
427 	CLASSERT(LNET_PROC_HASH_BITS >= LNET_PEER_HASH_BITS);
428 	LASSERT(!write);
429 
430 	if (*lenp == 0)
431 		return 0;
432 
433 	if (cpt >= LNET_CPT_NUMBER) {
434 		*lenp = 0;
435 		return 0;
436 	}
437 
438 	LIBCFS_ALLOC(tmpstr, tmpsiz);
439 	if (tmpstr == NULL)
440 		return -ENOMEM;
441 
442 	s = tmpstr; /* points to current position in tmpstr[] */
443 
444 	if (*ppos == 0) {
445 		s += snprintf(s, tmpstr + tmpsiz - s,
446 			      "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
447 			      "nid", "refs", "state", "last", "max",
448 			      "rtr", "min", "tx", "min", "queue");
449 		LASSERT(tmpstr + tmpsiz - s > 0);
450 
451 		hoff++;
452 	} else {
453 		struct lnet_peer *peer;
454 		struct list_head *p;
455 		int skip;
456  again:
457 		p = NULL;
458 		peer = NULL;
459 		skip = hoff - 1;
460 
461 		lnet_net_lock(cpt);
462 		ptable = the_lnet.ln_peer_tables[cpt];
463 		if (hoff == 1)
464 			ver = LNET_PROC_VERSION(ptable->pt_version);
465 
466 		if (ver != LNET_PROC_VERSION(ptable->pt_version)) {
467 			lnet_net_unlock(cpt);
468 			LIBCFS_FREE(tmpstr, tmpsiz);
469 			return -ESTALE;
470 		}
471 
472 		while (hash < LNET_PEER_HASH_SIZE) {
473 			if (p == NULL)
474 				p = ptable->pt_hash[hash].next;
475 
476 			while (p != &ptable->pt_hash[hash]) {
477 				lnet_peer_t *lp = list_entry(p, lnet_peer_t,
478 								 lp_hashlist);
479 				if (skip == 0) {
480 					peer = lp;
481 
482 					/* minor optimization: start from idx+1
483 					 * on next iteration if we've just
484 					 * drained lp_hashlist */
485 					if (lp->lp_hashlist.next ==
486 					    &ptable->pt_hash[hash]) {
487 						hoff = 1;
488 						hash++;
489 					} else {
490 						hoff++;
491 					}
492 
493 					break;
494 				}
495 
496 				skip--;
497 				p = lp->lp_hashlist.next;
498 			}
499 
500 			if (peer != NULL)
501 				break;
502 
503 			p = NULL;
504 			hoff = 1;
505 			hash++;
506 		}
507 
508 		if (peer != NULL) {
509 			lnet_nid_t nid = peer->lp_nid;
510 			int nrefs = peer->lp_refcount;
511 			int lastalive = -1;
512 			char *aliveness = "NA";
513 			int maxcr = peer->lp_ni->ni_peertxcredits;
514 			int txcr = peer->lp_txcredits;
515 			int mintxcr = peer->lp_mintxcredits;
516 			int rtrcr = peer->lp_rtrcredits;
517 			int minrtrcr = peer->lp_minrtrcredits;
518 			int txqnob = peer->lp_txqnob;
519 
520 			if (lnet_isrouter(peer) ||
521 			    lnet_peer_aliveness_enabled(peer))
522 				aliveness = peer->lp_alive ? "up" : "down";
523 
524 			if (lnet_peer_aliveness_enabled(peer)) {
525 				unsigned long now = cfs_time_current();
526 				long delta;
527 
528 				delta = cfs_time_sub(now, peer->lp_last_alive);
529 				lastalive = cfs_duration_sec(delta);
530 
531 				/* No need to mess up peers contents with
532 				 * arbitrarily long integers - it suffices to
533 				 * know that lastalive is more than 10000s old
534 				 */
535 				if (lastalive >= 10000)
536 					lastalive = 9999;
537 			}
538 
539 			lnet_net_unlock(cpt);
540 
541 			s += snprintf(s, tmpstr + tmpsiz - s,
542 				      "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
543 				      libcfs_nid2str(nid), nrefs, aliveness,
544 				      lastalive, maxcr, rtrcr, minrtrcr, txcr,
545 				      mintxcr, txqnob);
546 			LASSERT(tmpstr + tmpsiz - s > 0);
547 
548 		} else { /* peer is NULL */
549 			lnet_net_unlock(cpt);
550 		}
551 
552 		if (hash == LNET_PEER_HASH_SIZE) {
553 			cpt++;
554 			hash = 0;
555 			hoff = 1;
556 			if (peer == NULL && cpt < LNET_CPT_NUMBER)
557 				goto again;
558 		}
559 	}
560 
561 	len = s - tmpstr;     /* how many bytes was written */
562 
563 	if (len > *lenp) {    /* linux-supplied buffer is too small */
564 		rc = -EINVAL;
565 	} else if (len > 0) { /* wrote something */
566 		if (copy_to_user(buffer, tmpstr, len))
567 			rc = -EFAULT;
568 		else
569 			*ppos = LNET_PROC_POS_MAKE(cpt, ver, hash, hoff);
570 	}
571 
572 	LIBCFS_FREE(tmpstr, tmpsiz);
573 
574 	if (rc == 0)
575 		*lenp = len;
576 
577 	return rc;
578 }
579 
__proc_lnet_buffers(void * data,int write,loff_t pos,void __user * buffer,int nob)580 static int __proc_lnet_buffers(void *data, int write,
581 			       loff_t pos, void __user *buffer, int nob)
582 {
583 	char *s;
584 	char *tmpstr;
585 	int tmpsiz;
586 	int idx;
587 	int len;
588 	int rc;
589 	int i;
590 
591 	LASSERT(!write);
592 
593 	/* (4 %d) * 4 * LNET_CPT_NUMBER */
594 	tmpsiz = 64 * (LNET_NRBPOOLS + 1) * LNET_CPT_NUMBER;
595 	LIBCFS_ALLOC(tmpstr, tmpsiz);
596 	if (tmpstr == NULL)
597 		return -ENOMEM;
598 
599 	s = tmpstr; /* points to current position in tmpstr[] */
600 
601 	s += snprintf(s, tmpstr + tmpsiz - s,
602 		      "%5s %5s %7s %7s\n",
603 		      "pages", "count", "credits", "min");
604 	LASSERT(tmpstr + tmpsiz - s > 0);
605 
606 	if (the_lnet.ln_rtrpools == NULL)
607 		goto out; /* I'm not a router */
608 
609 	for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
610 		lnet_rtrbufpool_t *rbp;
611 
612 		lnet_net_lock(LNET_LOCK_EX);
613 		cfs_percpt_for_each(rbp, i, the_lnet.ln_rtrpools) {
614 			s += snprintf(s, tmpstr + tmpsiz - s,
615 				      "%5d %5d %7d %7d\n",
616 				      rbp[idx].rbp_npages,
617 				      rbp[idx].rbp_nbuffers,
618 				      rbp[idx].rbp_credits,
619 				      rbp[idx].rbp_mincredits);
620 			LASSERT(tmpstr + tmpsiz - s > 0);
621 		}
622 		lnet_net_unlock(LNET_LOCK_EX);
623 	}
624 
625  out:
626 	len = s - tmpstr;
627 
628 	if (pos >= min_t(int, len, strlen(tmpstr)))
629 		rc = 0;
630 	else
631 		rc = cfs_trace_copyout_string(buffer, nob,
632 					      tmpstr + pos, NULL);
633 
634 	LIBCFS_FREE(tmpstr, tmpsiz);
635 	return rc;
636 }
637 
proc_lnet_buffers(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)638 static int proc_lnet_buffers(struct ctl_table *table, int write,
639 			     void __user *buffer, size_t *lenp, loff_t *ppos)
640 {
641 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
642 				 __proc_lnet_buffers);
643 }
644 
proc_lnet_nis(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)645 static int proc_lnet_nis(struct ctl_table *table, int write,
646 			 void __user *buffer, size_t *lenp, loff_t *ppos)
647 {
648 	int tmpsiz = 128 * LNET_CPT_NUMBER;
649 	int rc = 0;
650 	char *tmpstr;
651 	char *s;
652 	int len;
653 
654 	LASSERT(!write);
655 
656 	if (*lenp == 0)
657 		return 0;
658 
659 	LIBCFS_ALLOC(tmpstr, tmpsiz);
660 	if (tmpstr == NULL)
661 		return -ENOMEM;
662 
663 	s = tmpstr; /* points to current position in tmpstr[] */
664 
665 	if (*ppos == 0) {
666 		s += snprintf(s, tmpstr + tmpsiz - s,
667 			      "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
668 			      "nid", "status", "alive", "refs", "peer",
669 			      "rtr", "max", "tx", "min");
670 		LASSERT(tmpstr + tmpsiz - s > 0);
671 	} else {
672 		struct list_head *n;
673 		lnet_ni_t *ni   = NULL;
674 		int skip = *ppos - 1;
675 
676 		lnet_net_lock(0);
677 
678 		n = the_lnet.ln_nis.next;
679 
680 		while (n != &the_lnet.ln_nis) {
681 			lnet_ni_t *a_ni = list_entry(n, lnet_ni_t, ni_list);
682 
683 			if (skip == 0) {
684 				ni = a_ni;
685 				break;
686 			}
687 
688 			skip--;
689 			n = n->next;
690 		}
691 
692 		if (ni != NULL) {
693 			struct lnet_tx_queue *tq;
694 			char *stat;
695 			time64_t now = ktime_get_real_seconds();
696 			int last_alive = -1;
697 			int i;
698 			int j;
699 
700 			if (the_lnet.ln_routing)
701 				last_alive = now - ni->ni_last_alive;
702 
703 			/* @lo forever alive */
704 			if (ni->ni_lnd->lnd_type == LOLND)
705 				last_alive = 0;
706 
707 			lnet_ni_lock(ni);
708 			LASSERT(ni->ni_status != NULL);
709 			stat = (ni->ni_status->ns_status ==
710 				LNET_NI_STATUS_UP) ? "up" : "down";
711 			lnet_ni_unlock(ni);
712 
713 			/* we actually output credits information for
714 			 * TX queue of each partition */
715 			cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
716 				for (j = 0; ni->ni_cpts != NULL &&
717 				     j < ni->ni_ncpts; j++) {
718 					if (i == ni->ni_cpts[j])
719 						break;
720 				}
721 
722 				if (j == ni->ni_ncpts)
723 					continue;
724 
725 				if (i != 0)
726 					lnet_net_lock(i);
727 
728 				s += snprintf(s, tmpstr + tmpsiz - s,
729 				      "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
730 				      libcfs_nid2str(ni->ni_nid), stat,
731 				      last_alive, *ni->ni_refs[i],
732 				      ni->ni_peertxcredits,
733 				      ni->ni_peerrtrcredits,
734 				      tq->tq_credits_max,
735 				      tq->tq_credits, tq->tq_credits_min);
736 				if (i != 0)
737 					lnet_net_unlock(i);
738 			}
739 			LASSERT(tmpstr + tmpsiz - s > 0);
740 		}
741 
742 		lnet_net_unlock(0);
743 	}
744 
745 	len = s - tmpstr;     /* how many bytes was written */
746 
747 	if (len > *lenp) {    /* linux-supplied buffer is too small */
748 		rc = -EINVAL;
749 	} else if (len > 0) { /* wrote something */
750 		if (copy_to_user(buffer, tmpstr, len))
751 			rc = -EFAULT;
752 		else
753 			*ppos += 1;
754 	}
755 
756 	LIBCFS_FREE(tmpstr, tmpsiz);
757 
758 	if (rc == 0)
759 		*lenp = len;
760 
761 	return rc;
762 }
763 
764 struct lnet_portal_rotors {
765 	int pr_value;
766 	const char *pr_name;
767 	const char *pr_desc;
768 };
769 
770 static struct lnet_portal_rotors	portal_rotors[] = {
771 	{
772 		.pr_value = LNET_PTL_ROTOR_OFF,
773 		.pr_name  = "OFF",
774 		.pr_desc  = "Turn off message rotor for wildcard portals"
775 	},
776 	{
777 		.pr_value = LNET_PTL_ROTOR_ON,
778 		.pr_name  = "ON",
779 		.pr_desc  = "round-robin dispatch all PUT messages for wildcard portals"
780 	},
781 	{
782 		.pr_value = LNET_PTL_ROTOR_RR_RT,
783 		.pr_name  = "RR_RT",
784 		.pr_desc  = "round-robin dispatch routed PUT message for wildcard portals"
785 	},
786 	{
787 		.pr_value = LNET_PTL_ROTOR_HASH_RT,
788 		.pr_name  = "HASH_RT",
789 		.pr_desc  = "dispatch routed PUT message by hashing source NID for wildcard portals"
790 	},
791 	{
792 		.pr_value = -1,
793 		.pr_name  = NULL,
794 		.pr_desc  = NULL
795 	},
796 };
797 
798 extern int portal_rotor;
799 
__proc_lnet_portal_rotor(void * data,int write,loff_t pos,void __user * buffer,int nob)800 static int __proc_lnet_portal_rotor(void *data, int write,
801 				    loff_t pos, void __user *buffer, int nob)
802 {
803 	const int buf_len = 128;
804 	char *buf;
805 	char *tmp;
806 	int rc;
807 	int i;
808 
809 	LIBCFS_ALLOC(buf, buf_len);
810 	if (buf == NULL)
811 		return -ENOMEM;
812 
813 	if (!write) {
814 		lnet_res_lock(0);
815 
816 		for (i = 0; portal_rotors[i].pr_value >= 0; i++) {
817 			if (portal_rotors[i].pr_value == portal_rotor)
818 				break;
819 		}
820 
821 		LASSERT(portal_rotors[i].pr_value == portal_rotor);
822 		lnet_res_unlock(0);
823 
824 		rc = snprintf(buf, buf_len,
825 			      "{\n\tportals: all\n"
826 			      "\trotor: %s\n\tdescription: %s\n}",
827 			      portal_rotors[i].pr_name,
828 			      portal_rotors[i].pr_desc);
829 
830 		if (pos >= min_t(int, rc, buf_len)) {
831 			rc = 0;
832 		} else {
833 			rc = cfs_trace_copyout_string(buffer, nob,
834 					buf + pos, "\n");
835 		}
836 		goto out;
837 	}
838 
839 	rc = cfs_trace_copyin_string(buf, buf_len, buffer, nob);
840 	if (rc < 0)
841 		goto out;
842 
843 	tmp = cfs_trimwhite(buf);
844 
845 	rc = -EINVAL;
846 	lnet_res_lock(0);
847 	for (i = 0; portal_rotors[i].pr_name != NULL; i++) {
848 		if (strncasecmp(portal_rotors[i].pr_name, tmp,
849 				strlen(portal_rotors[i].pr_name)) == 0) {
850 			portal_rotor = portal_rotors[i].pr_value;
851 			rc = 0;
852 			break;
853 		}
854 	}
855 	lnet_res_unlock(0);
856 out:
857 	LIBCFS_FREE(buf, buf_len);
858 	return rc;
859 }
860 
proc_lnet_portal_rotor(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)861 static int proc_lnet_portal_rotor(struct ctl_table *table, int write,
862 				  void __user *buffer, size_t *lenp,
863 				  loff_t *ppos)
864 {
865 	return proc_call_handler(table->data, write, ppos, buffer, lenp,
866 				 __proc_lnet_portal_rotor);
867 }
868 
869 static struct ctl_table lnet_table[] = {
870 	/*
871 	 * NB No .strategy entries have been provided since sysctl(8) prefers
872 	 * to go via /proc for portability.
873 	 */
874 	{
875 		.procname     = "stats",
876 		.mode         = 0644,
877 		.proc_handler = &proc_lnet_stats,
878 	},
879 	{
880 		.procname     = "routes",
881 		.mode         = 0444,
882 		.proc_handler = &proc_lnet_routes,
883 	},
884 	{
885 		.procname     = "routers",
886 		.mode         = 0444,
887 		.proc_handler = &proc_lnet_routers,
888 	},
889 	{
890 		.procname     = "peers",
891 		.mode         = 0444,
892 		.proc_handler = &proc_lnet_peers,
893 	},
894 	{
895 		.procname     = "buffers",
896 		.mode         = 0444,
897 		.proc_handler = &proc_lnet_buffers,
898 	},
899 	{
900 		.procname     = "nis",
901 		.mode         = 0444,
902 		.proc_handler = &proc_lnet_nis,
903 	},
904 	{
905 		.procname     = "portal_rotor",
906 		.mode         = 0644,
907 		.proc_handler = &proc_lnet_portal_rotor,
908 	},
909 	{
910 	}
911 };
912 
lnet_router_debugfs_init(void)913 void lnet_router_debugfs_init(void)
914 {
915 	lustre_insert_debugfs(lnet_table, NULL);
916 }
917 
lnet_router_debugfs_fini(void)918 void lnet_router_debugfs_fini(void)
919 {
920 }
921