Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / coda / sysctl.c
blob4215c3b41506c92d38e696d97e168390babdb2cf
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 "- ", /* 1 */
80 "root ", /* 2 */
81 "open_by_fd ", /* 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 "- ", /* 21 */
100 "vget ", /* 22 */
101 "signal ", /* 23 */
102 "replace ", /* 24 */
103 "flush ", /* 25 */
104 "purgeuser ", /* 26 */
105 "zapfile ", /* 27 */
106 "zapdir ", /* 28 */
107 "- ", /* 29 */
108 "purgefid ", /* 30 */
109 "open_by_path", /* 31 */
110 "resolve ", /* 32 */
111 "reintegrate ", /* 33 */
112 "statfs " /* 34 */
116 void reset_coda_vfs_stats( void )
118 memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
121 void reset_coda_upcall_stats( void )
123 memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
126 void reset_coda_permission_stats( void )
128 memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
131 void reset_coda_cache_inv_stats( void )
133 memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
137 void do_time_stats( struct coda_upcall_stats_entry * pentry,
138 unsigned long runtime )
140 unsigned long time = runtime; /* time in us */
141 CDEBUG(D_SPECIAL, "time: %ld\n", time);
143 if ( pentry->count == 0 ) {
144 pentry->time_sum = pentry->time_squared_sum = 0;
147 pentry->count++;
148 pentry->time_sum += time;
149 pentry->time_squared_sum += time*time;
154 void coda_upcall_stats(int opcode, long unsigned runtime)
156 struct coda_upcall_stats_entry * pentry;
158 if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
159 printk("Nasty opcode %d passed to coda_upcall_stats\n",
160 opcode);
161 return;
164 pentry = &coda_upcall_stat[opcode];
165 do_time_stats(pentry, runtime);
167 /* fill in the totals */
168 pentry = &coda_upcall_stat[0];
169 do_time_stats(pentry, runtime);
173 unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
175 return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
178 static inline unsigned long absolute( unsigned long x )
180 return x >= 0 ? x : -x;
183 static unsigned long sqr_root( unsigned long x )
185 unsigned long y = x, r;
186 int n_bit = 0;
188 if ( x == 0 )
189 return 0;
190 if ( x < 0)
191 x = -x;
193 while ( y ) {
194 y >>= 1;
195 n_bit++;
198 r = 1 << (n_bit/2);
200 while ( 1 ) {
201 r = (r + x/r)/2;
202 if ( r*r <= x && x < (r+1)*(r+1) )
203 break;
206 return r;
209 unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
211 unsigned long time_avg;
213 if ( pentry->count <= 1 )
214 return 0;
216 time_avg = get_time_average( pentry );
218 return sqr_root( (pentry->time_squared_sum / pentry->count) -
219 time_avg * time_avg );
222 int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
223 void * buffer, size_t * lenp )
225 if ( write ) {
226 reset_coda_vfs_stats();
228 filp->f_pos += *lenp;
229 } else {
230 *lenp = 0;
233 return 0;
236 int do_reset_coda_upcall_stats( ctl_table * table, int write,
237 struct file * filp, void * buffer,
238 size_t * lenp )
240 if ( write ) {
241 if (*lenp > 0) {
242 char c;
243 if (get_user(c, (char *)buffer))
244 return -EFAULT;
245 coda_upcall_timestamping = (c == '1');
247 reset_coda_upcall_stats();
249 filp->f_pos += *lenp;
250 } else {
251 *lenp = 0;
254 return 0;
257 int do_reset_coda_permission_stats( ctl_table * table, int write,
258 struct file * filp, void * buffer,
259 size_t * lenp )
261 if ( write ) {
262 reset_coda_permission_stats();
264 filp->f_pos += *lenp;
265 } else {
266 *lenp = 0;
269 return 0;
272 int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
273 struct file * filp, void * buffer,
274 size_t * lenp )
276 if ( write ) {
277 reset_coda_cache_inv_stats();
279 filp->f_pos += *lenp;
280 } else {
281 *lenp = 0;
284 return 0;
287 int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
288 int length)
290 int len=0;
291 off_t begin;
292 struct coda_vfs_stats * ps = & coda_vfs_stat;
294 /* this works as long as we are below 1024 characters! */
295 len += sprintf( buffer,
296 "Coda VFS statistics\n"
297 "===================\n\n"
298 "File Operations:\n"
299 "\topen\t\t%9d\n"
300 "\trelase\t\t%9d\n"
301 "\tfsync\t\t%9d\n\n"
302 "Dir Operations:\n"
303 "\treaddir\t\t%9d\n\n"
304 "Inode Operations\n"
305 "\tcreate\t\t%9d\n"
306 "\tlookup\t\t%9d\n"
307 "\tlink\t\t%9d\n"
308 "\tunlink\t\t%9d\n"
309 "\tsymlink\t\t%9d\n"
310 "\tmkdir\t\t%9d\n"
311 "\trmdir\t\t%9d\n"
312 "\trename\t\t%9d\n"
313 "\tpermission\t%9d\n",
315 /* file operations */
316 ps->open,
317 ps->release,
318 ps->fsync,
320 /* dir operations */
321 ps->readdir,
323 /* inode operations */
324 ps->create,
325 ps->lookup,
326 ps->link,
327 ps->unlink,
328 ps->symlink,
329 ps->mkdir,
330 ps->rmdir,
331 ps->rename,
332 ps->permission);
334 begin = offset;
335 *start = buffer + begin;
336 len -= begin;
338 if ( len > length )
339 len = length;
340 if ( len < 0 )
341 len = 0;
343 return len;
346 int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
347 int length)
349 int len=0;
350 int i;
351 off_t begin;
352 off_t pos = 0;
353 char tmpbuf[80];
354 int tmplen = 0;
356 ENTRY;
357 /* this works as long as we are below 1024 characters! */
358 if ( offset < 80 )
359 len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
360 if ( offset < 160)
361 len += sprintf( buffer + len,"%-79s\n", "======================");
362 if ( offset < 240)
363 len += sprintf( buffer + len,"%-79s\n", "upcall count avg time(us) std deviation(us)");
364 if ( offset < 320)
365 len += sprintf( buffer + len,"%-79s\n", "------ ----- ------------ -----------------");
366 pos = 320;
367 for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
368 tmplen += sprintf(tmpbuf,"%s %9d %10ld %10ld",
369 coda_upcall_names[i],
370 coda_upcall_stat[i].count,
371 get_time_average(&coda_upcall_stat[i]),
372 coda_upcall_stat[i].time_squared_sum);
373 pos += 80;
374 if ( pos < offset )
375 continue;
376 len += sprintf(buffer + len, "%-79s\n", tmpbuf);
377 if ( len >= length )
378 break;
381 begin = len- (pos - offset);
382 *start = buffer + begin;
383 len -= begin;
385 if ( len > length )
386 len = length;
387 if ( len < 0 )
388 len = 0;
389 EXIT;
390 return len;
393 int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
394 int length)
396 int len=0;
397 off_t begin;
398 struct coda_permission_stats * ps = & coda_permission_stat;
400 /* this works as long as we are below 1024 characters! */
401 len += sprintf( buffer,
402 "Coda permission statistics\n"
403 "==========================\n\n"
404 "count\t\t%9d\n"
405 "hit count\t%9d\n",
407 ps->count,
408 ps->hit_count );
410 begin = offset;
411 *start = buffer + begin;
412 len -= begin;
414 if ( len > length )
415 len = length;
416 if ( len < 0 )
417 len = 0;
419 return len;
422 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
423 int length)
425 int len=0;
426 off_t begin;
427 struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
429 /* this works as long as we are below 1024 characters! */
430 len += sprintf( buffer,
431 "Coda cache invalidation statistics\n"
432 "==================================\n\n"
433 "flush\t\t%9d\n"
434 "purge user\t%9d\n"
435 "zap_dir\t\t%9d\n"
436 "zap_file\t%9d\n"
437 "zap_vnode\t%9d\n"
438 "purge_fid\t%9d\n"
439 "replace\t\t%9d\n",
440 ps->flush,
441 ps->purge_user,
442 ps->zap_dir,
443 ps->zap_file,
444 ps->zap_vnode,
445 ps->purge_fid,
446 ps->replace );
448 begin = offset;
449 *start = buffer + begin;
450 len -= begin;
452 if ( len > length )
453 len = length;
454 if ( len < 0 )
455 len = 0;
457 return len;
461 #ifdef CONFIG_PROC_FS
464 target directory structure:
465 /proc/fs (see linux/fs/proc/root.c)
466 /proc/fs/coda
467 /proc/fs/coda/{vfs_stats,
471 struct proc_dir_entry* proc_fs_coda;
473 #endif
475 #define coda_proc_create(name,get_info) \
476 create_proc_info_entry(name, 0, proc_fs_coda, get_info)
478 void coda_sysctl_init()
480 memset(&coda_callstats, 0, sizeof(coda_callstats));
481 reset_coda_vfs_stats();
482 reset_coda_upcall_stats();
483 reset_coda_permission_stats();
484 reset_coda_cache_inv_stats();
486 #ifdef CONFIG_PROC_FS
487 proc_fs_coda = proc_mkdir("coda", proc_root_fs);
488 proc_fs_coda->owner = THIS_MODULE;
489 coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
490 coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
491 coda_proc_create("permission_stats", coda_permission_stats_get_info);
492 coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
493 #endif
495 #ifdef CONFIG_SYSCTL
496 if ( !fs_table_header )
497 fs_table_header = register_sysctl_table(fs_table, 0);
498 #endif
501 void coda_sysctl_clean()
504 #ifdef CONFIG_SYSCTL
505 if ( fs_table_header ) {
506 unregister_sysctl_table(fs_table_header);
507 fs_table_header = 0;
509 #endif
511 #if CONFIG_PROC_FS
512 remove_proc_entry("cache_inv_stats", proc_fs_coda);
513 remove_proc_entry("permission_stats", proc_fs_coda);
514 remove_proc_entry("upcall_stats", proc_fs_coda);
515 remove_proc_entry("vfs_stats", proc_fs_coda);
516 remove_proc_entry("coda", proc_root_fs);
517 #endif