diff --git a/src/afs/LINUX/osi_compat.h b/src/afs/LINUX/osi_compat.h index 3588799b27..44bcb440ef 100644 --- a/src/afs/LINUX/osi_compat.h +++ b/src/afs/LINUX/osi_compat.h @@ -49,6 +49,10 @@ typedef struct path afs_linux_path_t; # define d_alias d_u.d_alias #endif +#if defined(STRUCT_DENTRY_HAS_D_U_D_CHILD) +# define d_child d_u.d_child +#endif + #if defined(STRUCT_FILE_HAS_F_PATH) # if !defined(f_dentry) # define f_dentry f_path.dentry diff --git a/src/afs/LINUX/osi_vcache.c b/src/afs/LINUX/osi_vcache.c index 38fd3b4b8d..897fd37abd 100644 --- a/src/afs/LINUX/osi_vcache.c +++ b/src/afs/LINUX/osi_vcache.c @@ -272,3 +272,56 @@ osi_ShouldDeferRemunlink(struct vcache *avc) } return 0; } + +/* + * Invalidate Linux-specific cached data for the given vcache. This doesn't + * handle anything with the OpenAFS disk cache or stat cache, etc; those things + * are handled by afs_ResetVCache(). + * + * The Linux-specific stuff we clear here is dcache entries. This means + * clearing d_time in all dentry's for the vcache, and all immediate children + * (for directories). We don't call d_invalidate() or any similar functions + * here; let afs_linux_dentry_revalidate() figure out what to do with the + * invalid dentry's whenever they are accessed. + * + * @pre AFS_GLOCK held + */ +void +osi_ResetVCache(struct vcache *avc) +{ + struct dentry *dp; + struct inode *ip = AFSTOV(avc); +#if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE) + struct hlist_node *node; +#endif + + AFS_GUNLOCK(); + + afs_d_alias_lock(ip); + + afs_d_alias_foreach(dp, ip, node) { + spin_lock(&dp->d_lock); + + /* Invalidate the dentry for the given vcache. */ + dp->d_time = 0; + + if (S_ISDIR(ip->i_mode)) { + /* + * If the vcache is a dir, also invalidate all of its children. + * Note that we can lock child->d_lock while dp->d_lock is held, + * because 'dp' is an ancestor of 'child'. + */ + struct dentry *child; + list_for_each_entry(child, &dp->d_subdirs, d_child) { + spin_lock(&child->d_lock); + child->d_time = 0; + spin_unlock(&child->d_lock); + } + } + + spin_unlock(&dp->d_lock); + } + afs_d_alias_unlock(ip); + + AFS_GLOCK(); +} diff --git a/src/afs/afs_osi.h b/src/afs/afs_osi.h index f92c3f9391..79c44a985e 100644 --- a/src/afs/afs_osi.h +++ b/src/afs/afs_osi.h @@ -149,6 +149,12 @@ extern void osi_PrePopulateVCache(struct vcache *); extern void osi_PostPopulateVCache(struct vcache *); extern void osi_AttachVnode(struct vcache *, int seq); +#ifdef AFS_LINUX_ENV +extern void osi_ResetVCache(struct vcache *avc); +#else +# define osi_ResetVCache(avc) do { } while (0) +#endif + /** * Increment the refcount on the given vcache. * diff --git a/src/afs/afs_vcache.c b/src/afs/afs_vcache.c index 6d22f6f609..5644d61e47 100644 --- a/src/afs/afs_vcache.c +++ b/src/afs/afs_vcache.c @@ -2561,6 +2561,8 @@ afs_ResetVCache(struct vcache *avc, afs_ucred_t *acred, afs_int32 skipdnlc) afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1); avc->linkData = NULL; } + + osi_ResetVCache(avc); } /*! diff --git a/src/cf/linux-kernel-struct.m4 b/src/cf/linux-kernel-struct.m4 index 8082308e8c..ce7037e436 100644 --- a/src/cf/linux-kernel-struct.m4 +++ b/src/cf/linux-kernel-struct.m4 @@ -14,6 +14,9 @@ AC_CHECK_LINUX_STRUCT([backing_dev_info], [name], AC_CHECK_LINUX_STRUCT([cred], [session_keyring], [cred.h]) AC_CHECK_LINUX_STRUCT([ctl_table], [ctl_name], [sysctl.h]) AC_CHECK_LINUX_STRUCT([dentry], [d_u.d_alias], [dcache.h]) +dnl linux 2.6.16 moved dentry->d_child to dentry->d_u.d_child +dnl linux 3.19 moved it back to dentry->d_child +AC_CHECK_LINUX_STRUCT([dentry], [d_u.d_child], [dcache.h]) AC_CHECK_LINUX_STRUCT([dentry_operations], [d_automount], [dcache.h]) AC_CHECK_LINUX_STRUCT([group_info], [gid], [cred.h]) AC_CHECK_LINUX_STRUCT([inode], [i_alloc_sem], [fs.h])