diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 7d81d82b89..d8e08fc244 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -525,97 +525,6 @@ afs_RemoveVCB(afid) } /*afs_RemoveVCB*/ -#if defined(AFS_LINUX22_ENV) -/* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by - * children of the dentry - * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires - * AFS_GLOCK, so it can call dput, which may call iput, but - * keeps afs_xvcache exclusively. - * - * Tree traversal algorithm from fs/dcache.c: select_parent() - */ -static void afs_TryFlushDcacheChildren(struct dentry *parent) -{ - struct dentry *this_parent = parent; - struct list_head *next; - - repeat: - next = this_parent->d_subdirs.next; - resume: - while (next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); - - next = tmp->next; - if (!DCOUNT(dentry) && !dentry->d_inode) { - DGET(dentry); - DUNLOCK(); - AFS_GUNLOCK(); - d_drop(dentry); - dput(dentry); - AFS_GLOCK(); - DLOCK(); - goto repeat; - } - - /* - * Descend a level if the d_subdirs list is non-empty. - */ - if (!list_empty(&dentry->d_subdirs)) { - this_parent = dentry; - goto repeat; - } - } - - /* - * All done at this level ... ascend and resume the search. - */ - if (this_parent != parent) { - next = this_parent->d_child.next; - this_parent = this_parent->d_parent; - goto resume; - } -} - -/* afs_TryFlushDcache -- Shakes loose vcache references held by the Linux - * dcache. - * - * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires - * AFS_GLOCK, so it can call dput, which may call iput, but - * keeps afs_xvcache exclusively. - */ -static void afs_TryFlushDcache(struct vcache *vcp) -{ - struct inode *ip = (struct inode *) vcp; - - DLOCK(); - retry: - if (!list_empty(&ip->i_dentry)) { - struct list_head *cur, *head = &ip->i_dentry; - cur = head; - while ((cur = cur->next) != head) { - struct dentry *dentry = list_entry(cur, struct dentry, d_alias); - - if (DCOUNT(dentry)) { - afs_TryFlushDcacheChildren(dentry); - } - - if (!DCOUNT(dentry)) { - DGET(dentry); - DUNLOCK(); - AFS_GUNLOCK(); - d_drop(dentry); - dput(dentry); - AFS_GLOCK(); - DLOCK(); - goto retry; - } - } - DUNLOCK(); - } -} -#endif - /* * afs_NewVCache * @@ -650,6 +559,63 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp, int code, fv_slept; AFS_STATCNT(afs_NewVCache); +#ifdef AFS_LINUX22_ENV + if (!freeVCList) { + /* Free some if possible. */ + struct afs_q *tq, *uq; + int i; char *panicstr; + int vmax = 2 * afs_cacheStats; + int vn = VCACHE_FREE; + + i = 0; + for(tq = VLRU.prev; tq != &VLRU && vn > 0; tq = uq) { + tvc = QTOV(tq); + uq = QPrev(tq); + if (tvc->states & CVFlushed) + refpanic ("CVFlushed on VLRU"); + else if (i++ > vmax) + refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)"); + else if (QNext(uq) != tq) + refpanic ("VLRU inconsistent"); + + if (tvc == afs_globalVp) + continue; + + if ( VREFCOUNT(tvc) && tvc->opens == 0 ) { + struct inode *ip = (struct inode*)tvc; + if (list_empty(&ip->i_dentry)) { + vn --; + } + else { + struct list_head *cur; + struct list_head *head = &ip->i_dentry; + int all = 1; + restart: + DLOCK(); + cur = head; + while ((cur = cur->next) != head) { + struct dentry *dentry = list_entry(cur, struct dentry, d_alias); + if (!DCOUNT(dentry)) { + AFS_GUNLOCK(); + DGET(dentry); + DUNLOCK(); + d_drop(dentry); + dput(dentry); + AFS_GLOCK(); + goto restart; + } + else { + all = 0; + } + } + DUNLOCK(); + if (all) vn --; + } + } + if (tq == uq) break; + } + } +#endif /* AFS_LINUX22_ENV */ #ifdef AFS_OSF_ENV #ifdef AFS_OSF30_ENV if (afs_vcount >= afs_maxvcount) @@ -740,10 +706,6 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp, continue; /* start over - may have raced. */ } } -#endif -#if defined(AFS_LINUX22_ENV) - if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0) - afs_TryFlushDcache(tvc); #endif if (VREFCOUNT(tvc) == 0 && tvc->opens == 0 && (tvc->states & CUnlinkedDel) == 0) {