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