libafs: afs_SetupVolSlot function
[openafs.git] / src / afs / afs_volume.c
index 247a045..827ff12 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
@@ -31,7 +31,7 @@
 #ifdef AFS_SGI62_ENV
 #include "h/hashing.h"
 #endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
+#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
 #include <netinet/in_var.h>
 #endif /* ! AFS_HPUX110_ENV */
 #endif /* !defined(UKERNEL) */
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "afs/afs_dynroot.h"
 
-#if    defined(AFS_SUN56_ENV)
+#if    defined(AFS_SUN5_ENV)
 #include <inet/led.h>
 #include <inet/common.h>
-#if     defined(AFS_SUN58_ENV)
 #include <netinet/ip6.h>
-#endif
 #include <inet/ip.h>
 #endif
 
@@ -74,15 +72,15 @@ static int inVolList(struct VenusFid *fid, afs_int32 nvols, afs_int32 * vID,
 
 
 /**
- * Convert a volume name to a number; 
+ * Convert a volume name to a number;
  * @param aname Volume name.
  * @return return 0 if can't parse as a number.
  */
 static int
-afs_vtoi(register char *aname)
+afs_vtoi(char *aname)
 {
-    register afs_int32 temp;
-    register int tc;
+    afs_int32 temp;
+    int tc;
     temp = 0;
     AFS_STATCNT(afs_vtoi);
     while ((tc = *aname++)) {
@@ -106,18 +104,57 @@ afs_vtoi(register char *aname)
 static struct fvolume staticFVolume;
 afs_int32 afs_FVIndex = -1;
 
-/** 
- * UFS specific version of afs_GetVolSlot 
+/*!
+ * Initialize a newly gotten volume slot.
+ *
+ * \param tv volume slot to be initialized
+ * \param tf volume item data; null if none
+ * \param volid volume id for this volume slot
+ * \param cell cell for this volume slot
+ * \return none
+ */
+static void
+afs_InitVolSlot(struct volume *tv, struct fvolume *tf, afs_int32 volid,
+               struct cell *tcell)
+{
+    AFS_STATCNT(afs_InitVolSlot);
+    memset(tv, 0, sizeof(struct volume));
+    tv->cell = tcell->cellNum;
+    AFS_RWLOCK_INIT(&tv->lock, "volume lock");
+    tv->volume = volid;
+    if (tf) {
+       tv->vtix = afs_FVIndex;
+       tv->mtpoint = tf->mtpoint;
+       tv->dotdot = tf->dotdot;
+       tv->rootVnode = tf->rootVnode;
+       tv->rootUnique = tf->rootUnique;
+    } else {
+       tv->vtix = -1;
+       tv->rootVnode = tv->rootUnique = 0;
+       afs_GetDynrootMountFid(&tv->dotdot);
+       afs_GetDynrootMountFid(&tv->mtpoint);
+       tv->mtpoint.Fid.Vnode =
+           VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tcell->cellIndex << 2);
+       tv->mtpoint.Fid.Unique = volid;
+    }
+}
+
+/**
+ * UFS specific version of afs_GetVolSlot
  * @return
  */
 struct volume *
-afs_UFSGetVolSlot(void)
+afs_UFSGetVolSlot(afs_int32 volid, struct cell *tcell)
 {
-    register struct volume *tv, **lv;
+    struct volume *tv = NULL, **lv;
     struct osi_file *tfile;
-    register afs_int32 i, code;
+    afs_int32 i = -1, code;
     afs_int32 bestTime;
-    struct volume *bestVp, **bestLp;
+    struct volume *bestVp, *oldLp = NULL, **bestLp = NULL;
+    char *oldname = NULL;
+    afs_int32 oldvtix = -2; /* Initialize to a value that doesn't occur */
+    struct fvolume *tf = NULL;
+    int j = 0;
 
     AFS_STATCNT(afs_UFSGetVolSlot);
     if (!afs_freeVolList) {
@@ -137,13 +174,19 @@ afs_UFSGetVolSlot(void)
                }
            }
        }
-       if (!bestVp)
-           osi_Panic("getvolslot none");
+       if (!bestVp) {
+           afs_warn("afs_UFSGetVolSlot: no vol slots available\n");
+           goto error;
+       }
        tv = bestVp;
+
+       oldLp = *bestLp;
        *bestLp = tv->next;
-       if (tv->name)
-           afs_osi_Free(tv->name, strlen(tv->name) + 1);
+
+       oldname = tv->name;
        tv->name = NULL;
+
+       oldvtix = tv->vtix;
        /* now write out volume structure to file */
        if (tv->vtix < 0) {
            tv->vtix = afs_volCounter++;
@@ -161,9 +204,12 @@ afs_UFSGetVolSlot(void)
                code =
                    afs_osi_Read(tfile, sizeof(struct fvolume) * tv->vtix,
                                 &staticFVolume, sizeof(struct fvolume));
-               if (code != sizeof(struct fvolume))
-                   osi_Panic("read volumeinfo");
                osi_UFSClose(tfile);
+               if (code != sizeof(struct fvolume)) {
+                   afs_warn("afs_UFSGetVolSlot: error %d reading volumeinfo\n",
+                            (int)code);
+                   goto error;
+               }
                afs_FVIndex = tv->vtix;
            }
        }
