Coda File System

[PATCH] Coda

From: Peter J. Braam <braam_at_cs.cmu.edu>
Date: Mon, 16 Mar 1998 02:07:34 -0500 (EST)
Hi Linus,

Another little patch for Coda. 

Instructions:
rm fs/coda/super.c
patch -p? < ..

You asked me how good the current dcache API suits Coda and I have now
looked into it in detail.  It's splendid. In a mere 20 lines of code the
cache and attribute validations are stuffed into dentry_revalidate and
inode_revalidate, and do exactly what Coda wants (I think).

The negative entries and variable size of the dcache have led to an
enormous performance increase compared to 2.0 where we managed our own
fixed size cache without negative dentries. 

I have found it pretty time consuming to understand what is going on --
I'll try to give a clear exposition of it at Linux Expo, hopefully
this will help some others. 

BTW the Linux 2.1 kernels on my dual PII 2940UW just scream, it's great.
Are we close to 2.2?

- Peter - 

diff -urN linux-2.1.89.orig/fs/coda/Makefile linux/fs/coda/Makefile
--- linux-2.1.89.orig/fs/coda/Makefile	Sun Dec 21 17:45:13 1997
+++ linux/fs/coda/Makefile	Sun Mar 15 22:02:34 1998
@@ -3,7 +3,7 @@
 #
 
 O_TARGET := coda.o
-O_OBJS   := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.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
 M_OBJS   := $(O_TARGET)
 
diff -urN linux-2.1.89.orig/fs/coda/cache.c linux/fs/coda/cache.c
--- linux-2.1.89.orig/fs/coda/cache.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/cache.c	Mon Mar 16 00:14:54 1998
@@ -24,16 +24,22 @@
 #include <linux/coda_fs_i.h>
 #include <linux/coda_cache.h>
 
-/* Keep various stats */
-struct cfsnc_statistics cfsnc_stat;
+static void coda_ccinsert(struct coda_cache *el, struct super_block *sb);
+static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii);
+static void coda_ccremove(struct coda_cache *el);
+static void coda_cnremove(struct coda_cache *el);
+static void coda_cache_create(struct inode *inode, int mask);
+static struct coda_cache * coda_cache_find(struct inode *inode);
 
 
-/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */
+/* Keep various stats */
+struct cfsnc_statistics cfsnc_stat;
 
-void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
+/* insert a acl-cache entry in sb list */
+static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
 {
 	struct coda_sb_info *sbi = coda_sbp(sb);
-ENTRY;
+	ENTRY;
 	if ( !sbi ||  !el) {
 		printk("coda_ccinsert: NULL sbi or el!\n");
 		return ;
@@ -42,17 +48,19 @@
 	list_add(&el->cc_cclist, &sbi->sbi_cchead);
 }
 
-void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp)
+/* insert a acl-cache entry in the inode list */
+static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
 {
-ENTRY;
-	if ( !cnp ||  !el) {
-		printk("coda_cninsert: NULL cnp or el!\n");
+	ENTRY;
+	if ( !cii ||  !el) {
+		printk("coda_cninsert: NULL cii or el!\n");
 		return ;
 	}
-	list_add(&el->cc_cnlist, &cnp->c_cnhead);
+	list_add(&el->cc_cnlist, &cii->c_cnhead);
 }
 
-void coda_ccremove(struct coda_cache *el)
+/* remove a cache entry from the superblock list */
+static void coda_ccremove(struct coda_cache *el)
 {
 	ENTRY;
         if (el->cc_cclist.next && el->cc_cclist.prev)
@@ -61,7 +69,8 @@
 		printk("coda_cnremove: trying to remove 0 entry!");
 }
 
-void coda_cnremove(struct coda_cache *el)
+/* remove a cache entry from the inode's list */
+static void coda_cnremove(struct coda_cache *el)
 {
 	ENTRY;
 	if (el->cc_cnlist.next && el->cc_cnlist.prev)
@@ -70,10 +79,10 @@
 		printk("coda_cnremove: trying to remove 0 entry!");
 }
 
-
-void coda_cache_create(struct inode *inode, int mask)
+/* create a new cache entry and enlist it */
+static void coda_cache_create(struct inode *inode, int mask)
 {
-	struct coda_inode_info *cnp = ITOC(inode);
+	struct coda_inode_info *cii = ITOC(inode);
 	struct super_block *sb = inode->i_sb;
 	struct coda_cache *cc = NULL;
 	ENTRY;
@@ -85,17 +94,19 @@
 	}
 	coda_load_creds(&cc->cc_cred);
 	cc->cc_mask = mask;
-	coda_cninsert(cc, cnp);
+	coda_cninsert(cc, cii);
 	coda_ccinsert(cc, sb);
 }
 
-struct coda_cache * coda_cache_find(struct inode *inode)
+/* see if there is a match for the current 
+   credentials already */
+static struct coda_cache * coda_cache_find(struct inode *inode)
 {
-	struct coda_inode_info *cnp = ITOC(inode);
+	struct coda_inode_info *cii = ITOC(inode);
 	struct list_head *lh, *le;
 	struct coda_cache *cc = NULL;
 	
-	le = lh = &cnp->c_cnhead;
+	le = lh = &cii->c_cnhead;
 	while( (le = le->next ) != lh )  {
 		/* compare name and creds */
 		cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -107,6 +118,7 @@
 		return NULL;
 }
 
+/* create or extend an acl cache hit */
 void coda_cache_enter(struct inode *inode, int mask)
 {
 	struct coda_cache *cc;
@@ -120,17 +132,21 @@
 	}
 }
 
