#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 */
} /*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
*
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)
}
}
#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) {
code = afs_FlushVCache(tvc, &fv_slept);