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