OSDN Git Service

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