-void coda_cache_clear_cnp(struct coda_inode_info *cnp)
+/* remove all cached acl matches from an inode */
+void coda_cache_clear_inode(struct inode *inode)
 {
 	struct list_head *lh, *le;
+	struct coda_inode_info *cii;
 	struct coda_cache *cc;
+	ENTRY;
 
-	if ( !cnp ) {
-		printk("coda_cache_cnp_clear: NULL cnode\n");
+	if ( !inode ) {
+		CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n");
 		return;
 	}
+	cii = ITOC(inode);
 	
-	lh = le = &cnp->c_cnhead;
+	lh = le = &cii->c_cnhead;
 	while ( (le = le->next ) != lh ) {
 		cc = list_entry(le, struct coda_cache, cc_cnlist);
 		coda_cnremove(cc);
@@ -139,6 +155,7 @@
 	}
 }
 
+/* remove all acl caches */
 void coda_cache_clear_all(struct super_block *sb)
 {
 	struct list_head *lh, *le;
@@ -150,6 +167,9 @@
 		return;
 	}
 	
+	if ( list_empty(&sbi->sbi_cchead) )
+		return;
+
 	lh = le = &sbi->sbi_cchead;
 	while ( (le = le->next ) != lh ) {
 		cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -159,6 +179,7 @@
 	}
 }
 
+/* remove all acl caches for a principal */
 void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
 {
 	struct list_head *lh, *le;
@@ -170,6 +191,9 @@
 		return;
 	}
 	
+	if (list_empty(&sbi->sbi_cchead))
+		return;
+
 	lh = le = &sbi->sbi_cchead;
 	while ( (le = le->next ) != lh ) {
 		cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -180,15 +204,17 @@
 		}
 	}
 }
-		
 
+
+/* check if the mask has been matched against the acl
+   already */
 int coda_cache_check(struct inode *inode, int mask)
 {
-	struct coda_inode_info *cnp = ITOC(inode);
+	struct coda_inode_info *cii = ITOC(inode);
 	struct list_head *lh, *le;
 	struct coda_cache *cc = NULL;
 	
-	le = lh = &cnp->c_cnhead;
+	le = lh = &cii->c_cnhead;
 	while( (le = le->next ) != lh )  {
 		/* compare name and creds */
 		cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -204,110 +230,70 @@
 }
 
 
-/*   DENTRY related stuff */
+/*   DCACHE & ZAPPING related stuff */
 
-/* when the dentry count falls to 0 this is called. If Venus has
-   asked for it to be flushed, we take it out of the dentry hash 
-   table with d_drop */
-
-static void coda_flag_children(struct dentry *parent)
+/* the following routines set flags in the inodes. They are 
+   detected by:
+   - a dentry method: coda_dentry_revalidate (for lookups)
+     if the flag is C_PURGE
+   - an inode method coda_revalidate (for attributes) if the 
+     flag is C_ATTR
+*/
+static void coda_flag_children(struct dentry *parent, int flag)
 {
 	struct list_head *child;
-	struct coda_inode_info *cnp;
 	struct dentry *de;
 
 	child = parent->d_subdirs.next;
 	while ( child != &parent->d_subdirs ) {
 		de = list_entry(child, struct dentry, d_child);
-		cnp = ITOC(de->d_inode);
-		if (cnp) 
-			cnp->c_flags |= C_ZAPFID;
-		CDEBUG(D_CACHE, "ZAPFID for %s\n", coda_f2s(&cnp->c_fid));
-		
+		coda_flag_inode(de->d_inode, flag);
+		CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag, 
+		       de->d_name.len, de->d_name.name, 
+		       de->d_parent->d_name.len, de->d_parent->d_name.name);
 		child = child->next;
+		if ( !de->d_inode )
+			d_drop(de); 
 	}
 	return; 
 }
 
