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