Make sure we don't add timers back in history. This gets serial
[linux-2.6/linux-mips.git] / fs / coda / sysctl.c
blobcbfff3e5b354b6f19b943f78e5c31b892f685c41
1 /*
2 * Sysctl operations for Coda filesystem
3 * Original version: (C) 1996 P. Braam and M. Callahan
4 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
8 *
9 * CODA operation statistics
10 * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 #include <linux/mm.h>
17 #include <linux/sysctl.h>
18 #include <linux/swapctl.h>
19 #include <linux/proc_fs.h>
20 #include <linux/malloc.h>
21 #include <linux/stat.h>
22 #include <linux/ctype.h>
23 #include <asm/bitops.h>
24 #include <asm/segment.h>
25 #include <asm/uaccess.h>
26 #include <linux/utsname.h>
27 #define __NO_VERSION__
28 #include <linux/module.h>
30 #include <linux/coda.h>
31 #include <linux/coda_linux.h>
32 #include <linux/coda_fs_i.h>
33 #include <linux/coda_psdev.h>
34 #include <linux/coda_cache.h>
35 #include <linux/coda_proc.h>
37 static struct ctl_table_header *fs_table_header;
39 #define FS_CODA 1 /* Coda file system */
41 #define CODA_DEBUG 1 /* control debugging */
42 #define CODA_ENTRY 2 /* control enter/leave pattern */
43 #define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
44 #define CODA_MC 4 /* use/do not use the access cache */
45 #define CODA_HARD 5 /* mount type "hard" or "soft" */
46 #define CODA_VFS 6 /* vfs statistics */
47 #define CODA_UPCALL 7 /* upcall statistics */
48 #define CODA_PERMISSION 8 /* permission statistics */
49 #define CODA_CACHE_INV 9 /* cache invalidation statistics */
51 static ctl_table coda_table[] = {
52 {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &proc_dointvec},
53 {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
54 {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &proc_dointvec},
55 {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
56 {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
57 {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
58 {CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
59 {CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
60 {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
61 { 0 }
64 static ctl_table fs_table[] = {
65 {FS_CODA, "coda", NULL, 0, 0555, coda_table},
66 {0}
69 struct coda_vfs_stats coda_vfs_stat;
70 struct coda_permission_stats coda_permission_stat;
71 struct coda_cache_inv_stats coda_cache_inv_stat;
72 struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS];
73 struct coda_upcallstats coda_callstats;
74 int coda_upcall_timestamping = 0;
76 /* keep this in sync with coda.h! */
77 char *coda_upcall_names[] = {
78 "totals ", /* 0 */
79 "noop ", /* 1 */
80 "root ", /* 2 */
81 "sync ", /* 3 */
82 "open ", /* 4 */
83 "close ", /* 5 */
84 "ioctl ", /* 6 */
85 "getattr ", /* 7 */
86 "setattr ", /* 8 */
87 "access ", /* 9 */
88 "lookup ", /* 10 */
89 "create ", /* 11 */
90 "remove ", /* 12 */
91 "link ", /* 13 */
92 "rename ", /* 14 */
93 "mkdir ", /* 15 */
94 "rmdir ", /* 16 */
95 "readdir ", /* 17 */
96 "symlink ", /* 18 */
97 "readlink ", /* 19 */
98 "fsync ", /* 20 */
99 "inactive ", /* 21 */
100 "vget ", /* 22 */
101 "signal ", /* 23 */
102 "replace ", /* 24 */
103 "flush ", /* 25 */
104 "purgeuser ", /* 26 */
105 "zapfile ", /* 27 */
106 "zapdir ", /* 28 */
107 "noop2 ", /* 29 */
108 "purgefid ", /* 30 */
109 "open_by_path", /* 31 */
110 "resolve ", /* 32 */
111 "reintegrate ", /* 33 */
112 "statfs ", /* 34 */
113 "make_cinode " /* 35 */
117 void reset_coda_vfs_stats( void )
119 memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
122 void reset_coda_upcall_stats( void )
124 memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
127 void reset_coda_permission_stats( void )
129 memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
132 void reset_coda_cache_inv_stats( void )
134 memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
138 void do_time_stats( struct coda_upcall_stats_entry * pentry,
139 unsigned long runtime )
141 unsigned long time = runtime; /* time in us */
142 CDEBUG(D_SPECIAL, "time: %ld\n", time);
144 if ( pentry->count == 0 ) {
145 pentry->time_sum = pentry->time_squared_sum = 0;
148 pentry->count++;
149 pentry->time_sum += time;
150 pentry->time_squared_sum += time*time;
155 void coda_upcall_stats(int opcode, long unsigned runtime)
157 struct coda_upcall_stats_entry * pentry;
159 if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
160 printk("Nasty opcode %d passed to coda_upcall_stats\n",
161 opcode);
162 return;
165 pentry = &coda_upcall_stat[opcode];
166 do_time_stats(pentry, runtime);
168 /* fill in the totals */
169 pentry = &coda_upcall_stat[0];
170 do_time_stats(pentry, runtime);
174 unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
176 return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
179 static inline unsigned long absolute( unsigned long x )
181 return x >= 0 ? x : -x;
184 static unsigned long sqr_root( unsigned long x )
186 unsigned long y = x, r;
187 int n_bit = 0;
189 if ( x == 0 )
190 return 0;
191 if ( x < 0)
192 x = -x;
194 while ( y ) {
195 y >>= 1;
196 n_bit++;
199 r = 1 << (n_bit/2);
201 while ( 1 ) {
202 r = (r + x/r)/2;
203 if ( r*r <= x && x < (r+1)*(r+1) )
204 break;
207 return r;
210 unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
212 unsigned long time_avg;
214 if ( pentry->count <= 1 )
215 return 0;
217 time_avg = get_time_average( pentry );
219 return sqr_root( (pentry->time_squared_sum / pentry->count) -
220 time_avg * time_avg );
223 int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
224 void * buffer, size_t * lenp )
226 if ( write ) {
227 reset_coda_vfs_stats();
229 filp->f_pos += *lenp;
230 } else {
231 *lenp = 0;
234 return 0;
237 int do_reset_coda_upcall_stats( ctl_table * table, int write,
238 struct file * filp, void * buffer,
239 size_t * lenp )
241 if ( write ) {
242 if (*lenp > 0) {
243 char c;
244 if (get_user(c, (char *)buffer))
245 return -EFAULT;
246 coda_upcall_timestamping = (c == '1');
248 reset_coda_upcall_stats();
250 filp->f_pos += *lenp;
251 } else {
252 *lenp = 0;
255 return 0;
258 int do_reset_coda_permission_stats( ctl_table * table, int write,
259 struct file * filp, void * buffer,
260 size_t * lenp )
262 if ( write ) {
263 reset_coda_permission_stats();
265 filp->f_pos += *lenp;
266 } else {
267 *lenp = 0;
270 return 0;
273 int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
274 struct file * filp, void * buffer,
275 size_t * lenp )
277 if ( write ) {
278 reset_coda_cache_inv_stats();
280 filp->f_pos += *lenp;
281 } else {
282 *lenp = 0;
285 return 0;
288 int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
289 int length)
291 int len=0;
292 off_t begin;
293 struct coda_vfs_stats * ps = & coda_vfs_stat;
295 /* this works as long as we are below 1024 characters! */
296 len += sprintf( buffer,
297 "Coda VFS statistics\n"
298 "===================\n\n"
299 "File Operations:\n"
300 "\topen\t\t%9d\n"
301 "\trelase\t\t%9d\n"
302 "\tfsync\t\t%9d\n\n"
303 "Dir Operations:\n"
304 "\treaddir\t\t%9d\n\n"
305 "Inode Operations\n"
306 "\tcreate\t\t%9d\n"
307 "\tlookup\t\t%9d\n"
308 "\tlink\t\t%9d\n"
309 "\tunlink\t\t%9d\n"
310 "\tsymlink\t\t%9d\n"
311 "\tmkdir\t\t%9d\n"
312 "\trmdir\t\t%9d\n"
313 "\trename\t\t%9d\n"
314 "\tpermission\t%9d\n",
316 /* file operations */
317 ps->open,
318 ps->release,
319 ps->fsync,
321 /* dir operations */
322 ps->readdir,
324 /* inode operations */
325 ps->create,
326 ps->lookup,
327 ps->link,
328 ps->unlink,
329 ps->symlink,
330 ps->mkdir,
331 ps->rmdir,
332 ps->rename,
333 ps->permission);
335 begin = offset;
336 *start = buffer + begin;
337 len -= begin;
339 if ( len > length )
340 len = length;
341 if ( len < 0 )
342 len = 0;
344 return len;
347 int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
348 int length)
350 int len=0;
351 int i;
352 off_t begin;
353 off_t pos = 0;
354 char tmpbuf[80];
355 int tmplen = 0;
357 ENTRY;
358 /* this works as long as we are below 1024 characters! */
359 if ( offset < 80 )
360 len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
361 if ( offset < 160)
362 len += sprintf( buffer + len,"%-79s\n", "======================");
363 if ( offset < 240)
364 len += sprintf( buffer + len,"%-79s\n", "upcall count avg time(us) std deviation(us)");
365 if ( offset < 320)
366 len += sprintf( buffer + len,"%-79s\n", "------ ----- ------------ -----------------");
367 pos = 320;
368 for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
369 tmplen += sprintf(tmpbuf,"%s %9d %10ld %10ld",
370 coda_upcall_names[i],
371 coda_upcall_stat[i].count,
372 get_time_average(&coda_upcall_stat[i]),
373 coda_upcall_stat[i].time_squared_sum);
374 pos += 80;
375 if ( pos < offset )
376 continue;
377 len += sprintf(buffer + len, "%-79s\n", tmpbuf);
378 if ( len >= length )
379 break;
382 begin = len- (pos - offset);
383 *start = buffer + begin;
384 len -= begin;
386 if ( len > length )
387 len = length;
388 if ( len < 0 )
389 len = 0;
390 EXIT;
391 return len;
394 int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
395 int length)
397 int len=0;
398 off_t begin;
399 struct coda_permission_stats * ps = & coda_permission_stat;
401 /* this works as long as we are below 1024 characters! */
402 len += sprintf( buffer,
403 "Coda permission statistics\n"
404 "==========================\n\n"
405 "count\t\t%9d\n"
406 "hit count\t%9d\n",
408 ps->count,
409 ps->hit_count );
411 begin = offset;
412 *start = buffer + begin;
413 len -= begin;
415 if ( len > length )
416 len = length;
417 if ( len < 0 )
418 len = 0;
420 return len;
423 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
424 int length)
426 int len=0;
427 off_t begin;
428 struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
430 /* this works as long as we are below 1024 characters! */
431 len += sprintf( buffer,
432 "Coda cache invalidation statistics\n"
433 "==================================\n\n"
434 "flush\t\t%9d\n"
435 "purge user\t%9d\n"
436 "zap_dir\t\t%9d\n"
437 "zap_file\t%9d\n"
438 "zap_vnode\t%9d\n"
439 "purge_fid\t%9d\n"
440 "replace\t\t%9d\n",
441 ps->flush,
442 ps->purge_user,
443 ps->zap_dir,
444 ps->zap_file,
445 ps->zap_vnode,
446 ps->purge_fid,
447 ps->replace );
449 begin = offset;
450 *start = buffer + begin;
451 len -= begin;
453 if ( len > length )
454 len = length;
455 if ( len < 0 )
456 len = 0;
458 return len;
462 #ifdef CONFIG_PROC_FS
465 target directory structure:
466 /proc/fs (see linux/fs/proc/root.c)
467 /proc/fs/coda
468 /proc/fs/coda/{vfs_stats,
472 struct proc_dir_entry* proc_fs_coda;
474 #endif
476 #define coda_proc_create(name,get_info) \
477 create_proc_info_entry(name, 0, proc_fs_coda, get_info)
479 void coda_sysctl_init()
481 memset(&coda_callstats, 0, sizeof(coda_callstats));
482 reset_coda_vfs_stats();
483 reset_coda_upcall_stats();
484 reset_coda_permission_stats();
485 reset_coda_cache_inv_stats();
487 #ifdef CONFIG_PROC_FS
488 proc_fs_coda = proc_mkdir("coda", proc_root_fs);
489 proc_fs_coda->owner = THIS_MODULE;
490 coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
491 coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
492 coda_proc_create("permission_stats", coda_permission_stats_get_info);
493 coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
494 #endif
496 #ifdef CONFIG_SYSCTL
497 if ( !fs_table_header )
498 fs_table_header = register_sysctl_table(fs_table, 0);
499 #endif
502 void coda_sysctl_clean()
505 #ifdef CONFIG_SYSCTL
506 if ( fs_table_header ) {
507 unregister_sysctl_table(fs_table_header);
508 fs_table_header = 0;
510 #endif
512 #if CONFIG_PROC_FS
513 remove_proc_entry("cache_inv_stats", proc_fs_coda);
514 remove_proc_entry("permission_stats", proc_fs_coda);
515 remove_proc_entry("upcall_stats", proc_fs_coda);
516 remove_proc_entry("vfs_stats", proc_fs_coda);
517 remove_proc_entry("coda", proc_root_fs);
518 #endif