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