@@ -178,50 +224,157 @@ afs_UFSGetVolSlot(void)
        code =
            afs_osi_Write(tfile, sizeof(struct fvolume) * afs_FVIndex,
                          &staticFVolume, sizeof(struct fvolume));
-       if (code != sizeof(struct fvolume))
-           osi_Panic("write volumeinfo");
        osi_UFSClose(tfile);
+       if (code != sizeof(struct fvolume)) {
+           afs_warn("afs_UFSGetVolSlot: error %d writing volumeinfo\n",
+                    (int)code);
+           goto error;
+       }
+       if (oldname) {
+           afs_osi_Free(oldname, strlen(oldname) + 1);
+           oldname = NULL;
+       }
     } else {
        tv = afs_freeVolList;
        afs_freeVolList = tv->next;
     }
+
+    /* read volume item data from disk for the gotten slot */
+    for (j = fvTable[FVHash(tcell->cellNum, volid)]; j != 0; j = tf->next) {
+       if (afs_FVIndex != j) {
+           tfile = osi_UFSOpen(&volumeInode);
+           code =
+               afs_osi_Read(tfile, sizeof(struct fvolume) * j,
+                            &staticFVolume, sizeof(struct fvolume));
+           osi_UFSClose(tfile);
+           if (code != sizeof(struct fvolume)) {
+               afs_warn("afs_SetupVolume: error %d reading volumeinfo\n",
+                        (int)code);
+               /* put tv back on the free list; the data in it is not valid */
+               tv->next = afs_freeVolList;
+               afs_freeVolList = tv;
+               /* staticFVolume contents are not valid */
+               afs_FVIndex = -1;
+               return NULL;
+           }
+           afs_FVIndex = j;
+       }
+       if (j != 0) {           /* volume items record 0 is not used */
+           tf = &staticFVolume;
+           if (tf->cell == tcell->cellNum && tf->volume == volid) {
+               break;
+           }
+       }
+    }
+
+    afs_InitVolSlot(tv, tf, volid, tcell);
     return tv;
 
+ error:
+    if (tv) {
+       if (oldvtix == -2) {
+           afs_warn("afs_UFSGetVolSlot: oldvtix is uninitialized\n");
+           return NULL;
+       }
+       if (oldname) {
+           tv->name = oldname;
+           oldname = NULL;
+       }
+       if (oldvtix < 0) {
+           afs_volCounter--;
+           fvTable[i] = staticFVolume.next;
+       }
+       if (bestLp) {
+           *bestLp = oldLp;
+       }
+       tv->vtix = oldvtix;
+       /* we messed with staticFVolume, so make sure someone else
+        * doesn't think it's fine to use */
+       afs_FVIndex = -1;
+    }
+    return NULL;
 }                              /*afs_UFSGetVolSlot */
 
 
 /**
- *   Get an available volume list slot. If the list does not exist, 
+ *   Get an available volume list slot. If the list does not exist,
  * create one containing a single element.
- * @return 
+ * @return
  */
 struct volume *
-afs_MemGetVolSlot(void)
+afs_MemGetVolSlot(afs_int32 volid, struct cell *tcell)
 {
-    register struct volume *tv;
+    struct volume *tv;
 
     AFS_STATCNT(afs_MemGetVolSlot);
     if (!afs_freeVolList) {
        struct volume *newVp;
 
-       newVp = (struct volume *)afs_osi_Alloc(sizeof(struct volume));
+       newVp = afs_osi_Alloc(sizeof(struct volume));
+       osi_Assert(newVp != NULL);
 
        newVp->next = NULL;
        afs_freeVolList = newVp;
     }
     tv = afs_freeVolList;
     afs_freeVolList = tv->next;
+
+    afs_InitVolSlot(tv, NULL, volid, tcell);
     return tv;
 
 }                              /*afs_MemGetVolSlot */
 