-/* flag dentry and possibly  children of a dentry with C_ZAPFID */
-void  coda_dentry_delete(struct dentry *dentry)
-{
-	struct inode *inode = dentry->d_inode;
-	struct coda_inode_info *cnp = NULL;
-	ENTRY;
-
-	if (inode) { 
-		cnp = ITOC(inode);
-		if ( cnp ) 
-			CHECK_CNODE(cnp);
-	} else {
-		CDEBUG(D_CACHE, "No inode for dentry_delete!\n");
-		return;
-	}
 
-	
-	if ( !cnp ) {
-		printk("No cnode for dentry_delete!\n");
-		return;
-	}
+void coda_flag_alias_children(struct inode *inode, int flag)
+{
+	struct list_head *alias;
+	struct dentry *alias_de;
 
-	if ( cnp->c_flags & (C_ZAPFID | C_ZAPDIR) )
-		d_drop(dentry);
-	if ( (cnp->c_flags & C_ZAPDIR) && S_ISDIR(inode->i_mode) ) {
-		coda_flag_children(dentry);
+	if ( !inode ) 
+		return; 
+	alias = inode->i_dentry.next; 
+	while ( alias != &inode->i_dentry ) {
+		alias_de = list_entry(alias, struct dentry, d_alias);
+		if ( !alias_de ) {
+			printk("Corrupt alias list for %*s\n",
+			       alias_de->d_name.len, alias_de->d_name.name);
+			return;
+		}
+		coda_flag_children(alias_de, flag);
+		alias= alias->next;
 	}
-	return;
 }
 
-static void coda_zap_cnode(struct coda_inode_info *cnp, int flags)
+void coda_flag_inode(struct inode *inode, int flag)
 {
-	cnp->c_flags |= flags;
-	coda_cache_clear_cnp(cnp);
-}
+	struct coda_inode_info *cii;
 
-
-
-/* the dache will notice the flags and drop entries (possibly with
-   children) the moment they are no longer in use  */
-void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag)
-{
-	struct inode *inode = NULL;
-	struct coda_inode_info *cnp;
-
-	ENTRY;
- 
-	if ( !sb ) {
-		printk("coda_zapfid: no sb!\n");
+	if ( !inode ) {
+		CDEBUG(D_CACHE, " no inode!\n");
 		return;
 	}
+	cii = ITOC(inode);
+	cii->c_flags |= flag;
+}		
 
-	if ( !fid ) {
-		printk("coda_zapfid: no fid!\n");
-		return;
-	}
 
-	if ( coda_fid_is_volroot(fid) ) {
-		struct list_head *lh, *le;
-		struct coda_sb_info *sbi = coda_sbp(sb);
-		le = lh = &sbi->sbi_volroothead;
-		while ( (le = le->next) != lh ) {
-			cnp = list_entry(le, struct coda_inode_info, c_volrootlist);
-			if ( cnp->c_fid.Volume == fid->Volume) 
-				coda_zap_cnode(cnp, flag);
-		}
-		return;
-	}
 
 
-	inode = coda_fid_to_inode(fid, sb);
-	if ( !inode ) {
-		CDEBUG(D_CACHE, "coda_zapfid: no inode!\n");
-		return;
-	}
-	cnp = ITOC(inode);
-	coda_zap_cnode(cnp, flag);
-}
-		
 
 int
 cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
diff -urN linux-2.1.89.orig/fs/coda/cnode.c linux/fs/coda/cnode.c
--- linux-2.1.89.orig/fs/coda/cnode.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/cnode.c	Mon Mar 16 00:18:41 1998
@@ -15,8 +15,6 @@
 
 /* cnode.c */
 
-
-              
 static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
 {
         CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
@@ -56,8 +54,8 @@
         ENTRY;
 
         /* 
-         * We get inode numbers from Venus -- see venus source
-         */
+        * We get inode numbers from Venus -- see venus source
+	*/
 
 	error = venus_getattr(sb, fid, &attr);
 	if ( error ) {
@@ -79,7 +77,7 @@
 		memset(cnp, 0, (int) sizeof(struct coda_inode_info));
 		cnp->c_fid = *fid;
 		cnp->c_magic = CODA_CNODE_MAGIC;
-		cnp->c_flags = C_VATTR;
+		cnp->c_flags = 0;
 		cnp->c_vnode = *inode;
 		INIT_LIST_HEAD(&(cnp->c_cnhead));
 		INIT_LIST_HEAD(&(cnp->c_volrootlist));
@@ -111,20 +109,51 @@
 
  
 
-/* convert a fid to an inode. Avoids having a hash table
-   such as present in the Mach minicache */
+/* convert a fid to an inode. Mostly we can compute
+   the inode number from the FID, but not for volume
+   mount points: those are in a list */
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) 
 {
 	ino_t nr;
 	struct inode *inode;
 	struct coda_inode_info *cnp;
-ENTRY;
+	ENTRY;
 
 	CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
 
+	if ( !sb ) {
+		printk("coda_fid_to_inode: no sb!\n");
+		return NULL;
+	}
+
+	if ( !fid ) {
+		printk("coda_fid_to_inode: no fid!\n");
+		return NULL;
+	}
+
+
+	if ( coda_fid_is_volroot(fid) ) {
+		struct coda_inode_info *cii;
+		struct list_head *lh, *le;
+		struct coda_sb_info *sbi = coda_sbp(sb);
+		le = lh = &sbi->sbi_volroothead;
+
+		while ( (le = le->next) != lh ) {
+			cii = list_entry(le, struct coda_inode_info, 
+					 c_volrootlist);
+			if ( cii->c_fid.Volume == fid->Volume) {
+				inode = cii->c_vnode;
+				CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
+				return cii->c_vnode;
+			}
+			
+		}
+		return NULL;
+	}
+
+	/* fid is not volume root, hence ino is computable */
 	nr = coda_f2i(fid);
 	inode = iget(sb, nr);
-
 	if ( !inode ) {
 		printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
 		       sb, nr);
@@ -133,19 +162,25 @@
 
 	/* check if this inode is linked to a cnode */
 	cnp = ITOC(inode);
-
 	if ( cnp->c_magic != CODA_CNODE_MAGIC ) {
+		CDEBUG(D_INODE, "uninitialized inode. Return.\n");
 		iput(inode);
 		return NULL;
 	}
 
-	/* make sure fid is the one we want */
-	if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+	/* make sure fid is the one we want; 
+	   unfortunately Venus will shamelessly send us mount-symlinks.
+	   These have the same inode as the root of the volume they
+	   mount, but the fid will be wrong. 
+	*/
+	if ( !coda_fideq(fid, &(cnp->c_fid)) && 
+	     !coda_fid_is_volroot(&(cnp->c_fid))) {
 		printk("coda_fid2inode: bad cnode! Tell Peter.\n");
 		iput(inode);
 		return NULL;
 	}
 
+	CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
 	iput(inode);	
 	return inode;
 }
diff -urN linux-2.1.89.orig/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c
--- linux-2.1.89.orig/fs/coda/coda_linux.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/coda_linux.c	Mon Mar 16 00:36:21 1998
@@ -32,14 +32,15 @@
 /* caller must allocate 36 byte string ! */
 char * coda_f2s(ViceFid *f)
 {
-	static char s[50];
+	static char s[60];
 	if ( f ) {
-		sprintf(s, "(%10lx,%10lx,%10lx)", 
+		sprintf(s, "(%-#lx,%-#lx,%-#lx)", 
 			 f->Volume, f->Vnode, f->Unique);
 	}
 	return s;
 }
 
+/* recognize special .CONTROL name */
 int coda_iscontrol(const char *name, size_t length)
 {
 	if ((CFS_CONTROLLEN == length) && 
@@ -48,16 +49,23 @@
 	return 0;
 }
 
+/* recognize /coda inode */
 int coda_isroot(struct inode *i)
 {
     if ( i->i_sb->s_root->d_inode == i ) {
-	return 1;
+	    return 1;
     } else {
-	return 0;
+	    return 0;
     }
 }
 
-	
+/* is this a volume root FID */
+int coda_fid_is_volroot(struct ViceFid *fid)
+{
+	return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
+}
+
+/* put the current process credentials in the cred */
 void coda_load_creds(struct coda_cred *cred)
 {
         cred->cr_uid = (vuid_t) current->uid;
@@ -97,11 +105,6 @@
 	return coda_flags;
 }
 
-
-int coda_fid_is_volroot(struct ViceFid *fid)
-{
-	return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
-}
 
 /* utility functions below */
 void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
diff -urN linux-2.1.89.orig/fs/coda/dir.c linux/fs/coda/dir.c
--- linux-2.1.89.orig/fs/coda/dir.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/dir.c	Mon Mar 16 00:30:14 1998
@@ -40,17 +40,21 @@
 /* dir file-ops */
 static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
 
+/* dentry ops */
+int coda_dentry_revalidate(struct dentry *de);
+
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
 			      filldir_t filldir);
 int coda_fsync(struct file *, struct dentry *dentry);
+static int coda_refresh_inode(struct dentry *dentry);
 
 struct dentry_operations coda_dentry_operations =
 {
-	NULL, /* revalidate */
+	coda_dentry_revalidate, /* revalidate */
 	NULL, /* hash */
 	NULL,
-	coda_dentry_delete
+	NULL,
 };
 
 struct inode_operations coda_dir_inode_operations =
@@ -74,7 +78,7 @@
 	coda_permission,        /* permission */
 	NULL,                   /* smap */
 	NULL,                   /* update page */
-        NULL                    /* revalidate */
+        coda_revalidate_inode   /* revalidate */
 };
 
 struct file_operations coda_dir_operations = {
@@ -117,7 +121,6 @@
 	}
 
 	dircnp = ITOC(dir);
-	CHECK_CNODE(dircnp);
 
 	if ( length > CFS_MAXNAMLEN ) {
 	        printk("name too long: lookup, %s (%*s)\n", 
@@ -141,9 +144,13 @@
 			     (const char *)name, length, &type, &resfid);
 
 	res_inode = NULL;
-	if (!error || (error == -CFS_NOCACHE) ) {
-		if (error == -CFS_NOCACHE) 
+	if (!error) {
+		if (type & CFS_NOCACHE) {
+			type &= (~CFS_NOCACHE);
+			CDEBUG(D_INODE, "dropme set for %s\n", 
+			       coda_f2s(&resfid));
 			dropme = 1;
+		}
 	    	error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
 		if (error)
 			return -error;
@@ -152,7 +159,7 @@
 		       coda_f2s(&dircnp->c_fid), length, name, error);
 		return error;
 	}
-	CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+	CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
 	       name, coda_f2s(&resfid), type, error, dropme);
 
 exit:
@@ -228,7 +235,6 @@
         CHECK_CNODE(dircnp);
 
         if ( length > CFS_MAXNAMLEN ) {
-		char str[50];
 		printk("name too long: create, %s(%s)\n", 
 		       coda_f2s(&dircnp->c_fid), name);
 		return -ENAMETOOLONG;
@@ -238,7 +244,6 @@
 				0, mode, &newfid, &attrs);
 
         if ( error ) {
-		char str[50];
 		CDEBUG(D_INODE, "create: %s, result %d\n",
 		       coda_f2s(&newfid), error); 
 		d_drop(de);
@@ -321,7 +326,6 @@
         const char * name = de->d_name.name;
 	int len = de->d_name.len;
         struct coda_inode_info *dir_cnp, *cnp;
-	char str[50];
 	int error;
 
         ENTRY;
@@ -408,7 +412,6 @@
         int error;
 	const char *name = de->d_name.name;
 	int len = de->d_name.len;
-	char fidstr[50];
 
 	ENTRY;
 
@@ -781,3 +784,82 @@
         CODA_FREE(buff, size);
         return error;
 }
+
+int coda_dentry_revalidate(struct dentry *de)
+{
+	int valid = 1;
+	struct inode *inode = de->d_inode;
+	struct coda_inode_info *cii;
+	ENTRY;
+
+	if (inode) {
+		if (is_bad_inode(inode))
+			return 0;
+		cii = ITOC(de->d_inode);
+		if (cii->c_flags & C_PURGE) 
+			valid = 0;
+	}
+	return valid ||  coda_isroot(de->d_inode);
+}
+
+
+static int coda_refresh_inode(struct dentry *dentry)
+{
+	struct coda_vattr attr;
+	int error;
+	int old_mode;
+	ino_t old_ino;
+	struct inode *inode = dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(inode);
+	
+	ENTRY;
+	error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
+	if ( error ) { 
+		make_bad_inode(inode);
+		return -EIO;
+	}
+
+	/* this baby may be lost if:
+	   - it's type changed
+            - it's ino changed 
+	*/
+	old_mode = inode->i_mode;
+	old_ino = inode->i_ino;
+	coda_vattr_to_iattr(inode, &attr);
+
+	if ((inode->i_ino != old_ino) ||
+	    ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) {
+		make_bad_inode(inode);
+		inode->i_mode = old_mode;
+		return -EIO;
+	}
+	
+	cii->c_flags &= ~C_VATTR;
+	return 0;
+}
+
+
+/*
+ * This is called when we want to check if the inode has
+ * changed on the server.  Coda makes this easy since the
+ * cache manager Venus issues a downcall to the kernel when this 
+ * happens 
+ */
+
+int coda_revalidate_inode(struct dentry *dentry)
+{
+	int error = 0;
+	struct coda_inode_info *cii = ITOC(dentry->d_inode);
+
+	ENTRY;
+	CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
+	       dentry->d_name.len, dentry->d_name.name,
+	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
+
+	if ( cii->c_flags & (C_VATTR | C_PURGE )) {
+		error = coda_refresh_inode(dentry);
+	}
+
+	return error;
+}
+
diff -urN linux-2.1.89.orig/fs/coda/file.c linux/fs/coda/file.c
--- linux-2.1.89.orig/fs/coda/file.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/file.c	Sun Mar 15 22:00:07 1998
@@ -30,7 +30,7 @@
 static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off);
 static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
 
-/* exported from this file */
+/* also exported from this file (used for dirs) */
 int coda_fsync(struct file *, struct dentry *dentry);
 
 struct inode_operations coda_file_inode_operations = {
@@ -43,7 +43,7 @@
 	NULL,			/* mkdir */
 	NULL,			/* rmdir */
 	NULL,			/* mknod */
-	NULL,		/* rename */
+	NULL,		        /* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
 	coda_readpage,    	/* readpage */
@@ -53,7 +53,7 @@
         coda_permission,        /* permission */
 	NULL,                   /* smap */
 	NULL,                   /* update page */
-        NULL                    /* revalidate */
+        coda_revalidate_inode   /* revalidate */
 };
 
 struct file_operations coda_file_operations = {
@@ -74,41 +74,47 @@
 };
 
 /*  File file operations */
-static int coda_readpage(struct file * file, struct page * page)
+static int coda_readpage(struct file * coda_file, struct page * page)
 {
-	struct dentry *de = file->f_dentry;
-	struct inode *inode = de->d_inode;
+	struct dentry *de = coda_file->f_dentry;
+	struct inode *coda_inode = de->d_inode;
 	struct dentry cont_dentry;
-        struct inode *cont_inode;
-        struct coda_inode_info *cnp;
+	struct file cont_file;
+        struct coda_inode_info *cii;
 
         ENTRY;
         
-        cnp = ITOC(inode);
-        CHECK_CNODE(cnp);
+        cii = ITOC(coda_inode);
 
-        if ( ! cnp->c_ovp ) {
-            printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino);
+        if ( ! cii->c_ovp ) {
+		printk("coda_readpage: no open inode for ino %ld, %s\n", 
+		       coda_inode->i_ino, de->d_name.name);
                 return -ENXIO;
         }
+       
+        coda_prepare_openfile(coda_inode, coda_file, cii->c_ovp,
+			      &cont_file, &cont_dentry);
 
-        cont_inode = cnp->c_ovp;
-	cont_dentry.d_inode = cont_inode;
-
-        CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset);
+        CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", 
+	       coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
 
-        generic_readpage(&cont_dentry, page);
+        generic_readpage(&cont_file, page);
         EXIT;
         return 0;
 }
 
 static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
