Whamcloud - gitweb
LU-10185 gnilnd: SLES 12 SP2 support and cleanup
[fs/lustre-release.git] / lnet / klnds / gnilnd / gnilnd_proc.c
1 /*
2  * Copyright (C) 2009-2012, 2016 Cray, Inc.
3  *
4  * Copyright (c) 2013, 2015, Intel Corporation.
5  *
6  *   Author: Nic Henke <nic@cray.com>
7  *   Author: James Shimek <jshimek@cray.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /* this code liberated and modified from lnet/lnet/router_proc.c */
26
27 #define DEBUG_SUBSYSTEM S_LND
28 #include "gnilnd.h"
29 #include <linux/seq_file.h>
30 #include <lprocfs_status.h>
31
32 #define GNILND_PROC_STATS       "stats"
33 #define GNILND_PROC_MDD         "mdd"
34 #define GNILND_PROC_SMSG        "smsg"
35 #define GNILND_PROC_CONN        "conn"
36 #define GNILND_PROC_PEER_CONNS  "peer_conns"
37 #define GNILND_PROC_PEER        "peer"
38 #define GNILND_PROC_CKSUM_TEST  "cksum_test"
39
40 static int
41 _kgnilnd_proc_run_cksum_test(int caseno, int nloops, int nob)
42 {
43         lnet_kiov_t              *src, *dest;
44         struct timespec          begin, end, diff;
45         int                      niov;
46         int                      rc = 0;
47         int                      i = 0, j = 0, n;
48         __u16                    cksum, cksum2;
49         __u64                    mbytes;
50
51         LIBCFS_ALLOC(src, LNET_MAX_IOV * sizeof(lnet_kiov_t));
52         LIBCFS_ALLOC(dest, LNET_MAX_IOV * sizeof(lnet_kiov_t));
53
54         if (src == NULL || dest == NULL) {
55                 CERROR("couldn't allocate iovs\n");
56                 GOTO(unwind, rc = -ENOMEM);
57         }
58
59         for (i = 0; i < LNET_MAX_IOV; i++) {
60                 src[i].kiov_offset = 0;
61                 src[i].kiov_len = PAGE_SIZE;
62                 src[i].kiov_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
63
64                 if (src[i].kiov_page == NULL) {
65                         CERROR("couldn't allocate page %d\n", i);
66                         GOTO(unwind, rc = -ENOMEM);
67                 }
68
69                 dest[i].kiov_offset = 0;
70                 dest[i].kiov_len = PAGE_SIZE;
71                 dest[i].kiov_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
72
73                 if (dest[i].kiov_page == NULL) {
74                         CERROR("couldn't allocate page %d\n", i);
75                         GOTO(unwind, rc = -ENOMEM);
76                 }
77         }
78
79         /* add extra 2 pages - one for offset of src, 2nd to allow dest offset */
80         niov = (nob / PAGE_SIZE) + 2;
81         if (niov > LNET_MAX_IOV) {
82                 CERROR("bytes %d too large, requires niov %d > %d\n",
83                         nob, niov, LNET_MAX_IOV);
84                 GOTO(unwind, rc = -E2BIG);
85         }
86
87         /* setup real data */
88         src[0].kiov_offset = 317;
89         dest[0].kiov_offset = 592;
90         switch (caseno) {
91         default:
92                 /* odd -> even */
93                 break;
94         case 1:
95                 /* odd -> odd */
96                 dest[0].kiov_offset -= 1;
97                 break;
98         case 2:
99                 /* even -> even */
100                 src[0].kiov_offset += 1;
101                 break;
102         case 3:
103                 /* even -> odd */
104                 src[0].kiov_offset += 1;
105                 dest[0].kiov_offset -= 1;
106         }
107         src[0].kiov_len = PAGE_SIZE - src[0].kiov_offset;
108         dest[0].kiov_len = PAGE_SIZE - dest[0].kiov_offset;
109
110         for (i = 0; i < niov; i++) {
111                 memset(page_address(src[i].kiov_page) + src[i].kiov_offset,
112                        0xf0 + i, src[i].kiov_len);
113         }
114
115         lnet_copy_kiov2kiov(niov, dest, 0, niov, src, 0, nob);
116
117         getnstimeofday(&begin);
118
119         for (n = 0; n < nloops; n++) {
120                 CDEBUG(D_BUFFS, "case %d loop %d src %d dest %d nob %d niov %d\n",
121                        caseno, n, src[0].kiov_offset, dest[0].kiov_offset, nob, niov);
122                 cksum = kgnilnd_cksum_kiov(niov, src, 0, nob - (n % nob), 1);
123                 cksum2 = kgnilnd_cksum_kiov(niov, dest, 0, nob - (n % nob), 1);
124
125                 if (cksum != cksum2) {
126                         CERROR("case %d loop %d different checksums %x expected %x\n",
127                                j, n, cksum2, cksum);
128                         GOTO(unwind, rc = -ENOKEY);
129                 }
130         }
131
132         getnstimeofday(&end);
133
134         mbytes = ((__u64)nloops * nob * 2) / (1024*1024);
135
136         diff = kgnilnd_ts_sub(end, begin);
137
138         LCONSOLE_INFO("running %lldMB took %ld.%ld seconds\n",
139                       mbytes, diff.tv_sec, diff.tv_nsec);
140
141 unwind:
142         CDEBUG(D_NET, "freeing %d pages\n", i);
143         for (i -= 1; i >= 0; i--) {
144                 if (src[i].kiov_page != NULL) {
145                         __free_page(src[i].kiov_page);
146                 }
147                 if (dest[i].kiov_page != NULL) {
148                         __free_page(dest[i].kiov_page);
149                 }
150         }
151
152         if (src != NULL)
153                 LIBCFS_FREE(src, LNET_MAX_IOV * sizeof(lnet_kiov_t));
154         if (dest != NULL)
155                 LIBCFS_FREE(dest, LNET_MAX_IOV * sizeof(lnet_kiov_t));
156         return rc;
157 }
158
159 static ssize_t
160 kgnilnd_proc_cksum_test_write(struct file *file, const char __user *ubuffer,
161                               size_t count, loff_t *ppos)
162 {
163         char                    dummy[256 + 1] = { '\0' };
164         int                     testno, nloops, nbytes;
165         int                     rc;
166         ENTRY;
167
168         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
169                 CERROR("can't run cksum test, kgnilnd is not initialized yet\n");
170                 RETURN(-ENOSYS);
171         }
172
173         if (count >= sizeof(dummy) || count == 0)
174                 RETURN(-EINVAL);
175
176         if (copy_from_user(dummy, ubuffer, count))
177                 RETURN(-EFAULT);
178
179         if (sscanf(dummy, "%d:%d:%d", &testno, &nloops, &nbytes) == 3) {
180                 rc = _kgnilnd_proc_run_cksum_test(testno, nloops, nbytes);
181                 if (rc < 0) {
182                         RETURN(rc);
183                 } else {
184                         /* spurious, but lets us know the parse was ok */
185                         RETURN(count);
186                 }
187         }
188         RETURN(count);
189 }
190
191 static int
192 kgnilnd_cksum_test_seq_open(struct inode *inode, struct file *file)
193 {
194         return single_open(file, NULL, PDE_DATA(inode));
195 }
196
197 static const struct file_operations kgn_cksum_test_fops = {
198         .owner   = THIS_MODULE,
199         .open    = kgnilnd_cksum_test_seq_open,
200         .write   = kgnilnd_proc_cksum_test_write,
201         .llseek  = seq_lseek,
202         .release = seq_release,
203 };
204
205 static int
206 kgnilnd_stats_seq_show(struct seq_file *sf, void *v)
207 {
208         kgn_device_t           *dev;
209         struct timeval          now;
210         int                     rc;
211
212         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
213                 rc = seq_printf(sf, "kgnilnd is not initialized yet\n");
214                 return rc;
215         }
216
217         /* only do the first device */
218         dev = &kgnilnd_data.kgn_devices[0];
219
220         /* sampling is racy, but so is reading this file! */
221         smp_rmb();
222         do_gettimeofday(&now);
223
224         rc = seq_printf(sf, "time: %lu.%lu\n"
225                            "ntx: %d\n"
226                            "npeers: %d\n"
227                            "nconns: %d\n"
228                            "nEPs: %d\n"
229                            "ndgrams: %d\n"
230                            "nfmablk: %d\n"
231                            "n_mdd: %d\n"
232                            "n_mdd_held: %d\n"
233                            "n_eager_allocs: %d\n"
234                            "GART map bytes: %ld\n"
235                            "TX queued maps: %d\n"
236                            "TX phys nmaps: %d\n"
237                            "TX phys bytes: %lu\n"
238                            "TX virt nmaps: %d\n"
239                            "TX virt bytes: %llu\n"
240                            "RDMAQ bytes_auth: %ld\n"
241                            "RDMAQ bytes_left: %ld\n"
242                            "RDMAQ nstalls: %d\n"
243                            "dev mutex delay: %ld\n"
244                            "dev n_yield: %d\n"
245                            "dev n_schedule: %d\n"
246                            "SMSG fast_try: %d\n"
247                            "SMSG fast_ok: %d\n"
248                            "SMSG fast_block: %d\n"
249                            "SMSG ntx: %u\n"
250                            "SMSG tx_bytes: %lu\n"
251                            "SMSG nrx: %u\n"
252                            "SMSG rx_bytes: %lu\n"
253                            "RDMA ntx: %u\n"
254                            "RDMA tx_bytes: %lu\n"
255                            "RDMA nrx: %u\n"
256                            "RDMA rx_bytes: %lu\n"
257                            "VMAP short: %d\n"
258                            "VMAP cksum: %d\n"
259                            "KMAP short: %d\n"
260                            "RDMA REV length: %d\n"
261                            "RDMA REV offset: %d\n"
262                            "RDMA REV copy: %d\n",
263                 now.tv_sec, now.tv_usec,
264                 atomic_read(&kgnilnd_data.kgn_ntx),
265                 atomic_read(&kgnilnd_data.kgn_npeers),
266                 atomic_read(&kgnilnd_data.kgn_nconns),
267                 atomic_read(&dev->gnd_neps),
268                 atomic_read(&dev->gnd_ndgrams),
269                 atomic_read(&dev->gnd_nfmablk),
270                 atomic_read(&dev->gnd_n_mdd), atomic_read(&dev->gnd_n_mdd_held),
271                 atomic_read(&kgnilnd_data.kgn_neager_allocs),
272                 atomic64_read(&dev->gnd_nbytes_map),
273                 atomic_read(&dev->gnd_nq_map),
274                 dev->gnd_map_nphys, dev->gnd_map_physnop * PAGE_SIZE,
275                 dev->gnd_map_nvirt, dev->gnd_map_virtnob,
276                 atomic64_read(&dev->gnd_rdmaq_bytes_out),
277                 atomic64_read(&dev->gnd_rdmaq_bytes_ok),
278                 atomic_read(&dev->gnd_rdmaq_nstalls),
279                 dev->gnd_mutex_delay,
280                 atomic_read(&dev->gnd_n_yield), atomic_read(&dev->gnd_n_schedule),
281                 atomic_read(&dev->gnd_fast_try), atomic_read(&dev->gnd_fast_ok),
282                 atomic_read(&dev->gnd_fast_block),
283                 atomic_read(&dev->gnd_short_ntx), atomic64_read(&dev->gnd_short_txbytes),
284                 atomic_read(&dev->gnd_short_nrx), atomic64_read(&dev->gnd_short_rxbytes),
285                 atomic_read(&dev->gnd_rdma_ntx), atomic64_read(&dev->gnd_rdma_txbytes),
286                 atomic_read(&dev->gnd_rdma_nrx), atomic64_read(&dev->gnd_rdma_rxbytes),
287                 atomic_read(&kgnilnd_data.kgn_nvmap_short),
288                 atomic_read(&kgnilnd_data.kgn_nvmap_cksum),
289                 atomic_read(&kgnilnd_data.kgn_nkmap_short),
290                 atomic_read(&kgnilnd_data.kgn_rev_length),
291                 atomic_read(&kgnilnd_data.kgn_rev_offset),
292                 atomic_read(&kgnilnd_data.kgn_rev_copy_buff));
293
294         return rc;
295 }
296
297 static ssize_t
298 kgnilnd_proc_stats_write(struct file *file, const char __user *ubuffer,
299                          size_t count, loff_t *ppos)
300 {
301         kgn_device_t           *dev;
302
303         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
304                 CERROR("kgnilnd is not initialized for stats write\n");
305                 return -EINVAL;
306         }
307
308         /* only do the first device */
309         dev = &kgnilnd_data.kgn_devices[0];
310
311         atomic_set(&dev->gnd_short_ntx, 0);
312         atomic_set(&dev->gnd_short_nrx, 0);
313         atomic64_set(&dev->gnd_short_txbytes, 0);
314         atomic64_set(&dev->gnd_short_rxbytes, 0);
315         atomic_set(&dev->gnd_rdma_ntx, 0);
316         atomic_set(&dev->gnd_rdma_nrx, 0);
317         atomic_set(&dev->gnd_fast_ok, 0);
318         atomic_set(&dev->gnd_fast_try, 0);
319         atomic_set(&dev->gnd_fast_block, 0);
320         atomic64_set(&dev->gnd_rdma_txbytes, 0);
321         atomic64_set(&dev->gnd_rdma_rxbytes, 0);
322         atomic_set(&dev->gnd_rdmaq_nstalls, 0);
323         set_mb(dev->gnd_mutex_delay, 0);
324         atomic_set(&dev->gnd_n_yield, 0);
325         atomic_set(&dev->gnd_n_schedule, 0);
326         atomic_set(&kgnilnd_data.kgn_nvmap_short, 0);
327         atomic_set(&kgnilnd_data.kgn_nvmap_cksum, 0);
328         atomic_set(&kgnilnd_data.kgn_nkmap_short, 0);
329         /* sampling is racy, but so is writing this file! */
330         smp_wmb();
331         return count;
332 }
333
334 static int
335 kgnilnd_stats_seq_open(struct inode *inode, struct file *file)
336 {
337         return single_open(file, kgnilnd_stats_seq_show, PDE_DATA(inode));
338 }
339
340 static const struct file_operations kgn_stats_fops = {
341         .owner   = THIS_MODULE,
342         .open    = kgnilnd_stats_seq_open,
343         .read    = seq_read,
344         .write   = kgnilnd_proc_stats_write,
345         .llseek  = seq_lseek,
346         .release = seq_release,
347 };
348
349 typedef struct {
350         kgn_device_t           *gmdd_dev;
351         kgn_tx_t               *gmdd_tx;
352         loff_t                  gmdd_off;
353 } kgn_mdd_seq_iter_t;
354
355 int
356 kgnilnd_mdd_seq_seek(kgn_mdd_seq_iter_t *gseq, loff_t off)
357 {
358         kgn_tx_t                *tx;
359         struct list_head        *r;
360         loff_t                  here;
361         int                     rc = 0;
362
363         if (off == 0) {
364                 gseq->gmdd_tx = NULL;
365                 gseq->gmdd_off = 0;
366                 return 0;
367         }
368
369         tx = gseq->gmdd_tx;
370
371         if (tx == NULL || gseq->gmdd_off > off) {
372                 /* search from start */
373                 r = gseq->gmdd_dev->gnd_map_list.next;
374                 here = 1;
375         } else {
376                 /* continue current search */
377                 r = &tx->tx_map_list;
378                 here = gseq->gmdd_off;
379         }
380
381         gseq->gmdd_off = off;
382
383         while (r != &gseq->gmdd_dev->gnd_map_list) {
384                 kgn_tx_t      *t;
385
386                 t = list_entry(r, kgn_tx_t, tx_map_list);
387
388                 if (here == off) {
389                         gseq->gmdd_tx = t;
390                         rc = 0;
391                         goto out;
392                 }
393                 r = r->next;
394                 here++;
395         }
396
397         gseq->gmdd_tx = NULL;
398         rc = -ENOENT;
399 out:
400         return rc;
401 }
402
403 static void *
404 kgnilnd_mdd_seq_start(struct seq_file *s, loff_t *pos)
405 {
406
407         kgn_mdd_seq_iter_t      *gseq;
408         int                      rc;
409
410         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
411                 return NULL;
412         }
413
414         LIBCFS_ALLOC(gseq, sizeof(*gseq));
415         if (gseq == NULL) {
416                 CERROR("could not allocate mdd sequence iterator\n");
417                 return NULL;
418         }
419
420         /* only doing device 0 for now */
421         gseq->gmdd_dev = &kgnilnd_data.kgn_devices[0];
422         gseq->gmdd_tx = NULL;
423
424         /* need to lock map while we poke - huge disturbance
425          * but without it, no way to get the data printed */
426         spin_lock(&gseq->gmdd_dev->gnd_map_lock);
427
428         /* set private to gseq for stop */
429         s->private = gseq;
430
431         rc = kgnilnd_mdd_seq_seek(gseq, *pos);
432         if (rc == 0)
433                 return gseq;
434         else
435                 return NULL;
436 }
437
438 static void
439 kgnilnd_mdd_seq_stop(struct seq_file *s, void *iter)
440 {
441         kgn_mdd_seq_iter_t     *gseq = s->private;
442
443         if (gseq != NULL) {
444                 spin_unlock(&gseq->gmdd_dev->gnd_map_lock);
445                 LIBCFS_FREE(gseq, sizeof(*gseq));
446         }
447 }
448
449 static void *
450 kgnilnd_mdd_seq_next(struct seq_file *s, void *iter, loff_t *pos)
451 {
452         kgn_mdd_seq_iter_t     *gseq = iter;
453         int                     rc;
454         loff_t                  next = *pos + 1;
455
456         rc = kgnilnd_mdd_seq_seek(gseq, next);
457         if (rc != 0) {
458                 return NULL;
459         }
460         *pos = next;
461         return gseq;
462 }
463
464 static int
465 kgnilnd_mdd_seq_show(struct seq_file *s, void *iter)
466 {
467         kgn_mdd_seq_iter_t     *gseq = iter;
468         kgn_tx_t               *tx;
469         __u64                   nob;
470         __u32                   physnop;
471         int                     id;
472         int                     buftype;
473         gni_mem_handle_t        hndl;
474
475         if (gseq->gmdd_off == 0) {
476                 seq_printf(s, "%s %22s %16s %8s %8s %37s\n",
477                         "tx", "tx_id", "nob", "physnop",
478                         "buftype", "mem handle");
479                 return 0;
480         }
481
482         tx = gseq->gmdd_tx;
483         LASSERT(tx != NULL);
484
485         id = tx->tx_id.txe_smsg_id;
486         nob = tx->tx_nob;
487         physnop = tx->tx_phys_npages;
488         buftype = tx->tx_buftype;
489         hndl.qword1 = tx->tx_map_key.qword1;
490         hndl.qword2 = tx->tx_map_key.qword2;
491
492         seq_printf(s, "%p %x %16llu %8d %#8x %#llx.%#llxx\n",
493                 tx, id, nob, physnop, buftype,
494                 hndl.qword1, hndl.qword2);
495
496         return 0;
497 }
498
499 static struct seq_operations kgn_mdd_sops = {
500         .start = kgnilnd_mdd_seq_start,
501         .stop  = kgnilnd_mdd_seq_stop,
502         .next  = kgnilnd_mdd_seq_next,
503         .show  = kgnilnd_mdd_seq_show,
504
505 };
506
507 static int
508 kgnilnd_mdd_seq_open(struct inode *inode, struct file *file)
509 {
510         struct seq_file       *sf;
511         int                    rc;
512
513         rc = seq_open(file, &kgn_mdd_sops);
514         if (rc == 0) {
515                 sf = file->private_data;
516
517                 /* NULL means we've not yet open() */
518                 sf->private = NULL;
519         }
520         return rc;
521 }
522
523 static struct file_operations kgn_mdd_fops = {
524         .owner   = THIS_MODULE,
525         .open    = kgnilnd_mdd_seq_open,
526         .read    = seq_read,
527         .llseek  = seq_lseek,
528         .release = seq_release,
529 };
530
531 typedef struct {
532         __u64                   gsmsg_version;
533         kgn_device_t           *gsmsg_dev;
534         kgn_fma_memblock_t     *gsmsg_fmablk;
535         loff_t                  gsmsg_off;
536 } kgn_smsg_seq_iter_t;
537
538 int
539 kgnilnd_smsg_seq_seek(kgn_smsg_seq_iter_t *gseq, loff_t off)
540 {
541         kgn_fma_memblock_t             *fmablk;
542         kgn_device_t                   *dev;
543         struct list_head               *r;
544         loff_t                          here;
545         int                             rc = 0;
546
547         /* offset 0 is the header, so we start real entries at
548          * here == off == 1 */
549         if (off == 0) {
550                 gseq->gsmsg_fmablk = NULL;
551                 gseq->gsmsg_off = 0;
552                 return 0;
553         }
554
555         fmablk = gseq->gsmsg_fmablk;
556         dev = gseq->gsmsg_dev;
557
558         spin_lock(&dev->gnd_fmablk_lock);
559
560         if (fmablk != NULL &&
561                 gseq->gsmsg_version != atomic_read(&dev->gnd_fmablk_vers)) {
562                 /* list changed */
563                 rc = -ESTALE;
564                 goto out;
565         }
566
567         if (fmablk == NULL || gseq->gsmsg_off > off) {
568                 /* search from start */
569                 r = dev->gnd_fma_buffs.next;
570                 here = 1;
571         } else {
572                 /* continue current search */
573                 r = &fmablk->gnm_bufflist;
574                 here = gseq->gsmsg_off;
575         }
576
577         gseq->gsmsg_version = atomic_read(&dev->gnd_fmablk_vers);
578         gseq->gsmsg_off = off;
579
580         while (r != &dev->gnd_fma_buffs) {
581                 kgn_fma_memblock_t      *t;
582
583                 t = list_entry(r, kgn_fma_memblock_t, gnm_bufflist);
584
585                 if (here == off) {
586                         gseq->gsmsg_fmablk = t;
587                         rc = 0;
588                         goto out;
589                 }
590                 r = r->next;
591                 here++;
592         }
593
594         gseq->gsmsg_fmablk = NULL;
595         rc = -ENOENT;
596 out:
597         spin_unlock(&dev->gnd_fmablk_lock);
598         return rc;
599 }
600
601 static void *
602 kgnilnd_smsg_seq_start(struct seq_file *s, loff_t *pos)
603 {
604
605         kgn_smsg_seq_iter_t     *gseq;
606         int                      rc;
607
608         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
609                 return NULL;
610         }
611
612         LIBCFS_ALLOC(gseq, sizeof(*gseq));
613         if (gseq == NULL) {
614                 CERROR("could not allocate smsg sequence iterator\n");
615                 return NULL;
616         }
617
618         /* only doing device 0 for now */
619         gseq->gsmsg_dev = &kgnilnd_data.kgn_devices[0];
620         gseq->gsmsg_fmablk = NULL;
621         rc = kgnilnd_smsg_seq_seek(gseq, *pos);
622         if (rc == 0)
623                 return gseq;
624
625         LIBCFS_FREE(gseq, sizeof(*gseq));
626         return NULL;
627 }
628
629 static void
630 kgnilnd_smsg_seq_stop(struct seq_file *s, void *iter)
631 {
632         kgn_smsg_seq_iter_t     *gseq = iter;
633
634         if (gseq != NULL)
635                 LIBCFS_FREE(gseq, sizeof(*gseq));
636 }
637
638 static void *
639 kgnilnd_smsg_seq_next(struct seq_file *s, void *iter, loff_t *pos)
640 {
641         kgn_smsg_seq_iter_t    *gseq = iter;
642         int                     rc;
643         loff_t                  next = *pos + 1;
644
645         rc = kgnilnd_smsg_seq_seek(gseq, next);
646         if (rc != 0) {
647                 LIBCFS_FREE(gseq, sizeof(*gseq));
648                 return NULL;
649         }
650         *pos = next;
651         return gseq;
652 }
653
654 static int
655 kgnilnd_smsg_seq_show(struct seq_file *s, void *iter)
656 {
657         kgn_smsg_seq_iter_t    *gseq = iter;
658         kgn_fma_memblock_t     *fmablk;
659         kgn_device_t           *dev;
660         int                     avail_mboxs, held_mboxs, num_mboxs;
661         unsigned int            blk_size;
662         int                     live;
663         kgn_fmablk_state_t      state;
664         gni_mem_handle_t        hndl;
665
666         if (gseq->gsmsg_off == 0) {
667                 seq_printf(s, "%5s %4s %6s/%5s/%5s %9s %18s %37s\n",
668                         "blk#", "type", "avail", "held", "total", "size",
669                         "fmablk", "mem handle");
670                 return 0;
671         }
672
673         fmablk = gseq->gsmsg_fmablk;
674         dev = gseq->gsmsg_dev;
675         LASSERT(fmablk != NULL);
676
677         spin_lock(&dev->gnd_fmablk_lock);
678
679         if (gseq->gsmsg_version != atomic_read(&dev->gnd_fmablk_vers)) {
680                 /* list changed */
681                 spin_unlock(&dev->gnd_fmablk_lock);
682                 return -ESTALE;
683         }
684
685         live = fmablk->gnm_hold_timeout == 0;
686         /* none are available if it isn't live... */
687         avail_mboxs = live ? fmablk->gnm_avail_mboxs : 0;
688         held_mboxs = fmablk->gnm_held_mboxs;
689         num_mboxs = fmablk->gnm_num_mboxs;
690         blk_size = fmablk->gnm_blk_size;
691         state = fmablk->gnm_state;
692         hndl.qword1 = fmablk->gnm_hndl.qword1;
693         hndl.qword2 = fmablk->gnm_hndl.qword2;
694
695         spin_unlock(&dev->gnd_fmablk_lock);
696
697         if (live) {
698                 seq_printf(s, "%5d %4s %6d/%5d/%5d %9d %18p   %#llx.%#llx\n",
699                            (int) gseq->gsmsg_off, kgnilnd_fmablk_state2str(state),
700                            avail_mboxs, held_mboxs, num_mboxs, blk_size,
701                            fmablk, hndl.qword1, hndl.qword2);
702         } else {
703                 seq_printf(s, "%5d %4s %6d/%5d/%5d %9d %18p %37s\n",
704                            (int) gseq->gsmsg_off, kgnilnd_fmablk_state2str(state),
705                            avail_mboxs, held_mboxs, num_mboxs, blk_size,
706                            fmablk, "PURGATORY.HOLD");
707         }
708
709         return 0;
710 }
711
712 static struct seq_operations kgn_smsg_sops = {
713         .start = kgnilnd_smsg_seq_start,
714         .stop  = kgnilnd_smsg_seq_stop,
715         .next  = kgnilnd_smsg_seq_next,
716         .show  = kgnilnd_smsg_seq_show,
717
718 };
719
720 static int
721 kgnilnd_smsg_seq_open(struct inode *inode, struct file *file)
722 {
723         struct seq_file       *sf;
724         int                    rc;
725
726         rc = seq_open(file, &kgn_smsg_sops);
727         if (rc == 0) {
728                 sf = file->private_data;
729                 sf->private = PDE_DATA(inode);
730         }
731
732         return rc;
733 }
734
735 static struct file_operations kgn_smsg_fops = {
736         .owner   = THIS_MODULE,
737         .open    = kgnilnd_smsg_seq_open,
738         .read    = seq_read,
739         .llseek  = seq_lseek,
740         .release = seq_release,
741 };
742
743 typedef struct {
744         __u64                   gconn_version;
745         struct list_head       *gconn_list;
746         kgn_conn_t             *gconn_conn;
747         loff_t                  gconn_off;
748         int                     gconn_hashidx;
749 } kgn_conn_seq_iter_t;
750
751 int
752 kgnilnd_conn_seq_seek(kgn_conn_seq_iter_t *gseq, loff_t off)
753 {
754         struct list_head       *list, *tmp;
755         loff_t                  here = 0;
756         int                     rc = 0;
757
758         if (off == 0) {
759                 gseq->gconn_hashidx = 0;
760                 gseq->gconn_list = NULL;
761         }
762
763         if (off > atomic_read(&kgnilnd_data.kgn_nconns)) {
764                 gseq->gconn_list = NULL;
765                 rc = -ENOENT;
766         }
767
768         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
769         if (gseq->gconn_list != NULL &&
770                 gseq->gconn_version != kgnilnd_data.kgn_conn_version) {
771                 /* list changed */
772                 rc = -ESTALE;
773                 goto out;
774         }
775
776         if ((gseq->gconn_list == NULL) ||
777                 (gseq->gconn_off > off) ||
778                 (gseq->gconn_hashidx >= *kgnilnd_tunables.kgn_peer_hash_size)) {
779                 /* search from start */
780                 gseq->gconn_hashidx = 0;
781                 list = &kgnilnd_data.kgn_conns[gseq->gconn_hashidx];
782                 here = 0;
783         } else {
784                 /* continue current search */
785                 list = gseq->gconn_list;
786         }
787
788         gseq->gconn_version = kgnilnd_data.kgn_conn_version;
789         gseq->gconn_off = off;
790
791 start_list:
792
793         list_for_each(tmp, list) {
794                 if (here == off) {
795                         kgn_conn_t *conn;
796                         conn = list_entry(tmp, kgn_conn_t, gnc_hashlist);
797                         gseq->gconn_conn = conn;
798                         rc = 0;
799                         goto out;
800                 }
801                 here++;
802         }
803         /* if we got through this hash bucket with 'off' still to go, try next*/
804         gseq->gconn_hashidx++;
805         if ((here <= off) &&
806                 (gseq->gconn_hashidx < *kgnilnd_tunables.kgn_peer_hash_size)) {
807                 list = &kgnilnd_data.kgn_conns[gseq->gconn_hashidx];
808                 goto start_list;
809         }
810
811         gseq->gconn_list = NULL;
812         rc = -ENOENT;
813 out:
814         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
815         return rc;
816 }
817
818 static void *
819 kgnilnd_conn_seq_start(struct seq_file *s, loff_t *pos)
820 {
821
822         kgn_conn_seq_iter_t     *gseq;
823         int                      rc;
824
825         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
826                 return NULL;
827         }
828
829         LIBCFS_ALLOC(gseq, sizeof(*gseq));
830         if (gseq == NULL) {
831                 CERROR("could not allocate conn sequence iterator\n");
832                 return NULL;
833         }
834
835         /* only doing device 0 for now */
836         gseq->gconn_list = NULL;
837         rc = kgnilnd_conn_seq_seek(gseq, *pos);
838         if (rc == 0)
839                 return gseq;
840
841         LIBCFS_FREE(gseq, sizeof(*gseq));
842         return NULL;
843 }
844
845 static void
846 kgnilnd_conn_seq_stop(struct seq_file *s, void *iter)
847 {
848         kgn_conn_seq_iter_t     *gseq = iter;
849
850         if (gseq != NULL)
851                 LIBCFS_FREE(gseq, sizeof(*gseq));
852 }
853
854 static void *
855 kgnilnd_conn_seq_next(struct seq_file *s, void *iter, loff_t *pos)
856 {
857         kgn_conn_seq_iter_t    *gseq = iter;
858         int                     rc;
859         loff_t                  next = *pos + 1;
860
861         rc = kgnilnd_conn_seq_seek(gseq, next);
862         if (rc != 0) {
863                 LIBCFS_FREE(gseq, sizeof(*gseq));
864                 return NULL;
865         }
866         *pos = next;
867         return gseq;
868 }
869
870 static int
871 kgnilnd_conn_seq_show(struct seq_file *s, void *iter)
872 {
873         kgn_conn_seq_iter_t    *gseq = iter;
874         kgn_peer_t             *peer = NULL;
875         kgn_conn_t             *conn;
876
877         /* there is no header data for conns, so offset 0 is the first
878          * real entry. */
879
880         conn = gseq->gconn_conn;
881         LASSERT(conn != NULL);
882
883         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
884         if (gseq->gconn_list != NULL &&
885                 gseq->gconn_version != kgnilnd_data.kgn_conn_version) {
886                 /* list changed */
887                 read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
888                 return -ESTALE;
889         }
890
891         /* instead of saving off the data, just refcount */
892         kgnilnd_conn_addref(conn);
893         if (conn->gnc_peer) {
894                 /* don't use link - after unlock it could get nuked */
895                 peer = conn->gnc_peer;
896                 kgnilnd_peer_addref(peer);
897         }
898
899         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
900
901         seq_printf(s, "%p->%s [%d] q %d/%d/%d "
902                 "tx sq %u %dms/%dms "
903                 "rx sq %u %dms/%dms "
904                 "noop r/s %d/%d w/s/cq %lds/%lds/%lds "
905                 "sched a/d %lds/%lds "
906                 "tx_re %lld TO %ds %s\n",
907                 conn, peer ? libcfs_nid2str(peer->gnp_nid) : "<?>",
908                 atomic_read(&conn->gnc_refcount),
909                 kgnilnd_count_list(&conn->gnc_fmaq),
910                 atomic_read(&conn->gnc_nlive_fma),
911                 atomic_read(&conn->gnc_nlive_rdma),
912                 atomic_read(&conn->gnc_tx_seq),
913                 jiffies_to_msecs(jiffies - conn->gnc_last_tx),
914                 jiffies_to_msecs(jiffies - conn->gnc_last_tx_cq),
915                 atomic_read(&conn->gnc_rx_seq),
916                 jiffies_to_msecs(jiffies - conn->gnc_last_rx),
917                 jiffies_to_msecs(jiffies - conn->gnc_last_rx_cq),
918                 atomic_read(&conn->gnc_reaper_noop),
919                 atomic_read(&conn->gnc_sched_noop),
920                 cfs_duration_sec(jiffies - conn->gnc_last_noop_want),
921                 cfs_duration_sec(jiffies - conn->gnc_last_noop_sent),
922                 cfs_duration_sec(jiffies - conn->gnc_last_noop_cq),
923                 cfs_duration_sec(jiffies - conn->gnc_last_sched_ask),
924                 cfs_duration_sec(jiffies - conn->gnc_last_sched_do),
925                 conn->gnc_tx_retrans, conn->gnc_timeout,
926                 kgnilnd_conn_state2str(conn));
927
928         if (peer)
929                 kgnilnd_peer_decref(peer);
930         kgnilnd_conn_decref(conn);
931
932         return 0;
933 }
934
935 static struct seq_operations kgn_conn_sops = {
936         .start = kgnilnd_conn_seq_start,
937         .stop  = kgnilnd_conn_seq_stop,
938         .next  = kgnilnd_conn_seq_next,
939         .show  = kgnilnd_conn_seq_show,
940
941 };
942
943 #define KGN_DEBUG_PEER_NID_DEFAULT -1
944 static int kgnilnd_debug_peer_nid = KGN_DEBUG_PEER_NID_DEFAULT;
945
946 static ssize_t
947 kgnilnd_proc_peer_conns_write(struct file *file, const char __user *ubuffer,
948                               size_t count, loff_t *ppos)
949 {
950         char dummy[8];
951         int  rc;
952
953         if (count >= sizeof(dummy) || count == 0)
954                 return -EINVAL;
955
956         if (copy_from_user(dummy, ubuffer, count))
957                 return -EFAULT;
958
959         rc = sscanf(dummy, "%d", &kgnilnd_debug_peer_nid);
960
961         if (rc != 1) {
962                 return -EINVAL;
963         }
964
965         RETURN(count);
966 }
967
968 /* debug data to print from conns associated with peer nid
969   -  date/time
970   -  peer nid
971   -  mbox_addr (msg_buffer + mbox_offset)
972   -  gnc_dgram_type
973   -  gnc_in_purgatory
974   -  gnc_state
975   -  gnc_error
976   -  gnc_peer_error
977   -  gnc_tx_seq
978   -  gnc_last_tx
979   -  gnc_last_tx_cq
980   -  gnc_rx_seq
981   -  gnc_first_rx
982   -  gnc_last_rx
983   -  gnc_last_rx_cq
984   -  gnc_tx_retrans
985   -  gnc_close_sent
986   -  gnc_close_recvd
987 */
988
989 static int
990 kgnilnd_proc_peer_conns_seq_show(struct seq_file *sf, void *v)
991 {
992         kgn_peer_t      *peer;
993         kgn_conn_t      *conn;
994         struct tm       ctm;
995         struct timespec now;
996         unsigned long   jifs;
997         int             rc = 0;
998
999         if (kgnilnd_debug_peer_nid == KGN_DEBUG_PEER_NID_DEFAULT) {
1000                 rc = seq_printf(sf, "peer_conns not initialized\n");
1001                 return rc;
1002         }
1003
1004         /* sample date/time stamp - print time in UTC
1005          * 2012-12-11T16:06:16.966751 123@gni ...
1006          */
1007         getnstimeofday(&now);
1008         time_to_tm(now.tv_sec, 0, &ctm);
1009         jifs = jiffies;
1010
1011         write_lock(&kgnilnd_data.kgn_peer_conn_lock);
1012         peer = kgnilnd_find_peer_locked(kgnilnd_debug_peer_nid);
1013
1014         if (peer == NULL) {
1015                 rc = seq_printf(sf, "peer not found for this nid %d\n",
1016                              kgnilnd_debug_peer_nid);
1017                 write_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1018                 return rc;
1019         }
1020
1021         list_for_each_entry(conn, &peer->gnp_conns, gnc_list) {
1022                 rc = seq_printf(sf,
1023                         "%04ld-%02d-%02dT%02d:%02d:%02d.%06ld %s "
1024                         "mbox adr %p "
1025                         "dg type %s "
1026                         "%s "
1027                         "purg %d "
1028                         "close s/r %d/%d "
1029                         "err %d peer err %d "
1030                         "tx sq %u %dms/%dms "
1031                         "rx sq %u %dms/%dms/%dms "
1032                         "tx retran %lld\n",
1033                         ctm.tm_year+1900, ctm.tm_mon+1, ctm.tm_mday,
1034                         ctm.tm_hour, ctm.tm_min, ctm.tm_sec, now.tv_nsec,
1035                         libcfs_nid2str(peer->gnp_nid),
1036                         conn->remote_mbox_addr,
1037                         kgnilnd_conn_dgram_type2str(conn->gnc_dgram_type),
1038                         kgnilnd_conn_state2str(conn),
1039                         conn->gnc_in_purgatory,
1040                         conn->gnc_close_sent,
1041                         conn->gnc_close_recvd,
1042                         conn->gnc_error,
1043                         conn->gnc_peer_error,
1044                         atomic_read(&conn->gnc_tx_seq),
1045                         jiffies_to_msecs(jifs - conn->gnc_last_tx),
1046                         jiffies_to_msecs(jifs - conn->gnc_last_tx_cq),
1047                         atomic_read(&conn->gnc_rx_seq),
1048                         jiffies_to_msecs(jifs - conn->gnc_first_rx),
1049                         jiffies_to_msecs(jifs - conn->gnc_last_rx),
1050                         jiffies_to_msecs(jifs - conn->gnc_last_rx_cq),
1051                         conn->gnc_tx_retrans);
1052         }
1053
1054         write_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1055         return rc;
1056 }
1057
1058 static int
1059 kgnilnd_peer_conns_seq_open(struct inode *inode, struct file *file)
1060 {
1061         return single_open(file, kgnilnd_proc_peer_conns_seq_show,
1062                            PDE_DATA(inode));
1063 }
1064
1065 static const struct file_operations kgn_peer_conns_fops = {
1066         .owner   = THIS_MODULE,
1067         .open    = kgnilnd_peer_conns_seq_open,
1068         .read    = seq_read,
1069         .write   = kgnilnd_proc_peer_conns_write,
1070         .llseek  = seq_lseek,
1071         .release = seq_release,
1072 };
1073
1074 static int
1075 kgnilnd_conn_seq_open(struct inode *inode, struct file *file)
1076 {
1077         struct seq_file       *sf;
1078         int                    rc;
1079
1080         rc = seq_open(file, &kgn_conn_sops);
1081         if (rc == 0) {
1082                 sf = file->private_data;
1083                 sf->private = PDE_DATA(inode);
1084         }
1085
1086         return rc;
1087 }
1088
1089 static struct file_operations kgn_conn_fops = {
1090         .owner   = THIS_MODULE,
1091         .open    = kgnilnd_conn_seq_open,
1092         .read    = seq_read,
1093         .llseek  = seq_lseek,
1094         .release = seq_release,
1095 };
1096
1097 typedef struct {
1098         __u64                   gpeer_version;
1099         struct list_head       *gpeer_list;
1100         kgn_peer_t             *gpeer_peer;
1101         loff_t                  gpeer_off;
1102         int                     gpeer_hashidx;
1103 } kgn_peer_seq_iter_t;
1104
1105 int
1106 kgnilnd_peer_seq_seek(kgn_peer_seq_iter_t *gseq, loff_t off)
1107 {
1108         struct list_head       *list, *tmp;
1109         loff_t                  here = 0;
1110         int                     rc = 0;
1111
1112         if (off == 0) {
1113                 gseq->gpeer_hashidx = 0;
1114                 gseq->gpeer_list = NULL;
1115         }
1116
1117         if (off > atomic_read(&kgnilnd_data.kgn_npeers)) {
1118                 gseq->gpeer_list = NULL;
1119                 rc = -ENOENT;
1120         }
1121
1122         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
1123         if (gseq->gpeer_list != NULL &&
1124                 gseq->gpeer_version != kgnilnd_data.kgn_peer_version) {
1125                 /* list changed */
1126                 rc = -ESTALE;
1127                 goto out;
1128         }
1129
1130         if ((gseq->gpeer_list == NULL) ||
1131                 (gseq->gpeer_off > off) ||
1132                 (gseq->gpeer_hashidx >= *kgnilnd_tunables.kgn_peer_hash_size)) {
1133                 /* search from start */
1134                 gseq->gpeer_hashidx = 0;
1135                 list = &kgnilnd_data.kgn_peers[gseq->gpeer_hashidx];
1136                 here = 0;
1137         } else {
1138                 /* continue current search */
1139                 list = gseq->gpeer_list;
1140         }
1141
1142         gseq->gpeer_version = kgnilnd_data.kgn_peer_version;
1143         gseq->gpeer_off = off;
1144
1145 start_list:
1146
1147         list_for_each(tmp, list) {
1148                 if (here == off) {
1149                         kgn_peer_t *peer;
1150                         peer = list_entry(tmp, kgn_peer_t, gnp_list);
1151                         gseq->gpeer_peer = peer;
1152                         rc = 0;
1153                         goto out;
1154                 }
1155                 here++;
1156         }
1157         /* if we got through this hash bucket with 'off' still to go, try next*/
1158         gseq->gpeer_hashidx++;
1159         if ((here <= off) &&
1160                 (gseq->gpeer_hashidx < *kgnilnd_tunables.kgn_peer_hash_size)) {
1161                 list = &kgnilnd_data.kgn_peers[gseq->gpeer_hashidx];
1162                 goto start_list;
1163         }
1164
1165         gseq->gpeer_list = NULL;
1166         rc = -ENOENT;
1167 out:
1168         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1169         return rc;
1170 }
1171
1172 static void *
1173 kgnilnd_peer_seq_start(struct seq_file *s, loff_t *pos)
1174 {
1175
1176         kgn_peer_seq_iter_t     *gseq;
1177         int                      rc;
1178
1179         if (kgnilnd_data.kgn_init < GNILND_INIT_ALL) {
1180                 return NULL;
1181         }
1182
1183         LIBCFS_ALLOC(gseq, sizeof(*gseq));
1184         if (gseq == NULL) {
1185                 CERROR("could not allocate peer sequence iterator\n");
1186                 return NULL;
1187         }
1188
1189         /* only doing device 0 for now */
1190         gseq->gpeer_list = NULL;
1191         rc = kgnilnd_peer_seq_seek(gseq, *pos);
1192         if (rc == 0)
1193                 return gseq;
1194
1195         LIBCFS_FREE(gseq, sizeof(*gseq));
1196         return NULL;
1197 }
1198
1199 static void
1200 kgnilnd_peer_seq_stop(struct seq_file *s, void *iter)
1201 {
1202         kgn_peer_seq_iter_t     *gseq = iter;
1203
1204         if (gseq != NULL)
1205                 LIBCFS_FREE(gseq, sizeof(*gseq));
1206 }
1207
1208 static void *
1209 kgnilnd_peer_seq_next(struct seq_file *s, void *iter, loff_t *pos)
1210 {
1211         kgn_peer_seq_iter_t    *gseq = iter;
1212         int                     rc;
1213         loff_t                  next = *pos + 1;
1214
1215         rc = kgnilnd_peer_seq_seek(gseq, next);
1216         if (rc != 0) {
1217                 LIBCFS_FREE(gseq, sizeof(*gseq));
1218                 return NULL;
1219         }
1220         *pos = next;
1221         return gseq;
1222 }
1223
1224 static int
1225 kgnilnd_peer_seq_show(struct seq_file *s, void *iter)
1226 {
1227         kgn_peer_seq_iter_t    *gseq = iter;
1228         kgn_peer_t             *peer;
1229         kgn_conn_t             *conn;
1230         char                   conn_str;
1231         int                    purg_count = 0;
1232         /* there is no header data for peers, so offset 0 is the first
1233          * real entry. */
1234
1235         peer = gseq->gpeer_peer;
1236         LASSERT(peer != NULL);
1237
1238         read_lock(&kgnilnd_data.kgn_peer_conn_lock);
1239         if (gseq->gpeer_list != NULL &&
1240                 gseq->gpeer_version != kgnilnd_data.kgn_peer_version) {
1241                 /* list changed */
1242                 read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1243                 return -ESTALE;
1244         }
1245
1246         /* instead of saving off the data, just refcount */
1247         kgnilnd_peer_addref(peer);
1248         conn = kgnilnd_find_conn_locked(peer);
1249
1250         if (peer->gnp_connecting) {
1251                 conn_str = 'S';
1252         } else if (conn != NULL) {
1253                 conn_str = 'C';
1254         } else {
1255                 conn_str = 'D';
1256         }
1257
1258         list_for_each_entry(conn, &peer->gnp_conns, gnc_list) {
1259                 if (conn->gnc_in_purgatory) {
1260                         purg_count++;
1261                 }
1262         }
1263
1264         read_unlock(&kgnilnd_data.kgn_peer_conn_lock);
1265
1266         seq_printf(s, "%p->%s [%d] %s NIC 0x%x q %d conn %c purg %d last %d@%dms dgram %d@%dms reconn %dms to %lus \n",
1267                 peer, libcfs_nid2str(peer->gnp_nid),
1268                 atomic_read(&peer->gnp_refcount),
1269                 (peer->gnp_state == GNILND_PEER_DOWN) ? "down" :
1270                 peer->gnp_state == GNILND_PEER_TIMED_OUT ? "timedout" : "up",
1271                 peer->gnp_host_id,
1272                 kgnilnd_count_list(&peer->gnp_tx_queue),
1273                 conn_str,
1274                 purg_count,
1275                 peer->gnp_last_errno,
1276                 jiffies_to_msecs(jiffies - peer->gnp_last_alive),
1277                 peer->gnp_last_dgram_errno,
1278                 jiffies_to_msecs(jiffies - peer->gnp_last_dgram_time),
1279                 peer->gnp_reconnect_interval != 0
1280                         ? jiffies_to_msecs(jiffies - peer->gnp_reconnect_time)
1281                         : 0,
1282                 peer->gnp_reconnect_interval);
1283
1284         kgnilnd_peer_decref(peer);
1285
1286         return 0;
1287 }
1288
1289 static struct seq_operations kgn_peer_sops = {
1290         .start = kgnilnd_peer_seq_start,
1291         .stop  = kgnilnd_peer_seq_stop,
1292         .next  = kgnilnd_peer_seq_next,
1293         .show  = kgnilnd_peer_seq_show,
1294 };
1295
1296 static int
1297 kgnilnd_peer_seq_open(struct inode *inode, struct file *file)
1298 {
1299         struct seq_file       *sf;
1300         int                    rc;
1301
1302         rc = seq_open(file, &kgn_peer_sops);
1303         if (rc == 0) {
1304                 sf = file->private_data;
1305                 sf->private = PDE_DATA(inode);
1306         }
1307
1308         return rc;
1309 }
1310
1311 static struct file_operations kgn_peer_fops = {
1312         .owner   = THIS_MODULE,
1313         .open    = kgnilnd_peer_seq_open,
1314         .read    = seq_read,
1315         .llseek  = seq_lseek,
1316         .release = seq_release,
1317 };
1318
1319 static struct proc_dir_entry *kgn_proc_root;
1320
1321 void
1322 kgnilnd_proc_init(void)
1323 {
1324         struct proc_dir_entry *pde;
1325         int             rc = 0;
1326         ENTRY;
1327
1328         /* setup dir */
1329         kgn_proc_root = proc_mkdir(libcfs_lnd2modname(GNILND), NULL);
1330         if (kgn_proc_root == NULL) {
1331                 CERROR("couldn't create proc dir %s\n",
1332                         libcfs_lnd2modname(GNILND));
1333                 return;
1334         }
1335
1336         /* Initialize CKSUM_TEST */
1337         pde = proc_create(GNILND_PROC_CKSUM_TEST, 0200, kgn_proc_root,
1338                           &kgn_cksum_test_fops);
1339         if (pde == NULL) {
1340                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_CKSUM_TEST);
1341                 GOTO(remove_dir, rc = -ENOENT);
1342         }
1343
1344         /* Initialize STATS */
1345         pde = proc_create(GNILND_PROC_STATS, 0644, kgn_proc_root,
1346                           &kgn_stats_fops);
1347         if (pde == NULL) {
1348                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_STATS);
1349                 GOTO(remove_test, rc = -ENOENT);
1350         }
1351
1352         /* Initialize MDD */
1353         pde = proc_create(GNILND_PROC_MDD, 0444, kgn_proc_root, &kgn_mdd_fops);
1354         if (pde == NULL) {
1355                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_MDD);
1356                 GOTO(remove_stats, rc = -ENOENT);
1357         }
1358
1359         /* Initialize SMSG */
1360         pde = proc_create(GNILND_PROC_SMSG, 0444, kgn_proc_root,
1361                           &kgn_smsg_fops);
1362         if (pde == NULL) {
1363                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_SMSG);
1364                 GOTO(remove_mdd, rc = -ENOENT);
1365         }
1366
1367         /* Initialize CONN */
1368         pde = proc_create(GNILND_PROC_CONN, 0444, kgn_proc_root,
1369                           &kgn_conn_fops);
1370         if (pde == NULL) {
1371                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_CONN);
1372                 GOTO(remove_smsg, rc = -ENOENT);
1373         }
1374
1375         /* Initialize peer conns debug */
1376         pde = proc_create(GNILND_PROC_PEER_CONNS, 0644, kgn_proc_root,
1377                           &kgn_peer_conns_fops);
1378         if (pde == NULL) {
1379                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_PEER_CONNS);
1380                 GOTO(remove_conn, rc = -ENOENT);
1381         }
1382
1383         /* Initialize PEER */
1384         pde = proc_create(GNILND_PROC_PEER, 0444, kgn_proc_root,
1385                           &kgn_peer_fops);
1386         if (pde == NULL) {
1387                 CERROR("couldn't create proc entry %s\n", GNILND_PROC_PEER);
1388                 GOTO(remove_pc, rc = -ENOENT);
1389         }
1390         RETURN_EXIT;
1391
1392 remove_pc:
1393         remove_proc_entry(GNILND_PROC_PEER_CONNS, kgn_proc_root);
1394 remove_conn:
1395         remove_proc_entry(GNILND_PROC_CONN, kgn_proc_root);
1396 remove_smsg:
1397         remove_proc_entry(GNILND_PROC_SMSG, kgn_proc_root);
1398 remove_mdd:
1399         remove_proc_entry(GNILND_PROC_MDD, kgn_proc_root);
1400 remove_stats:
1401         remove_proc_entry(GNILND_PROC_STATS, kgn_proc_root);
1402 remove_test:
1403         remove_proc_entry(GNILND_PROC_CKSUM_TEST, kgn_proc_root);
1404 remove_dir:
1405         remove_proc_entry(libcfs_lnd2modname(GNILND), NULL);
1406
1407         RETURN_EXIT;
1408 }
1409
1410 void
1411 kgnilnd_proc_fini(void)
1412 {
1413         remove_proc_entry(GNILND_PROC_PEER_CONNS, kgn_proc_root);
1414         remove_proc_entry(GNILND_PROC_PEER, kgn_proc_root);
1415         remove_proc_entry(GNILND_PROC_CONN, kgn_proc_root);
1416         remove_proc_entry(GNILND_PROC_MDD, kgn_proc_root);
1417         remove_proc_entry(GNILND_PROC_SMSG, kgn_proc_root);
1418         remove_proc_entry(GNILND_PROC_STATS, kgn_proc_root);
1419         remove_proc_entry(GNILND_PROC_CKSUM_TEST, kgn_proc_root);
1420         remove_proc_entry(libcfs_lnd2modname(GNILND), NULL);
1421 }