-/** 
- *   Reset volume information for all volume structs that
- * point to a speicific server.
- * @param srvp
+/*!
+ * Setup a volume slot for cell:volume.
+ *
+ * Find the volume slot for the cell:volume, otherwise get
+ * and initialize a new slot.
+ *
+ * \param volid volume id
+ * \param cell  cell
+ * \return volume
+ */
+static struct volume *
+afs_SetupVolSlot(afs_int32 volid, struct cell *tcell)
+{
+    struct volume *tv;
+    int i;
+
+    AFS_STATCNT(afs_SetupVolSlot);
+    ObtainWriteLock(&afs_xvolume, 108);
+    i = VHash(volid);
+    for (tv = afs_volumes[i]; tv; tv = tv->next) {
+       if (tv->volume == volid && tv->cell == tcell->cellNum) {
+           break;
+       }
+    }
+    if (!tv) {
+       tv = afs_GetVolSlot(volid, tcell);
+       if (!tv) {
+           ReleaseWriteLock(&afs_xvolume);
+           return NULL;
+       }
+       tv->next = afs_volumes[i];      /* thread into list */
+       afs_volumes[i] = tv;
+    }
+    tv->refCount++;
+    tv->states &= ~VRecheck;   /* just checked it */
+    tv->accessTime = osi_Time();
+    ReleaseWriteLock(&afs_xvolume);
+    return tv;
+}
+
+/*!
+ * Reset volume information for all volume structs that
+ * point to a speicific server, skipping a given volume if provided.
+ *
+ * @param[in] srvp
+ *      The server to reset volume info about
+ * @param[in] tv
+ *      The volume to skip resetting info about
  */
 void
-afs_ResetVolumes(struct server *srvp)
+afs_ResetVolumes(struct server *srvp, struct volume *tv)
 {
     int j, k;
     struct volume *vp;
@@ -229,10 +382,12 @@ afs_ResetVolumes(struct server *srvp)
     /* Find any volumes residing on this server and flush their state */
     for (j = 0; j < NVOLS; j++) {
        for (vp = afs_volumes[j]; vp; vp = vp->next) {
-           for (k = 0; k < MAXHOSTS; k++) {
+           for (k = 0; k < AFS_MAXHOSTS; k++) {
                if (!srvp || (vp->serverHost[k] == srvp)) {
-                   vp->serverHost[k] = 0;
-                   afs_ResetVolumeInfo(vp);
+                   if (tv && tv != vp) {
+                       vp->serverHost[k] = 0;
+                       afs_ResetVolumeInfo(vp);
+                   }
                    break;
                }
            }
@@ -240,8 +395,7 @@ afs_ResetVolumes(struct server *srvp)
     }
 }
 
-
-/** 
+/**
  *   Reset volume name to volume id mapping cache.
  * @param flags
  */
@@ -271,7 +425,7 @@ afs_CheckVolumeNames(int flags)
            for (tv = afs_volumes[i]; tv; tv = tv->next)
                ++vsize;
 
-       volumeID = (afs_int32 *) afs_osi_Alloc(2 * vsize * sizeof(*volumeID));
+       volumeID = afs_osi_Alloc(2 * vsize * sizeof(*volumeID));
        cellID = (volumeID) ? volumeID + vsize : 0;
     }
 
@@ -292,7 +446,7 @@ afs_CheckVolumeNames(int flags)
            }
            /* ??? */
            if (flags & (AFS_VOLCHECK_BUSY | AFS_VOLCHECK_FORCE)) {
-               for (j = 0; j < MAXHOSTS; j++)
+               for (j = 0; j < AFS_MAXHOSTS; j++)
                    tv->status[j] = not_busy;
            }
 
@@ -413,7 +567,7 @@ inVolList(struct VenusFid *fid, afs_int32 nvols, afs_int32 * vID,
 /* afs_PutVolume is now a macro in afs.h */
 
 
-/** 
+/**
  *    Return volume struct if we have it cached and it's up-to-date.
  *  Environment: Must be called with afs_xvolume unlocked.
  *  @param afid Volume FID.
@@ -476,12 +630,12 @@ afs_GetVolume(struct VenusFid *afid, struct vrequest *areq,
 
 
 /**
- * 
+ *
  * @param volid Volume ID. If it's 0, get it from the name.
  * @param aname Volume name.
  * @param ve Volume entry.
  * @param tcell The cell containing this volume.
- * @param agood 
+ * @param agood
  * @param type Type of volume.
  * @param areq Request.
  * @return Volume or NULL if failure.
@@ -496,7 +650,7 @@ afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell,
     struct uvldbentry *uve = (struct uvldbentry *)ve;
 
     int whichType;             /* which type of volume to look for */
-    int i, j, err = 0;
+    int i;
 
     if (!volid) {
        int len;
@@ -518,74 +672,25 @@ afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell,
                volid = nve->volumeId[whichType];
            } else {
                volid = ove->volumeId[whichType];
-           } 
+           }
        } /* end of if (volid == 0) */
     } /* end of if (!volid) */
 
