dread-do-validation-20041012
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 6aafccd..8add8d8 100644 (file)
@@ -36,6 +36,7 @@ extern struct inode_operations afs_symlink_iops, afs_dir_iops;
 #endif
 
 
+afs_int32 afs_bkvolpref = 0;
 afs_int32 afs_bulkStatsDone;
 static int bulkStatCounter = 0;        /* counter for bulk stat seq. numbers */
 int afs_fakestat_enable = 0;   /* 1: fakestat-all, 2: fakestat-crosscell */
@@ -65,7 +66,7 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
     struct cell *tcell;
     char *cpos, *volnamep;
     char type, *buf;
-    afs_int32 prefetchRO;      /* 1=>No  2=>Yes */
+    afs_int32 prefetch;                /* 1=>None  2=>RO  3=>BK */
     afs_int32 mtptCell, assocCell, hac = 0;
     afs_int32 samecell, roname, len;
 
@@ -111,28 +112,35 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
                                               && (avc->fid.Cell ==
                                                   assocCell));
 
-    /* Decide whether to prefetch the RO. Also means we want the RO.
-     * If this is a regular mountpoint with a RW volume name and
-     * we cross a cell boundary -or- start from a RO volume, then we will
-     * want to prefetch the RO volume when we get the RW below.
+    /* Decide whether to prefetch the BK, or RO.  Also means we want the BK or
+     * RO.
+     * If this is a regular mountpoint with a RW volume name
+     * - If BK preference is enabled AND we remain within the same cell AND
+     *   start from a BK volume, then we will want to prefetch the BK volume.
+     * - If we cross a cell boundary OR start from a RO volume, then we will
+     *   want to prefetch the RO volume.
      */
