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