• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) 2007, 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  * lnet/selftest/conctl.c
37  *
38  * Infrastructure of LST console
39  *
40  * Author: Liang Zhen <liangzhen@clusterfs.com>
41  */
42 
43 
44 #include "../../include/linux/libcfs/libcfs.h"
45 #include "../../include/linux/lnet/lib-lnet.h"
46 #include "console.h"
47 #include "conrpc.h"
48 
49 #define LST_NODE_STATE_COUNTER(nd, p)		   \
50 do {						    \
51 	if ((nd)->nd_state == LST_NODE_ACTIVE)	  \
52 		(p)->nle_nactive ++;		    \
53 	else if ((nd)->nd_state == LST_NODE_BUSY)       \
54 		(p)->nle_nbusy ++;		      \
55 	else if ((nd)->nd_state == LST_NODE_DOWN)       \
56 		(p)->nle_ndown ++;		      \
57 	else					    \
58 		(p)->nle_nunknown ++;		   \
59 	(p)->nle_nnode ++;			      \
60 } while (0)
61 
62 lstcon_session_t	console_session;
63 
64 static void
lstcon_node_get(lstcon_node_t * nd)65 lstcon_node_get(lstcon_node_t *nd)
66 {
67 	LASSERT (nd->nd_ref >= 1);
68 
69 	nd->nd_ref++;
70 }
71 
72 static int
lstcon_node_find(lnet_process_id_t id,lstcon_node_t ** ndpp,int create)73 lstcon_node_find(lnet_process_id_t id, lstcon_node_t **ndpp, int create)
74 {
75 	lstcon_ndlink_t *ndl;
76 	unsigned int     idx = LNET_NIDADDR(id.nid) % LST_GLOBAL_HASHSIZE;
77 
78 	LASSERT (id.nid != LNET_NID_ANY);
79 
80 	list_for_each_entry(ndl, &console_session.ses_ndl_hash[idx], ndl_hlink) {
81 		if (ndl->ndl_node->nd_id.nid != id.nid ||
82 		    ndl->ndl_node->nd_id.pid != id.pid)
83 			continue;
84 
85 		lstcon_node_get(ndl->ndl_node);
86 		*ndpp = ndl->ndl_node;
87 		return 0;
88 	}
89 
90 	if (!create)
91 		return -ENOENT;
92 
93 	LIBCFS_ALLOC(*ndpp, sizeof(lstcon_node_t) + sizeof(lstcon_ndlink_t));
94 	if (*ndpp == NULL)
95 		return -ENOMEM;
96 
97 	ndl = (lstcon_ndlink_t *)(*ndpp + 1);
98 
99 	ndl->ndl_node = *ndpp;
100 
101 	ndl->ndl_node->nd_ref   = 1;
102 	ndl->ndl_node->nd_id    = id;
103 	ndl->ndl_node->nd_stamp = cfs_time_current();
104 	ndl->ndl_node->nd_state = LST_NODE_UNKNOWN;
105 	ndl->ndl_node->nd_timeout = 0;
106 	memset(&ndl->ndl_node->nd_ping, 0, sizeof(lstcon_rpc_t));
107 
108 	/* queued in global hash & list, no refcount is taken by
109 	 * global hash & list, if caller release his refcount,
110 	 * node will be released */
111 	list_add_tail(&ndl->ndl_hlink, &console_session.ses_ndl_hash[idx]);
112 	list_add_tail(&ndl->ndl_link, &console_session.ses_ndl_list);
113 
114 	return 0;
115 }
116 
117 static void
lstcon_node_put(lstcon_node_t * nd)118 lstcon_node_put(lstcon_node_t *nd)
119 {
120 	lstcon_ndlink_t  *ndl;
121 
122 	LASSERT (nd->nd_ref > 0);
123 
124 	if (--nd->nd_ref > 0)
125 		return;
126 
127 	ndl = (lstcon_ndlink_t *)(nd + 1);
128 
129 	LASSERT (!list_empty(&ndl->ndl_link));
130 	LASSERT (!list_empty(&ndl->ndl_hlink));
131 
132 	/* remove from session */
133 	list_del(&ndl->ndl_link);
134 	list_del(&ndl->ndl_hlink);
135 
136 	LIBCFS_FREE(nd, sizeof(lstcon_node_t) + sizeof(lstcon_ndlink_t));
137 }
138 
139 static int
lstcon_ndlink_find(struct list_head * hash,lnet_process_id_t id,lstcon_ndlink_t ** ndlpp,int create)140 lstcon_ndlink_find(struct list_head *hash,
141 		   lnet_process_id_t id, lstcon_ndlink_t **ndlpp, int create)
142 {
143 	unsigned int     idx = LNET_NIDADDR(id.nid) % LST_NODE_HASHSIZE;
144 	lstcon_ndlink_t *ndl;
145 	lstcon_node_t   *nd;
146 	int	      rc;
147 
148 	if (id.nid == LNET_NID_ANY)
149 		return -EINVAL;
150 
151 	/* search in hash */
152 	list_for_each_entry(ndl, &hash[idx], ndl_hlink) {
153 		if (ndl->ndl_node->nd_id.nid != id.nid ||
154 		    ndl->ndl_node->nd_id.pid != id.pid)
155 			continue;
156 
157 		*ndlpp = ndl;
158 		return 0;
159 	}
160 
161 	if (create == 0)
162 		return -ENOENT;
163 
164 	/* find or create in session hash */
165 	rc = lstcon_node_find(id, &nd, (create == 1) ? 1 : 0);
166 	if (rc != 0)
167 		return rc;
168 
169 	LIBCFS_ALLOC(ndl, sizeof(lstcon_ndlink_t));
170 	if (ndl == NULL) {
171 		lstcon_node_put(nd);
172 		return -ENOMEM;
173 	}
174 
175 	*ndlpp = ndl;
176 
177 	ndl->ndl_node = nd;
178 	INIT_LIST_HEAD(&ndl->ndl_link);
179 	list_add_tail(&ndl->ndl_hlink, &hash[idx]);
180 
181 	return  0;
182 }
183 
184 static void
lstcon_ndlink_release(lstcon_ndlink_t * ndl)185 lstcon_ndlink_release(lstcon_ndlink_t *ndl)
186 {
187 	LASSERT (list_empty(&ndl->ndl_link));
188 	LASSERT (!list_empty(&ndl->ndl_hlink));
189 
190 	list_del(&ndl->ndl_hlink); /* delete from hash */
191 	lstcon_node_put(ndl->ndl_node);
192 
193 	LIBCFS_FREE(ndl, sizeof(*ndl));
194 }
195 
196 static int
lstcon_group_alloc(char * name,lstcon_group_t ** grpp)197 lstcon_group_alloc(char *name, lstcon_group_t **grpp)
198 {
199 	lstcon_group_t *grp;
200 	int	     i;
201 
202 	LIBCFS_ALLOC(grp, offsetof(lstcon_group_t,
203 				   grp_ndl_hash[LST_NODE_HASHSIZE]));
204 	if (grp == NULL)
205 		return -ENOMEM;
206 
207 	grp->grp_ref = 1;
208 	if (name != NULL)
209 		strcpy(grp->grp_name, name);
210 
211 	INIT_LIST_HEAD(&grp->grp_link);
212 	INIT_LIST_HEAD(&grp->grp_ndl_list);
213 	INIT_LIST_HEAD(&grp->grp_trans_list);
214 
215 	for (i = 0; i < LST_NODE_HASHSIZE; i++)
216 		INIT_LIST_HEAD(&grp->grp_ndl_hash[i]);
217 
218 	*grpp = grp;
219 
220 	return 0;
221 }
222 
223 static void
lstcon_group_addref(lstcon_group_t * grp)224 lstcon_group_addref(lstcon_group_t *grp)
225 {
226 	grp->grp_ref ++;
227 }
228 
229 static void lstcon_group_ndlink_release(lstcon_group_t *, lstcon_ndlink_t *);
230 
231 static void
lstcon_group_drain(lstcon_group_t * grp,int keep)232 lstcon_group_drain(lstcon_group_t *grp, int keep)
233 {
234 	lstcon_ndlink_t *ndl;
235 	lstcon_ndlink_t *tmp;
236 
237 	list_for_each_entry_safe(ndl, tmp, &grp->grp_ndl_list, ndl_link) {
238 		if ((ndl->ndl_node->nd_state & keep) == 0)
239 			lstcon_group_ndlink_release(grp, ndl);
240 	}
241 }
242 
243 static void
lstcon_group_decref(lstcon_group_t * grp)244 lstcon_group_decref(lstcon_group_t *grp)
245 {
246 	int     i;
247 
248 	if (--grp->grp_ref > 0)
249 		return;
250 
251 	if (!list_empty(&grp->grp_link))
252 		list_del(&grp->grp_link);
253 
254 	lstcon_group_drain(grp, 0);
255 
256 	for (i = 0; i < LST_NODE_HASHSIZE; i++) {
257 		LASSERT (list_empty(&grp->grp_ndl_hash[i]));
258 	}
259 
260 	LIBCFS_FREE(grp, offsetof(lstcon_group_t,
261 				  grp_ndl_hash[LST_NODE_HASHSIZE]));
262 }
263 
264 static int
lstcon_group_find(const char * name,lstcon_group_t ** grpp)265 lstcon_group_find(const char *name, lstcon_group_t **grpp)
266 {
267 	lstcon_group_t   *grp;
268 
269 	list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) {
270 		if (strncmp(grp->grp_name, name, LST_NAME_SIZE) != 0)
271 			continue;
272 
273 		lstcon_group_addref(grp);  /* +1 ref for caller */
274 		*grpp = grp;
275 		return 0;
276 	}
277 
278 	return -ENOENT;
279 }
280 
281 static void
lstcon_group_put(lstcon_group_t * grp)282 lstcon_group_put(lstcon_group_t *grp)
283 {
284 	lstcon_group_decref(grp);
285 }
286 
287 static int
lstcon_group_ndlink_find(lstcon_group_t * grp,lnet_process_id_t id,lstcon_ndlink_t ** ndlpp,int create)288 lstcon_group_ndlink_find(lstcon_group_t *grp, lnet_process_id_t id,
289 			 lstcon_ndlink_t **ndlpp, int create)
290 {
291 	int     rc;
292 
293 	rc = lstcon_ndlink_find(&grp->grp_ndl_hash[0], id, ndlpp, create);
294 	if (rc != 0)
295 		return rc;
296 
297 	if (!list_empty(&(*ndlpp)->ndl_link))
298 		return 0;
299 
300 	list_add_tail(&(*ndlpp)->ndl_link, &grp->grp_ndl_list);
301 	grp->grp_nnode ++;
302 
303 	return 0;
304 }
305 
306 static void
lstcon_group_ndlink_release(lstcon_group_t * grp,lstcon_ndlink_t * ndl)307 lstcon_group_ndlink_release(lstcon_group_t *grp, lstcon_ndlink_t *ndl)
308 {
309 	list_del_init(&ndl->ndl_link);
310 	lstcon_ndlink_release(ndl);
311 	grp->grp_nnode --;
312 }
313 
314 static void
lstcon_group_ndlink_move(lstcon_group_t * old,lstcon_group_t * new,lstcon_ndlink_t * ndl)315 lstcon_group_ndlink_move(lstcon_group_t *old,
316 			 lstcon_group_t *new, lstcon_ndlink_t *ndl)
317 {
318 	unsigned int idx = LNET_NIDADDR(ndl->ndl_node->nd_id.nid) %
319 			   LST_NODE_HASHSIZE;
320 
321 	list_del(&ndl->ndl_hlink);
322 	list_del(&ndl->ndl_link);
323 	old->grp_nnode --;
324 
325 	list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]);
326 	list_add_tail(&ndl->ndl_link, &new->grp_ndl_list);
327 	new->grp_nnode ++;
328 
329 	return;
330 }
331 
332 static void
lstcon_group_move(lstcon_group_t * old,lstcon_group_t * new)333 lstcon_group_move(lstcon_group_t *old, lstcon_group_t *new)
334 {
335 	lstcon_ndlink_t *ndl;
336 
337 	while (!list_empty(&old->grp_ndl_list)) {
338 		ndl = list_entry(old->grp_ndl_list.next,
339 				     lstcon_ndlink_t, ndl_link);
340 		lstcon_group_ndlink_move(old, new, ndl);
341 	}
342 }
343 
344 static int
lstcon_sesrpc_condition(int transop,lstcon_node_t * nd,void * arg)345 lstcon_sesrpc_condition(int transop, lstcon_node_t *nd, void *arg)
346 {
347 	lstcon_group_t *grp = (lstcon_group_t *)arg;
348 
349 	switch (transop) {
350 	case LST_TRANS_SESNEW:
351 		if (nd->nd_state == LST_NODE_ACTIVE)
352 			return 0;
353 		break;
354 
355 	case LST_TRANS_SESEND:
356 		if (nd->nd_state != LST_NODE_ACTIVE)
357 			return 0;
358 
359 		if (grp != NULL && nd->nd_ref > 1)
360 			return 0;
361 		break;
362 
363 	case LST_TRANS_SESQRY:
364 		break;
365 
366 	default:
367 		LBUG();
368 	}
369 
370 	return 1;
371 }
372 
373 static int
lstcon_sesrpc_readent(int transop,srpc_msg_t * msg,lstcon_rpc_ent_t * ent_up)374 lstcon_sesrpc_readent(int transop, srpc_msg_t *msg,
375 		      lstcon_rpc_ent_t *ent_up)
376 {
377 	srpc_debug_reply_t *rep;
378 
379 	switch (transop) {
380 	case LST_TRANS_SESNEW:
381 	case LST_TRANS_SESEND:
382 		return 0;
383 
384 	case LST_TRANS_SESQRY:
385 		rep = &msg->msg_body.dbg_reply;
386 
387 		if (copy_to_user(&ent_up->rpe_priv[0],
388 				     &rep->dbg_timeout, sizeof(int)) ||
389 		    copy_to_user(&ent_up->rpe_payload[0],
390 				     &rep->dbg_name, LST_NAME_SIZE))
391 			return -EFAULT;
392 
393 		return 0;
394 
395 	default:
396 		LBUG();
397 	}
398 
399 	return 0;
400 }
401 
402 static int
lstcon_group_nodes_add(lstcon_group_t * grp,int count,lnet_process_id_t * ids_up,unsigned * featp,struct list_head * result_up)403 lstcon_group_nodes_add(lstcon_group_t *grp,
404 		       int count, lnet_process_id_t *ids_up,
405 		       unsigned *featp, struct list_head *result_up)
406 {
407 	lstcon_rpc_trans_t      *trans;
408 	lstcon_ndlink_t	 *ndl;
409 	lstcon_group_t	  *tmp;
410 	lnet_process_id_t	id;
411 	int		      i;
412 	int		      rc;
413 
414 	rc = lstcon_group_alloc(NULL, &tmp);
415 	if (rc != 0) {
416 		CERROR("Out of memory\n");
417 		return -ENOMEM;
418 	}
419 
420 	for (i = 0 ; i < count; i++) {
421 		if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
422 			rc = -EFAULT;
423 			break;
424 		}
425 
426 		/* skip if it's in this group already */
427 		rc = lstcon_group_ndlink_find(grp, id, &ndl, 0);
428 		if (rc == 0)
429 			continue;
430 
431 		/* add to tmp group */
432 		rc = lstcon_group_ndlink_find(tmp, id, &ndl, 1);
433 		if (rc != 0) {
434 			CERROR("Can't create ndlink, out of memory\n");
435 			break;
436 		}
437 	}
438 
439 	if (rc != 0) {
440 		lstcon_group_put(tmp);
441 		return rc;
442 	}
443 
444 	rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list,
445 				     &tmp->grp_trans_list, LST_TRANS_SESNEW,
446 				     tmp, lstcon_sesrpc_condition, &trans);
447 	if (rc != 0) {
448 		CERROR("Can't create transaction: %d\n", rc);
449 		lstcon_group_put(tmp);
450 		return rc;
451 	}
452 
453 	/* post all RPCs */
454 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
455 
456 	rc = lstcon_rpc_trans_interpreter(trans, result_up,
457 					  lstcon_sesrpc_readent);
458 	*featp = trans->tas_features;
459 
460 	/* destroy all RPGs */
461 	lstcon_rpc_trans_destroy(trans);
462 
463 	lstcon_group_move(tmp, grp);
464 	lstcon_group_put(tmp);
465 
466 	return rc;
467 }
468 
469 static int
lstcon_group_nodes_remove(lstcon_group_t * grp,int count,lnet_process_id_t * ids_up,struct list_head * result_up)470 lstcon_group_nodes_remove(lstcon_group_t *grp,
471 			  int count, lnet_process_id_t *ids_up,
472 			  struct list_head *result_up)
473 {
474 	lstcon_rpc_trans_t     *trans;
475 	lstcon_ndlink_t	*ndl;
476 	lstcon_group_t	 *tmp;
477 	lnet_process_id_t       id;
478 	int		     rc;
479 	int		     i;
480 
481 	/* End session and remove node from the group */
482 
483 	rc = lstcon_group_alloc(NULL, &tmp);
484 	if (rc != 0) {
485 		CERROR("Out of memory\n");
486 		return -ENOMEM;
487 	}
488 
489 	for (i = 0; i < count; i++) {
490 		if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
491 			rc = -EFAULT;
492 			goto error;
493 		}
494 
495 		/* move node to tmp group */
496 		if (lstcon_group_ndlink_find(grp, id, &ndl, 0) == 0)
497 			lstcon_group_ndlink_move(grp, tmp, ndl);
498 	}
499 
500 	rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list,
501 				     &tmp->grp_trans_list, LST_TRANS_SESEND,
502 				     tmp, lstcon_sesrpc_condition, &trans);
503 	if (rc != 0) {
504 		CERROR("Can't create transaction: %d\n", rc);
505 		goto error;
506 	}
507 
508 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
509 
510 	rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
511 
512 	lstcon_rpc_trans_destroy(trans);
513 	/* release nodes anyway, because we can't rollback status */
514 	lstcon_group_put(tmp);
515 
516 	return rc;
517 error:
518 	lstcon_group_move(tmp, grp);
519 	lstcon_group_put(tmp);
520 
521 	return rc;
522 }
523 
524 int
lstcon_group_add(char * name)525 lstcon_group_add(char *name)
526 {
527 	lstcon_group_t *grp;
528 	int	     rc;
529 
530 	rc = (lstcon_group_find(name, &grp) == 0)? -EEXIST: 0;
531 	if (rc != 0) {
532 		/* find a group with same name */
533 		lstcon_group_put(grp);
534 		return rc;
535 	}
536 
537 	rc = lstcon_group_alloc(name, &grp);
538 	if (rc != 0) {
539 		CERROR("Can't allocate descriptor for group %s\n", name);
540 		return -ENOMEM;
541 	}
542 
543 	list_add_tail(&grp->grp_link, &console_session.ses_grp_list);
544 
545 	return rc;
546 }
547 
548 int
lstcon_nodes_add(char * name,int count,lnet_process_id_t * ids_up,unsigned * featp,struct list_head * result_up)549 lstcon_nodes_add(char *name, int count, lnet_process_id_t *ids_up,
550 		 unsigned *featp, struct list_head *result_up)
551 {
552 	lstcon_group_t	 *grp;
553 	int		     rc;
554 
555 	LASSERT (count > 0);
556 	LASSERT (ids_up != NULL);
557 
558 	rc = lstcon_group_find(name, &grp);
559 	if (rc != 0) {
560 		CDEBUG(D_NET, "Can't find group %s\n", name);
561 		return rc;
562 	}
563 
564 	if (grp->grp_ref > 2) {
565 		/* referred by other threads or test */
566 		CDEBUG(D_NET, "Group %s is busy\n", name);
567 		lstcon_group_put(grp);
568 
569 		return -EBUSY;
570 	}
571 
572 	rc = lstcon_group_nodes_add(grp, count, ids_up, featp, result_up);
573 
574 	lstcon_group_put(grp);
575 
576 	return rc;
577 }
578 
579 int
lstcon_group_del(char * name)580 lstcon_group_del(char *name)
581 {
582 	lstcon_rpc_trans_t *trans;
583 	lstcon_group_t     *grp;
584 	int		 rc;
585 
586 	rc = lstcon_group_find(name, &grp);
587 	if (rc != 0) {
588 		CDEBUG(D_NET, "Can't find group: %s\n", name);
589 		return rc;
590 	}
591 
592 	if (grp->grp_ref > 2) {
593 		/* referred by others threads or test */
594 		CDEBUG(D_NET, "Group %s is busy\n", name);
595 		lstcon_group_put(grp);
596 		return -EBUSY;
597 	}
598 
599 	rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
600 				     &grp->grp_trans_list, LST_TRANS_SESEND,
601 				     grp, lstcon_sesrpc_condition, &trans);
602 	if (rc != 0) {
603 		CERROR("Can't create transaction: %d\n", rc);
604 		lstcon_group_put(grp);
605 		return rc;
606 	}
607 
608 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
609 
610 	lstcon_rpc_trans_destroy(trans);
611 
612 	lstcon_group_put(grp);
613 	/* -ref for session, it's destroyed,
614 	 * status can't be rolled back, destroy group anyway */
615 	lstcon_group_put(grp);
616 
617 	return rc;
618 }
619 
620 int
lstcon_group_clean(char * name,int args)621 lstcon_group_clean(char *name, int args)
622 {
623 	lstcon_group_t *grp = NULL;
624 	int	     rc;
625 
626 	rc = lstcon_group_find(name, &grp);
627 	if (rc != 0) {
628 		CDEBUG(D_NET, "Can't find group %s\n", name);
629 		return rc;
630 	}
631 
632 	if (grp->grp_ref > 2) {
633 		/* referred by test */
634 		CDEBUG(D_NET, "Group %s is busy\n", name);
635 		lstcon_group_put(grp);
636 		return -EBUSY;
637 	}
638 
639 	args = (LST_NODE_ACTIVE | LST_NODE_BUSY |
640 		LST_NODE_DOWN | LST_NODE_UNKNOWN) & ~args;
641 
642 	lstcon_group_drain(grp, args);
643 
644 	lstcon_group_put(grp);
645 	/* release empty group */
646 	if (list_empty(&grp->grp_ndl_list))
647 		lstcon_group_put(grp);
648 
649 	return 0;
650 }
651 
652 int
lstcon_nodes_remove(char * name,int count,lnet_process_id_t * ids_up,struct list_head * result_up)653 lstcon_nodes_remove(char *name, int count,
654 		    lnet_process_id_t *ids_up, struct list_head *result_up)
655 {
656 	lstcon_group_t *grp = NULL;
657 	int	     rc;
658 
659 	rc = lstcon_group_find(name, &grp);
660 	if (rc != 0) {
661 		CDEBUG(D_NET, "Can't find group: %s\n", name);
662 		return rc;
663 	}
664 
665 	if (grp->grp_ref > 2) {
666 		/* referred by test */
667 		CDEBUG(D_NET, "Group %s is busy\n", name);
668 		lstcon_group_put(grp);
669 		return -EBUSY;
670 	}
671 
672 	rc = lstcon_group_nodes_remove(grp, count, ids_up, result_up);
673 
674 	lstcon_group_put(grp);
675 	/* release empty group */
676 	if (list_empty(&grp->grp_ndl_list))
677 		lstcon_group_put(grp);
678 
679 	return rc;
680 }
681 
682 int
lstcon_group_refresh(char * name,struct list_head * result_up)683 lstcon_group_refresh(char *name, struct list_head *result_up)
684 {
685 	lstcon_rpc_trans_t      *trans;
686 	lstcon_group_t	  *grp;
687 	int		      rc;
688 
689 	rc = lstcon_group_find(name, &grp);
690 	if (rc != 0) {
691 		CDEBUG(D_NET, "Can't find group: %s\n", name);
692 		return rc;
693 	}
694 
695 	if (grp->grp_ref > 2) {
696 		/* referred by test */
697 		CDEBUG(D_NET, "Group %s is busy\n", name);
698 		lstcon_group_put(grp);
699 		return -EBUSY;
700 	}
701 
702 	/* re-invite all inactive nodes int the group */
703 	rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
704 				     &grp->grp_trans_list, LST_TRANS_SESNEW,
705 				     grp, lstcon_sesrpc_condition, &trans);
706 	if (rc != 0) {
707 		/* local error, return */
708 		CDEBUG(D_NET, "Can't create transaction: %d\n", rc);
709 		lstcon_group_put(grp);
710 		return rc;
711 	}
712 
713 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
714 
715 	rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
716 
717 	lstcon_rpc_trans_destroy(trans);
718 	/* -ref for me */
719 	lstcon_group_put(grp);
720 
721 	return rc;
722 }
723 
724 int
lstcon_group_list(int index,int len,char * name_up)725 lstcon_group_list(int index, int len, char *name_up)
726 {
727 	lstcon_group_t *grp;
728 
729 	LASSERT (index >= 0);
730 	LASSERT (name_up != NULL);
731 
732 	list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) {
733 		if (index-- == 0) {
734 			return copy_to_user(name_up, grp->grp_name, len) ?
735 			       -EFAULT : 0;
736 		}
737 	}
738 
739 	return -ENOENT;
740 }
741 
742 static int
lstcon_nodes_getent(struct list_head * head,int * index_p,int * count_p,lstcon_node_ent_t * dents_up)743 lstcon_nodes_getent(struct list_head *head, int *index_p,
744 		    int *count_p, lstcon_node_ent_t *dents_up)
745 {
746 	lstcon_ndlink_t  *ndl;
747 	lstcon_node_t    *nd;
748 	int	       count = 0;
749 	int	       index = 0;
750 
751 	LASSERT (index_p != NULL && count_p != NULL);
752 	LASSERT (dents_up != NULL);
753 	LASSERT (*index_p >= 0);
754 	LASSERT (*count_p > 0);
755 
756 	list_for_each_entry(ndl, head, ndl_link) {
757 		if (index++ < *index_p)
758 			continue;
759 
760 		if (count >= *count_p)
761 			break;
762 
763 		nd = ndl->ndl_node;
764 		if (copy_to_user(&dents_up[count].nde_id,
765 				     &nd->nd_id, sizeof(nd->nd_id)) ||
766 		    copy_to_user(&dents_up[count].nde_state,
767 				     &nd->nd_state, sizeof(nd->nd_state)))
768 			return -EFAULT;
769 
770 		count ++;
771 	}
772 
773 	if (index <= *index_p)
774 		return -ENOENT;
775 
776 	*count_p = count;
777 	*index_p = index;
778 
779 	return 0;
780 }
781 
782 int
lstcon_group_info(char * name,lstcon_ndlist_ent_t * gents_p,int * index_p,int * count_p,lstcon_node_ent_t * dents_up)783 lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p,
784 		  int *index_p, int *count_p, lstcon_node_ent_t *dents_up)
785 {
786 	lstcon_ndlist_ent_t *gentp;
787 	lstcon_group_t      *grp;
788 	lstcon_ndlink_t     *ndl;
789 	int		  rc;
790 
791 	rc = lstcon_group_find(name, &grp);
792 	if (rc != 0) {
793 		CDEBUG(D_NET, "Can't find group %s\n", name);
794 		return rc;
795 	}
796 
797 	if (dents_up) {
798 		/* verbose query */
799 		rc = lstcon_nodes_getent(&grp->grp_ndl_list,
800 					 index_p, count_p, dents_up);
801 		lstcon_group_put(grp);
802 
803 		return rc;
804 	}
805 
806 	/* non-verbose query */
807 	LIBCFS_ALLOC(gentp, sizeof(lstcon_ndlist_ent_t));
808 	if (gentp == NULL) {
809 		CERROR("Can't allocate ndlist_ent\n");
810 		lstcon_group_put(grp);
811 
812 		return -ENOMEM;
813 	}
814 
815 	list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link)
816 		LST_NODE_STATE_COUNTER(ndl->ndl_node, gentp);
817 
818 	rc = copy_to_user(gents_p, gentp,
819 			      sizeof(lstcon_ndlist_ent_t)) ? -EFAULT: 0;
820 
821 	LIBCFS_FREE(gentp, sizeof(lstcon_ndlist_ent_t));
822 
823 	lstcon_group_put(grp);
824 
825 	return 0;
826 }
827 
828 static int
lstcon_batch_find(const char * name,lstcon_batch_t ** batpp)829 lstcon_batch_find(const char *name, lstcon_batch_t **batpp)
830 {
831 	lstcon_batch_t   *bat;
832 
833 	list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) {
834 		if (strncmp(bat->bat_name, name, LST_NAME_SIZE) == 0) {
835 			*batpp = bat;
836 			return 0;
837 		}
838 	}
839 
840 	return -ENOENT;
841 }
842 
843 int
lstcon_batch_add(char * name)844 lstcon_batch_add(char *name)
845 {
846 	lstcon_batch_t   *bat;
847 	int	       i;
848 	int	       rc;
849 
850 	rc = (lstcon_batch_find(name, &bat) == 0)? -EEXIST: 0;
851 	if (rc != 0) {
852 		CDEBUG(D_NET, "Batch %s already exists\n", name);
853 		return rc;
854 	}
855 
856 	LIBCFS_ALLOC(bat, sizeof(lstcon_batch_t));
857 	if (bat == NULL) {
858 		CERROR("Can't allocate descriptor for batch %s\n", name);
859 		return -ENOMEM;
860 	}
861 
862 	LIBCFS_ALLOC(bat->bat_cli_hash,
863 		     sizeof(struct list_head) * LST_NODE_HASHSIZE);
864 	if (bat->bat_cli_hash == NULL) {
865 		CERROR("Can't allocate hash for batch %s\n", name);
866 		LIBCFS_FREE(bat, sizeof(lstcon_batch_t));
867 
868 		return -ENOMEM;
869 	}
870 
871 	LIBCFS_ALLOC(bat->bat_srv_hash,
872 		     sizeof(struct list_head) * LST_NODE_HASHSIZE);
873 	if (bat->bat_srv_hash == NULL) {
874 		CERROR("Can't allocate hash for batch %s\n", name);
875 		LIBCFS_FREE(bat->bat_cli_hash, LST_NODE_HASHSIZE);
876 		LIBCFS_FREE(bat, sizeof(lstcon_batch_t));
877 
878 		return -ENOMEM;
879 	}
880 
881 	strcpy(bat->bat_name, name);
882 	bat->bat_hdr.tsb_index = 0;
883 	bat->bat_hdr.tsb_id.bat_id = ++console_session.ses_id_cookie;
884 
885 	bat->bat_ntest = 0;
886 	bat->bat_state = LST_BATCH_IDLE;
887 
888 	INIT_LIST_HEAD(&bat->bat_cli_list);
889 	INIT_LIST_HEAD(&bat->bat_srv_list);
890 	INIT_LIST_HEAD(&bat->bat_test_list);
891 	INIT_LIST_HEAD(&bat->bat_trans_list);
892 
893 	for (i = 0; i < LST_NODE_HASHSIZE; i++) {
894 		INIT_LIST_HEAD(&bat->bat_cli_hash[i]);
895 		INIT_LIST_HEAD(&bat->bat_srv_hash[i]);
896 	}
897 
898 	list_add_tail(&bat->bat_link, &console_session.ses_bat_list);
899 
900 	return rc;
901 }
902 
903 int
lstcon_batch_list(int index,int len,char * name_up)904 lstcon_batch_list(int index, int len, char *name_up)
905 {
906 	lstcon_batch_t    *bat;
907 
908 	LASSERT (name_up != NULL);
909 	LASSERT (index >= 0);
910 
911 	list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) {
912 		if (index-- == 0) {
913 			return copy_to_user(name_up, bat->bat_name, len) ?
914 			       -EFAULT: 0;
915 		}
916 	}
917 
918 	return -ENOENT;
919 }
920 
921 int
lstcon_batch_info(char * name,lstcon_test_batch_ent_t * ent_up,int server,int testidx,int * index_p,int * ndent_p,lstcon_node_ent_t * dents_up)922 lstcon_batch_info(char *name, lstcon_test_batch_ent_t *ent_up, int server,
923 		  int testidx, int *index_p, int *ndent_p,
924 		  lstcon_node_ent_t *dents_up)
925 {
926 	lstcon_test_batch_ent_t *entp;
927 	struct list_head	      *clilst;
928 	struct list_head	      *srvlst;
929 	lstcon_test_t	   *test = NULL;
930 	lstcon_batch_t	  *bat;
931 	lstcon_ndlink_t	 *ndl;
932 	int		      rc;
933 
934 	rc = lstcon_batch_find(name, &bat);
935 	if (rc != 0) {
936 		CDEBUG(D_NET, "Can't find batch %s\n", name);
937 		return -ENOENT;
938 	}
939 
940 	if (testidx > 0) {
941 		/* query test, test index start from 1 */
942 		list_for_each_entry(test, &bat->bat_test_list, tes_link) {
943 			if (testidx-- == 1)
944 				break;
945 		}
946 
947 		if (testidx > 0) {
948 			CDEBUG(D_NET, "Can't find specified test in batch\n");
949 			return -ENOENT;
950 		}
951 	}
952 
953 	clilst = (test == NULL) ? &bat->bat_cli_list :
954 				  &test->tes_src_grp->grp_ndl_list;
955 	srvlst = (test == NULL) ? &bat->bat_srv_list :
956 				  &test->tes_dst_grp->grp_ndl_list;
957 
958 	if (dents_up != NULL) {
959 		rc = lstcon_nodes_getent((server ? srvlst: clilst),
960 					 index_p, ndent_p, dents_up);
961 		return rc;
962 	}
963 
964 	/* non-verbose query */
965 	LIBCFS_ALLOC(entp, sizeof(lstcon_test_batch_ent_t));
966 	if (entp == NULL)
967 		return -ENOMEM;
968 
969 	if (test == NULL) {
970 		entp->u.tbe_batch.bae_ntest = bat->bat_ntest;
971 		entp->u.tbe_batch.bae_state = bat->bat_state;
972 
973 	} else {
974 
975 		entp->u.tbe_test.tse_type   = test->tes_type;
976 		entp->u.tbe_test.tse_loop   = test->tes_loop;
977 		entp->u.tbe_test.tse_concur = test->tes_concur;
978 	}
979 
980 	list_for_each_entry(ndl, clilst, ndl_link)
981 		LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_cli_nle);
982 
983 	list_for_each_entry(ndl, srvlst, ndl_link)
984 		LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_srv_nle);
985 
986 	rc = copy_to_user(ent_up, entp,
987 			      sizeof(lstcon_test_batch_ent_t)) ? -EFAULT : 0;
988 
989 	LIBCFS_FREE(entp, sizeof(lstcon_test_batch_ent_t));
990 
991 	return rc;
992 }
993 
994 static int
lstcon_batrpc_condition(int transop,lstcon_node_t * nd,void * arg)995 lstcon_batrpc_condition(int transop, lstcon_node_t *nd, void *arg)
996 {
997 	switch (transop) {
998 	case LST_TRANS_TSBRUN:
999 		if (nd->nd_state != LST_NODE_ACTIVE)
1000 			return -ENETDOWN;
1001 		break;
1002 
1003 	case LST_TRANS_TSBSTOP:
1004 		if (nd->nd_state != LST_NODE_ACTIVE)
1005 			return 0;
1006 		break;
1007 
1008 	case LST_TRANS_TSBCLIQRY:
1009 	case LST_TRANS_TSBSRVQRY:
1010 		break;
1011 	}
1012 
1013 	return 1;
1014 }
1015 
1016 static int
lstcon_batch_op(lstcon_batch_t * bat,int transop,struct list_head * result_up)1017 lstcon_batch_op(lstcon_batch_t *bat, int transop,
1018 		struct list_head *result_up)
1019 {
1020 	lstcon_rpc_trans_t *trans;
1021 	int		 rc;
1022 
1023 	rc = lstcon_rpc_trans_ndlist(&bat->bat_cli_list,
1024 				     &bat->bat_trans_list, transop,
1025 				     bat, lstcon_batrpc_condition, &trans);
1026 	if (rc != 0) {
1027 		CERROR("Can't create transaction: %d\n", rc);
1028 		return rc;
1029 	}
1030 
1031 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1032 
1033 	rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL);
1034 
1035 	lstcon_rpc_trans_destroy(trans);
1036 
1037 	return rc;
1038 }
1039 
1040 int
lstcon_batch_run(char * name,int timeout,struct list_head * result_up)1041 lstcon_batch_run(char *name, int timeout, struct list_head *result_up)
1042 {
1043 	lstcon_batch_t *bat;
1044 	int	     rc;
1045 
1046 	if (lstcon_batch_find(name, &bat) != 0) {
1047 		CDEBUG(D_NET, "Can't find batch %s\n", name);
1048 		return -ENOENT;
1049 	}
1050 
1051 	bat->bat_arg = timeout;
1052 
1053 	rc = lstcon_batch_op(bat, LST_TRANS_TSBRUN, result_up);
1054 
1055 	/* mark batch as running if it's started in any node */
1056 	if (lstcon_tsbop_stat_success(lstcon_trans_stat(), 0) != 0)
1057 		bat->bat_state = LST_BATCH_RUNNING;
1058 
1059 	return rc;
1060 }
1061 
1062 int
lstcon_batch_stop(char * name,int force,struct list_head * result_up)1063 lstcon_batch_stop(char *name, int force, struct list_head *result_up)
1064 {
1065 	lstcon_batch_t *bat;
1066 	int	     rc;
1067 
1068 	if (lstcon_batch_find(name, &bat) != 0) {
1069 		CDEBUG(D_NET, "Can't find batch %s\n", name);
1070 		return -ENOENT;
1071 	}
1072 
1073 	bat->bat_arg = force;
1074 
1075 	rc = lstcon_batch_op(bat, LST_TRANS_TSBSTOP, result_up);
1076 
1077 	/* mark batch as stopped if all RPCs finished */
1078 	if (lstcon_tsbop_stat_failure(lstcon_trans_stat(), 0) == 0)
1079 		bat->bat_state = LST_BATCH_IDLE;
1080 
1081 	return rc;
1082 }
1083 
1084 static void
lstcon_batch_destroy(lstcon_batch_t * bat)1085 lstcon_batch_destroy(lstcon_batch_t *bat)
1086 {
1087 	lstcon_ndlink_t    *ndl;
1088 	lstcon_test_t      *test;
1089 	int		 i;
1090 
1091 	list_del(&bat->bat_link);
1092 
1093 	while (!list_empty(&bat->bat_test_list)) {
1094 		test = list_entry(bat->bat_test_list.next,
1095 				      lstcon_test_t, tes_link);
1096 		LASSERT (list_empty(&test->tes_trans_list));
1097 
1098 		list_del(&test->tes_link);
1099 
1100 		lstcon_group_put(test->tes_src_grp);
1101 		lstcon_group_put(test->tes_dst_grp);
1102 
1103 		LIBCFS_FREE(test, offsetof(lstcon_test_t,
1104 					   tes_param[test->tes_paramlen]));
1105 	}
1106 
1107 	LASSERT (list_empty(&bat->bat_trans_list));
1108 
1109 	while (!list_empty(&bat->bat_cli_list)) {
1110 		ndl = list_entry(bat->bat_cli_list.next,
1111 				     lstcon_ndlink_t, ndl_link);
1112 		list_del_init(&ndl->ndl_link);
1113 
1114 		lstcon_ndlink_release(ndl);
1115 	}
1116 
1117 	while (!list_empty(&bat->bat_srv_list)) {
1118 		ndl = list_entry(bat->bat_srv_list.next,
1119 				     lstcon_ndlink_t, ndl_link);
1120 		list_del_init(&ndl->ndl_link);
1121 
1122 		lstcon_ndlink_release(ndl);
1123 	}
1124 
1125 	for (i = 0; i < LST_NODE_HASHSIZE; i++) {
1126 		LASSERT (list_empty(&bat->bat_cli_hash[i]));
1127 		LASSERT (list_empty(&bat->bat_srv_hash[i]));
1128 	}
1129 
1130 	LIBCFS_FREE(bat->bat_cli_hash,
1131 		    sizeof(struct list_head) * LST_NODE_HASHSIZE);
1132 	LIBCFS_FREE(bat->bat_srv_hash,
1133 		    sizeof(struct list_head) * LST_NODE_HASHSIZE);
1134 	LIBCFS_FREE(bat, sizeof(lstcon_batch_t));
1135 }
1136 
1137 static int
lstcon_testrpc_condition(int transop,lstcon_node_t * nd,void * arg)1138 lstcon_testrpc_condition(int transop, lstcon_node_t *nd, void *arg)
1139 {
1140 	lstcon_test_t    *test;
1141 	lstcon_batch_t   *batch;
1142 	lstcon_ndlink_t  *ndl;
1143 	struct list_head       *hash;
1144 	struct list_head       *head;
1145 
1146 	test = (lstcon_test_t *)arg;
1147 	LASSERT (test != NULL);
1148 
1149 	batch = test->tes_batch;
1150 	LASSERT (batch != NULL);
1151 
1152 	if (test->tes_oneside &&
1153 	    transop == LST_TRANS_TSBSRVADD)
1154 		return 0;
1155 
1156 	if (nd->nd_state != LST_NODE_ACTIVE)
1157 		return -ENETDOWN;
1158 
1159 	if (transop == LST_TRANS_TSBCLIADD) {
1160 		hash = batch->bat_cli_hash;
1161 		head = &batch->bat_cli_list;
1162 
1163 	} else {
1164 		LASSERT (transop == LST_TRANS_TSBSRVADD);
1165 
1166 		hash = batch->bat_srv_hash;
1167 		head = &batch->bat_srv_list;
1168 	}
1169 
1170 	LASSERT (nd->nd_id.nid != LNET_NID_ANY);
1171 
1172 	if (lstcon_ndlink_find(hash, nd->nd_id, &ndl, 1) != 0)
1173 		return -ENOMEM;
1174 
1175 	if (list_empty(&ndl->ndl_link))
1176 		list_add_tail(&ndl->ndl_link, head);
1177 
1178 	return 1;
1179 }
1180 
1181 static int
lstcon_test_nodes_add(lstcon_test_t * test,struct list_head * result_up)1182 lstcon_test_nodes_add(lstcon_test_t *test, struct list_head *result_up)
1183 {
1184 	lstcon_rpc_trans_t     *trans;
1185 	lstcon_group_t	 *grp;
1186 	int		     transop;
1187 	int		     rc;
1188 
1189 	LASSERT (test->tes_src_grp != NULL);
1190 	LASSERT (test->tes_dst_grp != NULL);
1191 
1192 	transop = LST_TRANS_TSBSRVADD;
1193 	grp  = test->tes_dst_grp;
1194 again:
1195 	rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list,
1196 				     &test->tes_trans_list, transop,
1197 				     test, lstcon_testrpc_condition, &trans);
1198 	if (rc != 0) {
1199 		CERROR("Can't create transaction: %d\n", rc);
1200 		return rc;
1201 	}
1202 
1203 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1204 
1205 	if (lstcon_trans_stat()->trs_rpc_errno != 0 ||
1206 	    lstcon_trans_stat()->trs_fwk_errno != 0) {
1207 		lstcon_rpc_trans_interpreter(trans, result_up, NULL);
1208 
1209 		lstcon_rpc_trans_destroy(trans);
1210 		/* return if any error */
1211 		CDEBUG(D_NET, "Failed to add test %s, "
1212 			      "RPC error %d, framework error %d\n",
1213 		       transop == LST_TRANS_TSBCLIADD ? "client" : "server",
1214 		       lstcon_trans_stat()->trs_rpc_errno,
1215 		       lstcon_trans_stat()->trs_fwk_errno);
1216 
1217 		return rc;
1218 	}
1219 
1220 	lstcon_rpc_trans_destroy(trans);
1221 
1222 	if (transop == LST_TRANS_TSBCLIADD)
1223 		return rc;
1224 
1225 	transop = LST_TRANS_TSBCLIADD;
1226 	grp = test->tes_src_grp;
1227 	test->tes_cliidx = 0;
1228 
1229 	/* requests to test clients */
1230 	goto again;
1231 }
1232 
1233 static int
lstcon_verify_batch(const char * name,lstcon_batch_t ** batch)1234 lstcon_verify_batch(const char *name, lstcon_batch_t **batch)
1235 {
1236 	int rc;
1237 
1238 	rc = lstcon_batch_find(name, batch);
1239 	if (rc != 0) {
1240 		CDEBUG(D_NET, "Can't find batch %s\n", name);
1241 		return rc;
1242 	}
1243 
1244 	if ((*batch)->bat_state != LST_BATCH_IDLE) {
1245 		CDEBUG(D_NET, "Can't change running batch %s\n", name);
1246 		return -EINVAL;
1247 	}
1248 
1249 	return 0;
1250 }
1251 
1252 static int
lstcon_verify_group(const char * name,lstcon_group_t ** grp)1253 lstcon_verify_group(const char *name, lstcon_group_t **grp)
1254 {
1255 	int			rc;
1256 	lstcon_ndlink_t		*ndl;
1257 
1258 	rc = lstcon_group_find(name, grp);
1259 	if (rc != 0) {
1260 		CDEBUG(D_NET, "can't find group %s\n", name);
1261 		return rc;
1262 	}
1263 
1264 	list_for_each_entry(ndl, &(*grp)->grp_ndl_list, ndl_link) {
1265 		if (ndl->ndl_node->nd_state == LST_NODE_ACTIVE)
1266 			return 0;
1267 	}
1268 
1269 	CDEBUG(D_NET, "Group %s has no ACTIVE nodes\n", name);
1270 
1271 	return -EINVAL;
1272 }
1273 
1274 int
lstcon_test_add(char * batch_name,int type,int loop,int concur,int dist,int span,char * src_name,char * dst_name,void * param,int paramlen,int * retp,struct list_head * result_up)1275 lstcon_test_add(char *batch_name, int type, int loop,
1276 		int concur, int dist, int span,
1277 		char *src_name, char *dst_name,
1278 		void *param, int paramlen, int *retp,
1279 		struct list_head *result_up)
1280 {
1281 	lstcon_test_t	 *test	 = NULL;
1282 	int		 rc;
1283 	lstcon_group_t	 *src_grp = NULL;
1284 	lstcon_group_t	 *dst_grp = NULL;
1285 	lstcon_batch_t	 *batch = NULL;
1286 
1287 	/*
1288 	 * verify that a batch of the given name exists, and the groups
1289 	 * that will be part of the batch exist and have at least one
1290 	 * active node
1291 	 */
1292 	rc = lstcon_verify_batch(batch_name, &batch);
1293 	if (rc != 0)
1294 		goto out;
1295 
1296 	rc = lstcon_verify_group(src_name, &src_grp);
1297 	if (rc != 0)
1298 		goto out;
1299 
1300 	rc = lstcon_verify_group(dst_name, &dst_grp);
1301 	if (rc != 0)
1302 		goto out;
1303 
1304 	if (dst_grp->grp_userland)
1305 		*retp = 1;
1306 
1307 	LIBCFS_ALLOC(test, offsetof(lstcon_test_t, tes_param[paramlen]));
1308 	if (!test) {
1309 		CERROR("Can't allocate test descriptor\n");
1310 		rc = -ENOMEM;
1311 
1312 		goto out;
1313 	}
1314 
1315 	test->tes_hdr.tsb_id	= batch->bat_hdr.tsb_id;
1316 	test->tes_batch		= batch;
1317 	test->tes_type		= type;
1318 	test->tes_oneside	= 0; /* TODO */
1319 	test->tes_loop		= loop;
1320 	test->tes_concur	= concur;
1321 	test->tes_stop_onerr	= 1; /* TODO */
1322 	test->tes_span		= span;
1323 	test->tes_dist		= dist;
1324 	test->tes_cliidx	= 0; /* just used for creating RPC */
1325 	test->tes_src_grp	= src_grp;
1326 	test->tes_dst_grp	= dst_grp;
1327 	INIT_LIST_HEAD(&test->tes_trans_list);
1328 
1329 	if (param != NULL) {
1330 		test->tes_paramlen = paramlen;
1331 		memcpy(&test->tes_param[0], param, paramlen);
1332 	}
1333 
1334 	rc = lstcon_test_nodes_add(test, result_up);
1335 
1336 	if (rc != 0)
1337 		goto out;
1338 
1339 	if (lstcon_trans_stat()->trs_rpc_errno != 0 ||
1340 	    lstcon_trans_stat()->trs_fwk_errno != 0)
1341 		CDEBUG(D_NET, "Failed to add test %d to batch %s\n", type,
1342 		       batch_name);
1343 
1344 	/* add to test list anyway, so user can check what's going on */
1345 	list_add_tail(&test->tes_link, &batch->bat_test_list);
1346 
1347 	batch->bat_ntest ++;
1348 	test->tes_hdr.tsb_index = batch->bat_ntest;
1349 
1350 	/*  hold groups so nobody can change them */
1351 	return rc;
1352 out:
1353 	if (test != NULL)
1354 		LIBCFS_FREE(test, offsetof(lstcon_test_t, tes_param[paramlen]));
1355 
1356 	if (dst_grp != NULL)
1357 		lstcon_group_put(dst_grp);
1358 
1359 	if (src_grp != NULL)
1360 		lstcon_group_put(src_grp);
1361 
1362 	return rc;
1363 }
1364 
1365 static int
lstcon_test_find(lstcon_batch_t * batch,int idx,lstcon_test_t ** testpp)1366 lstcon_test_find(lstcon_batch_t *batch, int idx, lstcon_test_t **testpp)
1367 {
1368 	lstcon_test_t *test;
1369 
1370 	list_for_each_entry(test, &batch->bat_test_list, tes_link) {
1371 		if (idx == test->tes_hdr.tsb_index) {
1372 			*testpp = test;
1373 			return 0;
1374 		}
1375 	}
1376 
1377 	return -ENOENT;
1378 }
1379 
1380 static int
lstcon_tsbrpc_readent(int transop,srpc_msg_t * msg,lstcon_rpc_ent_t * ent_up)1381 lstcon_tsbrpc_readent(int transop, srpc_msg_t *msg,
1382 		      lstcon_rpc_ent_t *ent_up)
1383 {
1384 	srpc_batch_reply_t *rep = &msg->msg_body.bat_reply;
1385 
1386 	LASSERT (transop == LST_TRANS_TSBCLIQRY ||
1387 		 transop == LST_TRANS_TSBSRVQRY);
1388 
1389 	/* positive errno, framework error code */
1390 	if (copy_to_user(&ent_up->rpe_priv[0],
1391 			     &rep->bar_active, sizeof(rep->bar_active)))
1392 		return -EFAULT;
1393 
1394 	return 0;
1395 }
1396 
1397 int
lstcon_test_batch_query(char * name,int testidx,int client,int timeout,struct list_head * result_up)1398 lstcon_test_batch_query(char *name, int testidx, int client,
1399 			int timeout, struct list_head *result_up)
1400 {
1401 	lstcon_rpc_trans_t *trans;
1402 	struct list_head	 *translist;
1403 	struct list_head	 *ndlist;
1404 	lstcon_tsb_hdr_t   *hdr;
1405 	lstcon_batch_t     *batch;
1406 	lstcon_test_t      *test = NULL;
1407 	int		 transop;
1408 	int		 rc;
1409 
1410 	rc = lstcon_batch_find(name, &batch);
1411 	if (rc != 0) {
1412 		CDEBUG(D_NET, "Can't find batch: %s\n", name);
1413 		return rc;
1414 	}
1415 
1416 	if (testidx == 0) {
1417 		translist = &batch->bat_trans_list;
1418 		ndlist    = &batch->bat_cli_list;
1419 		hdr       = &batch->bat_hdr;
1420 
1421 	} else {
1422 		/* query specified test only */
1423 		rc = lstcon_test_find(batch, testidx, &test);
1424 		if (rc != 0) {
1425 			CDEBUG(D_NET, "Can't find test: %d\n", testidx);
1426 			return rc;
1427 		}
1428 
1429 		translist = &test->tes_trans_list;
1430 		ndlist    = &test->tes_src_grp->grp_ndl_list;
1431 		hdr       = &test->tes_hdr;
1432 	}
1433 
1434 	transop = client ? LST_TRANS_TSBCLIQRY : LST_TRANS_TSBSRVQRY;
1435 
1436 	rc = lstcon_rpc_trans_ndlist(ndlist, translist, transop, hdr,
1437 				     lstcon_batrpc_condition, &trans);
1438 	if (rc != 0) {
1439 		CERROR("Can't create transaction: %d\n", rc);
1440 		return rc;
1441 	}
1442 
1443 	lstcon_rpc_trans_postwait(trans, timeout);
1444 
1445 	if (testidx == 0 && /* query a batch, not a test */
1446 	    lstcon_rpc_stat_failure(lstcon_trans_stat(), 0) == 0 &&
1447 	    lstcon_tsbqry_stat_run(lstcon_trans_stat(), 0) == 0) {
1448 		/* all RPCs finished, and no active test */
1449 		batch->bat_state = LST_BATCH_IDLE;
1450 	}
1451 
1452 	rc = lstcon_rpc_trans_interpreter(trans, result_up,
1453 					  lstcon_tsbrpc_readent);
1454 	lstcon_rpc_trans_destroy(trans);
1455 
1456 	return rc;
1457 }
1458 
1459 static int
lstcon_statrpc_readent(int transop,srpc_msg_t * msg,lstcon_rpc_ent_t * ent_up)1460 lstcon_statrpc_readent(int transop, srpc_msg_t *msg,
1461 		       lstcon_rpc_ent_t *ent_up)
1462 {
1463 	srpc_stat_reply_t *rep = &msg->msg_body.stat_reply;
1464 	sfw_counters_t    *sfwk_stat;
1465 	srpc_counters_t   *srpc_stat;
1466 	lnet_counters_t   *lnet_stat;
1467 
1468 	if (rep->str_status != 0)
1469 		return 0;
1470 
1471 	sfwk_stat = (sfw_counters_t *)&ent_up->rpe_payload[0];
1472 	srpc_stat = (srpc_counters_t *)((char *)sfwk_stat + sizeof(*sfwk_stat));
1473 	lnet_stat = (lnet_counters_t *)((char *)srpc_stat + sizeof(*srpc_stat));
1474 
1475 	if (copy_to_user(sfwk_stat, &rep->str_fw, sizeof(*sfwk_stat)) ||
1476 	    copy_to_user(srpc_stat, &rep->str_rpc, sizeof(*srpc_stat)) ||
1477 	    copy_to_user(lnet_stat, &rep->str_lnet, sizeof(*lnet_stat)))
1478 		return -EFAULT;
1479 
1480 	return 0;
1481 }
1482 
1483 static int
lstcon_ndlist_stat(struct list_head * ndlist,int timeout,struct list_head * result_up)1484 lstcon_ndlist_stat(struct list_head *ndlist,
1485 		   int timeout, struct list_head *result_up)
1486 {
1487 	struct list_head	  head;
1488 	lstcon_rpc_trans_t *trans;
1489 	int		 rc;
1490 
1491 	INIT_LIST_HEAD(&head);
1492 
1493 	rc = lstcon_rpc_trans_ndlist(ndlist, &head,
1494 				     LST_TRANS_STATQRY, NULL, NULL, &trans);
1495 	if (rc != 0) {
1496 		CERROR("Can't create transaction: %d\n", rc);
1497 		return rc;
1498 	}
1499 
1500 	lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout));
1501 
1502 	rc = lstcon_rpc_trans_interpreter(trans, result_up,
1503 					  lstcon_statrpc_readent);
1504 	lstcon_rpc_trans_destroy(trans);
1505 
1506 	return rc;
1507 }
1508 
1509 int
lstcon_group_stat(char * grp_name,int timeout,struct list_head * result_up)1510 lstcon_group_stat(char *grp_name, int timeout, struct list_head *result_up)
1511 {
1512 	lstcon_group_t     *grp;
1513 	int		 rc;
1514 
1515 	rc = lstcon_group_find(grp_name, &grp);
1516 	if (rc != 0) {
1517 		CDEBUG(D_NET, "Can't find group %s\n", grp_name);
1518 		return rc;
1519 	}
1520 
1521 	rc = lstcon_ndlist_stat(&grp->grp_ndl_list, timeout, result_up);
1522 
1523 	lstcon_group_put(grp);
1524 
1525 	return rc;
1526 }
1527 
1528 int
lstcon_nodes_stat(int count,lnet_process_id_t * ids_up,int timeout,struct list_head * result_up)1529 lstcon_nodes_stat(int count, lnet_process_id_t *ids_up,
1530 		  int timeout, struct list_head *result_up)
1531 {
1532 	lstcon_ndlink_t	 *ndl;
1533 	lstcon_group_t	  *tmp;
1534 	lnet_process_id_t	id;
1535 	int		      i;
1536 	int		      rc;
1537 
1538 	rc = lstcon_group_alloc(NULL, &tmp);
1539 	if (rc != 0) {
1540 		CERROR("Out of memory\n");
1541 		return -ENOMEM;
1542 	}
1543 
1544 	for (i = 0 ; i < count; i++) {
1545 		if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
1546 			rc = -EFAULT;
1547 			break;
1548 		}
1549 
1550 		/* add to tmp group */
1551 		rc = lstcon_group_ndlink_find(tmp, id, &ndl, 2);
1552 		if (rc != 0) {
1553 			CDEBUG((rc == -ENOMEM) ? D_ERROR : D_NET,
1554 			       "Failed to find or create %s: %d\n",
1555 			       libcfs_id2str(id), rc);
1556 			break;
1557 		}
1558 	}
1559 
1560 	if (rc != 0) {
1561 		lstcon_group_put(tmp);
1562 		return rc;
1563 	}
1564 
1565 	rc = lstcon_ndlist_stat(&tmp->grp_ndl_list, timeout, result_up);
1566 
1567 	lstcon_group_put(tmp);
1568 
1569 	return rc;
1570 }
1571 
1572 static int
lstcon_debug_ndlist(struct list_head * ndlist,struct list_head * translist,int timeout,struct list_head * result_up)1573 lstcon_debug_ndlist(struct list_head *ndlist,
1574 		    struct list_head *translist,
1575 		    int timeout, struct list_head *result_up)
1576 {
1577 	lstcon_rpc_trans_t *trans;
1578 	int		 rc;
1579 
1580 	rc = lstcon_rpc_trans_ndlist(ndlist, translist, LST_TRANS_SESQRY,
1581 				     NULL, lstcon_sesrpc_condition, &trans);
1582 	if (rc != 0) {
1583 		CERROR("Can't create transaction: %d\n", rc);
1584 		return rc;
1585 	}
1586 
1587 	lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout));
1588 
1589 	rc = lstcon_rpc_trans_interpreter(trans, result_up,
1590 					  lstcon_sesrpc_readent);
1591 	lstcon_rpc_trans_destroy(trans);
1592 
1593 	return rc;
1594 }
1595 
1596 int
lstcon_session_debug(int timeout,struct list_head * result_up)1597 lstcon_session_debug(int timeout, struct list_head *result_up)
1598 {
1599 	return lstcon_debug_ndlist(&console_session.ses_ndl_list,
1600 				   NULL, timeout, result_up);
1601 }
1602 
1603 int
lstcon_batch_debug(int timeout,char * name,int client,struct list_head * result_up)1604 lstcon_batch_debug(int timeout, char *name,
1605 		   int client, struct list_head *result_up)
1606 {
1607 	lstcon_batch_t *bat;
1608 	int	     rc;
1609 
1610 	rc = lstcon_batch_find(name, &bat);
1611 	if (rc != 0)
1612 		return -ENOENT;
1613 
1614 	rc = lstcon_debug_ndlist(client ? &bat->bat_cli_list :
1615 					  &bat->bat_srv_list,
1616 				 NULL, timeout, result_up);
1617 
1618 	return rc;
1619 }
1620 
1621 int
lstcon_group_debug(int timeout,char * name,struct list_head * result_up)1622 lstcon_group_debug(int timeout, char *name,
1623 		   struct list_head *result_up)
1624 {
1625 	lstcon_group_t *grp;
1626 	int	     rc;
1627 
1628 	rc = lstcon_group_find(name, &grp);
1629 	if (rc != 0)
1630 		return -ENOENT;
1631 
1632 	rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
1633 				 timeout, result_up);
1634 	lstcon_group_put(grp);
1635 
1636 	return rc;
1637 }
1638 
1639 int
lstcon_nodes_debug(int timeout,int count,lnet_process_id_t * ids_up,struct list_head * result_up)1640 lstcon_nodes_debug(int timeout,
1641 		   int count, lnet_process_id_t *ids_up,
1642 		   struct list_head *result_up)
1643 {
1644 	lnet_process_id_t  id;
1645 	lstcon_ndlink_t   *ndl;
1646 	lstcon_group_t    *grp;
1647 	int		i;
1648 	int		rc;
1649 
1650 	rc = lstcon_group_alloc(NULL, &grp);
1651 	if (rc != 0) {
1652 		CDEBUG(D_NET, "Out of memory\n");
1653 		return rc;
1654 	}
1655 
1656 	for (i = 0; i < count; i++) {
1657 		if (copy_from_user(&id, &ids_up[i], sizeof(id))) {
1658 			rc = -EFAULT;
1659 			break;
1660 		}
1661 
1662 		/* node is added to tmp group */
1663 		rc = lstcon_group_ndlink_find(grp, id, &ndl, 1);
1664 		if (rc != 0) {
1665 			CERROR("Can't create node link\n");
1666 			break;
1667 		}
1668 	}
1669 
1670 	if (rc != 0) {
1671 		lstcon_group_put(grp);
1672 		return rc;
1673 	}
1674 
1675 	rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL,
1676 				 timeout, result_up);
1677 
1678 	lstcon_group_put(grp);
1679 
1680 	return rc;
1681 }
1682 
1683 int
lstcon_session_match(lst_sid_t sid)1684 lstcon_session_match(lst_sid_t sid)
1685 {
1686 	return (console_session.ses_id.ses_nid   == sid.ses_nid &&
1687 		console_session.ses_id.ses_stamp == sid.ses_stamp) ?  1: 0;
1688 }
1689 
1690 static void
lstcon_new_session_id(lst_sid_t * sid)1691 lstcon_new_session_id(lst_sid_t *sid)
1692 {
1693 	lnet_process_id_t      id;
1694 
1695 	LASSERT (console_session.ses_state == LST_SESSION_NONE);
1696 
1697 	LNetGetId(1, &id);
1698 	sid->ses_nid   = id.nid;
1699 	sid->ses_stamp = cfs_time_current();
1700 }
1701 
1702 extern srpc_service_t lstcon_acceptor_service;
1703 
1704 int
lstcon_session_new(char * name,int key,unsigned feats,int timeout,int force,lst_sid_t * sid_up)1705 lstcon_session_new(char *name, int key, unsigned feats,
1706 		   int timeout, int force, lst_sid_t *sid_up)
1707 {
1708 	int     rc = 0;
1709 	int     i;
1710 
1711 	if (console_session.ses_state != LST_SESSION_NONE) {
1712 		/* session exists */
1713 		if (!force) {
1714 			CNETERR("Session %s already exists\n",
1715 				console_session.ses_name);
1716 			return -EEXIST;
1717 		}
1718 
1719 		rc = lstcon_session_end();
1720 
1721 		/* lstcon_session_end() only return local error */
1722 		if  (rc != 0)
1723 			return rc;
1724 	}
1725 
1726 	if ((feats & ~LST_FEATS_MASK) != 0) {
1727 		CNETERR("Unknown session features %x\n",
1728 			(feats & ~LST_FEATS_MASK));
1729 		return -EINVAL;
1730 	}
1731 
1732 	for (i = 0; i < LST_GLOBAL_HASHSIZE; i++)
1733 		LASSERT(list_empty(&console_session.ses_ndl_hash[i]));
1734 
1735 	lstcon_new_session_id(&console_session.ses_id);
1736 
1737 	console_session.ses_key	    = key;
1738 	console_session.ses_state   = LST_SESSION_ACTIVE;
1739 	console_session.ses_force   = !!force;
1740 	console_session.ses_features = feats;
1741 	console_session.ses_feats_updated = 0;
1742 	console_session.ses_timeout = (timeout <= 0) ?
1743 				      LST_CONSOLE_TIMEOUT : timeout;
1744 	strcpy(console_session.ses_name, name);
1745 
1746 	rc = lstcon_batch_add(LST_DEFAULT_BATCH);
1747 	if (rc != 0)
1748 		return rc;
1749 
1750 	rc = lstcon_rpc_pinger_start();
1751 	if (rc != 0) {
1752 		lstcon_batch_t *bat = NULL;
1753 
1754 		lstcon_batch_find(LST_DEFAULT_BATCH, &bat);
1755 		lstcon_batch_destroy(bat);
1756 
1757 		return rc;
1758 	}
1759 
1760 	if (copy_to_user(sid_up, &console_session.ses_id,
1761 			     sizeof(lst_sid_t)) == 0)
1762 		return rc;
1763 
1764 	lstcon_session_end();
1765 
1766 	return -EFAULT;
1767 }
1768 
1769 int
lstcon_session_info(lst_sid_t * sid_up,int * key_up,unsigned * featp,lstcon_ndlist_ent_t * ndinfo_up,char * name_up,int len)1770 lstcon_session_info(lst_sid_t *sid_up, int *key_up, unsigned *featp,
1771 		    lstcon_ndlist_ent_t *ndinfo_up, char *name_up, int len)
1772 {
1773 	lstcon_ndlist_ent_t *entp;
1774 	lstcon_ndlink_t     *ndl;
1775 	int		  rc = 0;
1776 
1777 	if (console_session.ses_state != LST_SESSION_ACTIVE)
1778 		return -ESRCH;
1779 
1780 	LIBCFS_ALLOC(entp, sizeof(*entp));
1781 	if (entp == NULL)
1782 		return -ENOMEM;
1783 
1784 	list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link)
1785 		LST_NODE_STATE_COUNTER(ndl->ndl_node, entp);
1786 
1787 	if (copy_to_user(sid_up, &console_session.ses_id,
1788 			     sizeof(lst_sid_t)) ||
1789 	    copy_to_user(key_up, &console_session.ses_key,
1790 			     sizeof(*key_up)) ||
1791 	    copy_to_user(featp, &console_session.ses_features,
1792 			     sizeof(*featp)) ||
1793 	    copy_to_user(ndinfo_up, entp, sizeof(*entp)) ||
1794 	    copy_to_user(name_up, console_session.ses_name, len))
1795 		rc = -EFAULT;
1796 
1797 	LIBCFS_FREE(entp, sizeof(*entp));
1798 
1799 	return rc;
1800 }
1801 
1802 int
lstcon_session_end(void)1803 lstcon_session_end(void)
1804 {
1805 	lstcon_rpc_trans_t *trans;
1806 	lstcon_group_t     *grp;
1807 	lstcon_batch_t     *bat;
1808 	int		 rc = 0;
1809 
1810 	LASSERT (console_session.ses_state == LST_SESSION_ACTIVE);
1811 
1812 	rc = lstcon_rpc_trans_ndlist(&console_session.ses_ndl_list,
1813 				     NULL, LST_TRANS_SESEND, NULL,
1814 				     lstcon_sesrpc_condition, &trans);
1815 	if (rc != 0) {
1816 		CERROR("Can't create transaction: %d\n", rc);
1817 		return rc;
1818 	}
1819 
1820 	console_session.ses_shutdown = 1;
1821 
1822 	lstcon_rpc_pinger_stop();
1823 
1824 	lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT);
1825 
1826 	lstcon_rpc_trans_destroy(trans);
1827 	/* User can do nothing even rpc failed, so go on */
1828 
1829 	/* waiting for orphan rpcs to die */
1830 	lstcon_rpc_cleanup_wait();
1831 
1832 	console_session.ses_id    = LST_INVALID_SID;
1833 	console_session.ses_state = LST_SESSION_NONE;
1834 	console_session.ses_key   = 0;
1835 	console_session.ses_force = 0;
1836 	console_session.ses_feats_updated = 0;
1837 
1838 	/* destroy all batches */
1839 	while (!list_empty(&console_session.ses_bat_list)) {
1840 		bat = list_entry(console_session.ses_bat_list.next,
1841 				     lstcon_batch_t, bat_link);
1842 
1843 		lstcon_batch_destroy(bat);
1844 	}
1845 
1846 	/* destroy all groups */
1847 	while (!list_empty(&console_session.ses_grp_list)) {
1848 		grp = list_entry(console_session.ses_grp_list.next,
1849 				     lstcon_group_t, grp_link);
1850 		LASSERT (grp->grp_ref == 1);
1851 
1852 		lstcon_group_put(grp);
1853 	}
1854 
1855 	/* all nodes should be released */
1856 	LASSERT (list_empty(&console_session.ses_ndl_list));
1857 
1858 	console_session.ses_shutdown = 0;
1859 	console_session.ses_expired  = 0;
1860 
1861 	return rc;
1862 }
1863 
1864 int
lstcon_session_feats_check(unsigned feats)1865 lstcon_session_feats_check(unsigned feats)
1866 {
1867 	int rc = 0;
1868 
1869 	if ((feats & ~LST_FEATS_MASK) != 0) {
1870 		CERROR("Can't support these features: %x\n",
1871 		       (feats & ~LST_FEATS_MASK));
1872 		return -EPROTO;
1873 	}
1874 
1875 	spin_lock(&console_session.ses_rpc_lock);
1876 
1877 	if (!console_session.ses_feats_updated) {
1878 		console_session.ses_feats_updated = 1;
1879 		console_session.ses_features = feats;
1880 	}
1881 
1882 	if (console_session.ses_features != feats)
1883 		rc = -EPROTO;
1884 
1885 	spin_unlock(&console_session.ses_rpc_lock);
1886 
1887 	if (rc != 0) {
1888 		CERROR("remote features %x do not match with "
1889 		       "session features %x of console\n",
1890 		       feats, console_session.ses_features);
1891 	}
1892 
1893 	return rc;
1894 }
1895 
1896 static int
lstcon_acceptor_handle(srpc_server_rpc_t * rpc)1897 lstcon_acceptor_handle (srpc_server_rpc_t *rpc)
1898 {
1899 	srpc_msg_t	*rep  = &rpc->srpc_replymsg;
1900 	srpc_msg_t	*req  = &rpc->srpc_reqstbuf->buf_msg;
1901 	srpc_join_reqst_t *jreq = &req->msg_body.join_reqst;
1902 	srpc_join_reply_t *jrep = &rep->msg_body.join_reply;
1903 	lstcon_group_t    *grp  = NULL;
1904 	lstcon_ndlink_t   *ndl;
1905 	int		rc   = 0;
1906 
1907 	sfw_unpack_message(req);
1908 
1909 	mutex_lock(&console_session.ses_mutex);
1910 
1911 	jrep->join_sid = console_session.ses_id;
1912 
1913 	if (console_session.ses_id.ses_nid == LNET_NID_ANY) {
1914 		jrep->join_status = ESRCH;
1915 		goto out;
1916 	}
1917 
1918 	if (lstcon_session_feats_check(req->msg_ses_feats) != 0) {
1919 		jrep->join_status = EPROTO;
1920 		goto out;
1921 	}
1922 
1923 	if (jreq->join_sid.ses_nid != LNET_NID_ANY &&
1924 	     !lstcon_session_match(jreq->join_sid)) {
1925 		jrep->join_status = EBUSY;
1926 		goto out;
1927 	}
1928 
1929 	if (lstcon_group_find(jreq->join_group, &grp) != 0) {
1930 		rc = lstcon_group_alloc(jreq->join_group, &grp);
1931 		if (rc != 0) {
1932 			CERROR("Out of memory\n");
1933 			goto out;
1934 		}
1935 
1936 		list_add_tail(&grp->grp_link,
1937 				  &console_session.ses_grp_list);
1938 		lstcon_group_addref(grp);
1939 	}
1940 
1941 	if (grp->grp_ref > 2) {
1942 		/* Group in using */
1943 		jrep->join_status = EBUSY;
1944 		goto out;
1945 	}
1946 
1947 	rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 0);
1948 	if (rc == 0) {
1949 		jrep->join_status = EEXIST;
1950 		goto out;
1951 	}
1952 
1953 	rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 1);
1954 	if (rc != 0) {
1955 		CERROR("Out of memory\n");
1956 		goto out;
1957 	}
1958 
1959 	ndl->ndl_node->nd_state   = LST_NODE_ACTIVE;
1960 	ndl->ndl_node->nd_timeout = console_session.ses_timeout;
1961 
1962 	if (grp->grp_userland == 0)
1963 		grp->grp_userland = 1;
1964 
1965 	strcpy(jrep->join_session, console_session.ses_name);
1966 	jrep->join_timeout = console_session.ses_timeout;
1967 	jrep->join_status  = 0;
1968 
1969 out:
1970 	rep->msg_ses_feats = console_session.ses_features;
1971 	if (grp != NULL)
1972 		lstcon_group_put(grp);
1973 
1974 	mutex_unlock(&console_session.ses_mutex);
1975 
1976 	return rc;
1977 }
1978 
1979 srpc_service_t lstcon_acceptor_service;
lstcon_init_acceptor_service(void)1980 static void lstcon_init_acceptor_service(void)
1981 {
1982 	/* initialize selftest console acceptor service table */
1983 	lstcon_acceptor_service.sv_name    = "join session";
1984 	lstcon_acceptor_service.sv_handler = lstcon_acceptor_handle;
1985 	lstcon_acceptor_service.sv_id      = SRPC_SERVICE_JOIN;
1986 	lstcon_acceptor_service.sv_wi_total = SFW_FRWK_WI_MAX;
1987 }
1988 
1989 extern int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_data *data);
1990 
1991 DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
1992 
1993 /* initialize console */
1994 int
lstcon_console_init(void)1995 lstcon_console_init(void)
1996 {
1997 	int     i;
1998 	int     rc;
1999 
2000 	memset(&console_session, 0, sizeof(lstcon_session_t));
2001 
2002 	console_session.ses_id		    = LST_INVALID_SID;
2003 	console_session.ses_state	    = LST_SESSION_NONE;
2004 	console_session.ses_timeout	    = 0;
2005 	console_session.ses_force	    = 0;
2006 	console_session.ses_expired	    = 0;
2007 	console_session.ses_feats_updated   = 0;
2008 	console_session.ses_features	    = LST_FEATS_MASK;
2009 	console_session.ses_laststamp	    = get_seconds();
2010 
2011 	mutex_init(&console_session.ses_mutex);
2012 
2013 	INIT_LIST_HEAD(&console_session.ses_ndl_list);
2014 	INIT_LIST_HEAD(&console_session.ses_grp_list);
2015 	INIT_LIST_HEAD(&console_session.ses_bat_list);
2016 	INIT_LIST_HEAD(&console_session.ses_trans_list);
2017 
2018 	LIBCFS_ALLOC(console_session.ses_ndl_hash,
2019 		     sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2020 	if (console_session.ses_ndl_hash == NULL)
2021 		return -ENOMEM;
2022 
2023 	for (i = 0; i < LST_GLOBAL_HASHSIZE; i++)
2024 		INIT_LIST_HEAD(&console_session.ses_ndl_hash[i]);
2025 
2026 
2027 	/* initialize acceptor service table */
2028 	lstcon_init_acceptor_service();
2029 
2030 	rc = srpc_add_service(&lstcon_acceptor_service);
2031 	LASSERT (rc != -EBUSY);
2032 	if (rc != 0) {
2033 		LIBCFS_FREE(console_session.ses_ndl_hash,
2034 			    sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2035 		return rc;
2036 	}
2037 
2038 	rc = srpc_service_add_buffers(&lstcon_acceptor_service,
2039 				      lstcon_acceptor_service.sv_wi_total);
2040 	if (rc != 0) {
2041 		rc = -ENOMEM;
2042 		goto out;
2043 	}
2044 
2045 	rc = libcfs_register_ioctl(&lstcon_ioctl_handler);
2046 
2047 	if (rc == 0) {
2048 		lstcon_rpc_module_init();
2049 		return 0;
2050 	}
2051 
2052 out:
2053 	srpc_shutdown_service(&lstcon_acceptor_service);
2054 	srpc_remove_service(&lstcon_acceptor_service);
2055 
2056 	LIBCFS_FREE(console_session.ses_ndl_hash,
2057 		    sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2058 
2059 	srpc_wait_service_shutdown(&lstcon_acceptor_service);
2060 
2061 	return rc;
2062 }
2063 
2064 int
lstcon_console_fini(void)2065 lstcon_console_fini(void)
2066 {
2067 	int     i;
2068 
2069 	libcfs_deregister_ioctl(&lstcon_ioctl_handler);
2070 
2071 	mutex_lock(&console_session.ses_mutex);
2072 
2073 	srpc_shutdown_service(&lstcon_acceptor_service);
2074 	srpc_remove_service(&lstcon_acceptor_service);
2075 
2076 	if (console_session.ses_state != LST_SESSION_NONE)
2077 		lstcon_session_end();
2078 
2079 	lstcon_rpc_module_fini();
2080 
2081 	mutex_unlock(&console_session.ses_mutex);
2082 
2083 	LASSERT (list_empty(&console_session.ses_ndl_list));
2084 	LASSERT (list_empty(&console_session.ses_grp_list));
2085 	LASSERT (list_empty(&console_session.ses_bat_list));
2086 	LASSERT (list_empty(&console_session.ses_trans_list));
2087 
2088 	for (i = 0; i < LST_NODE_HASHSIZE; i++) {
2089 		LASSERT (list_empty(&console_session.ses_ndl_hash[i]));
2090 	}
2091 
2092 	LIBCFS_FREE(console_session.ses_ndl_hash,
2093 		    sizeof(struct list_head) * LST_GLOBAL_HASHSIZE);
2094 
2095 	srpc_wait_service_shutdown(&lstcon_acceptor_service);
2096 
2097 	return 0;
2098 }
2099