From 229c0a034ad12cddfe12e3b50519aebc105da4bb Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Fri, 15 Nov 2002 13:29:28 +0000 Subject: [PATCH] STABLE12-linux-dcache-flushing-experimental-20020819 shadow@dementia.org at least partly to blame. hold the dcache lock only briefly; instead put dcache entries to be junked onto a free list, by unhashing them, then grab the dcache lock, junk them, and release it. --- src/afs/afs_trace.et | 2 +- src/afs/afs_vcache.c | 136 ++++++++++++++++++++++++++++++------------- 2 files changed, 96 insertions(+), 42 deletions(-) diff --git a/src/afs/afs_trace.et b/src/afs/afs_trace.et index 2b9658304..24817af5a 100644 --- a/src/afs/afs_trace.et +++ b/src/afs/afs_trace.et @@ -131,6 +131,6 @@ error_table 2 ZCM ec CM_TRACE_RESIDCMD, "ResidencyCmd tvc 0x%x command %d fid (%d:%d.%d.%d)" ec CM_TRACE_DENTRYDELETE, "d_delete inode 0x%x d_name %s/%s" ec CM_TRACE_DENTRYIPUT, "d_iput inode 0x%x d_name %s/%s" - ec CM_TRACE_TRYFLUSHDCACHECHILDREN, "TryFlushDcacheChildren ip 0x%x" + ec CM_TRACE_TRYFLUSHDCACHECHILDREN, "TryFlushDcacheChildren ip 0x%x name %s parent %s" end diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 28857055c..5fa9e8978 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -467,6 +467,68 @@ static afs_int32 afs_QueueVCB(struct vcache *avc) } #ifdef AFS_LINUX22_ENV + +static void __shrink_dcache_parent(struct dentry * parent) +{ + struct dentry *this_parent = parent; + struct list_head *next; + int found = 0; + LIST_HEAD(afs_dentry_unused); + +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 (!atomic_read(&dentry->d_count)) { + list_del(&dentry->d_lru); + list_add(&dentry->d_lru, afs_dentry_unused.prev); + found++; + } + /* + * 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; + } + + for (;;) { + struct dentry *dentry; + struct list_head *tmp; + + tmp = afs_dentry_unused.prev; + + if (tmp == &afs_dentry_unused) + break; + list_del_init(tmp); + dentry = list_entry(tmp, struct dentry, d_lru); + + /* Unused dentry with a count? */ + if (atomic_read(&dentry->d_count)) + BUG(); + + DGET(dentry); + list_del_init(&dentry->d_hash); /* d_drop */ + DUNLOCK(); + dput(dentry); + DLOCK(); + if (!--found) + break; + } +} + /* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by * children of the dentry * @@ -485,51 +547,43 @@ static void afs_TryFlushDcacheChildren(struct vcache *tvc) struct list_head *head = &ip->i_dentry; struct dentry *dentry; + AFS_GUNLOCK(); restart: +#ifndef old_vcache_scheme DLOCK(); cur = head; while ((cur = cur->next) != head) { dentry = list_entry(cur, struct dentry, d_alias); -#ifdef notdef - if (DCOUNT(dentry)) { - this_parent = dentry; - repeat: - next = this_parent->d_subdirs.next; - resume: - while (next && next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dchld = list_entry(tmp, struct dentry, d_child); - - next = tmp->next; - if (!DCOUNT(dchld) && !dchld->d_inode) { - DGET(dchld); - AFS_GUNLOCK(); - DUNLOCK(); - d_drop(dchld); - dput(dchld); - AFS_GLOCK(); - DLOCK(); - goto repeat; - } - /* - * Descend a level if the d_subdirs list is non-empty. - */ - if (!list_empty(&dchld->d_subdirs)) { - this_parent = dchld; - goto repeat; - } - } - - /* - * All done at this level ... ascend and resume the search. - */ - if (this_parent != dentry) { - next = this_parent->d_child.next; - this_parent = this_parent->d_parent; - goto resume; - } - } -#endif + + afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN, + ICL_TYPE_POINTER, ip, + ICL_TYPE_STRING, dentry->d_parent->d_name.name, + ICL_TYPE_STRING, dentry->d_name.name); + + if (!list_empty(&dentry->d_hash) && !list_empty(&dentry->d_subdirs)) + __shrink_dcache_parent(dentry); + + if (!atomic_read(&dentry->d_count)) { + DGET(dentry); + list_del_init(&dentry->d_hash); /* d_drop */ + DUNLOCK(); + dput(dentry); + goto restart; + } + } + DUNLOCK(); + AFS_GLOCK(); +#else +restart: + DLOCK(); + cur = head; + while ((cur = cur->next) != head) { + dentry = list_entry(cur, struct dentry, d_alias); + + afs_Trace3(afs_iclSetp, CM_TRACE_TRYFLUSHDCACHECHILDREN, + ICL_TYPE_POINTER, ip, + ICL_TYPE_STRING, dentry->d_parent->d_name.name, + ICL_TYPE_STRING, dentry->d_name.name); if (!DCOUNT(dentry)) { AFS_GUNLOCK(); @@ -542,7 +596,7 @@ restart: } } DUNLOCK(); - +#endif } #endif /* AFS_LINUX22_ENV */ -- 2.39.5