diff --git a/acinclude.m4 b/acinclude.m4 index f4cc6420c2..667a04190b 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -902,6 +902,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) LINUX_KEY_ALLOC_NEEDS_CRED LINUX_INIT_WORK_HAS_DATA LINUX_REGISTER_SYSCTL_TABLE_NOFLAG + LINUX_HAVE_DCACHE_LOCK dnl If we are guaranteed that keyrings will work - that is dnl a) The kernel has keyrings enabled diff --git a/src/afs/LINUX/osi_vcache.c b/src/afs/LINUX/osi_vcache.c index 10fb5cf068..21ad7c2097 100644 --- a/src/afs/LINUX/osi_vcache.c +++ b/src/afs/LINUX/osi_vcache.c @@ -18,6 +18,7 @@ osi_TryEvictVCache(struct vcache *avc, int *slept) { int code; struct dentry *dentry; + struct inode *inode = AFSTOV(avc); struct list_head *cur, *head; /* First, see if we can evict the inode from the dcache */ @@ -25,8 +26,10 @@ osi_TryEvictVCache(struct vcache *avc, int *slept) { *slept = 1; ReleaseWriteLock(&afs_xvcache); AFS_GUNLOCK(); + +#if defined(HAVE_DCACHE_LOCK) spin_lock(&dcache_lock); - head = &(AFSTOV(avc))->i_dentry; + head = &inode->i_dentry; restart: cur = head; @@ -35,7 +38,6 @@ restart: if (d_unhashed(dentry)) continue; - dget_locked(dentry); spin_unlock(&dcache_lock); @@ -49,6 +51,35 @@ restart: goto restart; } spin_unlock(&dcache_lock); +#else /* HAVE_DCACHE_LOCK */ + spin_lock(&inode->i_lock); + head = &inode->i_dentry; + +restart: + cur = head; + while ((cur = cur->next) != head) { + dentry = list_entry(cur, struct dentry, d_alias); + + spin_lock(&dentry->d_lock); + if (d_unhashed(dentry)) { + spin_unlock(&dentry->d_lock); + continue; + } + spin_unlock(&dentry->d_lock); + dget(dentry); + + spin_unlock(&inode->i_lock); + if (d_invalidate(dentry) == -EBUSY) { + dput(dentry); + /* perhaps lock and try to continue? (use cur as head?) */ + goto inuse; + } + dput(dentry); + spin_lock(&inode->i_lock); + goto restart; + } + spin_unlock(&inode->i_lock); +#endif /* HAVE_DCACHE_LOCK */ inuse: AFS_GLOCK(); ObtainWriteLock(&afs_xvcache, 733); diff --git a/src/afs/afs_daemons.c b/src/afs/afs_daemons.c index 81f9c5c140..f14c75c44d 100644 --- a/src/afs/afs_daemons.c +++ b/src/afs/afs_daemons.c @@ -389,7 +389,11 @@ afs_CheckRootVolume(void) dp = d_find_alias(AFSTOV(afs_globalVp)); #if defined(AFS_LINUX24_ENV) +#if defined(HAVE_DCACHE_LOCK) spin_lock(&dcache_lock); +#else + spin_lock(&AFSTOV(vcp)->i_lock); +#endif #if defined(AFS_LINUX26_ENV) spin_lock(&dp->d_lock); #endif @@ -401,7 +405,11 @@ afs_CheckRootVolume(void) #if defined(AFS_LINUX26_ENV) spin_unlock(&dp->d_lock); #endif +#if defined(HAVE_DCACHE_LOCK) spin_unlock(&dcache_lock); +#else + spin_unlock(&AFSTOV(vcp)->i_lock); +#endif #endif dput(dp); diff --git a/src/cf/linux-test4.m4 b/src/cf/linux-test4.m4 index 50814024f6..945b4f091c 100644 --- a/src/cf/linux-test4.m4 +++ b/src/cf/linux-test4.m4 @@ -581,3 +581,14 @@ AC_DEFUN([LINUX_HAVE_TRY_TO_FREEZE], [ []) ]) + +AC_DEFUN([LINUX_HAVE_DCACHE_LOCK], [ + AC_CHECK_LINUX_BUILD([for dcache_lock], + [ac_cv_linux_have_dcache_lock], + [#include ], + [printk("%p", &dcache_lock);], + [HAVE_DCACHE_LOCK], + [define if dcache_lock exists], + []) +]) +