#include "afs/sysincludes.h"
#include "afsincludes.h"
#include "afs/afs_stats.h"
-#include "afs/afs_osidnlc.h"
#include "h/mm.h"
#ifdef HAVE_MM_INLINE_H
#include "h/mm_inline.h"
afs_linux_dentry_revalidate(struct dentry *dp)
#endif
{
- char *name = NULL;
- cred_t *credp = crref();
struct vrequest treq;
- struct vcache *lookupvcp = NULL;
- int code, bad_dentry = 1;
- struct sysname_info sysState;
- struct vcache *vcp, *parentvcp;
-
- sysState.allocked = 0;
+ cred_t *credp = NULL;
+ struct vcache *vcp, *pvcp, *tvc = NULL;
+ int valid;
#ifdef AFS_LINUX24_ENV
lock_kernel();
AFS_GLOCK();
vcp = ITOAFS(dp->d_inode);
- parentvcp = ITOAFS(dp->d_parent->d_inode);
+ pvcp = ITOAFS(dp->d_parent->d_inode); /* dget_parent()? */
- /* If it's a negative dentry, then there's nothing to do. */
- if (!vcp || !parentvcp)
- goto done;
+ if (vcp) {
- /* If it is the AFS root, then there's no chance it needs
- * revalidating */
- if (vcp == afs_globalVp) {
- bad_dentry = 0;
- goto done;
- }
+ /* If it's the AFS root no chance it needs revalidating */
+ if (vcp == afs_globalVp)
+ goto good_dentry;
- if ((code = afs_InitReq(&treq, credp)))
- goto done;
-
- Check_AtSys(parentvcp, dp->d_name.name, &sysState, &treq);
- name = sysState.name;
-
- /* First try looking up the DNLC */
- if ((lookupvcp = osi_dnlc_lookup(parentvcp, name, WRITE_LOCK))) {
- /* Verify that the dentry does not point to an old inode */
- if (vcp != lookupvcp)
- goto done;
- /* Check and correct mvid */
- if (*name != '/' && vcp->mvstat == 2)
- check_bad_parent(dp);
- vcache2inode(vcp);
- bad_dentry = 0;
- goto done;
- }
+ /* check_bad_parent()? */
+
+#ifdef notdef
+ /* If the last looker changes, we should make sure the current
+ * looker still has permission to examine this file. This would
+ * always require a crref() which would be "slow".
+ */
+ if (vcp->last_looker != treq.uid) {
+ if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
+ goto bad_dentry;
+
+ vcp->last_looker = treq.uid;
+ }
+#endif
- /* A DNLC lookup failure cannot be trusted. Try a real lookup.
- Make sure to try the real name and not the @sys expansion;
- afs_lookup will expand @sys itself. */
-
- code = afs_lookup(parentvcp, dp->d_name.name, &lookupvcp, credp);
+ /* If the parent's DataVersion has changed or the vnode
+ * is longer valid, we need to do a full lookup. VerifyVCache
+ * isn't enough since the vnode may have been renamed.
+ */
+ if (hgetlo(pvcp->m.DataVersion) > dp->d_time || !(vcp->states & CStatd)) {
+
+ credp = crref();
+ if (afs_InitReq(&treq, credp))
+ goto bad_dentry;
+ afs_lookup(pvcp, dp->d_name.name, &tvc, credp);
+ if (!tvc || tvc != vcp)
+ goto bad_dentry;
+ if (afs_VerifyVCache(vcp, &treq)) /* update inode attributes */
+ goto bad_dentry;
+
+ dp->d_time = hgetlo(pvcp->m.DataVersion);
+ }
- /* Verify that the dentry does not point to an old inode */
- if (vcp != lookupvcp)
- goto done;
+ } else {
+ if (hgetlo(pvcp->m.DataVersion) > dp->d_time)
+ goto bad_dentry;
- bad_dentry = 0;
+ /* No change in parent's DataVersion so this negative
+ * lookup is still valid.
+ */
+ }
+
+ good_dentry:
+ valid = 1;
done:
/* Clean up */
- if (lookupvcp)
- afs_PutVCache(lookupvcp);
- if (sysState.allocked)
- osi_FreeLargeSpace(name);
-
+ if (tvc)
+ afs_PutVCache(tvc);
AFS_GUNLOCK();
+ if (credp)
+ crfree(credp);
- if (bad_dentry) {
+ if (!valid) {
shrink_dcache_parent(dp);
d_drop(dp);
}
-
#ifdef AFS_LINUX24_ENV
unlock_kernel();
#endif
- crfree(credp);
+ return valid;
- return !bad_dentry;
+ bad_dentry:
+ valid = 0;
+ goto done;
}
-#if !defined(AFS_LINUX26_ENV)
+#if !defined(AFS_LINUX24_ENV)
/* afs_dentry_iput */
static void
afs_dentry_iput(struct dentry *dp, struct inode *ip)
{
- int isglock;
-
- if (ICL_SETACTIVE(afs_iclSetp)) {
- isglock = ISAFS_GLOCK();
- if (!isglock) AFS_GLOCK();
- afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYIPUT, ICL_TYPE_POINTER, ip,
- ICL_TYPE_STRING, dp->d_parent->d_name.name,
- ICL_TYPE_STRING, dp->d_name.name);
- if (!isglock) AFS_GUNLOCK();
- }
-
osi_iput(ip);
}
#endif
static int
afs_dentry_delete(struct dentry *dp)
{
- int isglock;
- if (ICL_SETACTIVE(afs_iclSetp)) {
- isglock = ISAFS_GLOCK();
- if (!isglock) AFS_GLOCK();
- afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYDELETE, ICL_TYPE_POINTER,
- dp->d_inode, ICL_TYPE_STRING, dp->d_parent->d_name.name,
- ICL_TYPE_STRING, dp->d_name.name);
- if (!isglock) AFS_GUNLOCK();
- }
-
if (dp->d_inode && (ITOAFS(dp->d_inode)->states & CUnlinked))
return 1; /* bad inode? */
struct dentry_operations afs_dentry_operations = {
.d_revalidate = afs_linux_dentry_revalidate,
.d_delete = afs_dentry_delete,
-#if !defined(AFS_LINUX26_ENV)
+#if !defined(AFS_LINUX24_ENV)
.d_iput = afs_dentry_iput,
#endif
};
#endif
dp->d_op = &afs_dentry_operations;
+ dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
d_instantiate(dp, ip);
}
cred_t *credp = crref();
struct vcache *vcp = NULL;
const char *comp = dp->d_name.name;
+#if 1
+ struct dentry *res = 0;
+#endif
#if defined(AFS_LINUX26_ENV)
lock_kernel();
} else if (S_ISDIR(ip->i_mode)) {
ip->i_op = &afs_dir_iops;
ip->i_fop = &afs_dir_fops;
+ d_prune_aliases(ip);
+ res = d_find_alias(ip);
} else if (S_ISLNK(ip->i_mode)) {
ip->i_op = &afs_symlink_iops;
ip->i_data.a_ops = &afs_symlink_aops;
#endif
}
dp->d_op = &afs_dentry_operations;
+ dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
+#if defined(AFS_LINUX24_ENV)
+ if (res) {
+ if (d_unhashed(res))
+ d_rehash(res);
+ } else
+#endif
d_add(dp, AFSTOI(vcp));
#if defined(AFS_LINUX26_ENV)
/* It's ok for the file to not be found. That's noted by the caller by
* seeing that the dp->d_inode field is NULL.
*/
+#if defined(AFS_LINUX24_ENV)
+ if (code == 0)
+ return res;
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
if (code == ENOENT)
return ERR_PTR(0);
}
AFS_GUNLOCK();
- if (!code)
+ if (!code) {
+ __dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
d_move(dp, __dp);
+ }
dput(__dp);
goto out;
tvcp->v.v_fop = &afs_dir_fops;
#endif
dp->d_op = &afs_dentry_operations;
+ dp->d_time = hgetlo(ITOAFS(dip)->m.DataVersion);
d_instantiate(dp, AFSTOI(tvcp));
}