Whamcloud - gitweb
LU-8191 lnet: remove unused, fix non-static functions
[fs/lustre-release.git] / lnet / selftest / conctl.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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2014, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lnet/selftest/conctl.c
32  *
33  * IOC handle in kernel
34  *
35  * Author: Liang Zhen <liangzhen@clusterfs.com>
36  */
37
38 #include <linux/generic-radix-tree.h>
39 #include <libcfs/linux/linux-net.h>
40 #include <libcfs/libcfs.h>
41 #include <lnet/lib-lnet.h>
42 #include "console.h"
43
44 static int
45 lst_debug_ioctl(struct lstio_debug_args *args)
46 {
47         char *name = NULL;
48         int client = 1;
49         int rc;
50
51         if (args->lstio_dbg_key != console_session.ses_key)
52                 return -EACCES;
53
54         if (args->lstio_dbg_resultp == NULL)
55                 return -EINVAL;
56
57         if (args->lstio_dbg_namep != NULL && /* name of batch/group */
58             (args->lstio_dbg_nmlen <= 0 ||
59              args->lstio_dbg_nmlen > LST_NAME_SIZE))
60                 return -EINVAL;
61
62         if (args->lstio_dbg_namep != NULL) {
63                 LIBCFS_ALLOC(name, args->lstio_dbg_nmlen + 1);
64                 if (name == NULL)
65                         return -ENOMEM;
66
67                 if (copy_from_user(name, args->lstio_dbg_namep,
68                                    args->lstio_dbg_nmlen)) {
69                         LIBCFS_FREE(name, args->lstio_dbg_nmlen + 1);
70
71                         return -EFAULT;
72                 }
73
74                 name[args->lstio_dbg_nmlen] = 0;
75         }
76
77         rc = -EINVAL;
78
79         switch (args->lstio_dbg_type) {
80         case LST_OPC_SESSION:
81                 rc = lstcon_session_debug(args->lstio_dbg_timeout,
82                                           args->lstio_dbg_resultp);
83                 break;
84
85         case LST_OPC_BATCHSRV:
86                 client = 0;
87                 fallthrough;
88         case LST_OPC_BATCHCLI:
89                 if (name == NULL)
90                         goto out;
91
92                 rc = lstcon_batch_debug(args->lstio_dbg_timeout,
93                                         name, client, args->lstio_dbg_resultp);
94                 break;
95
96         case LST_OPC_GROUP:
97                 if (name == NULL)
98                         goto out;
99
100                 rc = lstcon_group_debug(args->lstio_dbg_timeout,
101                                         name, args->lstio_dbg_resultp);
102                 break;
103
104         case LST_OPC_NODES:
105                 if (args->lstio_dbg_count <= 0 ||
106                     args->lstio_dbg_idsp == NULL)
107                         goto out;
108
109                 rc = lstcon_nodes_debug(args->lstio_dbg_timeout,
110                                         args->lstio_dbg_count,
111                                         args->lstio_dbg_idsp,
112                                         args->lstio_dbg_resultp);
113                 break;
114
115         default:
116                 break;
117         }
118
119 out:
120         if (name != NULL)
121                 LIBCFS_FREE(name, args->lstio_dbg_nmlen + 1);
122
123         return rc;
124 }
125
126 static int
127 lst_group_add_ioctl(struct lstio_group_add_args *args)
128 {
129         char *name;
130         int rc;
131
132         if (args->lstio_grp_key != console_session.ses_key)
133                 return -EACCES;
134
135         if (args->lstio_grp_namep == NULL ||
136             args->lstio_grp_nmlen <= 0 ||
137             args->lstio_grp_nmlen > LST_NAME_SIZE)
138                 return -EINVAL;
139
140         LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
141         if (name == NULL)
142                 return -ENOMEM;
143
144         if (copy_from_user(name, args->lstio_grp_namep,
145                            args->lstio_grp_nmlen)) {
146                 LIBCFS_FREE(name, args->lstio_grp_nmlen);
147                 return -EFAULT;
148         }
149
150         name[args->lstio_grp_nmlen] = 0;
151
152         rc = lstcon_group_add(name);
153
154         LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
155
156         return rc;
157 }
158
159 static int
160 lst_group_del_ioctl(struct lstio_group_del_args *args)
161 {
162         int rc;
163         char *name;
164
165         if (args->lstio_grp_key != console_session.ses_key)
166                 return -EACCES;
167
168         if (args->lstio_grp_namep == NULL ||
169             args->lstio_grp_nmlen <= 0 ||
170             args->lstio_grp_nmlen > LST_NAME_SIZE)
171                 return -EINVAL;
172
173         LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
174         if (name == NULL)
175                 return -ENOMEM;
176
177         if (copy_from_user(name, args->lstio_grp_namep,
178                            args->lstio_grp_nmlen)) {
179                 LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
180                 return -EFAULT;
181         }
182
183         name[args->lstio_grp_nmlen] = 0;
184
185         rc = lstcon_group_del(name);
186
187         LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
188
189         return rc;
190 }
191
192 static int
193 lst_group_update_ioctl(struct lstio_group_update_args *args)
194 {
195         int rc;
196         char *name;
197
198         if (args->lstio_grp_key != console_session.ses_key)
199                 return -EACCES;
200
201         if (args->lstio_grp_resultp == NULL ||
202             args->lstio_grp_namep == NULL ||
203             args->lstio_grp_nmlen <= 0 ||
204             args->lstio_grp_nmlen > LST_NAME_SIZE)
205                 return -EINVAL;
206
207         LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
208         if (name == NULL)
209                 return -ENOMEM;
210
211         if (copy_from_user(name, args->lstio_grp_namep,
212                            args->lstio_grp_nmlen)) {
213                 LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
214                 return -EFAULT;
215         }
216
217         name[args->lstio_grp_nmlen] = 0;
218
219         switch (args->lstio_grp_opc) {
220         case LST_GROUP_CLEAN:
221                 rc = lstcon_group_clean(name, args->lstio_grp_args);
222                 break;
223
224         case LST_GROUP_REFRESH:
225                 rc = lstcon_group_refresh(name, args->lstio_grp_resultp);
226                 break;
227
228         case LST_GROUP_RMND:
229                 if (args->lstio_grp_count <= 0 ||
230                     args->lstio_grp_idsp == NULL) {
231                         rc = -EINVAL;
232                         break;
233                 }
234                 rc = lstcon_nodes_remove(name, args->lstio_grp_count,
235                                          args->lstio_grp_idsp,
236                                          args->lstio_grp_resultp);
237                 break;
238
239         default:
240                 rc = -EINVAL;
241                 break;
242         }
243
244         LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
245
246         return rc;
247 }
248
249 static int
250 lst_nodes_add_ioctl(struct lstio_group_nodes_args *args)
251 {
252         unsigned int feats;
253         int rc;
254         char *name;
255
256         if (args->lstio_grp_key != console_session.ses_key)
257                 return -EACCES;
258
259         if (args->lstio_grp_idsp == NULL || /* array of ids */
260             args->lstio_grp_count <= 0 ||
261             args->lstio_grp_resultp == NULL ||
262             args->lstio_grp_featp == NULL ||
263             args->lstio_grp_namep == NULL ||
264             args->lstio_grp_nmlen <= 0 ||
265             args->lstio_grp_nmlen > LST_NAME_SIZE)
266                 return -EINVAL;
267
268         LIBCFS_ALLOC(name, args->lstio_grp_nmlen + 1);
269         if (name == NULL)
270                 return -ENOMEM;
271
272         if (copy_from_user(name, args->lstio_grp_namep,
273                            args->lstio_grp_nmlen)) {
274                 LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
275
276                 return -EFAULT;
277         }
278
279         name[args->lstio_grp_nmlen] = 0;
280
281         rc = lstcon_nodes_add(name, args->lstio_grp_count,
282                               args->lstio_grp_idsp, &feats,
283                               args->lstio_grp_resultp);
284
285         LIBCFS_FREE(name, args->lstio_grp_nmlen + 1);
286         if (rc == 0 &&
287             copy_to_user(args->lstio_grp_featp, &feats, sizeof(feats))) {
288                 return -EINVAL;
289         }
290
291         return rc;
292 }
293
294 static int
295 lst_batch_add_ioctl(struct lstio_batch_add_args *args)
296 {
297         int rc;
298         char *name;
299
300         if (args->lstio_bat_key != console_session.ses_key)
301                 return -EACCES;
302
303         if (args->lstio_bat_namep == NULL ||
304             args->lstio_bat_nmlen <= 0 ||
305             args->lstio_bat_nmlen > LST_NAME_SIZE)
306                 return -EINVAL;
307
308         LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
309         if (name == NULL)
310                 return -ENOMEM;
311
312         if (copy_from_user(name, args->lstio_bat_namep,
313                            args->lstio_bat_nmlen)) {
314                 LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
315                 return -EFAULT;
316         }
317
318         name[args->lstio_bat_nmlen] = 0;
319
320         rc = lstcon_batch_add(name);
321
322         LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
323
324         return rc;
325 }
326
327 static int
328 lst_batch_run_ioctl(struct lstio_batch_run_args *args)
329 {
330         int rc;
331         char *name;
332
333         if (args->lstio_bat_key != console_session.ses_key)
334                 return -EACCES;
335
336         if (args->lstio_bat_namep == NULL ||
337             args->lstio_bat_nmlen <= 0 ||
338             args->lstio_bat_nmlen > LST_NAME_SIZE)
339                 return -EINVAL;
340
341         LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
342         if (name == NULL)
343                 return -ENOMEM;
344
345         if (copy_from_user(name, args->lstio_bat_namep,
346                            args->lstio_bat_nmlen)) {
347                 LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
348                 return -EFAULT;
349         }
350
351         name[args->lstio_bat_nmlen] = 0;
352
353         rc = lstcon_batch_run(name, args->lstio_bat_timeout,
354                               args->lstio_bat_resultp);
355
356         LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
357
358         return rc;
359 }
360
361 static int
362 lst_batch_stop_ioctl(struct lstio_batch_stop_args *args)
363 {
364         int rc;
365         char *name;
366
367         if (args->lstio_bat_key != console_session.ses_key)
368                 return -EACCES;
369
370         if (args->lstio_bat_resultp == NULL ||
371             args->lstio_bat_namep == NULL ||
372             args->lstio_bat_nmlen <= 0 ||
373             args->lstio_bat_nmlen > LST_NAME_SIZE)
374                 return -EINVAL;
375
376         LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
377         if (name == NULL)
378                 return -ENOMEM;
379
380         if (copy_from_user(name, args->lstio_bat_namep,
381                            args->lstio_bat_nmlen)) {
382                 LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
383                 return -EFAULT;
384         }
385
386         name[args->lstio_bat_nmlen] = 0;
387
388         rc = lstcon_batch_stop(name, args->lstio_bat_force,
389                                args->lstio_bat_resultp);
390
391         LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
392
393         return rc;
394 }
395
396 static int
397 lst_batch_query_ioctl(struct lstio_batch_query_args *args)
398 {
399         char *name;
400         int rc;
401
402         if (args->lstio_bat_key != console_session.ses_key)
403                 return -EACCES;
404
405         if (args->lstio_bat_resultp == NULL ||
406             args->lstio_bat_namep == NULL ||
407             args->lstio_bat_nmlen <= 0 ||
408             args->lstio_bat_nmlen > LST_NAME_SIZE)
409                 return -EINVAL;
410
411         if (args->lstio_bat_testidx < 0)
412                 return -EINVAL;
413
414         LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
415         if (name == NULL)
416                 return -ENOMEM;
417
418         if (copy_from_user(name, args->lstio_bat_namep,
419                            args->lstio_bat_nmlen)) {
420                 LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
421                 return -EFAULT;
422         }
423
424         name[args->lstio_bat_nmlen] = 0;
425
426         rc = lstcon_test_batch_query(name,
427                                      args->lstio_bat_testidx,
428                                      args->lstio_bat_client,
429                                      args->lstio_bat_timeout,
430                                      args->lstio_bat_resultp);
431
432         LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
433
434         return rc;
435 }
436
437 static int
438 lst_batch_list_ioctl(struct lstio_batch_list_args *args)
439 {
440         if (args->lstio_bat_key != console_session.ses_key)
441                 return -EACCES;
442
443         if (args->lstio_bat_idx < 0 ||
444             args->lstio_bat_namep == NULL ||
445             args->lstio_bat_nmlen <= 0 ||
446             args->lstio_bat_nmlen > LST_NAME_SIZE)
447                 return -EINVAL;
448
449         return lstcon_batch_list(args->lstio_bat_idx,
450                                  args->lstio_bat_nmlen,
451                                  args->lstio_bat_namep);
452 }
453
454 static int
455 lst_batch_info_ioctl(struct lstio_batch_info_args *args)
456 {
457         char *name;
458         int rc;
459         int index;
460         int ndent;
461
462         if (args->lstio_bat_key != console_session.ses_key)
463                 return -EACCES;
464
465         if (args->lstio_bat_namep == NULL || /* batch name */
466             args->lstio_bat_nmlen <= 0 ||
467             args->lstio_bat_nmlen > LST_NAME_SIZE)
468                 return -EINVAL;
469
470         if (args->lstio_bat_entp == NULL && /* output: batch entry */
471             args->lstio_bat_dentsp == NULL) /* output: node entry */
472                 return -EINVAL;
473
474         if (args->lstio_bat_dentsp != NULL) { /* have node entry */
475                 if (args->lstio_bat_idxp == NULL || /* node index */
476                     args->lstio_bat_ndentp == NULL) /* # of node entry */
477                         return -EINVAL;
478
479                 if (copy_from_user(&index, args->lstio_bat_idxp,
480                                    sizeof(index)) ||
481                     copy_from_user(&ndent, args->lstio_bat_ndentp,
482                                    sizeof(ndent)))
483                         return -EFAULT;
484
485                 if (ndent <= 0 || index < 0)
486                         return -EINVAL;
487         }
488
489         LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1);
490         if (name == NULL)
491                 return -ENOMEM;
492
493         if (copy_from_user(name, args->lstio_bat_namep,
494                            args->lstio_bat_nmlen)) {
495                 LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
496                 return -EFAULT;
497         }
498
499         name[args->lstio_bat_nmlen] = 0;
500
501         rc = lstcon_batch_info(name,
502                                args->lstio_bat_entp, args->lstio_bat_server,
503                                args->lstio_bat_testidx, &index, &ndent,
504                                args->lstio_bat_dentsp);
505
506         LIBCFS_FREE(name, args->lstio_bat_nmlen + 1);
507
508         if (rc != 0)
509                 return rc;
510
511         if (args->lstio_bat_dentsp != NULL &&
512             (copy_to_user(args->lstio_bat_idxp, &index, sizeof(index)) ||
513              copy_to_user(args->lstio_bat_ndentp, &ndent, sizeof(ndent))))
514                 rc = -EFAULT;
515
516         return rc;
517 }
518
519 static int
520 lst_stat_query_ioctl(struct lstio_stat_args *args)
521 {
522         int rc;
523         char *name = NULL;
524
525         /* TODO: not finished */
526         if (args->lstio_sta_key != console_session.ses_key)
527                 return -EACCES;
528
529         if (args->lstio_sta_resultp == NULL)
530                 return -EINVAL;
531
532         if (args->lstio_sta_idsp != NULL) {
533                 if (args->lstio_sta_count <= 0)
534                         return -EINVAL;
535
536                 rc = lstcon_nodes_stat(args->lstio_sta_count,
537                                        args->lstio_sta_idsp,
538                                        args->lstio_sta_timeout,
539                                        args->lstio_sta_resultp);
540         } else if (args->lstio_sta_namep != NULL) {
541                 if (args->lstio_sta_nmlen <= 0 ||
542                     args->lstio_sta_nmlen > LST_NAME_SIZE)
543                         return -EINVAL;
544
545                 LIBCFS_ALLOC(name, args->lstio_sta_nmlen + 1);
546                 if (name == NULL)
547                         return -ENOMEM;
548
549                 rc = copy_from_user(name, args->lstio_sta_namep,
550                                     args->lstio_sta_nmlen);
551                 if (rc == 0)
552                         rc = lstcon_group_stat(name, args->lstio_sta_timeout,
553                                                args->lstio_sta_resultp);
554                 else
555                         rc = -EFAULT;
556
557         } else {
558                 rc = -EINVAL;
559         }
560
561         if (name != NULL)
562                 LIBCFS_FREE(name, args->lstio_sta_nmlen + 1);
563         return rc;
564 }
565
566 static int lst_test_add_ioctl(struct lstio_test_args *args)
567 {
568         char *batch_name;
569         char *src_name = NULL;
570         char *dst_name = NULL;
571         void *param = NULL;
572         int ret = 0;
573         int rc = -ENOMEM;
574
575         if (args->lstio_tes_resultp == NULL ||
576             args->lstio_tes_retp == NULL ||
577             args->lstio_tes_bat_name == NULL || /* no specified batch */
578             args->lstio_tes_bat_nmlen <= 0 ||
579             args->lstio_tes_bat_nmlen > LST_NAME_SIZE ||
580             args->lstio_tes_sgrp_name == NULL || /* no source group */
581             args->lstio_tes_sgrp_nmlen <= 0 ||
582             args->lstio_tes_sgrp_nmlen > LST_NAME_SIZE ||
583             args->lstio_tes_dgrp_name == NULL || /* no target group */
584             args->lstio_tes_dgrp_nmlen <= 0 ||
585             args->lstio_tes_dgrp_nmlen > LST_NAME_SIZE)
586                 return -EINVAL;
587
588         if (args->lstio_tes_loop == 0 || /* negative is infinite */
589             args->lstio_tes_concur <= 0 ||
590             args->lstio_tes_dist <= 0 ||
591             args->lstio_tes_span <= 0)
592                 return -EINVAL;
593
594         /* have parameter, check if parameter length is valid */
595         if (args->lstio_tes_param != NULL &&
596             (args->lstio_tes_param_len <= 0 ||
597              args->lstio_tes_param_len >
598              PAGE_SIZE - sizeof(struct lstcon_test)))
599                 return -EINVAL;
600
601         LIBCFS_ALLOC(batch_name, args->lstio_tes_bat_nmlen + 1);
602         if (batch_name == NULL)
603                 return rc;
604
605         LIBCFS_ALLOC(src_name, args->lstio_tes_sgrp_nmlen + 1);
606         if (src_name == NULL)
607                 goto out;
608
609         LIBCFS_ALLOC(dst_name, args->lstio_tes_dgrp_nmlen + 1);
610         if (dst_name == NULL)
611                 goto out;
612
613         if (args->lstio_tes_param != NULL) {
614                 LIBCFS_ALLOC(param, args->lstio_tes_param_len);
615                 if (param == NULL)
616                         goto out;
617                 if (copy_from_user(param, args->lstio_tes_param,
618                                    args->lstio_tes_param_len)) {
619                         rc = -EFAULT;
620                         goto out;
621                 }
622         }
623
624         rc = -EFAULT;
625         if (copy_from_user(batch_name, args->lstio_tes_bat_name,
626                            args->lstio_tes_bat_nmlen) ||
627             copy_from_user(src_name, args->lstio_tes_sgrp_name,
628                            args->lstio_tes_sgrp_nmlen) ||
629             copy_from_user(dst_name, args->lstio_tes_dgrp_name,
630                            args->lstio_tes_dgrp_nmlen))
631                 goto out;
632
633         rc = lstcon_test_add(batch_name,
634                              args->lstio_tes_type,
635                              args->lstio_tes_loop,
636                              args->lstio_tes_concur,
637                              args->lstio_tes_dist, args->lstio_tes_span,
638                              src_name, dst_name, param,
639                              args->lstio_tes_param_len,
640                              &ret, args->lstio_tes_resultp);
641
642         if (ret != 0)
643                 rc = (copy_to_user(args->lstio_tes_retp, &ret,
644                                    sizeof(ret))) ? -EFAULT : 0;
645 out:
646         if (batch_name != NULL)
647                 LIBCFS_FREE(batch_name, args->lstio_tes_bat_nmlen + 1);
648
649         if (src_name != NULL)
650                 LIBCFS_FREE(src_name, args->lstio_tes_sgrp_nmlen + 1);
651
652         if (dst_name != NULL)
653                 LIBCFS_FREE(dst_name, args->lstio_tes_dgrp_nmlen + 1);
654
655         if (param != NULL)
656                 LIBCFS_FREE(param, args->lstio_tes_param_len);
657
658         return rc;
659 }
660
661 int
662 lstcon_ioctl_entry(struct notifier_block *nb,
663                    unsigned long cmd, void *vdata)
664 {
665         struct libcfs_ioctl_hdr *hdr = vdata;
666         struct libcfs_ioctl_data *data;
667         char *buf = NULL;
668         int rc = -EINVAL;
669         int opc;
670
671         if (cmd != IOC_LIBCFS_LNETST)
672                 goto err;
673
674         data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
675
676         opc = data->ioc_u32[0];
677
678         if (data->ioc_plen1 > PAGE_SIZE)
679                 goto err;
680
681         LIBCFS_ALLOC(buf, data->ioc_plen1);
682         if (buf == NULL) {
683                 rc = -ENOMEM;
684                 goto err;
685         }
686
687         /* copy in parameter */
688         if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
689                 rc = -EFAULT;
690                 goto out_free_buf;
691         }
692
693         mutex_lock(&console_session.ses_mutex);
694
695         console_session.ses_laststamp = ktime_get_real_seconds();
696
697         if (console_session.ses_shutdown) {
698                 rc = -ESHUTDOWN;
699                 goto out;
700         }
701
702         if (console_session.ses_expired)
703                 lstcon_session_end();
704
705         if (opc != LSTIO_SESSION_NEW &&
706             console_session.ses_state == LST_SESSION_NONE) {
707                 CDEBUG(D_NET, "LST no active session\n");
708                 rc = -ESRCH;
709                 goto out;
710         }
711
712         memset(&console_session.ses_trans_stat, 0,
713                sizeof(struct lstcon_trans_stat));
714
715         switch (opc) {
716         case LSTIO_SESSION_NEW:
717                 fallthrough;
718         case LSTIO_SESSION_END:
719                 fallthrough;
720         case LSTIO_SESSION_INFO:
721                 rc = -EOPNOTSUPP;
722                 break;
723         case LSTIO_DEBUG:
724                 rc = lst_debug_ioctl((struct lstio_debug_args *)buf);
725                 break;
726         case LSTIO_GROUP_ADD:
727                 rc = lst_group_add_ioctl((struct lstio_group_add_args *)buf);
728                 break;
729         case LSTIO_GROUP_DEL:
730                 rc = lst_group_del_ioctl((struct lstio_group_del_args *)buf);
731                 break;
732         case LSTIO_GROUP_UPDATE:
733                 rc = lst_group_update_ioctl((struct lstio_group_update_args *)buf);
734                 break;
735         case LSTIO_NODES_ADD:
736                 rc = lst_nodes_add_ioctl((struct lstio_group_nodes_args *)buf);
737                 break;
738         case LSTIO_GROUP_LIST:
739                 fallthrough;
740         case LSTIO_GROUP_INFO:
741                 rc = -EOPNOTSUPP;
742                 break;
743         case LSTIO_BATCH_ADD:
744                 rc = lst_batch_add_ioctl((struct lstio_batch_add_args *)buf);
745                 break;
746         case LSTIO_BATCH_START:
747                 rc = lst_batch_run_ioctl((struct lstio_batch_run_args *)buf);
748                 break;
749         case LSTIO_BATCH_STOP:
750                 rc = lst_batch_stop_ioctl((struct lstio_batch_stop_args *)buf);
751                 break;
752         case LSTIO_BATCH_QUERY:
753                 rc = lst_batch_query_ioctl((struct lstio_batch_query_args *)buf);
754                 break;
755         case LSTIO_BATCH_LIST:
756                 rc = lst_batch_list_ioctl((struct lstio_batch_list_args *)buf);
757                 break;
758         case LSTIO_BATCH_INFO:
759                 rc = lst_batch_info_ioctl((struct lstio_batch_info_args *)buf);
760                 break;
761         case LSTIO_TEST_ADD:
762                 rc = lst_test_add_ioctl((struct lstio_test_args *)buf);
763                 break;
764         case LSTIO_STAT_QUERY:
765                 rc = lst_stat_query_ioctl((struct lstio_stat_args *)buf);
766                 break;
767         default:
768                 rc = -EINVAL;
769                 goto out;
770         }
771
772         if (copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat,
773                          sizeof(struct lstcon_trans_stat)))
774                 rc = -EFAULT;
775 out:
776         mutex_unlock(&console_session.ses_mutex);
777 out_free_buf:
778         LIBCFS_FREE(buf, data->ioc_plen1);
779 err:
780         return notifier_from_ioctl_errno(rc);
781 }
782
783 static struct genl_family lst_family;
784
785 static const struct ln_key_list lst_session_keys = {
786         .lkl_maxattr                    = LNET_SELFTEST_SESSION_MAX,
787         .lkl_list                       = {
788                 [LNET_SELFTEST_SESSION_HDR]     = {
789                         .lkp_value              = "session",
790                         .lkp_key_format         = LNKF_MAPPING,
791                         .lkp_data_type          = NLA_NUL_STRING,
792                 },
793                 [LNET_SELFTEST_SESSION_NAME]    = {
794                         .lkp_value              = "name",
795                         .lkp_data_type          = NLA_STRING,
796                 },
797                 [LNET_SELFTEST_SESSION_KEY]     = {
798                         .lkp_value              = "key",
799                         .lkp_data_type          = NLA_U32,
800                 },
801                 [LNET_SELFTEST_SESSION_TIMESTAMP] = {
802                         .lkp_value              = "timestamp",
803                         .lkp_data_type          = NLA_S64,
804                 },
805                 [LNET_SELFTEST_SESSION_NID]     = {
806                         .lkp_value              = "nid",
807                         .lkp_data_type          = NLA_STRING,
808                 },
809                 [LNET_SELFTEST_SESSION_NODE_COUNT] = {
810                         .lkp_value              = "nodes",
811                         .lkp_data_type          = NLA_U16,
812                 },
813         },
814 };
815
816 static int lst_sessions_show_dump(struct sk_buff *msg,
817                                   struct netlink_callback *cb)
818 {
819         const struct ln_key_list *all[] = {
820                 &lst_session_keys, NULL
821         };
822 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
823         struct netlink_ext_ack *extack = NULL;
824 #endif
825         int portid = NETLINK_CB(cb->skb).portid;
826         int seq = cb->nlh->nlmsg_seq;
827         unsigned int node_count = 0;
828         struct lstcon_ndlink *ndl;
829         int flag = NLM_F_MULTI;
830         int rc = 0;
831         void *hdr;
832
833 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
834         extack = cb->extack;
835 #endif
836         if (console_session.ses_state != LST_SESSION_ACTIVE) {
837                 NL_SET_ERR_MSG(extack, "session is not active");
838                 GOTO(out_unlock, rc = -ESRCH);
839         }
840
841         list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link)
842                 node_count++;
843
844         rc = lnet_genl_send_scalar_list(msg, portid, seq, &lst_family,
845                                         NLM_F_CREATE | NLM_F_MULTI,
846                                         LNET_SELFTEST_CMD_SESSIONS, all);
847         if (rc < 0) {
848                 NL_SET_ERR_MSG(extack, "failed to send key table");
849                 GOTO(out_unlock, rc);
850         }
851
852         if (console_session.ses_force)
853                 flag |= NLM_F_REPLACE;
854
855         hdr = genlmsg_put(msg, portid, seq, &lst_family, flag,
856                           LNET_SELFTEST_CMD_SESSIONS);
857         if (!hdr) {
858                 NL_SET_ERR_MSG(extack, "failed to send values");
859                 genlmsg_cancel(msg, hdr);
860                 GOTO(out_unlock, rc = -EMSGSIZE);
861         }
862
863         nla_put_string(msg, LNET_SELFTEST_SESSION_NAME,
864                        console_session.ses_name);
865         nla_put_u32(msg, LNET_SELFTEST_SESSION_KEY,
866                     console_session.ses_key);
867         nla_put_u64_64bit(msg, LNET_SELFTEST_SESSION_TIMESTAMP,
868                           console_session.ses_id.ses_stamp,
869                           LNET_SELFTEST_SESSION_PAD);
870         nla_put_string(msg, LNET_SELFTEST_SESSION_NID,
871                        libcfs_nidstr(&console_session.ses_id.ses_nid));
872         nla_put_u16(msg, LNET_SELFTEST_SESSION_NODE_COUNT,
873                     node_count);
874         genlmsg_end(msg, hdr);
875 out_unlock:
876         return lnet_nl_send_error(cb->skb, portid, seq, rc);
877 }
878
879 static int lst_sessions_cmd(struct sk_buff *skb, struct genl_info *info)
880 {
881         struct sk_buff *msg = NULL;
882         int rc = 0;
883
884         mutex_lock(&console_session.ses_mutex);
885
886         console_session.ses_laststamp = ktime_get_real_seconds();
887
888         if (console_session.ses_shutdown) {
889                 GENL_SET_ERR_MSG(info, "session is shutdown");
890                 GOTO(out_unlock, rc = -ESHUTDOWN);
891         }
892
893         if (console_session.ses_expired)
894                 lstcon_session_end();
895
896         if (!(info->nlhdr->nlmsg_flags & NLM_F_CREATE) &&
897             console_session.ses_state == LST_SESSION_NONE) {
898                 GENL_SET_ERR_MSG(info, "session is not active");
899                 GOTO(out_unlock, rc = -ESRCH);
900         }
901
902         memset(&console_session.ses_trans_stat, 0,
903                sizeof(struct lstcon_trans_stat));
904
905         if (!(info->nlhdr->nlmsg_flags & NLM_F_CREATE)) {
906                 lstcon_session_end();
907                 GOTO(out_unlock, rc);
908         }
909
910         if (info->attrs[LN_SCALAR_ATTR_LIST]) {
911                 struct genlmsghdr *gnlh = nlmsg_data(info->nlhdr);
912                 const struct ln_key_list *all[] = {
913                         &lst_session_keys, NULL
914                 };
915                 char name[LST_NAME_SIZE];
916                 struct nlmsghdr *nlh;
917                 struct nlattr *item;
918                 bool force = false;
919                 s64 timeout = 300;
920                 void *hdr;
921                 int rem;
922
923                 if (info->nlhdr->nlmsg_flags & NLM_F_REPLACE)
924                         force = true;
925
926                 nla_for_each_nested(item, info->attrs[LN_SCALAR_ATTR_LIST],
927                                     rem) {
928                         if (nla_type(item) != LN_SCALAR_ATTR_VALUE)
929                                 continue;
930
931                         if (nla_strcmp(item, "name") == 0) {
932                                 ssize_t len;
933
934                                 item = nla_next(item, &rem);
935                                 if (nla_type(item) != LN_SCALAR_ATTR_VALUE)
936                                         GOTO(err_conf, rc = -EINVAL);
937
938                                 len = nla_strscpy(name, item, sizeof(name));
939                                 if (len < 0)
940                                         rc = len;
941                         } else if (nla_strcmp(item, "timeout") == 0) {
942                                 item = nla_next(item, &rem);
943                                 if (nla_type(item) !=
944                                     LN_SCALAR_ATTR_INT_VALUE)
945                                         GOTO(err_conf, rc = -EINVAL);
946
947                                 timeout = nla_get_s64(item);
948                                 if (timeout < 0)
949                                         rc = -ERANGE;
950                         }
951                         if (rc < 0) {
952 err_conf:
953                                 GENL_SET_ERR_MSG(info,
954                                                  "failed to get config");
955                                 GOTO(out_unlock, rc);
956                         }
957                 }
958
959                 rc = lstcon_session_new(name, info->nlhdr->nlmsg_pid,
960                                         gnlh->version, timeout,
961                                         force);
962                 if (rc < 0) {
963                         GENL_SET_ERR_MSG(info, "new session creation failed");
964                         lstcon_session_end();
965                         GOTO(out_unlock, rc);
966                 }
967
968                 msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
969                 if (!msg) {
970                         GENL_SET_ERR_MSG(info, "msg allocation failed");
971                         GOTO(out_unlock, rc = -ENOMEM);
972                 }
973
974                 rc = lnet_genl_send_scalar_list(msg, info->snd_portid,
975                                                 info->snd_seq, &lst_family,
976                                                 NLM_F_CREATE | NLM_F_MULTI,
977                                                 LNET_SELFTEST_CMD_SESSIONS,
978                                                 all);
979                 if (rc < 0) {
980                         GENL_SET_ERR_MSG(info, "failed to send key table");
981                         GOTO(out_unlock, rc);
982                 }
983
984                 hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
985                                   &lst_family, NLM_F_MULTI,
986                                   LNET_SELFTEST_CMD_SESSIONS);
987                 if (!hdr) {
988                         GENL_SET_ERR_MSG(info, "failed to send values");
989                         genlmsg_cancel(msg, hdr);
990                         GOTO(out_unlock, rc = -EMSGSIZE);
991                 }
992
993                 nla_put_string(msg, LNET_SELFTEST_SESSION_NAME,
994                                console_session.ses_name);
995                 nla_put_u32(msg, LNET_SELFTEST_SESSION_KEY,
996                             console_session.ses_key);
997                 nla_put_u64_64bit(msg, LNET_SELFTEST_SESSION_TIMESTAMP,
998                                   console_session.ses_id.ses_stamp,
999                                   LNET_SELFTEST_SESSION_PAD);
1000                 nla_put_string(msg, LNET_SELFTEST_SESSION_NID,
1001                                libcfs_nidstr(&console_session.ses_id.ses_nid));
1002                 nla_put_u16(msg, LNET_SELFTEST_SESSION_NODE_COUNT, 0);
1003
1004                 genlmsg_end(msg, hdr);
1005
1006                 nlh = nlmsg_put(msg, info->snd_portid, info->snd_seq,
1007                                 NLMSG_DONE, 0, NLM_F_MULTI);
1008                 if (!nlh) {
1009                         GENL_SET_ERR_MSG(info, "failed to complete message");
1010                         genlmsg_cancel(msg, hdr);
1011                         GOTO(out_unlock, rc = -ENOMEM);
1012                 }
1013                 rc = genlmsg_reply(msg, info);
1014                 if (rc)
1015                         GENL_SET_ERR_MSG(info, "failed to send reply");
1016         }
1017 out_unlock:
1018         if (rc < 0 && msg)
1019                 nlmsg_free(msg);
1020         mutex_unlock(&console_session.ses_mutex);
1021         return rc;
1022 }
1023
1024 static char *lst_node_state2str(int state)
1025 {
1026         if (state == LST_NODE_ACTIVE)
1027                 return "Active";
1028         if (state == LST_NODE_BUSY)
1029                 return "Busy";
1030         if (state == LST_NODE_DOWN)
1031                 return "Down";
1032
1033         return "Unknown";
1034 }
1035
1036 static int lst_node_str2state(char *str)
1037 {
1038         int state = 0;
1039
1040         if (strcasecmp(str, "Active") == 0)
1041                 state = LST_NODE_ACTIVE;
1042         else if (strcasecmp(str, "Busy") == 0)
1043                 state = LST_NODE_BUSY;
1044         else if (strcasecmp(str, "Down") == 0)
1045                 state = LST_NODE_DOWN;
1046         else if (strcasecmp(str, "Unknown") == 0)
1047                 state = LST_NODE_UNKNOWN;
1048         else if (strcasecmp(str, "Invalid") == 0)
1049                 state = LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY;
1050         return state;
1051 }
1052
1053 struct lst_genl_group_prop {
1054         struct lstcon_group     *lggp_grp;
1055         int                     lggp_state_filter;
1056 };
1057
1058 struct lst_genl_group_list {
1059         GENRADIX(struct lst_genl_group_prop)    lggl_groups;
1060         unsigned int                            lggl_count;
1061         unsigned int                            lggl_index;
1062         bool                                    lggl_verbose;
1063 };
1064
1065 static inline struct lst_genl_group_list *
1066 lst_group_dump_ctx(struct netlink_callback *cb)
1067 {
1068         return (struct lst_genl_group_list *)cb->args[0];
1069 }
1070
1071 static int lst_groups_show_done(struct netlink_callback *cb)
1072 {
1073         struct lst_genl_group_list *glist = lst_group_dump_ctx(cb);
1074
1075         if (glist) {
1076                 int i;
1077
1078                 for (i = 0; i < glist->lggl_count; i++) {
1079                         struct lst_genl_group_prop *prop;
1080
1081                         prop = genradix_ptr(&glist->lggl_groups, i);
1082                         if (!prop || !prop->lggp_grp)
1083                                 continue;
1084                         lstcon_group_decref(prop->lggp_grp);
1085                 }
1086                 genradix_free(&glist->lggl_groups);
1087                 LIBCFS_FREE(glist, sizeof(*glist));
1088         }
1089         cb->args[0] = 0;
1090
1091         return 0;
1092 }
1093
1094 /* LNet selftest groups ->start() handler for GET requests */
1095 static int lst_groups_show_start(struct netlink_callback *cb)
1096 {
1097         struct genlmsghdr *gnlh = nlmsg_data(cb->nlh);
1098 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
1099         struct netlink_ext_ack *extack = NULL;
1100 #endif
1101         struct nlattr *params = genlmsg_data(gnlh);
1102         struct lst_genl_group_list *glist;
1103         int msg_len = genlmsg_len(gnlh);
1104         struct lstcon_group *grp;
1105         struct nlattr *groups;
1106         int rem, rc = 0;
1107
1108         LIBCFS_ALLOC(glist, sizeof(*glist));
1109         if (!glist)
1110                 return -ENOMEM;
1111
1112         genradix_init(&glist->lggl_groups);
1113         cb->args[0] = (long)glist;
1114
1115         if (!msg_len) {
1116                 list_for_each_entry(grp, &console_session.ses_grp_list,
1117                                     grp_link) {
1118                         struct lst_genl_group_prop *prop;
1119
1120                         prop = genradix_ptr_alloc(&glist->lggl_groups,
1121                                                   glist->lggl_count++,
1122                                                   GFP_ATOMIC);
1123                         if (!prop) {
1124                                 NL_SET_ERR_MSG(extack,
1125                                                "failed to allocate group info");
1126                                 GOTO(report_err, rc = -ENOMEM);
1127                         }
1128                         lstcon_group_addref(grp);  /* +1 ref for caller */
1129                         prop->lggp_grp = grp;
1130                 }
1131
1132                 if (!glist->lggl_count) {
1133                         NL_SET_ERR_MSG(extack, "No groups found");
1134                         rc = -ENOENT;
1135                 }
1136                 GOTO(report_err, rc);
1137         }
1138         glist->lggl_verbose = true;
1139 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
1140         extack = cb->extack;
1141 #endif
1142
1143         if (!(nla_type(params) & LN_SCALAR_ATTR_LIST)) {
1144                 NL_SET_ERR_MSG(extack, "no configuration");
1145                 GOTO(report_err, rc);
1146         }
1147
1148         nla_for_each_nested(groups, params, rem) {
1149                 struct lst_genl_group_prop *prop = NULL;
1150                 struct nlattr *group;
1151                 int rem2;
1152
1153                 if (nla_type(groups) != LN_SCALAR_ATTR_LIST)
1154                         continue;
1155
1156                 nla_for_each_nested(group, groups, rem2) {
1157                         if (nla_type(group) == LN_SCALAR_ATTR_VALUE) {
1158                                 char name[LST_NAME_SIZE];
1159
1160                                 prop = genradix_ptr_alloc(&glist->lggl_groups,
1161                                                          glist->lggl_count++,
1162                                                          GFP_ATOMIC);
1163                                 if (!prop) {
1164                                         NL_SET_ERR_MSG(extack,
1165                                                        "failed to allocate group info");
1166                                         GOTO(report_err, rc = -ENOMEM);
1167                                 }
1168
1169                                 rc = nla_strscpy(name, group, sizeof(name));
1170                                 if (rc < 0) {
1171                                         NL_SET_ERR_MSG(extack,
1172                                                        "failed to get name");
1173                                         GOTO(report_err, rc);
1174                                 }
1175                                 rc = lstcon_group_find(name, &prop->lggp_grp);
1176                                 if (rc < 0) {
1177                                         /* don't stop reporting groups if one
1178                                          * doesn't exist.
1179                                          */
1180                                         CWARN("LNet selftest group %s does not exit\n",
1181                                               name);
1182                                         rc = 0;
1183                                 }
1184                         } else if (nla_type(group) == LN_SCALAR_ATTR_LIST) {
1185                                 struct nlattr *attr;
1186                                 int rem3;
1187
1188                                 if (!prop) {
1189                                         NL_SET_ERR_MSG(extack,
1190                                                        "missing group information");
1191                                         GOTO(report_err, rc = -EINVAL);
1192                                 }
1193
1194                                 nla_for_each_nested(attr, group, rem3) {
1195                                         char tmp[16];
1196
1197                                         if (nla_type(attr) != LN_SCALAR_ATTR_VALUE ||
1198                                             nla_strcmp(attr, "status") != 0)
1199                                                 continue;
1200
1201                                         attr = nla_next(attr, &rem3);
1202                                         if (nla_type(attr) !=
1203                                             LN_SCALAR_ATTR_VALUE) {
1204                                                 NL_SET_ERR_MSG(extack,
1205                                                                "invalid config param");
1206                                                 GOTO(report_err, rc = -EINVAL);
1207                                         }
1208
1209                                         rc = nla_strscpy(tmp, attr, sizeof(tmp));
1210                                         if (rc < 0) {
1211                                                 NL_SET_ERR_MSG(extack,
1212                                                                "failed to get prop attr");
1213                                                 GOTO(report_err, rc);
1214                                         }
1215                                         rc = 0;
1216                                         prop->lggp_state_filter |=
1217                                                 lst_node_str2state(tmp);
1218                                 }
1219                         }
1220                 }
1221         }
1222         if (!glist->lggl_count) {
1223                 NL_SET_ERR_MSG(extack, "No groups found");
1224                 rc = -ENOENT;
1225         }
1226 report_err:
1227         if (rc < 0)
1228                 lst_groups_show_done(cb);
1229
1230         return rc;
1231 }
1232
1233 static const struct ln_key_list lst_group_keys = {
1234         .lkl_maxattr                    = LNET_SELFTEST_GROUP_MAX,
1235         .lkl_list                       = {
1236                 [LNET_SELFTEST_GROUP_ATTR_HDR]  = {
1237                         .lkp_value              = "groups",
1238                         .lkp_key_format         = LNKF_SEQUENCE,
1239                         .lkp_data_type          = NLA_NUL_STRING,
1240                 },
1241                 [LNET_SELFTEST_GROUP_ATTR_NAME] = {
1242                         .lkp_data_type          = NLA_STRING,
1243                 },
1244                 [LNET_SELFTEST_GROUP_ATTR_NODELIST] = {
1245                         .lkp_key_format         = LNKF_MAPPING | LNKF_SEQUENCE,
1246                         .lkp_data_type          = NLA_NESTED,
1247                 },
1248         },
1249 };
1250
1251 static const struct ln_key_list lst_group_nodelist_keys = {
1252         .lkl_maxattr                    = LNET_SELFTEST_GROUP_NODELIST_PROP_MAX,
1253         .lkl_list                       = {
1254                 [LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID] = {
1255                         .lkp_value              = "nid",
1256                         .lkp_data_type          = NLA_STRING,
1257                 },
1258                 [LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS] = {
1259                         .lkp_value              = "status",
1260                         .lkp_data_type          = NLA_STRING,
1261                 },
1262         },
1263 };
1264
1265 static int lst_groups_show_dump(struct sk_buff *msg,
1266                                 struct netlink_callback *cb)
1267 {
1268         struct lst_genl_group_list *glist = lst_group_dump_ctx(cb);
1269 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
1270         struct netlink_ext_ack *extack = NULL;
1271 #endif
1272         int portid = NETLINK_CB(cb->skb).portid;
1273         int seq = cb->nlh->nlmsg_seq;
1274         int idx = 0, rc = 0;
1275
1276 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
1277         extack = cb->extack;
1278 #endif
1279         if (!glist->lggl_index) {
1280                 const struct ln_key_list *all[] = {
1281                         &lst_group_keys, &lst_group_nodelist_keys, NULL
1282                 };
1283
1284                 rc = lnet_genl_send_scalar_list(msg, portid, seq, &lst_family,
1285                                                 NLM_F_CREATE | NLM_F_MULTI,
1286                                                 LNET_SELFTEST_CMD_GROUPS, all);
1287                 if (rc < 0) {
1288                         NL_SET_ERR_MSG(extack, "failed to send key table");
1289                         GOTO(send_error, rc);
1290                 }
1291         }
1292
1293         for (idx = glist->lggl_index; idx < glist->lggl_count; idx++) {
1294                 struct lst_genl_group_prop *group;
1295                 struct lstcon_ndlink *ndl;
1296                 struct nlattr *nodelist;
1297                 unsigned int count = 1;
1298                 void *hdr;
1299
1300                 group = genradix_ptr(&glist->lggl_groups, idx);
1301                 if (!group)
1302                         continue;
1303
1304                 hdr = genlmsg_put(msg, portid, seq, &lst_family,
1305                                   NLM_F_MULTI, LNET_SELFTEST_CMD_GROUPS);
1306                 if (!hdr) {
1307                         NL_SET_ERR_MSG(extack, "failed to send values");
1308                         GOTO(send_error, rc = -EMSGSIZE);
1309                 }
1310
1311                 if (idx == 0)
1312                         nla_put_string(msg, LNET_SELFTEST_GROUP_ATTR_HDR, "");
1313
1314                 nla_put_string(msg, LNET_SELFTEST_GROUP_ATTR_NAME,
1315                                group->lggp_grp->grp_name);
1316
1317                 if (!glist->lggl_verbose)
1318                         goto skip_details;
1319
1320                 nodelist = nla_nest_start(msg,
1321                                           LNET_SELFTEST_GROUP_ATTR_NODELIST);
1322                 list_for_each_entry(ndl, &group->lggp_grp->grp_ndl_list,
1323                                     ndl_link) {
1324                         struct nlattr *node = nla_nest_start(msg, count);
1325                         char *ndstate;
1326
1327                         if (group->lggp_state_filter &&
1328                             !(group->lggp_state_filter & ndl->ndl_node->nd_state))
1329                                 continue;
1330
1331                         nla_put_string(msg,
1332                                        LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_NID,
1333                                        libcfs_id2str(ndl->ndl_node->nd_id));
1334
1335                         ndstate = lst_node_state2str(ndl->ndl_node->nd_state);
1336                         nla_put_string(msg,
1337                                        LNET_SELFTEST_GROUP_NODELIST_PROP_ATTR_STATUS,
1338                                        ndstate);
1339                         nla_nest_end(msg, node);
1340                 }
1341                 nla_nest_end(msg, nodelist);
1342 skip_details:
1343                 genlmsg_end(msg, hdr);
1344         }
1345         glist->lggl_index = idx;
1346 send_error:
1347         return lnet_nl_send_error(cb->skb, portid, seq, rc);
1348 }
1349
1350 #ifndef HAVE_NETLINK_CALLBACK_START
1351 static int lst_old_groups_show_dump(struct sk_buff *msg,
1352                                     struct netlink_callback *cb)
1353 {
1354         if (!cb->args[0]) {
1355                 int rc = lst_groups_show_start(cb);
1356
1357                 if (rc < 0)
1358                         return rc;
1359         }
1360
1361         return lst_groups_show_dump(msg, cb);
1362 }
1363 #endif
1364
1365 static const struct genl_multicast_group lst_mcast_grps[] = {
1366         { .name = "sessions",           },
1367         { .name = "groups",             },
1368 };
1369
1370 static const struct genl_ops lst_genl_ops[] = {
1371         {
1372                 .cmd            = LNET_SELFTEST_CMD_SESSIONS,
1373                 .dumpit         = lst_sessions_show_dump,
1374                 .doit           = lst_sessions_cmd,
1375         },
1376         {
1377                 .cmd            = LNET_SELFTEST_CMD_GROUPS,
1378 #ifdef HAVE_NETLINK_CALLBACK_START
1379                 .start          = lst_groups_show_start,
1380                 .dumpit         = lst_groups_show_dump,
1381 #else
1382                 .dumpit         = lst_old_groups_show_dump,
1383 #endif
1384                 .done           = lst_groups_show_done,
1385         },
1386 };
1387
1388 static struct genl_family lst_family = {
1389         .name           = LNET_SELFTEST_GENL_NAME,
1390         .version        = LNET_SELFTEST_GENL_VERSION,
1391         .maxattr        = LN_SCALAR_MAX,
1392         .module         = THIS_MODULE,
1393         .ops            = lst_genl_ops,
1394         .n_ops          = ARRAY_SIZE(lst_genl_ops),
1395         .mcgrps         = lst_mcast_grps,
1396         .n_mcgrps       = ARRAY_SIZE(lst_mcast_grps),
1397 #ifdef GENL_FAMILY_HAS_RESV_START_OP
1398         .resv_start_op  = __LNET_SELFTEST_CMD_MAX_PLUS_ONE,
1399 #endif
1400 };
1401
1402 int lstcon_init_netlink(void)
1403 {
1404         return genl_register_family(&lst_family);
1405 }
1406
1407 void lstcon_fini_netlink(void)
1408 {
1409         genl_unregister_family(&lst_family);
1410 }