-
-    ObtainWriteLock(&afs_xvolume, 108);
-    i = VHash(volid);
-    for (tv = afs_volumes[i]; tv; tv = tv->next) {
-       if (tv->volume == volid && tv->cell == tcell->cellNum) {
-           break;
-       }
-    }
+    tv = afs_SetupVolSlot(volid, tcell);
     if (!tv) {
-       struct fvolume *tf = 0;
-
-       tv = afs_GetVolSlot();
-       memset((char *)tv, 0, sizeof(struct volume));
-       tv->cell = tcell->cellNum;
-       AFS_RWLOCK_INIT(&tv->lock, "volume lock");
-       tv->next = afs_volumes[i];      /* thread into list */
-       afs_volumes[i] = tv;
-       tv->volume = volid;
-       for (j = fvTable[FVHash(tv->cell, volid)]; j != 0; j = tf->next) {
-           if (afs_FVIndex != j) {
-               struct osi_file *tfile;
-               tfile = osi_UFSOpen(&volumeInode);
-               err =
-                   afs_osi_Read(tfile, sizeof(struct fvolume) * j,
-                                &staticFVolume, sizeof(struct fvolume));
-               if (err != sizeof(struct fvolume))
-                   osi_Panic("read volumeinfo2");
-               osi_UFSClose(tfile);
-               afs_FVIndex = j;
-           }
-           tf = &staticFVolume;
-           if (tf->cell == tv->cell && tf->volume == volid)
-               break;
-       }
-       if (tf && (j != 0)) {
-           tv->vtix = afs_FVIndex;
-           tv->mtpoint = tf->mtpoint;
-           tv->dotdot = tf->dotdot;
-           tv->rootVnode = tf->rootVnode;
-           tv->rootUnique = tf->rootUnique;
-       } else {
-           tv->vtix = -1;
-           tv->rootVnode = tv->rootUnique = 0;
-            afs_GetDynrootMountFid(&tv->dotdot);
-            afs_GetDynrootMountFid(&tv->mtpoint);
-            tv->mtpoint.Fid.Vnode =
-              VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tcell->cellIndex << 2);
-            tv->mtpoint.Fid.Unique = volid;
-       }
+       return NULL;
     }
-    tv->refCount++;
-    tv->states &= ~VRecheck;   /* just checked it */
-    tv->accessTime = osi_Time();
-    ReleaseWriteLock(&afs_xvolume);
-    ObtainWriteLock(&tv->lock, 111);
+
     if (type == 2) {
-       InstallUVolumeEntry(tv, uve, tcell->cellNum, tcell, areq);
+       LockAndInstallUVolumeEntry(tv, uve, tcell->cellNum, tcell, areq);
     } else if (type == 1)
-       InstallNVolumeEntry(tv, nve, tcell->cellNum);
+       LockAndInstallNVolumeEntry(tv, nve, tcell->cellNum);
     else
-       InstallVolumeEntry(tv, ove, tcell->cellNum);
+       LockAndInstallVolumeEntry(tv, ove, tcell->cellNum);
     if (agood) {
        if (!tv->name) {
            tv->name = afs_osi_Alloc(strlen(aname) + 1);
+           osi_Assert(tv->name != NULL);
            strcpy(tv->name, aname);
        }
     }
@@ -601,14 +706,14 @@ afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell,
  * Seek volume by it's name and attributes.
  * If volume not found, try to add one.
  * @param aname Volume name.
- * @param acell Cell 
+ * @param acell Cell
  * @param agood
  * @param areq
  * @param locktype Type of lock to be used.
- * @return 
+ * @return
  */
 struct volume *
-afs_GetVolumeByName(register char *aname, afs_int32 acell, int agood,
+afs_GetVolumeByName(char *aname, afs_int32 acell, int agood,
                    struct vrequest *areq, afs_int32 locktype)
 {
     afs_int32 i;
@@ -638,7 +743,7 @@ afs_GetVolumeByName(register char *aname, afs_int32 acell, int agood,
 
 /**
  *   Init a new dynroot volume.
- * @param Volume FID. 
+ * @param Volume FID.
  * @return Volume or NULL if not found.
  */
 static struct volume *
@@ -653,6 +758,7 @@ afs_NewDynrootVolume(struct VenusFid *fid)
     if (!tcell)
        return NULL;
     tve = afs_osi_Alloc(sizeof(*tve));
+    osi_Assert(tve != NULL);
     if (!(tcell->states & CHasVolRef))
        tcell->states |= CHasVolRef;
 
@@ -673,7 +779,7 @@ int lastnvcode;
 /**
  * @param aname Volume name.
  * @param acell Cell id.
- * @param agood 
+ * @param agood
  * @param areq Request type.
  * @param locktype Type of lock to be used.
  * @return Volume or NULL if failure.
@@ -691,6 +797,7 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
     char *tbuffer, *ve;
     struct afs_conn *tconn;
     struct vrequest treq;
+    struct rx_connection *rxconn;
 
     if (strlen(aname) > VL_MAXNAMELEN) /* Invalid volume name */
        return NULL;
@@ -715,45 +822,45 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
     do {
        tconn =
            afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
-                            &treq, SHARED_LOCK);
+                            &treq, SHARED_LOCK, 0, &rxconn);
        if (tconn) {
-           if (tconn->srvr->server->flags & SNO_LHOSTS) {
+           if (tconn->parent->srvr->server->flags & SNO_LHOSTS) {
                type = 0;
                RX_AFS_GUNLOCK();
-               code = VL_GetEntryByNameO(tconn->id, aname, tve);
+               code = VL_GetEntryByNameO(rxconn, aname, tve);
                RX_AFS_GLOCK();
-           } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
+           } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
                type = 1;
                RX_AFS_GUNLOCK();
-               code = VL_GetEntryByNameN(tconn->id, aname, ntve);
+               code = VL_GetEntryByNameN(rxconn, aname, ntve);
                RX_AFS_GLOCK();
            } else {
                type = 2;
                RX_AFS_GUNLOCK();
-               code = VL_GetEntryByNameU(tconn->id, aname, utve);
+               code = VL_GetEntryByNameU(rxconn, aname, utve);
                RX_AFS_GLOCK();
-               if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
+               if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
                    if (code == RXGEN_OPCODE) {
                        type = 1;
                        RX_AFS_GUNLOCK();
-                       code = VL_GetEntryByNameN(tconn->id, aname, ntve);
+                       code = VL_GetEntryByNameN(rxconn, aname, ntve);
                        RX_AFS_GLOCK();
                        if (code == RXGEN_OPCODE) {
                            type = 0;
-                           tconn->srvr->server->flags |= SNO_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SNO_LHOSTS;
                            RX_AFS_GUNLOCK();
-                           code = VL_GetEntryByNameO(tconn->id, aname, tve);
+                           code = VL_GetEntryByNameO(rxconn, aname, tve);
                            RX_AFS_GLOCK();
                        } else if (!code)
-                           tconn->srvr->server->flags |= SYES_LHOSTS;
+                           tconn->parent->srvr->server->flags |= SYES_LHOSTS;
                    } else if (!code)
-                       tconn->srvr->server->flags |= SVLSRV_UUID;
+                       tconn->parent->srvr->server->flags |= SVLSRV_UUID;
                }
                lastnvcode = code;
            }
        } else
            code = -1;
