patch-2.1.132 linux/fs/coda/sysctl.c
Next file: linux/fs/coda/upcall.c
Previous file: linux/fs/coda/symlink.c
Back to the patch index
Back to the overall index
- Lines: 633
- Date:
Fri Dec 18 14:09:31 1998
- Orig file:
v2.1.131/linux/fs/coda/sysctl.c
- Orig date:
Thu May 7 22:51:53 1998
diff -u --recursive --new-file v2.1.131/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c
@@ -5,9 +5,13 @@
*
* 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>
+ *
*/
-/* sysctl entries for Coda! */
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
@@ -27,19 +31,9 @@
#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
-extern int coda_debug;
-/* extern int cfsnc_use; */
-extern int coda_print_entry;
-/* extern int cfsnc_flushme; */
-extern int cfsnc_procsize;
-/* extern void cfsnc_flush(void); */
-void coda_sysctl_init(void);
-void coda_sysctl_clean(void);
-int coda_dointvec(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp);
+static struct ctl_table_header *fs_table_header;
-struct ctl_table_header *fs_table_header, *coda_table_header;
#define FS_CODA 1 /* Coda file system */
#define CODA_DEBUG 1 /* control debugging */
@@ -52,14 +46,12 @@
#define CODA_PERMISSION 8 /* permission statistics */
#define CODA_CACHE_INV 9 /* cache invalidation statistics */
-
-
static ctl_table coda_table[] = {
- {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
+ {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},
@@ -67,114 +59,478 @@
{ 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;
+
+/* keep this in sync with coda.h! */
+char *coda_upcall_names[] = {
+ "totals ", /* 0 */
+ "noop ", /* 1 */
+ "root ", /* 2 */
+ "sync ", /* 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 */
+ "inactive ", /* 21 */
+ "vget ", /* 22 */
+ "signal ", /* 23 */
+ "replace ", /* 24 */
+ "flush ", /* 25 */
+ "purgeuser ", /* 26 */
+ "zapfile ", /* 27 */
+ "zapdir ", /* 28 */
+ "zapvnode ", /* 28 */
+ "purgefid ", /* 30 */
+ "open_by_path" /* 31 */
+};
-void coda_sysctl_init()
+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 * 1000 /HZ; /* time in ms */
+ CDEBUG(D_SPECIAL, "time: %ld\n", 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_stats\n",
+ 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();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int do_reset_coda_upcall_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp )
{
- fs_table_header = register_sysctl_table(fs_table, 0);
-/* coda_table_header = register_sysctl_table(coda_table, 0);*/
+ if ( write ) {
+ reset_coda_upcall_stats();
+ }
+
+ *lenp = 0;
+ return 0;
}
-void coda_sysctl_clean() {
- /*unregister_sysctl_table(coda_table_header);*/
- unregister_sysctl_table(fs_table_header);
-}
-
-int coda_dointvec(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp)
-{
- int *i, vleft, first=1, len, left, neg, val;
- #define TMPBUFLEN 20
- char buf[TMPBUFLEN], *p;
-
- if (!table->data || !table->maxlen || !*lenp ||
- (filp->f_pos && !write)) {
- *lenp = 0;
- return 0;
- }
-
- i = (int *) table->data;
- vleft = table->maxlen / sizeof(int);
- left = *lenp;
-
- for (; left && vleft--; i++, first=0) {
- if (write) {
- while (left) {
- char c;
- if(get_user(c,(char *) buffer))
- return -EFAULT;
- if (!isspace(c))
- break;
- left--;
- ((char *) buffer)++;
- }
- if (!left)
- break;
- neg = 0;
- len = left;
- if (len > TMPBUFLEN-1)
- len = TMPBUFLEN-1;
- if (copy_from_user(buf, buffer, len))
- return -EFAULT;
- buf[len] = 0;
- p = buf;
- if (*p == '-' && left > 1) {
- neg = 1;
- left--, p++;
- }
- if (*p < '0' || *p > '9')
- break;
- val = simple_strtoul(p, &p, 0);
- len = p-buf;
- if ((len < left) && *p && !isspace(*p))
- break;
- if (neg)
- val = -val;
- buffer += len;
- left -= len;
- *i = val;
- } else {
- p = buf;
- if (!first)
- *p++ = '\t';
- sprintf(p, "%d", *i);
- len = strlen(buf);
- if (len > left)
- len = left;
- if (copy_to_user(buffer, buf, len))
- return -EFAULT;
- left -= len;
- buffer += len;
- }
- }
-
- if (!write && !first && left) {
- if(put_user('\n', (char *) buffer))
- return -EFAULT;
- left--, buffer++;
- }
- if (write) {
- p = (char *) buffer;
- while (left) {
- char c;
- if(get_user(c, p++))
- return -EFAULT;
- if (!isspace(c))
- break;
- left--;
- }
- }
- if (write && first)
- return -EINVAL;
- *lenp -= left;
- filp->f_pos += *lenp;
- 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();
+ }
+
+ *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();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ 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 statistics\n"
+ "===================\n\n"
+ "File Operations:\n"
+ "\tfile_read\t%9d\n"
+ "\tfile_write\t%9d\n"
+ "\tfile_mmap\t%9d\n"
+ "\topen\t\t%9d\n"
+ "\trelase\t\t%9d\n"
+ "\tfsync\t\t%9d\n\n"
+ "Dir Operations:\n"
+ "\treaddir\t\t%9d\n\n"
+ "Inode Operations\n"
+ "\tcreate\t\t%9d\n"
+ "\tlookup\t\t%9d\n"
+ "\tlink\t\t%9d\n"
+ "\tunlink\t\t%9d\n"
+ "\tsymlink\t\t%9d\n"
+ "\tmkdir\t\t%9d\n"
+ "\trmdir\t\t%9d\n"
+ "\trename\t\t%9d\n"
+ "\tpermission\t%9d\n"
+ "\treadpage\t%9d\n",
+
+ /* file operations */
+ ps->file_read,
+ ps->file_write,
+ ps->file_mmap,
+ ps->open,
+ 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,
+ ps->readpage );
+
+ 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 dummy )
+{
+ int len=0;
+ int i;
+ off_t begin;
+ off_t pos = 0;
+ char tmpbuf[80];
+ int tmplen = 0;
+
+ ENTRY;
+ /* this works as long as we are below 1024 characters! */
+ if ( offset < 80 )
+ len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
+ if ( offset < 160)
+ len += sprintf( buffer + len,"%-79s\n", "======================");
+ if ( offset < 240)
+ len += sprintf( buffer + len,"%-79s\n", "upcall\t\t count\tavg time(ms)\tstd deviation(ms)");
+ if ( offset < 320)
+ len += sprintf( buffer + len,"%-79s\n", "------\t\t -----\t------------\t-----------------");
+ pos = 320;
+ for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
+ tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%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, "%-79s\n", tmpbuf);
+ if ( len >= length )
+ break;
+ }
+
+ begin = len- (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+
+ if ( len > length )
+ len = length;
+ if ( len < 0 )
+ len = 0;
+ EXIT;
+ return len;
+}
+
+int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ 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 statistics\n"
+ "==========================\n\n"
+ "count\t\t%9d\n"
+ "hit count\t%9d\n",
+
+ 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 dummy )
+{
+ 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 statistics\n"
+ "==================================\n\n"
+ "flush\t\t%9d\n"
+ "purge user\t%9d\n"
+ "zap_dir\t\t%9d\n"
+ "zap_file\t%9d\n"
+ "zap_vnode\t%9d\n"
+ "purge_fid\t%9d\n"
+ "replace\t\t%9d\n",
+ 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 = {
+ PROC_FS_CODA, 4, "coda",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
+};
+
+struct proc_dir_entry proc_coda_vfs = {
+ PROC_VFS_STATS , 9, "vfs_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_vfs_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_upcall = {
+ PROC_UPCALL_STATS , 12, "upcall_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_upcall_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_permission = {
+ PROC_PERMISSION_STATS , 16, "permission_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_permission_stats_get_info
+ };
+
+
+struct proc_dir_entry proc_coda_cache_inv = {
+ PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_cache_inv_stats_get_info
+ };
+
+#endif
+
+
+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_register(&proc_root_fs,&proc_fs_coda);
+ proc_register(&proc_fs_coda,&proc_coda_vfs);
+ proc_register(&proc_fs_coda,&proc_coda_upcall);
+ proc_register(&proc_fs_coda,&proc_coda_permission);
+ proc_register(&proc_fs_coda,&proc_coda_cache_inv);
+#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
+ proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
+ proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
+#endif
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov