sysctl.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
- /*
- * Sysctl operations for Coda filesystem
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users to contribute improvements to
- * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
- *
- * CODA operation statistics
- * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
- *
- */
- #include <linux/config.h>
- #include <linux/sched.h>
- #include <linux/mm.h>
- #include <linux/sysctl.h>
- #include <linux/swapctl.h>
- #include <linux/proc_fs.h>
- #include <linux/slab.h>
- #include <linux/stat.h>
- #include <linux/ctype.h>
- #include <asm/bitops.h>
- #include <asm/segment.h>
- #include <asm/uaccess.h>
- #include <linux/utsname.h>
- #define __NO_VERSION__
- #include <linux/module.h>
- #include <linux/coda.h>
- #include <linux/coda_linux.h>
- #include <linux/coda_fs_i.h>
- #include <linux/coda_psdev.h>
- #include <linux/coda_cache.h>
- #include <linux/coda_proc.h>
- static struct ctl_table_header *fs_table_header;
- #define FS_CODA 1 /* Coda file system */
- #define CODA_DEBUG 1 /* control debugging */
- #define CODA_ENTRY 2 /* control enter/leave pattern */
- #define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
- #define CODA_MC 4 /* use/do not use the access cache */
- #define CODA_HARD 5 /* mount type "hard" or "soft" */
- #define CODA_VFS 6 /* vfs statistics */
- #define CODA_UPCALL 7 /* upcall statistics */
- #define CODA_PERMISSION 8 /* permission statistics */
- #define CODA_CACHE_INV 9 /* cache invalidation statistics */
- #define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */
- static ctl_table coda_table[] = {
- {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &proc_dointvec},
- {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
- {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &proc_dointvec},
- {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
- {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
- {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
- {CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
- {CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
- {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
- {CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
- { 0 }
- };
- static ctl_table fs_table[] = {
- {FS_CODA, "coda", NULL, 0, 0555, coda_table},
- {0}
- };
- struct coda_vfs_stats coda_vfs_stat;
- struct coda_permission_stats coda_permission_stat;
- struct coda_cache_inv_stats coda_cache_inv_stat;
- struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS];
- struct coda_upcallstats coda_callstats;
- int coda_upcall_timestamping = 0;
- /* keep this in sync with coda.h! */
- char *coda_upcall_names[] = {
- "totals ", /* 0 */
- "- ", /* 1 */
- "root ", /* 2 */
- "open_by_fd ", /* 3 */
- "open ", /* 4 */
- "close ", /* 5 */
- "ioctl ", /* 6 */
- "getattr ", /* 7 */
- "setattr ", /* 8 */
- "access ", /* 9 */
- "lookup ", /* 10 */
- "create ", /* 11 */
- "remove ", /* 12 */
- "link ", /* 13 */
- "rename ", /* 14 */
- "mkdir ", /* 15 */
- "rmdir ", /* 16 */
- "readdir ", /* 17 */
- "symlink ", /* 18 */
- "readlink ", /* 19 */
- "fsync ", /* 20 */
- "- ", /* 21 */
- "vget ", /* 22 */
- "signal ", /* 23 */
- "replace ", /* 24 */
- "flush ", /* 25 */
- "purgeuser ", /* 26 */
- "zapfile ", /* 27 */
- "zapdir ", /* 28 */
- "- ", /* 29 */
- "purgefid ", /* 30 */
- "open_by_path", /* 31 */
- "resolve ", /* 32 */
- "reintegrate ", /* 33 */
- "statfs ", /* 34 */
- "store ", /* 35 */
- "release " /* 36 */
- };
- void reset_coda_vfs_stats( void )
- {
- memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
- }
- void reset_coda_upcall_stats( void )
- {
- memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
- }
- void reset_coda_permission_stats( void )
- {
- memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
- }
- void reset_coda_cache_inv_stats( void )
- {
- memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
- }
- void do_time_stats( struct coda_upcall_stats_entry * pentry,
- unsigned long runtime )
- {
- unsigned long time = runtime; /* time in us */
- CDEBUG(D_SPECIAL, "time: %ldn", time);
- if ( pentry->count == 0 ) {
- pentry->time_sum = pentry->time_squared_sum = 0;
- }
-
- pentry->count++;
- pentry->time_sum += time;
- pentry->time_squared_sum += time*time;
- }
- void coda_upcall_stats(int opcode, long unsigned runtime)
- {
- struct coda_upcall_stats_entry * pentry;
-
- if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
- printk("Nasty opcode %d passed to coda_upcall_statsn",
- opcode);
- return;
- }
-
- pentry = &coda_upcall_stat[opcode];
- do_time_stats(pentry, runtime);
- /* fill in the totals */
- pentry = &coda_upcall_stat[0];
- do_time_stats(pentry, runtime);
- }
- unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
- {
- return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
- }
- static inline unsigned long absolute( unsigned long x )
- {
- return x >= 0 ? x : -x;
- }
- static unsigned long sqr_root( unsigned long x )
- {
- unsigned long y = x, r;
- int n_bit = 0;
-
- if ( x == 0 )
- return 0;
- if ( x < 0)
- x = -x;
- while ( y ) {
- y >>= 1;
- n_bit++;
- }
-
- r = 1 << (n_bit/2);
-
- while ( 1 ) {
- r = (r + x/r)/2;
- if ( r*r <= x && x < (r+1)*(r+1) )
- break;
- }
-
- return r;
- }
- unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
- {
- unsigned long time_avg;
-
- if ( pentry->count <= 1 )
- return 0;
-
- time_avg = get_time_average( pentry );
- return sqr_root( (pentry->time_squared_sum / pentry->count) -
- time_avg * time_avg );
- }
- int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
- void * buffer, size_t * lenp )
- {
- if ( write ) {
- reset_coda_vfs_stats();
- filp->f_pos += *lenp;
- } else {
- *lenp = 0;
- }
- return 0;
- }
- int do_reset_coda_upcall_stats( ctl_table * table, int write,
- struct file * filp, void * buffer,
- size_t * lenp )
- {
- if ( write ) {
- if (*lenp > 0) {
- char c;
- if (get_user(c, (char *)buffer))
- return -EFAULT;
- coda_upcall_timestamping = (c == '1');
- }
- reset_coda_upcall_stats();
- filp->f_pos += *lenp;
- } else {
- *lenp = 0;
- }
- return 0;
- }
- int do_reset_coda_permission_stats( ctl_table * table, int write,
- struct file * filp, void * buffer,
- size_t * lenp )
- {
- if ( write ) {
- reset_coda_permission_stats();
- filp->f_pos += *lenp;
- } else {
- *lenp = 0;
- }
- return 0;
- }
- int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
- struct file * filp, void * buffer,
- size_t * lenp )
- {
- if ( write ) {
- reset_coda_cache_inv_stats();
- filp->f_pos += *lenp;
- } else {
- *lenp = 0;
- }
-
- return 0;
- }
- int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
- int length)
- {
- int len=0;
- off_t begin;
- struct coda_vfs_stats * ps = & coda_vfs_stat;
-
- /* this works as long as we are below 1024 characters! */
- len += sprintf( buffer,
- "Coda VFS statisticsn"
- "===================nn"
- "File Operations:n"
- "topentt%9dn"
- "tflushtt%9dn"
- "treleasett%9dn"
- "tfsynctt%9dnn"
- "Dir Operations:n"
- "treaddirtt%9dnn"
- "Inode Operationsn"
- "tcreatett%9dn"
- "tlookuptt%9dn"
- "tlinktt%9dn"
- "tunlinktt%9dn"
- "tsymlinktt%9dn"
- "tmkdirtt%9dn"
- "trmdirtt%9dn"
- "trenamett%9dn"
- "tpermissiont%9dn",
- /* file operations */
- ps->open,
- ps->flush,
- ps->release,
- ps->fsync,
- /* dir operations */
- ps->readdir,
-
- /* inode operations */
- ps->create,
- ps->lookup,
- ps->link,
- ps->unlink,
- ps->symlink,
- ps->mkdir,
- ps->rmdir,
- ps->rename,
- ps->permission);
- begin = offset;
- *start = buffer + begin;
- len -= begin;
- if ( len > length )
- len = length;
- if ( len < 0 )
- len = 0;
- return len;
- }
- int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
- int length)
- {
- int len=0;
- int i;
- off_t begin;
- off_t pos = 0;
- char tmpbuf[80];
- int tmplen = 0;
- /* this works as long as we are below 1024 characters! */
- if ( offset < 80 )
- len += sprintf( buffer,"%-79sn", "Coda upcall statistics");
- if ( offset < 160)
- len += sprintf( buffer + len,"%-79sn", "======================");
- if ( offset < 240)
- len += sprintf( buffer + len,"%-79sn", "upcall count avg time(us) std deviation(us)");
- if ( offset < 320)
- len += sprintf( buffer + len,"%-79sn", "------ ----- ------------ -----------------");
- pos = 320;
- for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
- tmplen += sprintf(tmpbuf,"%s %9d %10ld %10ld",
- coda_upcall_names[i],
- coda_upcall_stat[i].count,
- get_time_average(&coda_upcall_stat[i]),
- coda_upcall_stat[i].time_squared_sum);
- pos += 80;
- if ( pos < offset )
- continue;
- len += sprintf(buffer + len, "%-79sn", tmpbuf);
- if ( len >= length )
- break;
- }
-
- begin = len- (pos - offset);
- *start = buffer + begin;
- len -= begin;
- if ( len > length )
- len = length;
- if ( len < 0 )
- len = 0;
- return len;
- }
- int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
- int length)
- {
- int len=0;
- off_t begin;
- struct coda_permission_stats * ps = & coda_permission_stat;
-
- /* this works as long as we are below 1024 characters! */
- len += sprintf( buffer,
- "Coda permission statisticsn"
- "==========================nn"
- "counttt%9dn"
- "hit countt%9dn",
- ps->count,
- ps->hit_count );
-
- begin = offset;
- *start = buffer + begin;
- len -= begin;
- if ( len > length )
- len = length;
- if ( len < 0 )
- len = 0;
- return len;
- }
- int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
- int length)
- {
- int len=0;
- off_t begin;
- struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
-
- /* this works as long as we are below 1024 characters! */
- len += sprintf( buffer,
- "Coda cache invalidation statisticsn"
- "==================================nn"
- "flushtt%9dn"
- "purge usert%9dn"
- "zap_dirtt%9dn"
- "zap_filet%9dn"
- "zap_vnodet%9dn"
- "purge_fidt%9dn"
- "replacett%9dn",
- ps->flush,
- ps->purge_user,
- ps->zap_dir,
- ps->zap_file,
- ps->zap_vnode,
- ps->purge_fid,
- ps->replace );
-
- begin = offset;
- *start = buffer + begin;
- len -= begin;
- if ( len > length )
- len = length;
- if ( len < 0 )
- len = 0;
- return len;
- }
- #ifdef CONFIG_PROC_FS
- /*
- target directory structure:
- /proc/fs (see linux/fs/proc/root.c)
- /proc/fs/coda
- /proc/fs/coda/{vfs_stats,
- */
- struct proc_dir_entry* proc_fs_coda;
- #endif
- #define coda_proc_create(name,get_info)
- create_proc_info_entry(name, 0, proc_fs_coda, get_info)
- void coda_sysctl_init()
- {
- memset(&coda_callstats, 0, sizeof(coda_callstats));
- reset_coda_vfs_stats();
- reset_coda_upcall_stats();
- reset_coda_permission_stats();
- reset_coda_cache_inv_stats();
- #ifdef CONFIG_PROC_FS
- proc_fs_coda = proc_mkdir("coda", proc_root_fs);
- if (proc_fs_coda) {
- proc_fs_coda->owner = THIS_MODULE;
- coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
- coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
- coda_proc_create("permission_stats", coda_permission_stats_get_info);
- coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
- }
- #endif
- #ifdef CONFIG_SYSCTL
- if ( !fs_table_header )
- fs_table_header = register_sysctl_table(fs_table, 0);
- #endif
- }
- void coda_sysctl_clean()
- {
- #ifdef CONFIG_SYSCTL
- if ( fs_table_header ) {
- unregister_sysctl_table(fs_table_header);
- fs_table_header = 0;
- }
- #endif
- #if CONFIG_PROC_FS
- remove_proc_entry("cache_inv_stats", proc_fs_coda);
- remove_proc_entry("permission_stats", proc_fs_coda);
- remove_proc_entry("upcall_stats", proc_fs_coda);
- remove_proc_entry("vfs_stats", proc_fs_coda);
- remove_proc_entry("coda", proc_root_fs);
- #endif
- }