-    } while (afs_Analyze(tconn, code, NULL, &treq, -1, /* no op code for this */
+    } while (afs_Analyze(tconn, rxconn, code, NULL, &treq, -1, /* no op code for this */
                         SHARED_LOCK, tcell));
 
     if (code) {
@@ -768,7 +875,7 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
            int i;
            struct server *sp;
            struct srvAddr *sap;
-           for (i = 0; i < MAXCELLHOSTS; i++) {
+           for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
                if ((sp = tcell->cellHosts[i]) == NULL)
                    break;
                for (sap = sp->addr; sap; sap = sap->next_sa)
@@ -798,23 +905,27 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
        ve = (char *)ntve;
     else
        ve = (char *)tve;
-    tv = afs_SetupVolume(0, aname, ve, tcell, agood, type, areq);
-    if ((agood == 3) && tv->backVol) {
+    tv = afs_SetupVolume(0, aname, ve, tcell, agood, type, &treq);
+    if ((agood == 3) && tv && tv->backVol) {
        /*
         * This means that very soon we'll ask for the BK volume so
         * we'll prefetch it (well we did already.)
         */
        tv1 =
-           afs_SetupVolume(tv->backVol, (char *)0, ve, tcell, 0, type, areq);
-       tv1->refCount--;
+           afs_SetupVolume(tv->backVol, (char *)0, ve, tcell, 0, type, &treq);
+       if (tv1) {
+           tv1->refCount--;
+       }
     }
-    if ((agood >= 2) && tv->roVol) {
+    if ((agood >= 2) && tv && tv->roVol) {
        /*
         * This means that very soon we'll ask for the RO volume so
         * we'll prefetch it (well we did already.)
         */
-       tv1 = afs_SetupVolume(tv->roVol, NULL, ve, tcell, 0, type, areq);
-       tv1->refCount--;
+       tv1 = afs_SetupVolume(tv->roVol, NULL, ve, tcell, 0, type, &treq);
+       if (tv1) {
+           tv1->refCount--;
+       }
     }
     osi_FreeLargeSpace(tbuffer);
     afs_PutCell(tcell, READ_LOCK);
@@ -824,58 +935,45 @@ afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
 
 
 
-/** 
+/**
  *   Call this with the volume structure locked; used for new-style vldb requests.
- * @param av Volume 
+ * @param av Volume
  * @param ve
  * @param acell
  */
 void
-InstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
+LockAndInstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
 {
-    register struct server *ts;
+    struct server *ts;
     struct cell *cellp;
-    register int i, j;
+    int i, j;
     afs_int32 mask;
     afs_uint32 temp;
+    char types = 0;
+    struct server *serverHost[AFS_MAXHOSTS];
 
     AFS_STATCNT(InstallVolumeEntry);
 
+    memset(serverHost, 0, sizeof(serverHost));
+
     /* Determine the type of volume we want */
     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
        mask = VLSF_RWVOL;
     } else if ((ve->flags & VLF_ROEXISTS)
               && (av->volume == ve->volumeId[ROVOL])) {
        mask = VLSF_ROVOL;
-       av->states |= VRO;
+       types |= VRO;
     } else if ((ve->flags & VLF_BACKEXISTS)
               && (av->volume == ve->volumeId[BACKVOL])) {
        /* backup always is on the same volume as parent */
        mask = VLSF_RWVOL;
-       av->states |= (VRO | VBackup);
+       types |= (VRO | VBackup);
     } else {
        mask = 0;               /* Can't find volume in vldb entry */
     }
 
-    /* fill in volume types */
-    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
-    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
-    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
-
-    if (ve->flags & VLF_DFSFILESET)
-       av->states |= VForeign;
-
     cellp = afs_GetCell(acell, 0);
 
-    /* This volume, av, is locked. Zero out the serverHosts[] array 
-     * so that if afs_GetServer() decides to replace the server 
-     * struct, we don't deadlock trying to afs_ResetVolumeInfo()
-     * this volume.
-     */
-    for (j = 0; j < MAXHOSTS; j++) {
-       av->serverHost[j] = 0;
-    }
-
     /* Step through the VLDB entry making sure each server listed is there */
     for (i = 0, j = 0; i < ve->nServers; i++) {
        if (((ve->serverFlags[i] & mask) == 0)
@@ -885,8 +983,8 @@ InstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
 
        temp = htonl(ve->serverNumber[i]);
        ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
-                          (afsUUID *) 0, 0);
-       av->serverHost[j] = ts;
+                          (afsUUID *) 0, 0, av);
+       serverHost[j] = ts;
 
        /*
         * The cell field could be 0 if the server entry was created
@@ -901,59 +999,59 @@ InstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
        afs_PutServer(ts, WRITE_LOCK);
        j++;
     }
-    if (j < MAXHOSTS) {
-       av->serverHost[j++] = 0;
-    }
-    afs_SortServers(av->serverHost, MAXHOSTS);
+
+    ObtainWriteLock(&av->lock, 109);
+
+    memcpy(av->serverHost, serverHost, sizeof(serverHost));
+
+    /* from above */
+    av->states |= types;
+
+    /* fill in volume types */
+    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
+    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
+    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
+
+    if (ve->flags & VLF_DFSFILESET)
+       av->states |= VForeign;
+
+    afs_SortServers(av->serverHost, AFS_MAXHOSTS);
 }                              /*InstallVolumeEntry */
 
 
 void
-InstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
+LockAndInstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
 {
-    register struct server *ts;
+    struct server *ts;
     struct cell *cellp;
-    register int i, j;
+    int i, j;
     afs_int32 mask;
     afs_uint32 temp;
+    char types = 0;
+    struct server *serverHost[AFS_MAXHOSTS];
 
     AFS_STATCNT(InstallVolumeEntry);
 
+    memset(serverHost, 0, sizeof(serverHost));
+
     /* Determine type of volume we want */
     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
        mask = VLSF_RWVOL;
     } else if ((ve->flags & VLF_ROEXISTS)
               && (av->volume == ve->volumeId[ROVOL])) {
        mask = VLSF_ROVOL;
-       av->states |= VRO;
+       types |= VRO;
     } else if ((ve->flags & VLF_BACKEXISTS)
               && (av->volume == ve->volumeId[BACKVOL])) {
        /* backup always is on the same volume as parent */
        mask = VLSF_RWVOL;
-       av->states |= (VRO | VBackup);
+       types |= (VRO | VBackup);
     } else {
        mask = 0;               /* Can't find volume in vldb entry */
     }
 
-    /* fill in volume types */
-    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
-    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
-    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
-
-    if (ve->flags & VLF_DFSFILESET)
-       av->states |= VForeign;
-
     cellp = afs_GetCell(acell, 0);
 
-    /* This volume, av, is locked. Zero out the serverHosts[] array 
-     * so that if afs_GetServer() decides to replace the server 
-     * struct, we don't deadlock trying to afs_ResetVolumeInfo()
-     * this volume.
-     */
-    for (j = 0; j < MAXHOSTS; j++) {
-       av->serverHost[j] = 0;
-    }
-
     /* Step through the VLDB entry making sure each server listed is there */
     for (i = 0, j = 0; i < ve->nServers; i++) {
        if (((ve->serverFlags[i] & mask) == 0)
@@ -963,8 +1061,8 @@ InstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
 
        temp = htonl(ve->serverNumber[i]);
        ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
-                          (afsUUID *) 0, 0);
-       av->serverHost[j] = ts;
+                          (afsUUID *) 0, 0, av);
+       serverHost[j] = ts;
        /*
         * The cell field could be 0 if the server entry was created
         * first with the 'fs setserverprefs' call which doesn't set
@@ -978,62 +1076,62 @@ InstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
        afs_PutServer(ts, WRITE_LOCK);
        j++;
     }
-    if (j < MAXHOSTS) {
-       av->serverHost[j++] = 0;
-    }
-    afs_SortServers(av->serverHost, MAXHOSTS);
+
+    ObtainWriteLock(&av->lock, 110);
+
+    memcpy(av->serverHost, serverHost, sizeof(serverHost));
+
+    /* from above */
+    av->states |= types;
+
+    /* fill in volume types */
+    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
+    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
+    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
+
+    if (ve->flags & VLF_DFSFILESET)
+       av->states |= VForeign;
+
+    afs_SortServers(av->serverHost, AFS_MAXHOSTS);
 }                              /*InstallNVolumeEntry */
 
 
 void
-InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
-                   struct cell *tcell, struct vrequest *areq)
+LockAndInstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
+                          struct cell *tcell, struct vrequest *areq)
 {
-    register struct server *ts;
+    struct server *ts;
     struct afs_conn *tconn;
     struct cell *cellp;
-    register int i, j;
+    int i, j;
     afs_uint32 serverid;
     afs_int32 mask;
     int k;
+    char type = 0;
+    struct server *serverHost[AFS_MAXHOSTS];
 
     AFS_STATCNT(InstallVolumeEntry);
 
+    memset(serverHost, 0, sizeof(serverHost));
+
     /* Determine type of volume we want */
     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
        mask = VLSF_RWVOL;
     } else if ((ve->flags & VLF_ROEXISTS)
               && av->volume == ve->volumeId[ROVOL]) {
        mask = VLSF_ROVOL;
-       av->states |= VRO;
+       type |= VRO;
     } else if ((ve->flags & VLF_BACKEXISTS)
               && (av->volume == ve->volumeId[BACKVOL])) {
        /* backup always is on the same volume as parent */
        mask = VLSF_RWVOL;
-       av->states |= (VRO | VBackup);
+       type |= (VRO | VBackup);
     } else {
        mask = 0;               /* Can't find volume in vldb entry */
     }
 
-    /* fill in volume types */
-    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
-    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
-    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
-
-    if (ve->flags & VLF_DFSFILESET)
-       av->states |= VForeign;
-
     cellp = afs_GetCell(acell, 0);
 
-    /* This volume, av, is locked. Zero out the serverHosts[] array 
-     * so that if afs_GetServer() decides to replace the server 
-     * struct, we don't deadlock trying to afs_ResetVolumeInfo()
-     * this volume.
-     */
-    for (j = 0; j < MAXHOSTS; j++) {
-       av->serverHost[j] = 0;
-    }
-
     /* Gather the list of servers the VLDB says the volume is on
      * and initialize the ve->serverHost[] array. If a server struct
      * is not found, then get the list of addresses for the
@@ -1045,11 +1143,11 @@ InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
            continue;           /* wrong volume don't use this volume */
        }
 