-        struct coda_inode_info *cnp;
-	cnp = ITOC(file->f_dentry->d_inode);
-	cnp->c_mmcount++;
+        struct coda_inode_info *cii;
+	int res;
+
+        ENTRY;
+	cii = ITOC(file->f_dentry->d_inode);
+	cii->c_mmcount++;
   
-	return generic_file_mmap(file, vma);
+	res =generic_file_mmap(file, vma);
+	EXIT;
+	return res;
 }
 
 static ssize_t coda_file_read(struct file *coda_file, char *buff, 
@@ -120,7 +126,6 @@
         struct file  cont_file;
 	struct dentry cont_dentry;
         int result = 0;
-
         ENTRY;
 
         cnp = ITOC(coda_inode);
diff -urN linux-2.1.89.orig/fs/coda/inode.c linux/fs/coda/inode.c
--- linux-2.1.89.orig/fs/coda/inode.c	Wed Dec 31 19:00:00 1969
+++ linux/fs/coda/inode.c	Sun Mar 15 22:00:07 1998
@@ -0,0 +1,369 @@
+/*
+ * Super block/filesystem wide operations
+ *
+ * Copryright (C) 1996 Peter J. Braam <braam_at_maths.ox.ac.uk> and 
+ * Michael Callahan <callahan_at_maths.ox.ac.uk> 
+ * 
+ * Rewritten for Linux 2.1.  Peter Braam <braam_at_cs.cmu.edu>
+ * Copyright (C) Carnegie Mellon University
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <asm/segment.h>
+
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_psdev.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
+
+
+/* VFS super_block ops */
+static struct super_block *coda_read_super(struct super_block *, void *, int);
+static void coda_read_inode(struct inode *);
+static int  coda_notify_change(struct dentry *dentry, struct iattr *attr);
+static void coda_put_inode(struct inode *);
+static void coda_delete_inode(struct inode *);
+static void coda_put_super(struct super_block *);
+static int coda_statfs(struct super_block *sb, struct statfs *buf, 
+		       int bufsiz);
+
+/* helper functions */
+static inline struct vcomm *coda_psinode2vcomm(struct inode *inode);
+static int coda_get_psdev(void *, struct inode **);
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode);
+
+/* exported operations */
+struct super_operations coda_super_operations =
+{
+	coda_read_inode,        /* read_inode */
+	NULL,                   /* write_inode */
+	coda_put_inode,	        /* put_inode */
+	coda_delete_inode,      /* delete_inode */
+	coda_notify_change,	/* notify_change */
+	coda_put_super,	        /* put_super */
+	NULL,			/* write_super */
+	coda_statfs,   		/* statfs */
+	NULL			/* remount_fs */
+};
+
+/*
+ * globals
+ */
+struct coda_sb_info coda_super_info[MAX_CODADEVS];
+
+
+static struct super_block * coda_read_super(struct super_block *sb, 
+					    void *data, int silent)
+{
+        struct inode *psdev = 0, *root = 0; 
+	struct coda_sb_info *sbi = NULL;
+	struct vcomm *vc = NULL;
+        ViceFid fid;
+	kdev_t dev = sb->s_dev;
+        int error;
+
+	ENTRY;
+        MOD_INC_USE_COUNT; 
+        if (coda_get_psdev(data, &psdev))
+                goto error;
+
+        vc = coda_psinode2vcomm(psdev);
+        if ( !vc )
+	        goto error;
+	vc->vc_sb = sb;
+	vc->vc_inuse = 1;
+
+	sbi = coda_psinode2sbi(psdev);
+	if ( !sbi )
+	        goto error;
+        sbi->sbi_psdev = psdev;
+	sbi->sbi_vcomm = vc;
+	INIT_LIST_HEAD(&(sbi->sbi_cchead));
+	INIT_LIST_HEAD(&(sbi->sbi_volroothead));
+
+        lock_super(sb);
+        sb->u.generic_sbp = sbi;
+        sb->s_blocksize = 1024;	/* XXXXX  what do we put here?? */
+        sb->s_blocksize_bits = 10;
+        sb->s_magic = CODA_SUPER_MAGIC;
+        sb->s_dev = dev;
+        sb->s_op = &coda_super_operations;
+
+	/* get root fid from Venus: this needs the root inode */
+	error = venus_rootfid(sb, &fid);
+	if ( error ) {
+	        printk("coda_read_super: coda_get_rootfid failed with %d\n",
+		       error);
+		sb->s_dev = 0;
+	        unlock_super(sb);
+		goto error;
+	}	  
+	printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
+	
+	/* make root inode */
+        error = coda_cnode_make(&root, &fid, sb);
+        if ( error || !root ) {
+	    printk("Failure of coda_cnode_make for root: error %d\n", error);
+	    sb->s_dev = 0;
+	    unlock_super(sb);
+	    goto error;
+	} 
+
+	printk("coda_read_super: rootinode is %ld dev %d\n", 
+	       root->i_ino, root->i_dev);
+	sbi->sbi_root = root;
+	sb->s_root = d_alloc_root(root, NULL);
+	unlock_super(sb);
+	EXIT;  
+        return sb;
+
+error:
+EXIT;  
+	MOD_DEC_USE_COUNT;
+	if (sbi) {
+		sbi->sbi_vcomm = NULL;
+		sbi->sbi_root = NULL;
+	}
+	if ( vc ) {
+		vc->vc_sb = NULL;
+		vc->vc_inuse = 0;
+	}
+        if (root) {
+                iput(root);
+        }
+        sb->s_dev = 0;
+        return NULL;
+}
+
+static void coda_put_super(struct super_block *sb)
+{
+        struct coda_sb_info *sb_info;
+
+        ENTRY;
+
+        lock_super(sb);
+
+        sb->s_dev = 0;
+	coda_cache_clear_all(sb);
+	sb_info = coda_sbp(sb);
+	sb_info->sbi_vcomm->vc_inuse = 0;
+	sb_info->sbi_vcomm->vc_sb = NULL;
+	printk("Coda: Bye bye.\n");
+	memset(sb_info, 0, sizeof(* sb_info));
+
+        unlock_super(sb);
+        MOD_DEC_USE_COUNT;
+	EXIT;
+}
+
+/* all filling in of inodes postponed until lookup */
+static void coda_read_inode(struct inode *inode)
+{
+	struct coda_inode_info *cii;
+	ENTRY;
+	cii = ITOC(inode);
+	cii->c_magic = 0;
+	return;
+}
+
+static void coda_put_inode(struct inode *in) 
+{
+	ENTRY;
+
+        CDEBUG(D_INODE,"ino: %ld, count %d\n", in->i_ino, in->i_count);
+
+	if ( in->i_count == 1 ) 
+		in->i_nlink = 0;
+		
+}
+
+static void coda_delete_inode(struct inode *inode)
+{
+        struct coda_inode_info *cii;
+        struct inode *open_inode;
+
+        ENTRY;
+        CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", 
+	       inode->i_ino, inode->i_count);        
+
+        cii = ITOC(inode);
+	if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) {
+	        clear_inode(inode);
+		return;
+	}
+
+
+	if ( coda_fid_is_volroot(&cii->c_fid) )
+		list_del(&cii->c_volrootlist);
+
+        open_inode = cii->c_ovp;
+        if ( open_inode ) {
+                CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",  
+		       open_inode->i_ino,  open_inode->i_count);
+                cii->c_ovp = NULL;
+                iput(open_inode);
+        }
+	
+	coda_cache_clear_inode(inode);
+
+	inode->u.generic_ip = NULL;
+        clear_inode(inode);
+	EXIT;
+}
+
+static int  coda_notify_change(struct dentry *de, struct iattr *iattr)
+{
+	struct inode *inode = de->d_inode;
+        struct coda_inode_info *cii;
+        struct coda_vattr vattr;
+        int error;
+	
+	ENTRY;
+        memset(&vattr, 0, sizeof(vattr)); 
+        cii = ITOC(inode);
+        CHECK_CNODE(cii);
+
+        coda_iattr_to_vattr(iattr, &vattr);
+        vattr.va_type = C_VNON; /* cannot set type */
+	CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
+
+        error = venus_setattr(inode->i_sb, &cii->c_fid, &vattr);
+
+        if ( !error ) {
+	        coda_vattr_to_iattr(inode, &vattr); 
+		coda_cache_clear_inode(inode);
+        }
+	CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", 
+	       inode->i_mode, error);
+
+	EXIT;
+        return error;
+}
+
+/*  we need _something_ for this routine. Let's mimic AFS */
+static int coda_statfs(struct super_block *sb, struct statfs *buf, 
+		       int bufsiz)
+{
+	struct statfs tmp;
+
+	tmp.f_type = CODA_SUPER_MAGIC;
+	tmp.f_bsize = 1024;
+	tmp.f_blocks = 9000000;
+	tmp.f_bfree = 9000000;
+	tmp.f_bavail = 9000000 ;
+	tmp.f_files = 9000000;
+	tmp.f_ffree = 9000000;
+	tmp.f_namelen = 0;
+	copy_to_user(buf, &tmp, bufsiz);
+	return 0; 
+}
+
+
+/* init_coda: used by filesystems.c to register coda */
+
+struct file_system_type coda_fs_type = {
+   "coda", 0, coda_read_super, NULL
+};
+
+int init_coda_fs(void)
+{
+	return register_filesystem(&coda_fs_type);
+}
+
+/* MODULE stuff is in psdev.c */
+
+/*  helpers */
+static inline struct vcomm *coda_psinode2vcomm(struct inode *inode) 
+{
+        
+	unsigned int minor = MINOR(inode->i_rdev);
+	CDEBUG(D_PSDEV,"minor %d\n", minor);
+	if ( minor < MAX_CODADEVS ) 
+	      return &(psdev_vcomm[minor]);
+	else
+	      return NULL;
+}
+
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode) 
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+
+	CDEBUG(D_PSDEV,"minor %d\n", minor);
+	if ( (minor >= 0) && (minor < MAX_CODADEVS)) 
+	        return &(coda_super_info[minor]);
+	else
+	        return NULL;
+}
+
+/* name lookup for psdev passed in by mount */
+static int coda_get_psdev(void *data, struct inode **res_dev)
+{
+        char **psdev_path;
+        struct inode *psdev = 0;
+	struct dentry *ent=NULL;
+
+ 
+	if ( ! data ) { 
+		printk("coda_get_psdev: no data!\n");
+		return 1;
+	} 
+
+	psdev_path = data;
+        ent = namei((char *) *psdev_path);
+        if (IS_ERR(ent)) {
+		printk("namei error %ld for %d\n", PTR_ERR(ent), 
+		       (int) psdev_path);
+		return 1;
+        }
+	psdev = ent->d_inode;
+
+        if (!S_ISCHR(psdev->i_mode)) {
+		printk("not a character device\n");
+		return 1;
+        }
+	CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n", 
+	       MAJOR(psdev->i_rdev), 
+	       MINOR(psdev->i_rdev), psdev->i_count);
+        
+        if (MAJOR(psdev->i_rdev) != CODA_PSDEV_MAJOR) {
+		printk("device %d not a Coda PSDEV device\n", 
+		       MAJOR(psdev->i_rdev));
+		return 1;
+        }
+
+        if (MINOR(psdev->i_rdev) >= MAX_CODADEVS) { 
+		printk("minor %d not an allocated Coda PSDEV\n", 
+		       psdev->i_rdev);
+		return 1;
+        }
+
+        if (psdev->i_count < 1) {
+		printk("coda device minor %d not open (i_count = %d)\n", 
+		       MINOR(psdev->i_rdev), psdev->i_count);
+		return 1;
+        }
+        
+        *res_dev = psdev;
+	EXIT;  
+        return 0;
+}
diff -urN linux-2.1.89.orig/fs/coda/psdev.c linux/fs/coda/psdev.c
--- linux-2.1.89.orig/fs/coda/psdev.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/psdev.c	Sun Mar 15 22:00:07 1998
@@ -447,7 +447,7 @@
 int init_module(void)
 {
   int status;
-  printk(KERN_INFO "Coda Kernel/User communications module 1.0\n");
+  printk(KERN_INFO "Coda Kernel/User communications module 2.0\n");
 
   status = init_coda_psdev();
   if ( status ) {
diff -urN linux-2.1.89.orig/fs/coda/psdev.c linux/fs/coda/psdev.c
--- linux-2.1.89.orig/fs/coda/psdev.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/psdev.c	Mon Mar 16 01:34:06 1998
@@ -65,7 +65,7 @@
 /* statistics */
 struct coda_upcallstats coda_callstats;
 int           coda_hard = 0;  /* introduces a timeout on upcalls */
-unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */
+unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
 extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
 struct vcomm psdev_vcomm[MAX_CODADEVS];
 
@@ -447,7 +447,7 @@
 int init_module(void)
 {
   int status;
-  printk(KERN_INFO "Coda Kernel/User communications module 1.0\n");
+  printk(KERN_INFO "Coda Kernel/User communications module 2.0\n");
 
   status = init_coda_psdev();
   if ( status ) {
diff -urN linux-2.1.89.orig/fs/coda/upcall.c linux/fs/coda/upcall.c
--- linux-2.1.89.orig/fs/coda/upcall.c	Wed Mar  4 18:14:32 1998
+++ linux/fs/coda/upcall.c	Mon Mar 16 01:35:00 1998
@@ -500,7 +500,6 @@
         union outputArgs *outp;
         int insize, outsize, error;
 	int iocsize;
-	char str[50];
 
 	insize = VC_MAXMSGSIZE;
 	UPARG(CFS_IOCTL);
@@ -587,7 +586,6 @@
 static inline void coda_waitfor_upcall(struct vmsg *vmp)
 {
 	struct wait_queue	wait = { current, NULL };
-	old_sigset_t pending;
 
 	vmp->vm_posttime = jiffies;
 
@@ -608,13 +606,9 @@
 		if ( jiffies > vmp->vm_posttime + coda_timeout * HZ )
 			break; 
 				
-		spin_lock_irq(&current->sigmask_lock);
-		pending = current->blocked.sig[0] & current->signal.sig[0];
-		spin_unlock_irq(&current->sigmask_lock);
-
 		/* if this process really wants to die, let it go */
-		if ( sigismember(&pending, SIGKILL) ||
-		     sigismember(&pending, SIGINT) )
+		if ( sigismember(&current->signal, SIGKILL) ||
+		     sigismember(&current->signal, SIGINT) )
 			break;
 		else 
 			schedule();
@@ -765,10 +759,14 @@
  *                  This call is a result of token expiration.
  *
  * The next arise as the result of callbacks on a file or directory.
- * CFS_ZAPDIR    -- flush the attributes for the dir from its cnode.
- *                  Zap all children of this directory from the namecache.
  * CFS_ZAPFILE   -- flush the cached attributes for a file.
- * CFS_ZAPVNODE  -- intended to be a zapfile for just one cred. Not used?
+
+ * CFS_ZAPDIR    -- flush the attributes for the dir and
+ *                  force a new lookup for all the children
+                    of this dir.
+
+ * CFS_ZAPVNODE  -- intended to be a zapfile for just one cred. 
+                    Not used?
  *
  * The next is a result of Venus detecting an inconsistent file.
  * CFS_PURGEFID  -- flush the attribute for the file
@@ -803,53 +801,48 @@
 	    return(0);
     }
     case CFS_ZAPDIR : {
+	    struct inode *inode;
 	    ViceFid *fid = &out->cfs_zapdir.CodaFid;
-	    char str[50];
 	    if ( !fid ) {
 		    printk("ZAPDIR: Null fid\n");
 		    return 0;
 	    }
 	    CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
 	    clstats(CFS_ZAPDIR);
-	    coda_zapfid(fid, sb, C_ZAPDIR);
-	    return(0);
-    }
-    case CFS_ZAPVNODE : {
-	    ViceFid *fid = &out->cfs_zapvnode.VFid;
-	    char str[50];
-	    struct coda_cred *cred = &out->cfs_zapvnode.cred;
-	    if ( !fid || !cred ) {
-		    printk("ZAPVNODE: Null fid or cred\n");
-		    return 0;
-	    }
-	    CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid));
-	    coda_zapfid(fid, sb, C_ZAPFID);
-	    coda_cache_clear_cred(sb, cred);
-	    clstats(CFS_ZAPVNODE);
+	    inode = coda_fid_to_inode(fid, sb);
+	    coda_flag_inode(inode, C_VATTR);
+	    coda_cache_clear_inode(inode);
+	    coda_flag_alias_children(inode, C_PURGE);
 	    return(0);
     }
+
+    case CFS_ZAPVNODE : 
     case CFS_ZAPFILE : {
+	    struct inode *inode;
 	    struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
-	    char str[50];
 	    clstats(CFS_ZAPFILE);
 	    if ( !fid ) {
 		    printk("ZAPFILE: Null fid\n");
 		    return 0;
 	    }
 	    CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
-	    coda_zapfid(fid, sb, C_ZAPFID);
+	    inode = coda_fid_to_inode(fid, sb);
+	    coda_flag_inode(inode, C_VATTR);
+	    coda_cache_clear_inode(inode);
 	    return 0;
     }
     case CFS_PURGEFID : {
+	    struct inode *inode;
 	    ViceFid *fid = &out->cfs_purgefid.CodaFid;
-	    char str[50];
 	    if ( !fid ) {
 		    printk("PURGEFID: Null fid\n");
 		    return 0;
 	    }
 	    CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
 	    clstats(CFS_PURGEFID);
-	    coda_zapfid(fid, sb, C_ZAPDIR);
+	    inode = coda_fid_to_inode(fid, sb);
+	    coda_flag_inode(inode, C_PURGE);
+	    coda_cache_clear_inode(inode);
 	    return 0;
     }
     case CFS_REPLACE : {
diff -urN linux-2.1.89.orig/include/linux/coda.h linux/include/linux/coda.h
--- linux-2.1.89.orig/include/linux/coda.h	Wed Mar  4 18:14:32 1998
+++ linux/include/linux/coda.h	Sun Mar 15 23:31:15 1998
@@ -587,9 +587,9 @@
 };
 
 /* 
- * Occasionally, don't cache the fid returned by CFS_LOOKUP. For instance, if
- * the fid is inconsistent. This case is handled by setting the top bit of the
- * return result parameter.
+ * Occasionally, we don't cache the fid returned by CFS_LOOKUP. 
+ * For instance, if the fid is inconsistent. 
+ * This case is handled by setting the top bit of the type result parameter.
  */
 #define CFS_NOCACHE          0x80000000
 
diff -urN linux-2.1.89.orig/include/linux/coda_cache.h linux/include/linux/coda_cache.h
--- linux-2.1.89.orig/include/linux/coda_cache.h	Wed Mar  4 18:14:32 1998
+++ linux/include/linux/coda_cache.h	Sun Mar 15 22:00:37 1998
@@ -21,19 +21,16 @@
 	struct coda_cred   cc_cred;
 };
 
-void coda_ccinsert(struct coda_cache *el, struct super_block *sb);
-void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp);
-void coda_ccremove(struct coda_cache *el);
-void coda_cnremove(struct coda_cache *el);
-void coda_cache_create(struct inode *inode, int mask);
-struct coda_cache *coda_cache_find(struct inode *inode);
+/* credential cache */
 void coda_cache_enter(struct inode *inode, int mask);
