Whamcloud - gitweb
invoking section 3 of the GNU LGPL, to instead apply the terms of the GPL
[fs/lustre-release.git] / lnet / libcfs / proc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5  *   Author: Zach Brown <zab@zabbo.net>
6  *   Author: Peter J. Braam <braam@clusterfs.com>
7  *   Author: Phil Schwan <phil@clusterfs.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 #define EXPORT_SYMTAB
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/mm.h>
31 #include <linux/string.h>
32 #include <linux/stat.h>
33 #include <linux/errno.h>
34 #include <linux/smp_lock.h>
35 #include <linux/unistd.h>
36 #include <net/sock.h>
37 #include <linux/uio.h>
38
39 #include <asm/system.h>
40 #include <asm/uaccess.h>
41
42 #include <linux/fs.h>
43 #include <linux/file.h>
44 #include <linux/stat.h>
45 #include <linux/list.h>
46 #include <asm/uaccess.h>
47 #include <asm/segment.h>
48
49 #include <linux/proc_fs.h>
50 #include <linux/sysctl.h>
51
52 # define DEBUG_SUBSYSTEM S_PORTALS
53
54 #include <linux/kp30.h>
55 #include <asm/div64.h>
56
57 static struct ctl_table_header *portals_table_header = NULL;
58 extern char debug_file_path[1024];
59 extern char debug_daemon_file_path[1024];
60 extern char portals_upcall[1024];
61
62 #define PSDEV_PORTALS  (0x100)
63 #define PSDEV_DEBUG           1   /* control debugging */
64 #define PSDEV_SUBSYSTEM_DEBUG 2   /* control debugging */
65 #define PSDEV_PRINTK          3   /* force all errors to console */
66 #define PSDEV_DEBUG_PATH      4   /* crashdump log location */
67 #define PSDEV_DEBUG_DUMP_PATH 5   /* crashdump tracelog location */
68 #define PSDEV_PORTALS_UPCALL  6   /* User mode upcall script  */
69
70 #define PORTALS_PRIMARY_CTLCNT 6
71 static struct ctl_table portals_table[PORTALS_PRIMARY_CTLCNT + 1] = {
72         {PSDEV_DEBUG, "debug", &portal_debug, sizeof(int), 0644, NULL,
73          &proc_dointvec},
74         {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &portal_subsystem_debug,
75          sizeof(int), 0644, NULL, &proc_dointvec},
76         {PSDEV_PRINTK, "printk", &portal_printk, sizeof(int), 0644, NULL,
77          &proc_dointvec},
78         {PSDEV_DEBUG_PATH, "debug_path", debug_file_path,
79          sizeof(debug_file_path), 0644, NULL, &proc_dostring, &sysctl_string},
80         {PSDEV_DEBUG_DUMP_PATH, "debug_daemon_path", debug_daemon_file_path,
81          sizeof(debug_daemon_file_path), 0644, NULL, &proc_dostring,
82          &sysctl_string},
83         {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
84          sizeof(portals_upcall), 0644, NULL, &proc_dostring,
85          &sysctl_string},
86         {0}
87 };
88
89 static struct ctl_table top_table[2] = {
90         {PSDEV_PORTALS, "portals", NULL, 0, 0555, portals_table},
91         {0}
92 };
93
94
95 #ifdef PORTALS_PROFILING
96 /*
97  * profiling stuff.  we do this statically for now 'cause its simple,
98  * but we could do some tricks with elf sections to have this array
99  * automatically built.
100  */
101 #define def_prof(FOO) [PROF__##FOO] = {#FOO, 0, }
102
103 struct prof_ent prof_ents[] = {
104         def_prof(our_recvmsg),
105         def_prof(our_sendmsg),
106         def_prof(socknal_recv),
107         def_prof(lib_parse),
108         def_prof(conn_list_walk),
109         def_prof(memcpy),
110         def_prof(lib_finalize),
111         def_prof(pingcli_time),
112         def_prof(gmnal_send),
113         def_prof(gmnal_recv),
114 };
115
116 EXPORT_SYMBOL(prof_ents);
117
118 /*
119  * this function is as crazy as the proc filling api
120  * requires.
121  *
122  * buffer: page allocated for us to scribble in.  the
123  *  data returned to the user will be taken from here.
124  * *start: address of the pointer that will tell the 
125  *  caller where in buffer the data the user wants is.
126  * ppos: offset in the entire /proc file that the user
127  *  currently wants.
128  * wanted: the amount of data the user wants.
129  *
130  * while going, 'curpos' is the offset in the entire
131  * file where we currently are.  We only actually
132  * start filling buffer when we get to a place in
133  * the file that the user cares about.
134  *
135  * we take care to only sprintf when the user cares because
136  * we're holding a lock while we do this.
137  *
138  * we're smart and know that we generate fixed size lines.
139  * we only start writing to the buffer when the user cares.
140  * This is unpredictable because we don't snapshot the
141  * list between calls that are filling in a file from
142  * the list.  The list could change mid read and the
143  * output will look very weird indeed.  oh well.
144  */
145
146 static int prof_read_proc(char *buffer, char **start, off_t ppos, int wanted,
147                           int *eof, void *data)
148 {
149         int len = 0, i;
150         int curpos;
151         char *header = "Interval        Cycles_per (Starts Finishes Total)\n";
152         int header_len = strlen(header);
153         char *format = "%-15s %.12Ld (%.12d %.12d %.12Ld)";
154         int line_len = (15 + 1 + 12 + 2 + 12 + 1 + 12 + 1 + 12 + 1);
155
156         *start = buffer;
157
158         if (ppos < header_len) {
159                 int diff = MIN(header_len, wanted);
160                 memcpy(buffer, header + ppos, diff);
161                 len += diff;
162                 ppos += diff;
163         }
164
165         if (len >= wanted)
166                 goto out;
167
168         curpos = header_len;
169
170         for ( i = 0; i < MAX_PROFS ; i++) {
171                 int copied;
172                 struct prof_ent *pe = &prof_ents[i];
173                 long long cycles_per;
174                 /*
175                  * find the part of the array that the buffer wants
176                  */
177                 if (ppos >= (curpos + line_len))  {
178                         curpos += line_len;
179                         continue;
180                 }
181                 /* the clever caller split a line */
182                 if (ppos > curpos) {
183                         *start = buffer + (ppos - curpos);
184                 }
185
186                 if (pe->finishes == 0)
187                         cycles_per = 0;
188                 else
189                 {
190                         cycles_per = pe->total_cycles;
191                         do_div (cycles_per, pe->finishes);
192                 }
193
194                 copied = sprintf(buffer + len, format, pe->str, cycles_per,
195                                  pe->starts, pe->finishes, pe->total_cycles);
196
197                 len += copied;
198
199                 /* pad to line len, -1 for \n */
200                 if ((copied < line_len-1)) {
201                         int diff = (line_len-1) - copied;
202                         memset(buffer + len, ' ', diff);
203                         len += diff;
204                         copied += diff;
205                 }
206
207                 buffer[len++]= '\n';
208
209                 /* bail if we have enough */
210                 if (((buffer + len) - *start) >= wanted)
211                         break;
212
213                 curpos += line_len;
214         }
215
216         /* lameness */
217         if (i == MAX_PROFS)
218                 *eof = 1;
219  out:
220
221         return MIN(((buffer + len) - *start), wanted);
222 }
223
224 /*
225  * all kids love /proc :/
226  */
227 static unsigned char basedir[]="net/portals";
228 #endif /* PORTALS_PROFILING */
229
230 int insert_proc(void)
231 {
232 #if PORTALS_PROFILING
233         unsigned char dir[128];
234         struct proc_dir_entry *ent;
235
236         if (ARRAY_SIZE(prof_ents) != MAX_PROFS) {
237                 CERROR("profiling enum and array are out of sync.\n");
238                 return -1;
239         }
240
241         /*
242          * This is pretty lame.  assuming that failure just
243          * means that they already existed.
244          */
245         strcat(dir, basedir);
246         create_proc_entry(dir, S_IFDIR, 0);
247
248         strcat(dir, "/cycles");
249         ent = create_proc_entry(dir, 0, 0);
250         if (!ent) {
251                 CERROR("couldn't register %s?\n", dir);
252                 return -1;
253         }
254
255         ent->data = NULL;
256         ent->read_proc = prof_read_proc;
257 #endif /* PORTALS_PROFILING */
258
259 #ifdef CONFIG_SYSCTL
260         if (!portals_table_header)
261                 portals_table_header = register_sysctl_table(top_table, 0);
262 #endif
263
264         return 0;
265 }
266
267 void remove_proc(void)
268 {
269 #if PORTALS_PROFILING
270         unsigned char dir[128];
271         int end;
272
273         dir[0]='\0';
274         strcat(dir, basedir);
275
276         end = strlen(dir);
277
278         strcat(dir, "/cycles");
279         remove_proc_entry(dir,0);
280
281         dir[end] = '\0';
282         remove_proc_entry(dir,0);
283 #endif /* PORTALS_PROFILING */
284
285 #ifdef CONFIG_SYSCTL
286         if (portals_table_header)
287                 unregister_sysctl_table(portals_table_header);
288         portals_table_header = NULL;
289 #endif
290 }