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