From 73437ee7d469765df30285369301e3907fee0a3c Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Wed, 19 Jan 2005 22:46:06 +0000 Subject: [PATCH] linux26-vcache-reclaim-cleanup-20050119 "ok, if you ever drop dcache_lock you need to go to restart (i think that's pretty clear). shrink_dcache_parent() _might_ reduce a dentry count to 0. in the previous version, it seemed to make the assumption that this would always happen. if shrink_dcache_parent() is unsuccessful and the dentry is a directory, we cant restart. we would just find the the dentry again and do the same thing over (we could always d_drop but you shouldnt do this to active directories -- see d_invalidate). if we find a busy dentry, we abort all processing for this inode. going back to restart would find the same busy inode. (i suppose we could use a d_flag to keep track of which dentry has been shrunk. this has other trouble, like who resets the flag and when?) since we only do this for directories and d_alias typically only grows due to soft/hard links (as far as i can tell) this scheme seems reasonable." --- src/afs/afs_vcache.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 6e38da845d..1629bc6aa7 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -844,20 +844,44 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp) struct list_head *cur, *head = &(AFSTOI(tvc))->i_dentry; AFS_FAST_HOLD(tvc); AFS_GUNLOCK(); -shrink_restart: - DLOCK(); - cur=head; + +restart: + spin_lock(&dcache_lock); + cur = head; while ((cur = cur->next) != head) { dentry = list_entry(cur, struct dentry, d_alias); - if (!d_unhashed(dentry) && - !list_empty(&dentry->d_subdirs)) { + + if (d_unhashed(dentry)) + continue; + + dget_locked(dentry); + + if (!list_empty(&dentry->d_subdirs)) { DUNLOCK(); shrink_dcache_parent(dentry); - goto shrink_restart; + DLOCK(); } + + spin_lock(&dentry->d_lock); + if (atomic_read(&dentry->d_count) > 1) { + if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + dput(dentry); + goto inuse; + } + } + + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + dput(dentry); + goto restart; + } DUNLOCK(); - d_prune_aliases(AFSTOI(tvc)); +inuse: + AFS_GLOCK(); AFS_FAST_RELE(tvc); #else