-       if (!(ve->serverFlags[i] & VLSERVER_FLAG_UUID)) {
+       if (!(ve->serverFlags[i] & VLSF_UUID)) {
            /* The server has no uuid */
            serverid = htonl(ve->serverNumber[i].time_low);
-           ts = afs_GetServer(&serverid, 1, acell, cellp->fsport, WRITE_LOCK,
-                              (afsUUID *) 0, 0);
+           ts = afs_GetServer(&serverid, 1, acell, cellp->fsport,
+                              WRITE_LOCK, (afsUUID *) 0, 0, av);
        } else {
            ts = afs_FindServer(0, cellp->fsport, &ve->serverNumber[i], 0);
            if (ts && (ts->sr_addr_uniquifier == ve->serverUnique[i])
@@ -1061,20 +1159,22 @@ InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
                bulkaddrs addrs;
                ListAddrByAttributes attrs;
                afsUUID uuid;
+               struct rx_connection *rxconn;
 
-               memset((char *)&attrs, 0, sizeof(attrs));
+               memset(&attrs, 0, sizeof(attrs));
                attrs.Mask = VLADDR_UUID;
                attrs.uuid = ve->serverNumber[i];
-               memset((char *)&uuid, 0, sizeof(uuid));
-               memset((char *)&addrs, 0, sizeof(addrs));
+               memset(&uuid, 0, sizeof(uuid));
+               memset(&addrs, 0, sizeof(addrs));
                do {
                    tconn =
                        afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
-                                        tcell->cellNum, areq, SHARED_LOCK);
+                                        tcell->cellNum, areq, SHARED_LOCK,
+                                        0, &rxconn);
                    if (tconn) {
                        RX_AFS_GUNLOCK();
                        code =
-                           VL_GetAddrsU(tconn->id, &attrs, &uuid, &unique,
+                           VL_GetAddrsU(rxconn, &attrs, &uuid, &unique,
                                         &nentries, &addrs);
                        RX_AFS_GLOCK();
                    } else {
@@ -1086,7 +1186,7 @@ InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
                        code = VL_NOENT;
 
                } while (afs_Analyze
-                        (tconn, code, NULL, areq, -1, SHARED_LOCK, tcell));
+                        (tconn, rxconn, code, NULL, areq, -1, SHARED_LOCK, tcell));
                if (code) {
                    /* Better handing of such failures; for now we'll simply retry this call */
                    areq->volumeError = 1;
@@ -1097,14 +1197,14 @@ InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
                for (k = 0; k < nentries; k++) {
                    addrp[k] = htonl(addrp[k]);
                }
-               ts = afs_GetServer(addrp, nentries, acell, cellp->fsport,
-                                  WRITE_LOCK, &ve->serverNumber[i],
-                                  ve->serverUnique[i]);
-               afs_osi_Free(addrs.bulkaddrs_val,
-                            addrs.bulkaddrs_len * sizeof(*addrp));
+               ts = afs_GetServer(addrp, nentries, acell,
+                                  cellp->fsport, WRITE_LOCK,
+                                  &ve->serverNumber[i],
+                                  ve->serverUnique[i], av);
+               xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
            }
        }
-       av->serverHost[j] = ts;
+       serverHost[j] = ts;
 
        /* The cell field could be 0 if the server entry was created
         * first with the 'fs setserverprefs' call which doesn't set
@@ -1119,14 +1219,29 @@ InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
        j++;
     }
 
-    afs_SortServers(av->serverHost, MAXHOSTS);
+    ObtainWriteLock(&av->lock, 111);
+
+    memcpy(av->serverHost, serverHost, sizeof(serverHost));
+
+    /* from above */
+    av->states |= type;
+
+    /* fill in volume types */
+    av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
+    av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
+    av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
+
+    if (ve->flags & VLF_DFSFILESET)
+       av->states |= VForeign;
+
+    afs_SortServers(av->serverHost, AFS_MAXHOSTS);
 }                              /*InstallVolumeEntry */
 
 
 /**
- *   Reset volume info for the specified volume strecture. Mark volume 
+ *   Reset volume info for the specified volume strecture. Mark volume
  * to be rechecked next time.
- * @param tv 
+ * @param tv
  */
 void
 afs_ResetVolumeInfo(struct volume *tv)
@@ -1136,7 +1251,12 @@ afs_ResetVolumeInfo(struct volume *tv)
     AFS_STATCNT(afs_ResetVolumeInfo);
     ObtainWriteLock(&tv->lock, 117);
     tv->states |= VRecheck;
-    for (i = 0; i < MAXHOSTS; i++)
+
+    /* the hard-mount code in afs_Analyze may not be able to reset this flag
+     * when VRecheck is set, so clear it here to ensure it gets cleared. */
+    tv->states &= ~VHardMount;
+
+    for (i = 0; i < AFS_MAXHOSTS; i++)
        tv->status[i] = not_busy;
     if (tv->name) {
        afs_osi_Free(tv->name, strlen(tv->name) + 1);