goto done;
}
- /* A DNLC lookup failure cannot be trusted. Try a real lookup */
- code = afs_lookup(parentvcp, name, &lookupvcp, credp);
+ /* 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);
/* Verify that the dentry does not point to an old inode */
if (vcp != lookupvcp)
return !bad_dentry;
}
-#ifdef notdef
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
-static int
-afs_linux_dentry_revalidate(struct dentry *dp, int flags)
-#else
-static int
-afs_linux_dentry_revalidate(struct dentry *dp)
-#endif
-{
- int code;
- cred_t *credp;
- struct vrequest treq;
- struct inode *ip = AFSTOI(dp->d_inode);
-
- unsigned long timeout = 3 * HZ; /* 3 seconds */
-
- if (!ip)
- printk("negative dentry: %s\n", dp->d_name.name);
-
- if (!(flags & LOOKUP_CONTINUE)) {
- long diff = CURRENT_TIME - dp->d_parent->d_inode->i_mtime;
-
- if (diff < 15 * 60)
- timeout = 0;
- }
-
- if (time_after(jiffies, dp->d_time + timeout))
- goto out_bad;
-
- out_valid:
- return 1;
-
- out_bad:
- return 0;
-}
-#endif
-
/* afs_dentry_iput */
static void
afs_dentry_iput(struct dentry *dp, struct inode *ip)
return -code;
}
+#define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
+
/* afs_linux_lookup */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
struct dentry *
cred_t *credp = crref();
struct vcache *vcp = NULL;
const char *comp = dp->d_name.name;
+ char *name = NULL;
+ struct sysname_info sysState;
+ struct qstr qstr;
+ struct vrequest treq;
+
+ sysState.allocked = 0;
+
AFS_GLOCK();
- code = afs_lookup(ITOAFS(dip), comp, &vcp, credp);
+ /* In order that we not get ESTALE on @sys links that resolve
+ into the 2nd or later item in an @sys list, resolve it ourselves
+ and force a lookup of the actual match here. The real directory
+ thus gets the dentry. */
+ if (AFS_EQ_ATSYS(comp) && !afs_InitReq(&treq, credp)) {
+ Check_AtSys(ITOAFS(dip), comp, &sysState, &treq);
+ name = sysState.name;
+
+ code = afs_lookup(ITOAFS(dip), name, &vcp, credp);
+ while (code == ENOENT && Next_AtSys(ITOAFS(dip), &treq, &sysState)) {
+ code = afs_lookup(ITOAFS(dip), name, &vcp, credp);
+ }
+ } else
+ code = afs_lookup(ITOAFS(dip), comp, &vcp, credp);
+
if (vcp) {
struct inode *ip = AFSTOI(vcp);
/* Reset ops if symlink or directory. */
dp->d_op = afs_dops;
d_add(dp, AFSTOI(vcp));
+#if 0
+ /* Set up a dentry alias. Should we be doing this for @sys?
+ You only get one for a directory, which would be fine,
+ @sys would only map to one at a time, but it's unclear
+ that this is consistent behavior. */
+ if (AFS_EQ_ATSYS(comp) && sysState.allocked) {
+ int result;
+ struct dentry *dentry;
+
+ qstr.name = name;
+ qstr.len = strlen(name);
+ qstr.hash = full_name_hash(name, qstr.len);
+ result = d_lookup(dp->d_parent, &qstr);
+ if (!result) {
+ dentry = d_alloc(dp->d_parent, &qstr);
+ if (dentry)
+ d_instantiate(dentry, AFSTOI(vcp));
+ }
+ }
+#endif
+
AFS_GUNLOCK();
crfree(credp);