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