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
- Lines: 204
- Date:
Fri Jul 10 15:33:37 1998
- Orig file:
v2.1.108/linux/fs/coda/cache.c
- Orig date:
Sun Jun 7 11:16:36 1998
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