(Illustration by Gaich Muramatsu)
Linus, No more hangs and I really went at it the last few hours. I applied the two changes you emailed to me and Ingo privately and things seem a lot better now (several builds working in parallel etc). I also include a Coda patch largely prepared by a group of students from Yale (Michihiro Kuramochi <kuramochi-michihiro_at_CS.YALE.EDU>, Xia Zhenyu <zhenyu.xia_at_yale.edu>, and Zhanyong Wan <zhanyong.wan_at_yale.edu>) for their OS course and somewhat edited by me. It basically provides /proc/fs/coda with a few files with nice statistics files etc. We did make a directory /proc/fs to hold this stuff, and put our Coda stuff underneath. Other filesystems may want to follow suit. We have had a lot of good use from /proc, particularly /proc/sys to control debugging options, hard and soft mounting _dynamically_. Patch instructions: rm include/linux/coda_sysctl.h patch ... < coda.patch I hope to prepare one more patch that solves two bugs we have seen before 2.2. - Peter - diff -uNr linux-2.1.99/fs/coda/Makefile linux/fs/coda/Makefile --- linux-2.1.99/fs/coda/Makefile Wed Mar 18 00:19:04 1998 +++ linux/fs/coda/Makefile Mon May 4 18:15:45 1998 @@ -4,7 +4,7 @@ O_TARGET := coda.o O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\ - symlink.o pioctl.o sysctl.o + symlink.o pioctl.o sysctl.o stats.o M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line diff -uNr linux-2.1.99/fs/coda/cache.c linux/fs/coda/cache.c --- linux-2.1.99/fs/coda/cache.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/cache.c Mon May 4 18:15:04 1998 @@ -32,9 +32,6 @@ static struct coda_cache * coda_cache_find(struct inode *inode); -/* Keep various stats */ -struct cfsnc_statistics cfsnc_stat; - /* insert a acl-cache entry in sb list */ static void coda_ccinsert(struct coda_cache *el, struct super_block *sb) { @@ -295,41 +292,3 @@ -int -cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - int len=0; - off_t begin; - - /* cfsnc_gather_stats(); */ - - /* this works as long as we are below 1024 characters! */ - len += sprintf(buffer,"Coda minicache statistics\n\n"); - len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits); - len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses); - len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters); - len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters); - len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters); - len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups); - len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove); - len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm); - len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids); - len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids); - len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile); - len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers); - len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes); - len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len); - len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len); - len += sprintf(buffer+len, "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len); - len += sprintf(buffer+len, "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len); - len += sprintf(buffer+len, "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len); - begin = offset; - *start = buffer + begin; - len -= begin; - - if(len>length) - len = length; - if (len< 0) - len = 0; - return len; -} diff -uNr linux-2.1.99/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c --- linux-2.1.99/fs/coda/coda_linux.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/coda_linux.c Mon May 4 18:15:06 1998 @@ -7,6 +7,7 @@ * the Coda project. Contact Peter Braam (coda_at_cs.cmu.edu). */ +#include <linux/version.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> diff -uNr linux-2.1.99/fs/coda/dir.c linux/fs/coda/dir.c --- linux-2.1.99/fs/coda/dir.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/dir.c Mon May 4 18:15:07 1998 @@ -23,6 +23,7 @@ #include <linux/coda_psdev.h> #include <linux/coda_fs_i.h> #include <linux/coda_cache.h> +#include <linux/coda_proc.h> /* dir inode-ops */ static int coda_create(struct inode *dir, struct dentry *new, int mode); @@ -179,6 +180,8 @@ int error; ENTRY; + coda_vfs_stat.permission++; + coda_permission_stat.count++; if ( mask == 0 ) { EXIT; @@ -187,6 +190,7 @@ if ( coda_access_cache == 1 ) { if ( coda_cache_check(inode, mask) ) { + coda_permission_stat.hit_count++; return 0; } } @@ -221,6 +225,8 @@ struct ViceFid newfid; struct coda_vattr attrs; + coda_vfs_stat.create++; + CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode); if (!dir || !S_ISDIR(dir->i_mode)) { @@ -274,6 +280,8 @@ struct ViceFid newfid; + coda_vfs_stat.mkdir++; + if (!dir || !S_ISDIR(dir->i_mode)) { printk("coda_mkdir: inode is NULL or not a directory\n"); return -ENOENT; @@ -329,6 +337,7 @@ int error; ENTRY; + coda_vfs_stat.link++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; @@ -373,6 +382,7 @@ int error=0; ENTRY; + coda_vfs_stat.symlink++; if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; @@ -414,6 +424,7 @@ int len = de->d_name.len; ENTRY; + coda_vfs_stat.unlink++; dircnp = ITOC(dir); CHECK_CNODE(dircnp); @@ -446,6 +457,8 @@ int len = de->d_name.len; int error, rehash = 0; + coda_vfs_stat.rmdir++; + if (!dir || !S_ISDIR(dir->i_mode)) { printk("coda_rmdir: inode is NULL or not a directory\n"); return -ENOENT; @@ -502,6 +515,8 @@ struct coda_inode_info *new_cnp, *old_cnp; int error, rehash = 0, update = 1; ENTRY; + coda_vfs_stat.rename++; + old_cnp = ITOC(old_dir); CHECK_CNODE(old_cnp); new_cnp = ITOC(new_dir); @@ -565,6 +580,7 @@ struct inode *inode=file->f_dentry->d_inode; ENTRY; + coda_vfs_stat.readdir++; if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) { printk("coda_readdir: inode is NULL or not a directory\n"); @@ -606,6 +622,7 @@ unsigned short coda_flags = coda_flags_to_cflags(flags); ENTRY; + coda_vfs_stat.open++; CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n", f->f_dentry->d_inode->i_ino, flags); @@ -659,6 +676,7 @@ unsigned short cflags = coda_flags_to_cflags(flags); ENTRY; + coda_vfs_stat.release++; cnp =ITOC(i); CHECK_CNODE(cnp); diff -uNr linux-2.1.99/fs/coda/file.c linux/fs/coda/file.c --- linux-2.1.99/fs/coda/file.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/file.c Mon May 4 18:15:07 1998 @@ -23,6 +23,7 @@ #include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> #include <linux/coda_cache.h> +#include <linux/coda_proc.h> /* file operations */ static int coda_readpage(struct file *file, struct page * page); @@ -83,6 +84,7 @@ struct coda_inode_info *cii; ENTRY; + coda_vfs_stat.readpage++; cii = ITOC(coda_inode); @@ -108,6 +110,8 @@ struct coda_inode_info *cii; int res; + coda_vfs_stat.file_mmap++; + ENTRY; cii = ITOC(file->f_dentry->d_inode); cii->c_mmcount++; @@ -126,7 +130,9 @@ struct file cont_file; struct dentry cont_dentry; int result = 0; - ENTRY; + + ENTRY; + coda_vfs_stat.file_read++; cnp = ITOC(coda_inode); CHECK_CNODE(cnp); @@ -167,6 +173,7 @@ int result = 0; ENTRY; + coda_vfs_stat.file_write++; cnp = ITOC(coda_inode); CHECK_CNODE(cnp); @@ -205,6 +212,7 @@ struct dentry cont_dentry; int result = 0; ENTRY; + coda_vfs_stat.fsync++; if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || S_ISLNK(coda_inode->i_mode))) diff -uNr linux-2.1.99/fs/coda/psdev.c linux/fs/coda/psdev.c --- linux-2.1.99/fs/coda/psdev.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/psdev.c Mon May 4 18:15:10 1998 @@ -44,7 +44,7 @@ #include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> #include <linux/coda_cache.h> -#include <linux/coda_sysctl.h> +#include <linux/coda_proc.h> /* @@ -401,19 +401,106 @@ #ifdef CONFIG_PROC_FS -struct proc_dir_entry proc_coda = { +struct proc_dir_entry proc_sys_root = { + PROC_SYS, 3, "sys", /* inode, name */ + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */ + 0, &proc_dir_inode_operations, /* size, ops */ + NULL, NULL, /* get_info, fill_inode */ + NULL, /* next */ + NULL, NULL /* parent, subdir */ +}; + +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_sys_coda = { 0, 4, "coda", - S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, 2, 0, 0, - 0, &proc_net_inode_operations, + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_dir_inode_operations, + NULL, NULL, + NULL, + NULL, NULL +}; +struct proc_dir_entry proc_fs = { + PROC_FS, 2, "fs", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_dir_inode_operations, + NULL, NULL, + NULL, + NULL, NULL }; +#if 0 struct proc_dir_entry proc_coda_ncstats = { 0 , 12, "coda-ncstats", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, cfsnc_nc_info }; +#endif + +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_vfs_control = { + 0 , 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_upcall_control = { + 0 , 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_permission_control = { + 0 , 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 + }; + +struct proc_dir_entry proc_coda_cache_inv_control = { + 0 , 15, "cache_inv_stats", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + coda_cache_inv_stats_get_info + }; #endif @@ -429,9 +516,27 @@ memset(coda_super_info, 0, sizeof(coda_super_info)); 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,&proc_coda); - proc_register(&proc_coda, &proc_coda_ncstats); + proc_register(&proc_root,&proc_fs); + proc_register(&proc_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); +#if 0 + proc_register(&proc_fs_coda, &proc_coda_ncstats); +#endif + proc_register(&proc_sys_root,&proc_sys_coda); + proc_register(&proc_sys_coda,&proc_coda_vfs_control); + proc_register(&proc_sys_coda,&proc_coda_upcall_control); + proc_register(&proc_sys_coda,&proc_coda_permission_control); + proc_register(&proc_sys_coda,&proc_coda_cache_inv_control); + coda_sysctl_init(); #endif return 0; @@ -476,8 +581,22 @@ #if CONFIG_PROC_FS coda_sysctl_clean(); - proc_unregister(&proc_coda, proc_coda_ncstats.low_ino); - proc_unregister(&proc_root, proc_coda.low_ino); + + proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino); + proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino); + proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino); + proc_unregister(&proc_sys_coda,proc_coda_vfs_control.low_ino); + proc_unregister(&proc_sys_root, proc_sys_coda.low_ino); + +#if 0 + proc_unregister(&proc_fs_coda, proc_coda_ncstats.low_ino); +#endif + 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_fs, proc_fs_coda.low_ino); + proc_unregister(&proc_root, proc_fs.low_ino); #endif } diff -uNr linux-2.1.99/fs/coda/stats.c linux/fs/coda/stats.c --- linux-2.1.99/fs/coda/stats.c Wed Dec 31 19:00:00 1969 +++ linux/fs/coda/stats.c Mon May 4 18:15:10 1998 @@ -0,0 +1,417 @@ +/* + * stats.c + * + * CODA operation statistics + * + * (c) March, 1998 Zhanyong Wan <zhanyong.wan_at_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/malloc.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> + +#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> + +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[CFS_NCALLS]; + +/* 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 reset_coda_vfs_stats( void ) +{ + memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) ); +} + +#if 0 +static void reset_upcall_entry( struct coda_upcall_stats_entry * pentry ) +{ + pentry->count = 0; + pentry->time_sum = pentry->time_squared_sum = 0; +} +#endif + +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 > CFS_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 ) +{ + if ( write ) { + reset_coda_upcall_stats(); + } + + *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(); + } + + *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 < CFS_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; +} + diff -uNr linux-2.1.99/fs/coda/symlink.c linux/fs/coda/symlink.c --- linux-2.1.99/fs/coda/symlink.c Wed Mar 4 18:14:32 1998 +++ linux/fs/coda/symlink.c Mon May 4 18:15:11 1998 @@ -23,6 +23,7 @@ #include <linux/coda_psdev.h> #include <linux/coda_fs_i.h> #include <linux/coda_cache.h> +#include <linux/coda_proc.h> static int coda_readlink(struct dentry *de, char *buffer, int length); static struct dentry *coda_follow_link(struct dentry *, struct dentry *); @@ -60,7 +61,7 @@ ENTRY; cp = ITOC(inode); - CHECK_CNODE(cp); + coda_vfs_stat.readlink++; /* the maximum length we receive is len */ if ( length > CFS_MAXPATHLEN ) @@ -93,11 +94,11 @@ unsigned int len; char mem[CFS_MAXPATHLEN]; char *path; -ENTRY; + ENTRY; CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino); cnp = ITOC(inode); - CHECK_CNODE(cnp); + coda_vfs_stat.follow_link++; len = CFS_MAXPATHLEN; error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len); diff -uNr linux-2.1.99/fs/coda/sysctl.c linux/fs/coda/sysctl.c --- linux-2.1.99/fs/coda/sysctl.c Wed Mar 4 18:14:32 1998 +++ linux/fs/coda/sysctl.c Mon May 4 18:15:11 1998 @@ -26,7 +26,7 @@ #include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> #include <linux/coda_cache.h> -#include <linux/coda_sysctl.h> +#include <linux/coda_proc.h> extern int coda_debug; /* extern int cfsnc_use; */ extern int coda_print_entry; @@ -47,6 +47,10 @@ #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 */ @@ -56,6 +60,10 @@ {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_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}, { 0 } }; diff -uNr linux-2.1.99/fs/coda/upcall.c linux/fs/coda/upcall.c --- linux-2.1.99/fs/coda/upcall.c Wed Mar 18 00:19:05 1998 +++ linux/fs/coda/upcall.c Mon May 4 18:15:12 1998 @@ -37,6 +37,11 @@ #include <linux/coda_psdev.h> #include <linux/coda_fs_i.h> #include <linux/coda_cache.h> +#include <linux/coda_proc.h> + + +static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, + union inputArgs *buffer); #define UPARG(op)\ do {\ @@ -68,10 +73,11 @@ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; -ENTRY; + ENTRY; insize = SIZE(root); UPARG(CFS_ROOT); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (error) { @@ -92,7 +98,7 @@ { union inputArgs *inp; union outputArgs *outp; - int insize, outsize, error; + int insize, outsize, error; ENTRY; insize = SIZE(getattr); UPARG(CFS_GETATTR); @@ -458,8 +464,8 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid) { union inputArgs *inp; - union outputArgs *outp; - int insize, outsize, error; + union outputArgs *outp; + int insize, outsize, error; insize=SIZE(fsync); UPARG(CFS_FSYNC); @@ -476,8 +482,8 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask) { union inputArgs *inp; - union outputArgs *outp; - int insize, outsize, error; + union outputArgs *outp; + int insize, outsize, error; insize = SIZE(access); UPARG(CFS_ACCESS); @@ -497,8 +503,8 @@ unsigned int cmd, struct PioctlData *data) { union inputArgs *inp; - union outputArgs *outp; - int insize, outsize, error; + union outputArgs *outp; + int insize, outsize, error; int iocsize; insize = VC_MAXMSGSIZE; @@ -583,11 +589,13 @@ * reply and return Venus' error, also POSITIVE. * */ -static inline void coda_waitfor_upcall(struct vmsg *vmp) +static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp) { struct wait_queue wait = { current, NULL }; + unsigned long posttime; vmp->vm_posttime = jiffies; + posttime = jiffies; add_wait_queue(&vmp->vm_sleep, &wait); for (;;) { @@ -616,13 +624,17 @@ remove_wait_queue(&vmp->vm_sleep, &wait); current->state = TASK_RUNNING; - return; + CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime); + return (jiffies - posttime); + } -int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize, +static int coda_upcall(struct coda_sb_info *sbi, + int inSize, int *outSize, union inputArgs *buffer) { + unsigned long runtime; struct vcomm *vcommp; union outputArgs *out; struct vmsg *vmp; @@ -635,7 +647,6 @@ } vcommp = sbi->sbi_vcomm; - clstats(((union inputArgs *)buffer)->ih.opcode); if (!vcomm_open(vcommp)) return(ENODEV); @@ -670,7 +681,8 @@ * ENODEV. */ /* Go to sleep. Wake up on signals only after the timeout. */ - coda_waitfor_upcall(vmp); + runtime = coda_waitfor_upcall(vmp); + coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime); CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", vmp->vm_opcode, jiffies - vmp->vm_posttime, diff -uNr linux-2.1.99/include/linux/coda_proc.h linux/include/linux/coda_proc.h --- linux-2.1.99/include/linux/coda_proc.h Wed Dec 31 19:00:00 1969 +++ linux/include/linux/coda_proc.h Mon May 4 18:16:25 1998 @@ -0,0 +1,144 @@ +/* + * coda_statis.h + * + * CODA operation statistics + * + * (c) March, 1998 + * by Michihiro Kuramochi, Zhenyu Xia and Zhanyong Wan + * zhanyong.wan_at_yale.edu + * + */ + +#ifndef _CODA_PROC_H +#define _CODA_PROC_H + +void coda_sysctl_init(void); +void coda_sysctl_clean(void); +void coda_upcall_stats(int opcode, unsigned long jiffies); + +#include <linux/sysctl.h> +#include <linux/coda_fs_i.h> +#include <linux/coda.h> + +/* these four files are presented to show the result of the statistics: + * + * /proc/fs/coda/vfs_stats + * upcall_stats + * permission_stats + * cache_inv_stats + * + * these four files are presented to reset the statistics to 0: + * + * /proc/sys/coda/vfs_stats + * upcall_stats + * permission_stats + * cache_inv_stats + */ + +/* VFS operation statistics */ +struct coda_vfs_stats +{ + /* file operations */ + int file_read; + int file_write; + int file_mmap; + int open; + int release; + int fsync; + + /* dir operations */ + int readdir; + + /* inode operations */ + int create; + int lookup; + int link; + int unlink; + int symlink; + int mkdir; + int rmdir; + int rename; + int permission; + int readpage; + + /* symlink operatoins*/ + int follow_link; + int readlink; +}; + +struct coda_upcall_stats_entry +{ + int count; + unsigned long time_sum; + unsigned long time_squared_sum; +}; + + + +/* cache hits for permissions statistics */ +struct coda_permission_stats +{ + int count; + int hit_count; +}; + +/* cache invalidation statistics */ +struct coda_cache_inv_stats +{ + int flush; + int purge_user; + int zap_dir; + int zap_file; + int zap_vnode; + int purge_fid; + int replace; +}; + +/* these global variables hold the actual statistics data */ +extern struct coda_vfs_stats coda_vfs_stat; +extern struct coda_permission_stats coda_permission_stat; +extern struct coda_cache_inv_stats coda_cache_inv_stat; + +/* reset statistics to 0 */ +void reset_coda_vfs_stats( void ); +void reset_coda_upcall_stats( void ); +void reset_coda_permission_stats( void ); +void reset_coda_cache_inv_stats( void ); + +/* some utitlities to make it easier for you to do statistics for time */ +void do_time_stats( struct coda_upcall_stats_entry * pentry, + unsigned long jiffy ); +/* +double get_time_average( const struct coda_upcall_stats_entry * pentry ); +double get_time_std_deviation( const struct coda_upcall_stats_entry * pentry ); +*/ +unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry ); +unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry ); + +/* like coda_dointvec, these functions are to be registered in the ctl_table + * data structure for /proc/sys/... files + */ +int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp, + void * buffer, size_t * lenp ); +int do_reset_coda_upcall_stats( ctl_table * table, int write, + struct file * filp, void * buffer, + size_t * lenp ); +int do_reset_coda_permission_stats( ctl_table * table, int write, + struct file * filp, void * buffer, + size_t * lenp ); +int do_reset_coda_cache_inv_stats( ctl_table * table, int write, + struct file * filp, void * buffer, + size_t * lenp ); + +/* these functions are called to form the content of /proc/fs/coda/... files */ +int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, + int length, int dummy ); +int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset, + int length, int dummy ); +int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset, + int length, int dummy ); +int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, + int length, int dummy ); + + +#endif /* _CODA_PROC_H */ diff -uNr linux-2.1.99/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h --- linux-2.1.99/include/linux/coda_psdev.h Fri Feb 20 21:28:23 1998 +++ linux/include/linux/coda_psdev.h Mon May 4 18:16:26 1998 @@ -94,8 +94,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, unsigned int cmd, struct PioctlData *data); int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb); -int coda_upcall(struct coda_sb_info *mntinfo, int inSize, - int *outSize, union inputArgs *buffer); int venus_fsync(struct super_block *sb, struct ViceFid *fid); diff -uNr linux-2.1.99/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- linux-2.1.99/include/linux/proc_fs.h Thu Apr 30 15:51:42 1998 +++ linux/include/linux/proc_fs.h Mon May 4 18:17:21 1998 @@ -51,6 +51,7 @@ PROC_PPC_HTAB, PROC_SOUND, PROC_MTRR, /* whether enabled or not */ + PROC_FS }; enum pid_directory_inos { @@ -203,6 +204,19 @@ PROC_BUS_PCI = PROC_MCA_LAST, PROC_BUS_PCI_DEVICES, PROC_BUS_LAST +}; + +enum fs_directory_inos { + PROC_FS_CODA = PROC_MCA_LAST, + PROC_FS_LAST +}; + +enum fs_coda_directory_inos { + PROC_VFS_STATS = PROC_MCA_LAST, + PROC_UPCALL_STATS, + PROC_PERMISSION_STATS, + PROC_CACHE_INV_STATS, + PROC_CODA_FS_LAST }; /* Finally, the dynamically allocatable proc entries are reserved: */Received on 1998-05-04 20:07:17