-    if ((type == '#') && !roname && (!samecell || (avc->states & CRO))) {
-       prefetchRO = 2;         /* Yes, prefetch the RO */
+    if ((type == '#') && !roname) {
+       if (afs_bkvolpref && samecell && (avc->states & CBackup))
+           prefetch = 3;       /* Prefetch the BK */
+       else if (!samecell || (avc->states & CRO))
+           prefetch = 2;       /* Prefetch the RO */
+       else
+           prefetch = 1;       /* Do not prefetch */
     } else {
-       prefetchRO = 1;         /* No prefetch of the RO */
+       prefetch = 1;           /* Do not prefetch */
     }
 
     /* Get the volume struct. Unless this volume name has ".readonly" or
      * ".backup" in it, this will get the volume struct for the RW volume.
      * The RO volume will be prefetched if requested (but not returned).
      */
-    tvp =
-       afs_GetVolumeByName(volnamep, mtptCell, prefetchRO, areq, WRITE_LOCK);
+    tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetch, areq, WRITE_LOCK);
 
     /* If no volume was found in this cell, try the associated linked cell */
     if (!tvp && hac && areq->volumeError) {
        tvp =
-           afs_GetVolumeByName(volnamep, assocCell, prefetchRO, areq,
+           afs_GetVolumeByName(volnamep, assocCell, prefetch, areq,
                                WRITE_LOCK);
     }
 
@@ -140,8 +148,8 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
      * doesn't exist? Try adding ".readonly" to volname and look for that.
      * Don't know why we do this. Would have still found it in above call - jpm.
      */
-    if (!tvp && (prefetchRO == 2)) {
-       buf = (char *)osi_AllocSmallSpace(strlen(volnamep) + 10);
+    if (!tvp && (prefetch == 2) && len < AFS_SMALLOCSIZ - 10) {
+       buf = (char *)osi_AllocSmallSpace(len + 10);
 
        strcpy(buf, volnamep);
        afs_strcat(buf, ".readonly");
@@ -164,10 +172,20 @@ EvalMountPoint(register struct vcache *avc, struct vcache *advc,
        return ENODEV;
     }
 
-    /* If we want (prefetched) the RO and it exists, then drop the
-     * RW volume and get the RO. Othewise, go with the RW.
+    /* If we want (prefetched) the BK and it exists, then drop the RW volume
+     * and get the BK.
+     * Otherwise, if we want (prefetched0 the RO and it exists, then drop the
+     * RW volume and get the RO.
+     * Otherwise, go with the RW.
      */
-    if ((prefetchRO == 2) && tvp->roVol) {
+    if ((prefetch == 3) && tvp->backVol) {
+       tfid.Fid.Volume = tvp->backVol; /* remember BK volume */
+       tfid.Cell = tvp->cell;
+       afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
+       tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK);   /* get the new one */
+       if (!tvp)
+           return ENODEV;      /* oops, can't do it */
+    } else if ((prefetch >= 2) && tvp->roVol) {
        tfid.Fid.Volume = tvp->roVol;   /* remember RO volume */
        tfid.Cell = tvp->cell;
        afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
@@ -382,40 +400,50 @@ afs_ENameOK(register char *aname)
     return 1;
 }
 
-int
+static int
 afs_getsysname(register struct vrequest *areq, register struct vcache *adp,
-              register char *bufp)
+              register char *bufp, int *num, char **sysnamelist[])
 {
     register struct unixuser *au;
     register afs_int32 error;
 
-    if (!afs_nfsexporter) {
-       strcpy(bufp, afs_sysname);
-       return 0;
-    }
     AFS_STATCNT(getsysname);
-    au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
-    afs_PutUser(au, 0);
-    if (au->exporter) {
-       error = EXP_SYSNAME(au->exporter, NULL, bufp);
-       if (error)
-           strcpy(bufp, "@sys");
-       return -1;
-    } else {
-       strcpy(bufp, afs_sysname);
-       return 0;
+
+    *sysnamelist = afs_sysnamelist;
+
+    if (!afs_nfsexporter)
+       strcpy(bufp, (*sysnamelist)[0]);
+    else {
+       au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
+       if (au->exporter) {
+           error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
+           if (error) {
+               strcpy(bufp, "@sys");
+               afs_PutUser(au, 0);
+               return -1;
+           } else {
+               strcpy(bufp, (*sysnamelist)[0]);
+           }
+       } else
+           strcpy(bufp, afs_sysname);
+       afs_PutUser(au, 0);
     }
+    return 0;
 }
 
 void
-Check_AtSys(register struct vcache *avc, const char *aname,
+Check_AtSys(register struct vcache *avc, char *aname,
            struct sysname_info *state, struct vrequest *areq)
 {
+    int num = 0;
+    char **sysnamelist[MAXSYSNAME];
+
     if (AFS_EQ_ATSYS(aname)) {
        state->offset = 0;
        state->name = (char *)osi_AllocLargeSpace(AFS_SMALLOCSIZ);
        state->allocked = 1;
-       state->index = afs_getsysname(areq, avc, state->name);
+       state->index =
+           afs_getsysname(areq, avc, state->name, &num, sysnamelist);
     } else {
        state->offset = -1;
        state->allocked = 0;
@@ -428,42 +456,71 @@ int
 Next_AtSys(register struct vcache *avc, struct vrequest *areq,
           struct sysname_info *state)
 {
+    int num = afs_sysnamecount;
+    char **sysnamelist[MAXSYSNAME];
+
     if (state->index == -1)
        return 0;               /* No list */
 
     /* Check for the initial state of aname != "@sys" in Check_AtSys */
     if (state->offset == -1 && state->allocked == 0) {
        register char *tname;
+
        /* Check for .*@sys */
        for (tname = state->name; *tname; tname++)
            /*Move to the end of the string */ ;
+
        if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
            state->offset = (tname - 4) - state->name;
            tname = (char *)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
            strncpy(tname, state->name, state->offset);
            state->name = tname;
            state->allocked = 1;
+           num = 0;
            state->index =
-               afs_getsysname(areq, avc, state->name + state->offset);
+               afs_getsysname(areq, avc, state->name + state->offset, &num,
+                              sysnamelist);
            return 1;
        } else
            return 0;           /* .*@sys doesn't match either */
-    } else if (++(state->index) >= afs_sysnamecount
-              || !afs_sysnamelist[(int)state->index])
-       return 0;               /* end of list */
-    strcpy(state->name + state->offset, afs_sysnamelist[(int)state->index]);
+    } else {
+       register struct unixuser *au;
+       register afs_int32 error;
+
+       *sysnamelist = afs_sysnamelist;
+
+       if (afs_nfsexporter) {
+           au = afs_GetUser(areq->uid, avc->fid.Cell, 0);
+           if (au->exporter) {
+               error =
+                   EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num);
+               if (error) {
+                   return 0;
+               }
+           }
+           afs_PutUser(au, 0);
+       }
+       if (++(state->index) >= num || !(*sysnamelist)[state->index])
+           return 0;           /* end of list */
+    }
+    strcpy(state->name + state->offset, (*sysnamelist)[state->index]);
     return 1;
 }
 
 #if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
 extern int BlobScan(ino64_t * afile, afs_int32 ablob);
 #else
+#if defined(AFS_HPUX1123_ENV)
+/* DEE should use the new afs_inode_t  for all */
+extern int BlobScan(ino_t * afile, afs_int32 ablob);
+#else
 #if defined AFS_LINUX_64BIT_KERNEL
 extern int BlobScan(long *afile, afs_int32 ablob);
 #else
 extern int BlobScan(afs_int32 * afile, afs_int32 ablob);
 #endif
 #endif
+#endif
 
 
 /* called with an unlocked directory and directory cookie.  Areqp
@@ -523,13 +580,13 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
     struct VenusFid dotdot;
     int flagIndex;             /* First file with bulk fetch flag set */
     int inlinebulk = 0;                /* Did we use InlineBulk RPC or not? */
-    XSTATS_DECLS
-       /* first compute some basic parameters.  We dont want to prefetch more
-        * than a fraction of the cache in any given call, and we want to preserve
-        * a portion of the LRU queue in any event, so as to avoid thrashing
-        * the entire stat cache (we will at least leave some of it alone).
-        * presently dont stat more than 1/8 the cache in any one call.      */
-       nentries = afs_cacheStats / 8;
+    XSTATS_DECLS;
+    /* first compute some basic parameters.  We dont want to prefetch more
+     * than a fraction of the cache in any given call, and we want to preserve
+     * a portion of the LRU queue in any event, so as to avoid thrashing
+     * the entire stat cache (we will at least leave some of it alone).
+     * presently dont stat more than 1/8 the cache in any one call.      */
+    nentries = afs_cacheStats / 8;
 
     /* dont bother prefetching more than one calls worth of info */
     if (nentries > AFSCBMAX)
@@ -617,7 +674,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
        /* look for first safe entry to examine in the directory.  BlobScan
         * looks for a the 1st allocated dir after the dirCookie slot.
         */
-       newIndex = BlobScan(&dcp->f.inode, (dirCookie >> 5));
+       newIndex = BlobScan(&dcp->f, (dirCookie >> 5));
        if (newIndex == 0)
            break;
 
@@ -626,7 +683,7 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
 
        /* get a ptr to the dir entry */
        dirEntryp =
-           (struct DirEntry *)afs_dir_GetBlob(&dcp->f.inode, newIndex);
+           (struct DirEntry *)afs_dir_GetBlob(&dcp->f, newIndex);
        if (!dirEntryp)
            break;
 
@@ -1057,7 +1114,7 @@ afs_lookup(adp, aname, avcp, acred, flags)
 afs_lookup(adp, aname, avcp, acred)
 #endif                         /* UKERNEL */
 #endif                         /* SUN5 || SGI */
-OSI_VC_DECL(adp);
+     OSI_VC_DECL(adp);
      struct vcache **avcp;
      char *aname;
      struct AFS_UCRED *acred;
@@ -1071,13 +1128,13 @@ OSI_VC_DECL(adp);
     int pass = 0, hit = 0;
     long dirCookie;
     extern afs_int32 afs_mariner;      /*Writing activity to log? */
-    OSI_VC_CONVERT(adp)
     afs_hyper_t versionNo;
     int no_read_access = 0;
     struct sysname_info sysState;      /* used only for @sys checking */
     int dynrootRetry = 1;
     struct afs_fakestat_state fakestate;
     int tryEvalOnly = 0;
+    OSI_VC_CONVERT(adp);
 
     AFS_STATCNT(afs_lookup);
     afs_InitFakeStat(&fakestate);
@@ -1236,7 +1293,7 @@ OSI_VC_DECL(adp);
     {                          /* sub-block just to reduce stack usage */
        register struct dcache *tdc;
        afs_size_t dirOffset, dirLen;
-       ino_t theDir;
+       struct fcache *theDir;
        struct VenusFid tfid;
 
        /* now we have to lookup the next fid */
@@ -1273,6 +1330,8 @@ OSI_VC_DECL(adp);
            ReleaseReadLock(&tdc->lock);
            ReleaseReadLock(&adp->lock);
            afs_PutDCache(tdc);
+           if (tname && tname != aname)
+               osi_FreeLargeSpace(tname);
            goto redo;
        }
 
@@ -1292,15 +1351,15 @@ OSI_VC_DECL(adp);
 
        /* lookup the name in the appropriate dir, and return a cache entry
         * on the resulting fid */
-       theDir = tdc->f.inode;
+       theDir = &tdc->f;
        code =
-           afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid,
+           afs_dir_LookupOffset(theDir, sysState.name, &tfid.Fid,
                                 &dirCookie);
 
        /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
        while (code == ENOENT && Next_AtSys(adp, &treq, &sysState))
            code =
-               afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid,
+               afs_dir_LookupOffset(theDir, sysState.name, &tfid.Fid,
                                     &dirCookie);
        tname = sysState.name;