linux-sysname-list-sys-links-resolve-dentry-20031109
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 3d402fd..413a893 100644 (file)
@@ -926,8 +926,11 @@ afs_linux_dentry_revalidate(struct dentry *dp)
        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)
@@ -954,43 +957,6 @@ afs_linux_dentry_revalidate(struct dentry *dp)
     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)
@@ -1106,6 +1072,8 @@ afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
     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 *
@@ -1119,9 +1087,30 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     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. */
@@ -1152,6 +1141,27 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp)
     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);