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