-void coda_cache_clear_cnp(struct coda_inode_info *cnp);
+void coda_cache_clear_inode(struct inode *);
 void coda_cache_clear_all(struct super_block *sb);
 void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred);
 int coda_cache_check(struct inode *inode, int mask);
-void coda_dentry_delete(struct dentry *dentry);
-void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag);
+
+/* for downcalls and attributes and lookups */
+void coda_flag_inode(struct inode *inode, int flag);
+void coda_flag_alias_children(struct inode *inode, int flag);
 
 
 /*
diff -urN linux-2.1.89.orig/include/linux/coda_fs_i.h linux/include/linux/coda_fs_i.h
--- linux-2.1.89.orig/include/linux/coda_fs_i.h	Wed Mar  4 18:14:32 1998
+++ linux/include/linux/coda_fs_i.h	Sun Mar 15 23:35:20 1998
@@ -17,7 +17,7 @@
 
 #define CODA_CNODE_MAGIC        0x47114711
 /*
- * smb fs inode data (in memory only)
+ * coda fs inode data
  */
 struct coda_inode_info {
         struct ViceFid     c_fid;	/* Coda identifier */
@@ -36,16 +36,13 @@
 #define C_VATTR       0x1         /* Validity of vattr in the cnode */
 #define C_SYMLINK     0x2         /* Validity of symlink pointer in the cnode */
 #define C_DYING       0x4	  /* Set for outstanding cnodes from venus (which died) */
-#define C_ZAPFID      0x8
+#define C_PURGE      0x8
 #define C_ZAPDIR      0x10
 #define C_INITED      0x20
 
 int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
-
-/* inode to cnode */
-#define ITOC(inode) ((struct coda_inode_info *)&((inode)->u.coda_i))
 
 
 #endif
diff -urN linux-2.1.89.orig/include/linux/coda_linux.h linux/include/linux/coda_linux.h
--- linux-2.1.89.orig/include/linux/coda_linux.h	Wed Mar  4 18:14:32 1998
+++ linux/include/linux/coda_linux.h	Sun Mar 15 23:35:28 1998
@@ -36,6 +36,7 @@
 int coda_open(struct inode *i, struct file *f);
 int coda_release(struct inode *i, struct file *f);
 int coda_permission(struct inode *inode, int mask);
+int coda_revalidate_inode(struct dentry *);
 
 /* global variables */
 extern int coda_debug;
@@ -43,10 +44,13 @@
 extern int coda_access_cache;
 
 /* this file:  heloers */
+static __inline__ struct ViceFid *coda_i2f(struct inode *);
 char *coda_f2s(ViceFid *f);
 int coda_isroot(struct inode *i);
 int coda_fid_is_volroot(struct ViceFid *);
 int coda_iscontrol(const char *name, size_t length);
+
+
 void coda_load_creds(struct coda_cred *cred);
 int coda_mycred(struct coda_cred *);
 void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
@@ -111,5 +115,19 @@
 
 
 #define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0)
+
+/* inode to cnode */
+
+static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
+{
+	return &(inode->u.coda_i.c_fid);
+}
+
+#define ITOC(inode) (&((inode)->u.coda_i))
+
+
+
+
+
 
 #endif
Received on 1998-03-16 02:11:57