Whamcloud - gitweb
- landing of b_hd_cleanup_merge to HEAD.
[fs/lustre-release.git] / lnet / router / proc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Portals
7  *   http://sourceforge.net/projects/sandiaportals/
8  *
9  *   Portals is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Portals is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Portals; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #include "router.h"
25
26 #define KPR_PROC_ROUTER "sys/portals/router"
27 #define KPR_PROC_ROUTES "sys/portals/routes"
28
29 /* Used for multi-page route list book keeping */
30 struct proc_route_data {
31         struct list_head *curr;
32         unsigned int generation;
33         off_t skip;
34 } kpr_read_routes_data;
35
36 /* nal2name support re-used from utils/portals.c */
37 struct name2num {
38         char *name;
39         int   num;
40 } nalnames[] = {
41         { "any",         0},
42         { "elan",        QSWNAL},
43         { "tcp",         SOCKNAL},
44         { "gm",          GMNAL},
45         { "ib",          OPENIBNAL},
46         { NULL,          -1}
47 };
48
49 static struct name2num *name2num_lookup_num(struct name2num *table, int num)
50 {
51         while (table->name != NULL)
52                 if (num == table->num)
53                         return (table);
54                 else
55                         table++;
56         return (NULL);
57 }
58
59 static char *nal2name(int nal)
60 {
61         struct name2num *e = name2num_lookup_num(nalnames, nal);
62         return ((e == NULL) ? "???" : e->name);
63 }
64
65
66 static int kpr_proc_router_read(char *page, char **start, off_t off,
67                                 int count, int *eof, void *data)
68 {
69         unsigned long long bytes = kpr_fwd_bytes;
70         unsigned long      packets = kpr_fwd_packets;
71         unsigned long      errors = kpr_fwd_errors;
72         unsigned int       qdepth = atomic_read (&kpr_queue_depth);
73         int                len;
74
75         *eof = 1;
76         if (off != 0)
77                 return (0);
78
79         len = sprintf(page, "%Ld %ld %ld %d\n", bytes, packets, errors, qdepth);
80
81         *start = page;
82         return (len);
83 }
84
85 static int kpr_proc_router_write(struct file *file, const char *ubuffer,
86                                  unsigned long count, void *data)
87 {
88         /* Ignore what we've been asked to write, and just zero the stats */
89         kpr_fwd_bytes = 0;
90         kpr_fwd_packets = 0;
91         kpr_fwd_errors = 0;
92
93         return (count);
94 }
95
96 static int kpr_proc_routes_read(char *page, char **start, off_t off,
97                                 int count, int *eof, void *data)
98 {
99         struct proc_route_data *prd = data;
100         kpr_route_entry_t     *re;
101         kpr_gateway_entry_t *ge;
102         int                 chunk_len = 0;
103         int                 line_len = 0;
104         int                 user_len = 0;
105
106         *eof = 1;
107         *start = page;
108
109         if (prd->curr == NULL) {
110                 if (off != 0)
111                         return 0;
112
113                 /* First pass, initialize our private data */
114                 prd->curr = kpr_routes.next;
115                 prd->generation = kpr_routes_generation;
116                 prd->skip = 0;
117         } else {
118                 /* Abort route list generation change */
119                 if (prd->generation != kpr_routes_generation) {
120                         prd->curr = NULL;
121                         return sprintf(page, "\nError: Routes Changed\n");
122                 }
123
124                 /* All the routes have been walked */
125                 if (prd->curr == &kpr_routes) {
126                         prd->curr = NULL;
127                         return 0;
128                 }
129         }
130
131         read_lock(&kpr_rwlock);
132         *start = page + prd->skip;
133         user_len = -prd->skip;
134
135         for (; prd->curr != &kpr_routes; prd->curr = prd->curr->next) {
136                 re = list_entry(prd->curr, kpr_route_entry_t, kpre_list);
137                 ge = re->kpre_gateway;
138
139                 line_len = sprintf(page + chunk_len,
140                         "%12s  "LPX64" : "LPX64" - "LPX64", %s\n",
141                         nal2name(ge->kpge_nalid), ge->kpge_nid,
142                         re->kpre_lo_nid, re->kpre_hi_nid,
143                         ge->kpge_alive ? "up" : "down");
144                 chunk_len += line_len;
145                 user_len += line_len;
146
147                 /* The route table will exceed one page */
148                 if ((chunk_len > (PAGE_SIZE - 80)) || (user_len > count)) {
149                         prd->curr = prd->curr->next;
150                         break;
151                 }
152         }
153
154         *eof = 0;
155
156         /* Caller received only a portion of the last entry, the
157          * remaining will be delivered in the next page if asked for.
158          */
159         if (user_len > count) {
160                 prd->curr = prd->curr->prev;
161                 prd->skip = line_len - (user_len - count);
162                 read_unlock(&kpr_rwlock);
163                 return count;
164         }
165
166         /* Not enough data to entirely satify callers request */
167         prd->skip = 0;
168         read_unlock(&kpr_rwlock);
169         return user_len;
170 }
171
172 static int kpr_proc_routes_write(struct file *file, const char *ubuffer,
173                                  unsigned long count, void *data)
174 {
175         /* no-op; lctl should be used to adjust the routes */
176         return (count);
177 }
178
179 void kpr_proc_init(void)
180 {
181         struct proc_dir_entry *router_entry;
182         struct proc_dir_entry *routes_entry;
183
184         /* Initialize KPR_PROC_ROUTER */
185         router_entry = create_proc_entry (KPR_PROC_ROUTER,
186                 S_IFREG | S_IRUGO | S_IWUSR, NULL);
187
188         if (router_entry == NULL) {
189                 CERROR("couldn't create proc entry %s\n", KPR_PROC_ROUTER);
190                 return;
191         }
192
193         router_entry->data = NULL;
194         router_entry->read_proc = kpr_proc_router_read;
195         router_entry->write_proc = kpr_proc_router_write;
196
197         /* Initialize KPR_PROC_ROUTES */
198         routes_entry = create_proc_entry (KPR_PROC_ROUTES,
199                 S_IFREG | S_IRUGO | S_IWUSR, NULL);
200
201         if (routes_entry == NULL) {
202                 CERROR("couldn't create proc entry %s\n", KPR_PROC_ROUTES);
203                 return;
204         }
205
206         kpr_read_routes_data.curr = NULL;
207         kpr_read_routes_data.generation = 0;
208         kpr_read_routes_data.skip = 0;
209
210         routes_entry->data = &kpr_read_routes_data;
211         routes_entry->read_proc = kpr_proc_routes_read;
212         routes_entry->write_proc = kpr_proc_routes_write;
213 }
214
215 void kpr_proc_fini(void)
216 {
217         remove_proc_entry(KPR_PROC_ROUTER, 0);
218         remove_proc_entry(KPR_PROC_ROUTES, 0);
219 }