patch-2.1.109 linux/fs/coda/cache.c

Next file: linux/fs/coda/cnode.c
Previous file: linux/drivers/video/virgefb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.108/linux/fs/coda/cache.c linux/fs/coda/cache.c
@@ -37,8 +37,10 @@
 {
 	struct coda_sb_info *sbi = coda_sbp(sb);
 	ENTRY;
-	if ( !sbi ||  !el) {
-		printk("coda_ccinsert: NULL sbi or el!\n");
+	/* third test verifies cc was initialized before adding it 
+	   to the sblist. Probably superfluous */
+	if ( !sbi || !el || !list_empty(&el->cc_cclist) ) {
+		printk("coda_ccinsert: NULL sbi or el->cc_cclist not empty!\n");
 		return ;
 	}
 
@@ -49,8 +51,8 @@
 static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
 {
 	ENTRY;
-	if ( !cii ||  !el) {
-		printk("coda_cninsert: NULL cii or el!\n");
+	if ( !cii ||  !el || ! list_empty(&el->cc_cnlist)) {
+		printk("coda_cninsert: NULL cii or el->cc_cnlist not empty!\n");
 		return ;
 	}
 	list_add(&el->cc_cnlist, &cii->c_cnhead);
@@ -60,20 +62,20 @@
 static void coda_ccremove(struct coda_cache *el)
 {
 	ENTRY;
-        if (el->cc_cclist.next && el->cc_cclist.prev)
+        if ( ! list_empty(&el->cc_cclist) )
 	        list_del(&el->cc_cclist);
 	else
-		printk("coda_cnremove: trying to remove 0 entry!");
+		printk("coda_cnremove: loose cc entry!");
 }
 
 /* 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)
+	if ( ! list_empty(&el->cc_cnlist) )
 		list_del(&el->cc_cnlist);
 	else
-		printk("coda_cnremove: trying to remove 0 entry!");
+		printk("coda_cnremove: loose cn entry!");
 }
 
 /* create a new cache entry and enlist it */
@@ -83,12 +85,17 @@
 	struct super_block *sb = inode->i_sb;
 	struct coda_cache *cc = NULL;
 	ENTRY;
+
 	CODA_ALLOC(cc, struct coda_cache *, sizeof(*cc));
 
 	if ( !cc ) {
 		printk("Out of memory in coda_cache_enter!\n");
 		return;
 	}
+
+	INIT_LIST_HEAD(&cc->cc_cclist);
+	INIT_LIST_HEAD(&cc->cc_cnlist);
+
 	coda_load_creds(&cc->cc_cred);
 	cc->cc_mask = mask;
 	coda_cninsert(cc, cii);
@@ -227,15 +234,58 @@
 }
 
 
-/*   DCACHE & ZAPPING related stuff */
-
-/* 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
+/* Purging dentries and children */
+/* The following routines drop dentries which are not
+   in use and flag dentries which are in use to be 
+   zapped later.
+
+   The flags are detected by:
+   - coda_dentry_revalidate (for lookups) if the flag is C_PURGE
+   - coda_dentry_delete: to remove dentry from the cache when d_count
+     falls to zero
    - an inode method coda_revalidate (for attributes) if the 
-     flag is C_ATTR
+     flag is C_VATTR
 */
+
+/* 
+   Some of this is pretty scary: what can disappear underneath us?
+   - shrink_dcache_parent calls on purge_one_dentry which is safe:
+     it only purges children.
+   - dput is evil since it  may recurse up the dentry tree
+ */
+
+void coda_purge_dentries(struct inode *inode)
+{
+	struct list_head *tmp, *head = &inode->i_dentry;
+
+	if (!inode)
+		return ;
+
+	/* better safe than sorry: dput could kill us */
+	iget(inode->i_sb, inode->i_ino);
+	/* catch the dentries later if some are still busy */
+	coda_flag_inode(inode, C_PURGE);
+
+restart:
+	tmp = head;
+	while ((tmp = tmp->next) != head) {
+		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+		if (!dentry->d_count) {
+			CDEBUG(D_DOWNCALL, 
+			       "coda_free_dentries: freeing %s/%s, i_count=%d\n",
+			       dentry->d_parent->d_name.name, dentry->d_name.name, 
+			       inode->i_count);
+			dget(dentry);
+			d_drop(dentry);
+			dput(dentry);
+			goto restart;
+		}
+			
+	}
+	iput(inode);
+}
+
+/* this won't do any harm: just flag all children */
 static void coda_flag_children(struct dentry *parent, int flag)
 {
 	struct list_head *child;
@@ -244,37 +294,44 @@
 	child = parent->d_subdirs.next;
 	while ( child != &parent->d_subdirs ) {
 		de = list_entry(child, struct dentry, d_child);
-		coda_flag_inode(de->d_inode, flag);
-		CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag, 
+		child = child->next;
+		/* don't know what to do with negative dentries */
+		if ( ! de->d_inode ) 
+			continue;
+		CDEBUG(D_DOWNCALL, "%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); 
+		coda_flag_inode(de->d_inode, flag);
 	}
 	return; 
 }
 
-
-void coda_flag_alias_children(struct inode *inode, int flag)
+void coda_purge_children(struct inode *inode)
 {
 	struct list_head *alias;
 	struct dentry *alias_de;
 
 	if ( !inode ) 
 		return; 
+
+	if (list_empty(&inode->i_dentry))
+	        return; 
+
+	/* I believe that shrink_dcache_parent will not
+	   remove dentries from the alias list. If it 
+	   does we are toast. 
+	*/
 	alias = inode->i_dentry.next; 
 	while ( alias != &inode->i_dentry ) {
 		alias_de = list_entry(alias, struct dentry, d_alias);
-		if ( !alias_de ) {
-			printk("Null alias list for inode %ld\n", inode->i_ino);
-			return;
-		}
-		coda_flag_children(alias_de, flag);
-		alias= alias->next;
+		coda_flag_children(alias_de, C_PURGE);
+		shrink_dcache_parent(alias_de);
+		alias = alias->next;
 	}
+
 }
 
+/* this will not zap the inode away */
 void coda_flag_inode(struct inode *inode, int flag)
 {
 	struct coda_inode_info *cii;
@@ -283,11 +340,8 @@
 		CDEBUG(D_CACHE, " no inode!\n");
 		return;
 	}
+
 	cii = ITOC(inode);
 	cii->c_flags |= flag;
 }		
-
-
-
-
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov