linux-newvcache-clean-up-dentries-20020115

With work and feedback from Omkar Sathe <somkar@in.ibm.com> and
Srikanth Vishwanathan <vsrikanth@in.ibm.com>
This commit is contained in:
Ted Anderson 2002-01-16 02:03:49 +00:00 committed by Derrick Brashear
parent 6fb7ad6797
commit d581ab206e
2 changed files with 102 additions and 73 deletions

View File

@ -533,11 +533,19 @@ struct SimpleLocks {
#define VREFCOUNT_SET(v, c) atomic_set(&((vnode_t *) v)->v_count, c)
#define VREFCOUNT_DEC(v) atomic_dec(&((vnode_t *) v)->v_count)
#define VREFCOUNT_INC(v) atomic_inc(&((vnode_t *) v)->v_count)
#define DLOCK() spin_lock(&dcache_lock)
#define DUNLOCK() spin_unlock(&dcache_lock)
#define DGET(d) dget_locked(d)
#define DCOUNT(d) atomic_read(&(d)->d_count)
#else
#define VREFCOUNT(v) ((v)->vrefCount)
#define VREFCOUNT_SET(v, c) (v)->vrefCount = c;
#define VREFCOUNT_DEC(v) (v)->vrefCount--;
#define VREFCOUNT_INC(v) (v)->vrefCount++;
#define DLOCK()
#define DUNLOCK()
#define DGET(d) dget(d)
#define DCOUNT(d) ((d)->d_count)
#endif
#define AFS_MAXDV 0x7fffffff /* largest dataversion number */

View File

@ -525,7 +525,97 @@ 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
*
@ -560,79 +650,6 @@ 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;
AFS_GUNLOCK();
shrink_dcache_sb(afs_globalVFS);
AFS_GLOCK();
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:
#if defined(AFS_LINUX24_ENV)
spin_lock(&dcache_lock);
#endif
cur = head;
while ((cur = cur->next) != head) {
struct dentry *dentry = list_entry(cur, struct dentry, d_alias);
#if defined(AFS_LINUX24_ENV)
if (!atomic_read(&dentry->d_count)) {
#else
if (!dentry->d_count) {
#endif
AFS_GUNLOCK();
#if defined(AFS_LINUX24_ENV)
dget_locked(dentry);
spin_unlock(&dcache_lock);
#else
dget(dentry);
#endif
d_drop(dentry);
dput(dentry);
AFS_GLOCK();
goto restart;
}
else {
all = 0;
}
}
#if defined(AFS_LINUX24_ENV)
spin_unlock(&dcache_lock);
#endif
if (all) vn --;
}
}
if (tq == uq) break;
}
}
#endif /* AFS_LINUX22_ENV */
#ifdef AFS_OSF_ENV
#ifdef AFS_OSF30_ENV
if (afs_vcount >= afs_maxvcount)
@ -723,6 +740,10 @@ 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) {