Import 2.3.25pre1
[davej-history.git] / fs / coda / sysctl.c
blob008088036ab743893c55bcbc67cc633c65c8a4c7
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 */
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 );
217 return
218 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, int dummy )
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 "\tfile_read\t%9d\n"
300 "\tfile_write\t%9d\n"
301 "\tfile_mmap\t%9d\n"
302 "\topen\t\t%9d\n"
303 "\trelase\t\t%9d\n"
304 "\tfsync\t\t%9d\n\n"
305 "Dir Operations:\n"
306 "\treaddir\t\t%9d\n\n"
307 "Inode Operations\n"
308 "\tcreate\t\t%9d\n"
309 "\tlookup\t\t%9d\n"
310 "\tlink\t\t%9d\n"
311 "\tunlink\t\t%9d\n"
312 "\tsymlink\t\t%9d\n"
313 "\tmkdir\t\t%9d\n"
314 "\trmdir\t\t%9d\n"
315 "\trename\t\t%9d\n"
316 "\tpermission\t%9d\n"
317 "\treadpage\t%9d\n",
319 /* file operations */
320 ps->file_read,
321 ps->file_write,
322 ps->file_mmap,
323 ps->open,
324 ps->release,
325 ps->fsync,
327 /* dir operations */
328 ps->readdir,
330 /* inode operations */
331 ps->create,
332 ps->lookup,
333 ps->link,
334 ps->unlink,
335 ps->symlink,
336 ps->mkdir,
337 ps->rmdir,
338 ps->rename,
339 ps->permission,
340 ps->readpage );
342 begin = offset;
343 *start = buffer + begin;
344 len -= begin;
346 if ( len > length )
347 len = length;
348 if ( len < 0 )
349 len = 0;
351 return len;
354 int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
355 int length, int dummy )
357 int len=0;
358 int i;
359 off_t begin;
360 off_t pos = 0;
361 char tmpbuf[80];
362 int tmplen = 0;
364 ENTRY;
365 /* this works as long as we are below 1024 characters! */
366 if ( offset < 80 )
367 len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
368 if ( offset < 160)
369 len += sprintf( buffer + len,"%-79s\n", "======================");
370 if ( offset < 240)
371 len += sprintf( buffer + len,"%-79s\n", "upcall count avg time(us) std deviation(us)");
372 if ( offset < 320)
373 len += sprintf( buffer + len,"%-79s\n", "------ ----- ------------ -----------------");
374 pos = 320;
375 for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
376 tmplen += sprintf(tmpbuf,"%s %9d %10ld %10ld",
377 coda_upcall_names[i],
378 coda_upcall_stat[i].count,
379 get_time_average(&coda_upcall_stat[i]),
380 coda_upcall_stat[i].time_squared_sum);
381 pos += 80;
382 if ( pos < offset )
383 continue;
384 len += sprintf(buffer + len, "%-79s\n", tmpbuf);
385 if ( len >= length )
386 break;
389 begin = len- (pos - offset);
390 *start = buffer + begin;
391 len -= begin;
393 if ( len > length )
394 len = length;
395 if ( len < 0 )
396 len = 0;
397 EXIT;
398 return len;
401 int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
402 int length, int dummy )
404 int len=0;
405 off_t begin;
406 struct coda_permission_stats * ps = & coda_permission_stat;
408 /* this works as long as we are below 1024 characters! */
409 len += sprintf( buffer,
410 "Coda permission statistics\n"
411 "==========================\n\n"
412 "count\t\t%9d\n"
413 "hit count\t%9d\n",
415 ps->count,
416 ps->hit_count );
418 begin = offset;
419 *start = buffer + begin;
420 len -= begin;
422 if ( len > length )
423 len = length;
424 if ( len < 0 )
425 len = 0;
427 return len;
430 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
431 int length, int dummy )
433 int len=0;
434 off_t begin;
435 struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
437 /* this works as long as we are below 1024 characters! */
438 len += sprintf( buffer,
439 "Coda cache invalidation statistics\n"
440 "==================================\n\n"
441 "flush\t\t%9d\n"
442 "purge user\t%9d\n"
443 "zap_dir\t\t%9d\n"
444 "zap_file\t%9d\n"
445 "zap_vnode\t%9d\n"
446 "purge_fid\t%9d\n"
447 "replace\t\t%9d\n",
448 ps->flush,
449 ps->purge_user,
450 ps->zap_dir,
451 ps->zap_file,
452 ps->zap_vnode,
453 ps->purge_fid,
454 ps->replace );
456 begin = offset;
457 *start = buffer + begin;
458 len -= begin;
460 if ( len > length )
461 len = length;
462 if ( len < 0 )
463 len = 0;
465 return len;
469 #ifdef CONFIG_PROC_FS
472 target directory structure:
473 /proc/fs (see linux/fs/proc/root.c)
474 /proc/fs/coda
475 /proc/fs/coda/{vfs_stats,
479 struct proc_dir_entry* proc_fs_coda;
481 static void coda_proc_modcount(struct inode *inode, int fill)
483 if (fill)
484 MOD_INC_USE_COUNT;
485 else
486 MOD_DEC_USE_COUNT;
490 #endif
492 #define coda_proc_create(name,get_info) \
493 create_proc_info_entry(name, 0, proc_fs_coda, get_info)
495 void coda_sysctl_init()
497 memset(&coda_callstats, 0, sizeof(coda_callstats));
498 reset_coda_vfs_stats();
499 reset_coda_upcall_stats();
500 reset_coda_permission_stats();
501 reset_coda_cache_inv_stats();
503 #ifdef CONFIG_PROC_FS
504 proc_fs_coda = create_proc_entry("coda", S_IFDIR, proc_root_fs);
505 proc_fs_coda->fill_inode = &coda_proc_modcount;
506 coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
507 coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
508 coda_proc_create("permission_stats", coda_permission_stats_get_info);
509 coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
510 #endif
512 #ifdef CONFIG_SYSCTL
513 if ( !fs_table_header )
514 fs_table_header = register_sysctl_table(fs_table, 0);
515 #endif
518 void coda_sysctl_clean()
521 #ifdef CONFIG_SYSCTL
522 if ( fs_table_header ) {
523 unregister_sysctl_table(fs_table_header);
524 fs_table_header = 0;
526 #endif
528 #if CONFIG_PROC_FS
529 remove_proc_entry("cache_inv_stats", proc_fs_coda);
530 remove_proc_entry("permission_stats", proc_fs_coda);
531 remove_proc_entry("upcall_stats", proc_fs_coda);
532 remove_proc_entry("vfs_stats", proc_fs_coda);
533 remove_proc_entry("coda", proc_root_fs);
534 #endif