vol: Blank opts in VOptDefaults
[openafs.git] / src / vol / volume.c
index a83e777..6d4af59 100644 (file)
@@ -36,6 +36,8 @@
 #else
 # include <opr/lockstub.h>
 #endif
+#include <opr/ffs.h>
+#include <opr/jhash.h>
 
 #include <afs/afsint.h>
 
@@ -43,9 +45,6 @@
 
 #ifndef AFS_NT40_ENV
 #if !defined(AFS_SGI_ENV)
-#ifdef AFS_OSF_ENV
-#include <ufs/fs.h>
-#else /* AFS_OSF_ENV */
 #ifdef AFS_VFSINCL_ENV
 #define VFS
 #ifdef AFS_SUN5_ENV
@@ -63,7 +62,6 @@
 #include <sys/fs.h>
 #endif
 #endif /* AFS_VFSINCL_ENV */
-#endif /* AFS_OSF_ENV */
 #endif /* AFS_SGI_ENV */
 #endif /* !AFS_NT40_ENV */
 
@@ -122,9 +120,6 @@ pthread_cond_t vol_vinit_cond;
 int vol_attach_threads = 1;
 #endif /* AFS_PTHREAD_ENV */
 
-/* start-time configurable I/O parameters */
-ih_init_params vol_io_params;
-
 #ifdef AFS_DEMAND_ATTACH_FS
 pthread_mutex_t vol_salvsync_mutex;
 
@@ -140,12 +135,8 @@ static volatile sig_atomic_t vol_disallow_salvsync = 0;
  */
 static int vol_shutting_down = 0;
 
-#ifdef AFS_OSF_ENV
-extern void *calloc(), *realloc();
-#endif
-
 /* Forward declarations */
-static Volume *attach2(Error * ec, VolId volumeId, char *path,
+static Volume *attach2(Error * ec, VolumeId volumeId, char *path,
                       struct DiskPartition64 *partp, Volume * vp,
                       int isbusy, int mode, int *acheckedOut);
 static void ReallyFreeVolume(Volume * vp);
@@ -159,11 +150,8 @@ static void VInitVolumeHeaderCache(afs_uint32 howMany);
 static int GetVolumeHeader(Volume * vp);
 static void ReleaseVolumeHeader(struct volHeader *hd);
 static void FreeVolumeHeader(Volume * vp);
-static void AddVolumeToHashTable(Volume * vp, int hashid);
+static void AddVolumeToHashTable(Volume * vp, VolumeId hashid);
 static void DeleteVolumeFromHashTable(Volume * vp);
-#if 0
-static int VHold(Volume * vp);
-#endif
 static int VHold_r(Volume * vp);
 static void VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class);
 static void VReleaseVolumeHandles_r(Volume * vp);
@@ -171,11 +159,9 @@ static void VCloseVolumeHandles_r(Volume * vp);
 static void LoadVolumeHeader(Error * ec, Volume * vp);
 static int VCheckOffline(Volume * vp);
 static int VCheckDetach(Volume * vp);
-static Volume * GetVolume(Error * ec, Error * client_ec, VolId volumeId,
+static Volume * GetVolume(Error * ec, Error * client_ec, VolumeId volumeId,
                           Volume * hint, const struct timespec *ts);
 
-int LogLevel;                  /* Vice loglevel--not defined as extern so that it will be
-                                * defined when not linked with vice, XXXX */
 ProgramType programType;       /* The type of program using the package */
 static VolumePackageOptions vol_opts;
 
@@ -195,9 +181,11 @@ pthread_t vol_glock_holder = 0;
  * an AVL or splay tree might work a lot better, but we'll just increase
  * the default hash table size for now
  */
-#define DEFAULT_VOLUME_HASH_SIZE 256   /* Must be a power of 2!! */
-#define DEFAULT_VOLUME_HASH_MASK (DEFAULT_VOLUME_HASH_SIZE-1)
-#define VOLUME_HASH(volumeId) (volumeId&(VolumeHashTable.Mask))
+#define DEFAULT_VOLUME_HASH_BITS 10
+#define DEFAULT_VOLUME_HASH_SIZE opr_jhash_size(DEFAULT_VOLUME_HASH_BITS)
+#define DEFAULT_VOLUME_HASH_MASK opr_jhash_mask(DEFAULT_VOLUME_HASH_BITS)
+#define VOLUME_HASH(volumeId) \
+    (opr_jhash_int(volumeId, 0) & VolumeHashTable.Mask)
 
 /*
  * turn volume hash chains into partially ordered lists.
@@ -218,6 +206,12 @@ pthread_t vol_glock_holder = 0;
  */
 #define VOLUME_HASH_REORDER_CHAIN_THRESH (VOLUME_HASH_REORDER_THRESHOLD / 2)
 
+/*
+ * The per volume uniquifier is bumped by 200 and and written to disk
+ * every 200 file creates.
+ */
+#define VOLUME_UPDATE_UNIQUIFIER_BUMP 200
+
 #include "rx/rx_queue.h"
 
 
@@ -231,24 +225,6 @@ VolumeHashTable_t VolumeHashTable = {
 static void VInitVolumeHash(void);
 
 
-#ifndef AFS_HAVE_FFS
-/* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
-ffs(x)
-{
-    afs_int32 ffs_i;
-    afs_int32 ffs_tmp = x;
-    if (ffs_tmp == 0)
-       return (-1);
-    else
-       for (ffs_i = 1;; ffs_i++) {
-           if (ffs_tmp & 1)
-               return (ffs_i);
-           else
-               ffs_tmp >>= 1;
-       }
-}
-#endif /* !AFS_HAVE_FFS */
-
 #ifdef AFS_PTHREAD_ENV
 /**
  * disk partition queue element
@@ -311,7 +287,7 @@ struct vinitvolumepackage_thread_param {
 
 static void *VInitVolumePackageThread(void *args);
 static struct DiskPartition64 *VInitNextPartition(struct partition_queue *pq);
-static VolId VInitNextVolumeId(DIR *dirp);
+static VolumeId VInitNextVolumeId(DIR *dirp);
 static int VInitPreAttachVolumes(int nthreads, struct volume_init_queue *vq);
 
 #endif /* !AFS_DEMAND_ATTACH_FS */
@@ -339,7 +315,7 @@ struct VLRU_DiskHeader {
 };
 
 struct VLRU_DiskEntry {
-    afs_uint32 vid;                       /* volume ID */
+    VolumeId vid;                       /* volume ID */
     afs_uint32 idx;                       /* generation */
     afs_uint32 last_get;                  /* timestamp of last get */
 };
@@ -480,14 +456,10 @@ bit32 VolumeCacheCheck;           /* Incremented everytime a volume goes on line--
 void
 VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
 {
-    opts->nLargeVnodes = opts->nSmallVnodes = 5;
-    opts->volcache = 0;
+    memset(opts, 0, sizeof(*opts));
 
-    opts->canScheduleSalvage = 0;
-    opts->canUseFSSYNC = 0;
-    opts->canUseSALVSYNC = 0;
+    opts->nLargeVnodes = opts->nSmallVnodes = 5;
 
-    opts->interrupt_rxcall = NULL;
     opts->offline_timeout = -1;
     opts->offline_shutdown_timeout = -1;
     opts->usage_threshold = 128;
@@ -495,9 +467,7 @@ VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
 
 #ifdef FAST_RESTART
     opts->unsafe_attach = 1;
-#else /* !FAST_RESTART */
-    opts->unsafe_attach = 0;
-#endif /* !FAST_RESTART */
+#endif
 
     switch (pt) {
     case fileServer:
@@ -938,7 +908,7 @@ VInitVolumePackageThread(void *args)
     Log("Scanning partitions on thread %d of %d\n", params->thread, params->nthreads);
     while((partition = VInitNextPartition(pq))) {
         DIR *dirp;
-        VolId vid;
+        VolumeId vid;
 
         Log("Partition %s: pre-attaching volumes\n", partition->name);
         dirp = opendir(VPartitionPath(partition));
@@ -1019,11 +989,11 @@ VInitNextPartition(struct partition_queue *pq)
 /**
  * Find next volume id on the partition.
  */
-static VolId
+static VolumeId
 VInitNextVolumeId(DIR *dirp)
 {
     struct dirent *d;
-    VolId vid = 0;
+    VolumeId vid = 0;
     char *ext;
 
     while((d = readdir(dirp))) {
@@ -1075,7 +1045,7 @@ VInitPreAttachVolumes(int nthreads, struct volume_init_queue *vq)
                     Log("Error looking up volume, code=%d\n", ec);
                 }
                 else if (dup) {
-                    Log("Warning: Duplicate volume id %d detected.\n", vp->hashid);
+                    Log("Warning: Duplicate volume id %" AFS_VOLID_FMT " detected.\n", afs_printable_VolumeId_lu(vp->hashid));
                 }
                 else {
                     /* put pre-attached volume onto the hash table
@@ -1133,7 +1103,7 @@ VAttachVolumesByPartition(struct DiskPartition64 *diskP, int * nAttached, int *
       (*(vp ? nAttached : nUnattached))++;
       if (error == VOFFLINE)
        Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
-      else if (LogLevel >= 5) {
+      else if (GetLogLevel() >= 5) {
        Log("Partition %s: attached volume %d (%s)\n",
            diskP->name, VolumeNumber(dp->d_name),
            dp->d_name);
@@ -1364,9 +1334,9 @@ VShutdown_r(void)
        for (queue_Scan(&VolumeHashTable.Table[i],vp,np,Volume)) {
            code = VHold_r(vp);
            if (code == 0) {
-               if (LogLevel >= 5)
-                   Log("VShutdown:  Attempting to take volume %u offline.\n",
-                       vp->hashid);
+               if (GetLogLevel() >= 5)
+                   Log("VShutdown:  Attempting to take volume %" AFS_VOLID_FMT " offline.\n",
+                       afs_printable_VolumeId_lu(vp->hashid));
 
                /* next, take the volume offline (drops reference count) */
                VOffline_r(vp, "File server was shut down");
@@ -1785,9 +1755,14 @@ ShutdownVByPForPass_r(struct DiskPartition64 * dp, int pass)
 {
     struct rx_queue * q = queue_First(&dp->vol_list, rx_queue);
     int i = 0;
+    const char *pass_strs[4] = {"{un/pre}attached vols", "vols w/ vol header loaded", "vols w/o vol header loaded", "vols with exclusive state"};
 
-    while (ShutdownVolumeWalk_r(dp, pass, &q))
+    while (ShutdownVolumeWalk_r(dp, pass, &q)) {
        i++;
+       if (0 == i%100) {
+           Log("VShutdownByPartition:  ... shut down %d volumes on %s in pass %d (%s)\n", i, VPartitionPath(dp), pass, pass_strs[pass]);
+       }
+    }
 
     return i;
 }
@@ -1815,15 +1790,18 @@ ShutdownVolumeWalk_r(struct DiskPartition64 * dp, int pass,
                (V_attachState(vp) != VOL_STATE_PREATTACHED)) {
                break;
            }
+           /* fall through */
        case 1:
            if ((V_attachState(vp) == VOL_STATE_ATTACHED) &&
                (vp->header == NULL)) {
                break;
            }
+           /* fall through */
        case 2:
            if (VIsExclusiveState(V_attachState(vp))) {
                break;
            }
+           /* fall through */
        case 3:
            *idx = nqp;
            DeleteVolumeFromVByPList_r(vp);
@@ -1847,9 +1825,10 @@ VShutdownVolume_r(Volume * vp)
 
     VCreateReservation_r(vp);
 
-    if (LogLevel >= 5) {
-       Log("VShutdownVolume_r:  vid=%u, device=%d, state=%hu\n",
-           vp->hashid, vp->partition->device, V_attachState(vp));
+    if (GetLogLevel() >= 5) {
+       Log("VShutdownVolume_r:  vid=%" AFS_VOLID_FMT ", device=%d, state=%u\n",
+           afs_printable_VolumeId_lu(vp->hashid), vp->partition->device,
+           (unsigned int) V_attachState(vp));
     }
 
     /* wait for other blocking ops to finish */
@@ -1874,9 +1853,9 @@ VShutdownVolume_r(Volume * vp)
     case VOL_STATE_ATTACHED:
        code = VHold_r(vp);
        if (!code) {
-           if (LogLevel >= 5)
-               Log("VShutdown:  Attempting to take volume %u offline.\n",
-                   vp->hashid);
+           if (GetLogLevel() >= 5)
+               Log("VShutdown:  Attempting to take volume %" AFS_VOLID_FMT " offline.\n",
+                   afs_printable_VolumeId_lu(vp->hashid));
 
            /* take the volume offline (drops reference count) */
            VOffline_r(vp, "File server was shut down");
@@ -1938,7 +1917,7 @@ ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
     fdP = IH_OPEN(h);
     if (fdP == NULL) {
        Log("ReadHeader: Failed to open %s header file "
-           "(volume=%u, inode=%s); errno=%d\n", HeaderName(magic), h->ih_vid,
+           "(volume=%" AFS_VOLID_FMT ", inode=%s); errno=%d\n", HeaderName(magic), afs_printable_VolumeId_lu(h->ih_vid),
            PrintInode(stmp, h->ih_ino), errno);
        *ec = VSALVAGE;
        return;
@@ -1948,7 +1927,7 @@ ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
     nbytes = FDH_PREAD(fdP, to, size, 0);
     if (nbytes < 0) {
        Log("ReadHeader: Failed to read %s header file "
-           "(volume=%u, inode=%s); errno=%d\n", HeaderName(magic), h->ih_vid,
+           "(volume=%" AFS_VOLID_FMT ", inode=%s); errno=%d\n", HeaderName(magic), afs_printable_VolumeId_lu(h->ih_vid),
            PrintInode(stmp, h->ih_ino), errno);
        *ec = VSALVAGE;
        FDH_REALLYCLOSE(fdP);
@@ -1956,18 +1935,18 @@ ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
     }
     if (nbytes != size) {
        Log("ReadHeader: Incorrect number of bytes read from %s header file "
-           "(volume=%u, inode=%s); expected=%d, read=%d\n",
-           HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino), size,
-           (int)nbytes);
+           "(volume=%" AFS_VOLID_FMT ", inode=%s); expected=%d, read=%d\n",
+           HeaderName(magic), afs_printable_VolumeId_lu(h->ih_vid), 
+           PrintInode(stmp, h->ih_ino), size, (int)nbytes);
        *ec = VSALVAGE;
        FDH_REALLYCLOSE(fdP);
        return;
     }
     if (vsn->magic != magic) {
        Log("ReadHeader: Incorrect magic for %s header file "
-           "(volume=%u, inode=%s); expected=0x%x, read=0x%x\n",
-           HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino), magic,
-           vsn->magic);
+           "(volume=%" AFS_VOLID_FMT ", inode=%s); expected=0x%x, read=0x%x\n",
+           HeaderName(magic), afs_printable_VolumeId_lu(h->ih_vid),
+           PrintInode(stmp, h->ih_ino), magic, vsn->magic);
        *ec = VSALVAGE;
        FDH_REALLYCLOSE(fdP);
        return;
@@ -1978,8 +1957,8 @@ ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
     /* Check is conditional, in case caller wants to inspect version himself */
     if (version && vsn->version != version) {
        Log("ReadHeader: Incorrect version for %s header file "
-           "(volume=%u, inode=%s); expected=%x, read=%x\n",
-           HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino),
+           "(volume=%" AFS_VOLID_FMT ", inode=%s); expected=%x, read=%x\n",
+           HeaderName(magic), afs_printable_VolumeId_lu(h->ih_vid), PrintInode(stmp, h->ih_ino),
            version, vsn->version);
        *ec = VSALVAGE;
     }
@@ -2145,7 +2124,7 @@ VPreAttachVolumeByName_r(Error * ec, char *partition, char *name)
 Volume *
 VPreAttachVolumeById_r(Error * ec,
                       char * partition,
-                      VolId volumeId)
+                      VolumeId volumeId)
 {
     Volume *vp;
     struct DiskPartition64 *partp;
@@ -2160,11 +2139,26 @@ VPreAttachVolumeById_r(Error * ec,
        return NULL;
     }
 
+    /* ensure that any vp we pass to VPreAttachVolumeByVp_r
+     * is NOT in exclusive state.
+     */
+ retry:
     vp = VLookupVolume_r(ec, volumeId, NULL);
+
     if (*ec) {
        return NULL;
     }
 
+    if (vp && VIsExclusiveState(V_attachState(vp))) {
+       VCreateReservation_r(vp);
+       VWaitExclusiveState_r(vp);
+       VCancelReservation_r(vp);
+       vp = NULL;
+       goto retry;    /* look up volume again */
+    }
+
+    /* vp == NULL or vp not exclusive both OK */
+
     return VPreAttachVolumeByVp_r(ec, partp, vp, volumeId);
 }
 
@@ -2180,6 +2174,8 @@ VPreAttachVolumeById_r(Error * ec,
  *
  * @pre VOL_LOCK is held.
  *
+ * @pre vp (if specified) must not be in exclusive state.
+ *
  * @warning Returned volume object pointer does not have to
  *          equal the pointer passed in as argument vp.  There
  *          are potential race conditions which can result in
@@ -2198,12 +2194,17 @@ Volume *
 VPreAttachVolumeByVp_r(Error * ec,
                       struct DiskPartition64 * partp,
                       Volume * vp,
-                      VolId vid)
+                      VolumeId vid)
 {
     Volume *nvp = NULL;
 
     *ec = 0;
 
+    /* don't proceed unless it's safe */
+    if (vp) {
+       opr_Assert(!VIsExclusiveState(V_attachState(vp)));
+    }
+
     /* check to see if pre-attach already happened */
     if (vp &&
        (V_attachState(vp) != VOL_STATE_UNATTACHED) &&
@@ -2217,8 +2218,9 @@ VPreAttachVolumeByVp_r(Error * ec,
         *   - volume is in an error state
         *   - volume is pre-attached
         */
-       Log("VPreattachVolumeByVp_r: volume %u not in quiescent state (state %u flags 0x%x)\n",
-           vid, V_attachState(vp), V_attachFlags(vp));
+       Log("VPreattachVolumeByVp_r: volume %" AFS_VOLID_FMT " not in quiescent state (state %u flags 0x%x)\n",
+           afs_printable_VolumeId_lu(vid), V_attachState(vp),
+           V_attachFlags(vp));
        goto done;
     } else if (vp) {
        /* we're re-attaching a volume; clear out some old state */
@@ -2278,8 +2280,8 @@ VPreAttachVolumeByVp_r(Error * ec,
     VLRU_Init_Node_r(vp);
     VChangeState_r(vp, VOL_STATE_PREATTACHED);
 
-    if (LogLevel >= 5)
-       Log("VPreAttachVolumeByVp_r:  volume %u pre-attached\n", vp->hashid);
+    if (GetLogLevel() >= 5)
+       Log("VPreAttachVolumeByVp_r:  volume %" AFS_VOLID_FMT " pre-attached\n", afs_printable_VolumeId_lu(vp->hashid));
 
   done:
     if (*ec)
@@ -2310,7 +2312,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
     struct DiskPartition64 *partp;
     char path[64];
     int isbusy = 0;
-    VolId volumeId;
+    VolumeId volumeId;
     int checkedOut;
 #ifdef AFS_DEMAND_ATTACH_FS
     VolumeStats stats_save;
@@ -2557,8 +2559,8 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
                goto done;
            }
        }
-       if (LogLevel)
-           Log("VOnline:  volume %u (%s) attached and online\n", V_id(vp),
+       if (GetLogLevel() != 0)
+         Log("VOnline:  volume %" AFS_VOLID_FMT " (%s) attached and online\n", afs_printable_VolumeId_lu(V_id(vp)),
                V_name(vp));
     }
 
@@ -2594,7 +2596,7 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
     struct DiskPartition64 *partp;
     char path[64];
     int isbusy = 0;
-    VolId volumeId;
+    VolumeId volumeId;
     Volume * nvp = NULL;
     VolumeStats stats_save;
     int checkedOut;
@@ -2681,7 +2683,8 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
 
     VUpdateVolume_r(ec, vp, 0);
     if (*ec) {
-       Log("VAttachVolume: Error updating volume %u\n", vp->hashid);
+       Log("VAttachVolume: Error updating volume %" AFS_VOLID_FMT "\n",
+           afs_printable_VolumeId_lu(vp->hashid));
        VPutVolume_r(vp);
        goto done;
     }
@@ -2699,15 +2702,16 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
 #endif /* !AFS_DEMAND_ATTACH_FS */
        VAddToVolumeUpdateList_r(ec, vp);
        if (*ec) {
-           Log("VAttachVolume: Error adding volume %u to update list\n", vp->hashid);
+           Log("VAttachVolume: Error adding volume %" AFS_VOLID_FMT " to update list\n",
+               afs_printable_VolumeId_lu(vp->hashid));
            if (vp)
                VPutVolume_r(vp);
            goto done;
        }
     }
-    if (LogLevel)
-       Log("VOnline:  volume %u (%s) attached and online\n", V_id(vp),
-           V_name(vp));
+    if (GetLogLevel() != 0)
+       Log("VOnline:  volume %" AFS_VOLID_FMT " (%s) attached and online\n",
+           afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
   done:
     if (reserve) {
        VCancelReservation_r(nvp);
@@ -3152,7 +3156,7 @@ attach_check_vop(Error *ec, VolumeId volid, struct DiskPartition64 *partp,
  * @post VOL_LOCK held
  */
 static Volume *
-attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
+attach2(Error * ec, VolumeId volumeId, char *path, struct DiskPartition64 *partp,
         Volume * vp, int isbusy, int mode, int *acheckedOut)
 {
     /* have we read in the header successfully? */
@@ -3450,6 +3454,9 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
                FreeVolumeHeader(vp);
            } else if (!V_inService(vp)) {
                Log("Volume %lu offline: not in service\n", afs_printable_uint32_lu(V_id(vp)));
+               /* the volume is offline and should be unattached */
+               *ec = VOFFLINE;
+               error_state = VOL_STATE_UNATTACHED;
                FreeVolumeHeader(vp);
            } else {
                Log("Volume %lu offline: needs salvage\n", afs_printable_uint32_lu(V_id(vp)));
@@ -3470,7 +3477,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
        V_checkoutMode(vp) = mode;
     }
 
-    AddVolumeToHashTable(vp, V_id(vp));
+    AddVolumeToHashTable(vp, vp->hashid);
 #ifdef AFS_DEMAND_ATTACH_FS
     if (VCanUnlockAttached() && (V_attachFlags(vp) & VOL_LOCKED)) {
        VUnlockVolume(vp);
@@ -3492,9 +3499,16 @@ unlocked_error:
 locked_error:
 #ifdef AFS_DEMAND_ATTACH_FS
     if (!VIsErrorState(V_attachState(vp))) {
-       if (VIsErrorState(error_state)) {
-           Log("attach2: forcing vol %u to error state (state %u flags 0x%x ec %d)\n",
-               vp->hashid, V_attachState(vp), V_attachFlags(vp), *ec);
+       if (programType != fileServer && *ec == VNOVOL) {
+           /* do not log anything in this case; it is common for
+            * non-fileserver programs to fail here with VNOVOL, since that
+            * is what happens when they simply try to use a volume, but that
+            * volume doesn't exist. */
+
+       } else if (VIsErrorState(error_state)) {
+           Log("attach2: forcing vol %" AFS_VOLID_FMT " to error state (state %u flags 0x%x ec %d)\n",
+               afs_printable_VolumeId_lu(vp->hashid), V_attachState(vp),
+               V_attachFlags(vp), *ec);
        }
        VChangeState_r(vp, error_state);
     }
@@ -3726,18 +3740,6 @@ VOfflineTimeout(struct timespec *ats)
 
 #endif /* !AFS_PTHREAD_ENV */
 
-#if 0
-static int
-VHold(Volume * vp)
-{
-    int retVal;
-    VOL_LOCK;
-    retVal = VHold_r(vp);
-    VOL_UNLOCK;
-    return retVal;
-}
-#endif
-
 static afs_int32
 VIsGoingOffline_r(struct Volume *vp)
 {
@@ -3910,7 +3912,7 @@ VPutVolumeWithCall(Volume *vp, struct VCallByVol *cbv)
    of whether or not the volume is in service or on/off line.  An error
    code, however, is returned with an indication of the volume's status */
 Volume *
-VGetVolume(Error * ec, Error * client_ec, VolId volumeId)
+VGetVolume(Error * ec, Error * client_ec, VolumeId volumeId)
 {
     Volume *retVal;
     VOL_LOCK;
@@ -3941,7 +3943,7 @@ VGetVolume(Error * ec, Error * client_ec, VolId volumeId)
  *       VPutVolumeWithCall
  */
 Volume *
-VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId,
+VGetVolumeWithCall(Error * ec, Error * client_ec, VolumeId volumeId,
                    const struct timespec *ts, struct VCallByVol *cbv)
 {
     Volume *retVal;
@@ -3953,7 +3955,7 @@ VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId,
 }
 
 Volume *
-VGetVolume_r(Error * ec, VolId volumeId)
+VGetVolume_r(Error * ec, VolumeId volumeId)
 {
     return GetVolume(ec, NULL, volumeId, NULL, NULL);
 }
@@ -3989,19 +3991,10 @@ VGetVolumeByVp_r(Error * ec, Volume * vp)
  * @note for LWP builds, 'timeout' must be NULL
  */
 static Volume *
-GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
+GetVolume(Error * ec, Error * client_ec, VolumeId volumeId, Volume * hint,
           const struct timespec *timeout)
 {
     Volume *vp = hint;
-    /* pull this profiling/debugging code out of regular builds */
-#ifdef notdef
-#define VGET_CTR_INC(x) x++
-    unsigned short V0 = 0, V1 = 0, V2 = 0, V3 = 0, V5 = 0, V6 =
-       0, V7 = 0, V8 = 0, V9 = 0;
-    unsigned short V10 = 0, V11 = 0, V12 = 0, V13 = 0, V14 = 0, V15 = 0;
-#else
-#define VGET_CTR_INC(x)
-#endif
 #ifdef AFS_DEMAND_ATTACH_FS
     Volume *avp, * rvp = hint;
 #endif
@@ -4030,7 +4023,6 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
        *ec = 0;
        if (client_ec)
            *client_ec = 0;
-       VGET_CTR_INC(V0);
 
        vp = VLookupVolume_r(ec, volumeId, vp);
        if (*ec) {
@@ -4047,9 +4039,7 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
 #endif /* AFS_DEMAND_ATTACH_FS */
 
        if (!vp) {
-           VGET_CTR_INC(V1);
            if (VInit < 2) {
-               VGET_CTR_INC(V2);
                /* Until we have reached an initialization level of 2
                 * we don't know whether this volume exists or not.
                 * We can't sleep and retry later because before a volume
@@ -4064,7 +4054,6 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
            break;
        }
 
-       VGET_CTR_INC(V3);
        IncUInt64(&VStats.hdr_gets);
 
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -4200,12 +4189,11 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
 
        LoadVolumeHeader(ec, vp);
        if (*ec) {
-           VGET_CTR_INC(V6);
            /* Only log the error if it was a totally unexpected error.  Simply
             * a missing inode is likely to be caused by the volume being deleted */
-           if (errno != ENXIO || LogLevel)
-               Log("Volume %u: couldn't reread volume header\n",
-                   vp->hashid);
+           if (errno != ENXIO || GetLogLevel() != 0)
+               Log("Volume %" AFS_VOLID_FMT ": couldn't reread volume header\n",
+                   afs_printable_VolumeId_lu(vp->hashid));
 #ifdef AFS_DEMAND_ATTACH_FS
            if (VCanScheduleSalvage()) {
                VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0 /*flags*/);
@@ -4220,21 +4208,17 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
            break;
        }
 
-       VGET_CTR_INC(V7);
        if (vp->shuttingDown) {
-           VGET_CTR_INC(V8);
            *ec = VNOVOL;
            vp = NULL;
            break;
        }
 
        if (programType == fileServer) {
-           VGET_CTR_INC(V9);
            if (vp->goingOffline) {
                if (timeout && VTimedOut(timeout)) {
                    /* we've timed out; don't wait for the vol */
                } else {
-                   VGET_CTR_INC(V10);
 #ifdef AFS_DEMAND_ATTACH_FS
                    /* wait for the volume to go offline */
                    if (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) {
@@ -4252,21 +4236,15 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
                }
            }
            if (vp->specialStatus) {
-               VGET_CTR_INC(V11);
                *ec = vp->specialStatus;
            } else if (V_inService(vp) == 0 || V_blessed(vp) == 0) {
-               VGET_CTR_INC(V12);
                *ec = VNOVOL;
            } else if (V_inUse(vp) == 0 || vp->goingOffline) {
-               VGET_CTR_INC(V13);
                *ec = VOFFLINE;
-           } else {
-               VGET_CTR_INC(V14);
            }
        }
        break;
     }
-    VGET_CTR_INC(V15);
 
 #ifdef AFS_DEMAND_ATTACH_FS
     /* if no error, bump nUsers */
@@ -4383,7 +4361,7 @@ VForceOffline_r(Volume * vp, int flags)
 
     strcpy(V_offlineMessage(vp),
           "Forced offline due to internal error: volume needs to be salvaged");
-    Log("Volume %u forced offline:  it needs salvaging!\n", V_id(vp));
+    Log("Volume %" AFS_VOLID_FMT " forced offline:  it needs salvaging!\n", afs_printable_VolumeId_lu(V_id(vp)));
 
     V_inUse(vp) = 0;
     vp->goingOffline = 0;
@@ -4451,14 +4429,14 @@ VScanCalls_r(struct Volume *vp)
 #endif /* AFS_DEMAND_ATTACH_FS */
 
     for(queue_Scan(&vp->rx_call_list, cbv, ncbv, VCallByVol)) {
-       if (LogLevel > 0) {
+       if (GetLogLevel() != 0) {
            struct rx_peer *peer;
            char hoststr[16];
            peer = rx_PeerOf(rx_ConnectionOf(cbv->call));
 
-           Log("Offlining volume %lu while client %s:%u is trying to read "
+           Log("Offlining volume %" AFS_VOLID_FMT " while client %s:%u is trying to read "
                "from it; kicking client off with error %ld\n",
-               (long unsigned) vp->hashid,
+               afs_printable_VolumeId_lu(vp->hashid),
                afs_inet_ntoa_r(rx_HostOf(peer), hoststr),
                (unsigned) ntohs(rx_PortOf(peer)),
                (long) err);
@@ -4745,16 +4723,6 @@ VDetachVolume_r(Error * ec, Volume * vp)
         * which the file server would attempt to put on line
         */
        FSYNC_VolOp(volume, tpartp->name, useDone, 0, NULL);
-       /* XXX this code path is only hit by volume utilities, thus
-        * V_BreakVolumeCallbacks will always be NULL.  if we really
-        * want to break callbacks in this path we need to use FSYNC_VolOp() */
-#ifdef notdef
-       /* Dettaching it so break all callbacks on it */
-       if (V_BreakVolumeCallbacks) {
-           Log("volume %u detached; breaking all call backs\n", volume);
-           (*V_BreakVolumeCallbacks) (volume);
-       }
-#endif
     }
 #endif /* FSSYNC_BUILD_CLIENT */
 }
@@ -4805,9 +4773,9 @@ VCloseVolumeHandles_r(Volume * vp)
        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
        IH_CONDSYNC(vp->diskDataHandle);
-#ifdef AFS_NT40_ENV
+#ifdef AFS_NAMEI_ENV
        IH_CONDSYNC(vp->linkHandle);
-#endif /* AFS_NT40_ENV */
+#endif /* AFS_NAMEI_ENV */
     }
 
     IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
@@ -4858,9 +4826,9 @@ VReleaseVolumeHandles_r(Volume * vp)
        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
        IH_CONDSYNC(vp->diskDataHandle);
-#ifdef AFS_NT40_ENV
+#ifdef AFS_NAMEI_ENV
        IH_CONDSYNC(vp->linkHandle);
-#endif /* AFS_NT40_ENV */
+#endif /* AFS_NAMEI_ENV */
     }
 
     IH_RELEASE(vp->vnodeIndex[vLarge].handle);
@@ -4896,10 +4864,20 @@ VUpdateVolume_r(Error * ec, Volume * vp, int flags)
 #endif
 
     *ec = 0;
-    if (programType == fileServer)
-       V_uniquifier(vp) =
-           (V_inUse(vp) ? V_nextVnodeUnique(vp) +
-            200 : V_nextVnodeUnique(vp));
+    if (programType == fileServer) {
+       if (!V_inUse(vp)) {
+           V_uniquifier(vp) = V_nextVnodeUnique(vp);
+       } else {
+           V_uniquifier(vp) =
+               V_nextVnodeUnique(vp) + VOLUME_UPDATE_UNIQUIFIER_BUMP;
+           if (V_uniquifier(vp) < V_nextVnodeUnique(vp)) {
+               /* uniquifier rolled over; reset the counters */
+               V_nextVnodeUnique(vp) = 2;      /* 1 is reserved for the root vnode */
+               V_uniquifier(vp) =
+                   V_nextVnodeUnique(vp) + VOLUME_UPDATE_UNIQUIFIER_BUMP;
+           }
+       }
+    }
 
 #ifdef AFS_DEMAND_ATTACH_FS
     state_save = VChangeState_r(vp, VOL_STATE_UPDATING);
@@ -4917,8 +4895,8 @@ VUpdateVolume_r(Error * ec, Volume * vp, int flags)
 #endif
 
     if (*ec) {
-       Log("VUpdateVolume: error updating volume header, volume %u (%s)\n",
-           V_id(vp), V_name(vp));
+       Log("VUpdateVolume: error updating volume header, volume %" AFS_VOLID_FMT " (%s)\n",
+           afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
        /* try to update on-disk header,
         * while preventing infinite recursion */
        if (!(flags & VOL_UPDATE_NOFORCEOFF)) {
@@ -5041,8 +5019,8 @@ VCheckDetach(Volume * vp)
            V_inUse(vp) = 0;
            VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
            if (ec) {
-               Log("VCheckDetach: volume header update for volume %u "
-                   "failed with errno %d\n", vp->hashid, errno);
+               Log("VCheckDetach: volume header update for volume %" AFS_VOLID_FMT " "
+                   "failed with errno %d\n", afs_printable_VolumeId_lu(vp->hashid), errno);
            }
        }
        VReleaseVolumeHandles_r(vp);
@@ -5075,8 +5053,8 @@ VCheckDetach(Volume * vp)
            V_inUse(vp) = 0;
            VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
            if (ec) {
-               Log("VCheckDetach: volume header update for volume %u failed with errno %d\n",
-                   vp->hashid, errno);
+               Log("VCheckDetach: volume header update for volume %" AFS_VOLID_FMT " failed with errno %d\n",
+                   afs_printable_VolumeId_lu(vp->hashid), errno);
            }
        }
        VReleaseVolumeHandles_r(vp);
@@ -5132,7 +5110,7 @@ VCheckOffline(Volume * vp)
        VUpdateVolume_r(&error, vp, 0);
        VCloseVolumeHandles_r(vp);
 
-       if (LogLevel) {
+       if (GetLogLevel() != 0) {
            if (V_offlineMessage(vp)[0]) {
                Log("VOffline: Volume %lu (%s) is now offline (%s)\n",
                    afs_printable_uint32_lu(V_id(vp)), V_name(vp),
@@ -5171,7 +5149,7 @@ VCheckOffline(Volume * vp)
        V_inUse(vp) = 0;
        VUpdateVolume_r(&error, vp, 0);
        VCloseVolumeHandles_r(vp);
-       if (LogLevel) {
+       if (GetLogLevel() != 0) {
            if (V_offlineMessage(vp)[0]) {
                Log("VOffline: Volume %lu (%s) is now offline (%s)\n",
                    afs_printable_uint32_lu(V_id(vp)), V_name(vp),
@@ -5632,7 +5610,7 @@ VRequestSalvage_r(Error * ec, Volume * vp, int reason, int flags)
 
            *ec = VSALVAGING;
        } else {
-           Log("VRequestSalvage: volume %u online salvaged too many times; forced offline.\n", vp->hashid);
+           Log("VRequestSalvage: volume %" AFS_VOLID_FMT " online salvaged too many times; forced offline.\n", afs_printable_VolumeId_lu(vp->hashid));
 
            /* make sure neither VScheduleSalvage_r nor
             * VUpdateSalvagePriority_r try to schedule another salvage */
@@ -5642,6 +5620,37 @@ VRequestSalvage_r(Error * ec, Volume * vp, int reason, int flags)
            *ec = VSALVAGE;
            code = 1;
        }
+       if ((flags & VOL_SALVAGE_NO_OFFLINE)) {
+           /* Here, we free the header for the volume, but make sure to only
+            * do this if VOL_SALVAGE_NO_OFFLINE is specified. The reason for
+            * this requires a bit of explanation.
+            *
+            * Normally, the volume header will be freed when the volume goes
+            * goes offline. However, if VOL_SALVAGE_NO_OFFLINE has been
+            * specified, the volume was in the process of being attached when
+            * we discovered that it needed salvaging. Thus, the volume will
+            * never go offline, since it never went fully online in the first
+            * place. Specifically, we do not call VOfflineForSalvage_r above,
+            * and we never get rid of the volume via VPutVolume_r; the volume
+            * has not been initialized enough for those to work.
+            *
+            * So instead, explicitly free the volume header here. If we do not
+            * do this, we are wasting a header that some other volume could be
+            * using, since the header remains attached to the volume. Also if
+            * we do not free the header here, we end up with a volume where
+            * nUsers == 0, but the volume has a header that is not on the
+            * header LRU. Some code expects that all nUsers == 0 volumes have
+            * their header on the header LRU (or have no header).
+            *
+            * Also note that we must not free the volume header here if
+            * VOL_SALVAGE_NO_OFFLINE is not set. Since, if
+            * VOL_SALVAGE_NO_OFFLINE is not set, someone else may have a
+            * reference to this volume, and they assume they can use the
+            * volume's header. If we free the volume out from under them, they
+            * can easily segfault.
+            */
+           FreeVolumeHeader(vp);
+       }
     }
     return code;
 }
@@ -5716,8 +5725,8 @@ static_inline int
 try_SALVSYNC(Volume *vp, char *partName, int *code) {
 #ifdef SALVSYNC_BUILD_CLIENT
     if (VCanUseSALVSYNC()) {
-       Log("Scheduling salvage for volume %lu on part %s over SALVSYNC\n",
-           afs_printable_uint32_lu(vp->hashid), partName);
+       Log("Scheduling salvage for volume %" AFS_VOLID_FMT " on part %s over SALVSYNC\n",
+           afs_printable_VolumeId_lu(vp->hashid), partName);
 
        /* can't use V_id() since there's no guarantee
         * we have the disk data header at this point */
@@ -5737,8 +5746,8 @@ static_inline int
 try_FSSYNC(Volume *vp, char *partName, int *code) {
 #ifdef FSSYNC_BUILD_CLIENT
     if (VCanUseFSSYNC()) {
-       Log("Scheduling salvage for volume %lu on part %s over FSSYNC\n",
-           afs_printable_uint32_lu(vp->hashid), partName);
+       Log("Scheduling salvage for volume %" AFS_VOLID_FMT " on part %s over FSSYNC\n",
+           afs_printable_VolumeId_lu(vp->hashid), partName);
 
        /*
         * If we aren't the fileserver, tell the fileserver the volume
@@ -5863,19 +5872,19 @@ VScheduleSalvage_r(Volume * vp)
                break;
            case SYNC_DENIED:
                ret = VCHECK_SALVAGE_DENIED;
-               Log("VScheduleSalvage_r: Salvage request for volume %lu "
-                   "denied\n", afs_printable_uint32_lu(vp->hashid));
+               Log("VScheduleSalvage_r: Salvage request for volume %" AFS_VOLID_FMT " "
+                   "denied\n", afs_printable_VolumeId_lu(vp->hashid));
                break;
            case SYNC_FAILED:
                ret = VCHECK_SALVAGE_FAIL;
-               Log("VScheduleSalvage_r: Salvage request for volume %lu "
-                   "failed\n", afs_printable_uint32_lu(vp->hashid));
+               Log("VScheduleSalvage_r: Salvage request for volume %" AFS_VOLID_FMT " "
+                   "failed\n", afs_printable_VolumeId_lu(vp->hashid));
                break;
            default:
                ret = VCHECK_SALVAGE_FAIL;
-               Log("VScheduleSalvage_r: Salvage request for volume %lu "
+               Log("VScheduleSalvage_r: Salvage request for volume %" AFS_VOLID_FMT " "
                    "received unknown protocol error %d\n",
-                   afs_printable_uint32_lu(vp->hashid), code);
+                   afs_printable_VolumeId_lu(vp->hashid), code);
                break;
            }
 
@@ -6350,7 +6359,7 @@ VAllocBitmapEntry_r(Error * ec, Volume * vp,
            index->bitmapOffset = (afs_uint32) (bp - index->bitmap);
            while (*bp == 0xff)
                bp++;
-           o = ffs(~*bp) - 1;  /* ffs is documented in BSTRING(3) */
+           o = opr_ffs(~*bp) - 1;
            *bp |= (1 << o);
            ret = ((bp - index->bitmap) * 8 + o);
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -6423,7 +6432,9 @@ VFreeBitMapEntry_r(Error * ec, Volume *vp, struct vnodeIndex *index,
 
  done:
 #ifdef AFS_DEMAND_ATTACH_FS
-    VCancelReservation_r(vp);
+    if (flags & VOL_FREE_BITMAP_WAIT) {
+       VCancelReservation_r(vp);
+    }
 #endif
     return; /* make the compiler happy for non-DAFS */
 }
@@ -6569,7 +6580,7 @@ VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class)
  *
  */
 void
-VGetVolumePath(Error * ec, VolId volumeId, char **partitionp, char **namep)
+VGetVolumePath(Error * ec, VolumeId volumeId, char **partitionp, char **namep)
 {
     static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
     char path[VMAXPATHLEN];
@@ -6579,7 +6590,7 @@ VGetVolumePath(Error * ec, VolId volumeId, char **partitionp, char **namep)
     *ec = 0;
     name[0] = OS_DIRSEPC;
     snprintf(&name[1], (sizeof name) - 1, VFORMAT,
-            afs_printable_uint32_lu(volumeId));
+            afs_printable_VolumeId_lu(volumeId));
     for (dp = DiskPartitionList; dp; dp = dp->next) {
        struct afs_stat_st status;
        strcpy(path, VPartitionPath(dp));
@@ -6642,7 +6653,7 @@ char *
 VolumeExternalName(VolumeId volumeId)
 {
     static char name[VMAXPATHLEN];
-    snprintf(name, sizeof name, VFORMAT, afs_printable_uint32_lu(volumeId));
+    snprintf(name, sizeof name, VFORMAT, afs_printable_VolumeId_lu(volumeId));
     return name;
 }
 
@@ -6663,7 +6674,7 @@ VolumeExternalName(VolumeId volumeId)
 int
 VolumeExternalName_r(VolumeId volumeId, char * name, size_t len)
 {
-    return snprintf(name, len, VFORMAT, afs_printable_uint32_lu(volumeId));
+    return snprintf(name, len, VFORMAT, afs_printable_VolumeId_lu(volumeId));
 }
 
 
@@ -7145,7 +7156,7 @@ VInitVLRU(void)
     /* setup the timing constants */
     VLRU_ComputeConstants();
 
-    /* XXX put inside LogLevel check? */
+    /* XXX put inside log level check? */
     Log("VLRU: starting scanner with the following configuration parameters:\n");
     Log("VLRU:  offlining volumes after minimum of %d seconds of inactivity\n", VLRU_offline_thresh);
     Log("VLRU:  running VLRU soft detach pass every %d seconds\n", VLRU_offline_interval);
@@ -8350,8 +8361,8 @@ VSetVolHashSize(int logsize)
     }
 
     if (!VInit) {
-        VolumeHashTable.Size = 1 << logsize;
-        VolumeHashTable.Mask = VolumeHashTable.Size - 1;
+        VolumeHashTable.Size = opr_jhash_size(logsize);
+        VolumeHashTable.Mask = opr_jhash_mask(logsize);
     } else {
        /* we can't yet support runtime modification of this
         * parameter. we'll need a configuration rwlock to
@@ -8402,7 +8413,7 @@ VInitVolumeHash(void)
  *       asynchronous hash chain reordering to finish.
  */
 static void
-AddVolumeToHashTable(Volume * vp, int hashid)
+AddVolumeToHashTable(Volume * vp, VolumeId hashid)
 {
     VolumeHashChainHead * head;
 
@@ -8422,7 +8433,6 @@ AddVolumeToHashTable(Volume * vp, int hashid)
     head->len++;
     vp->hashid = hashid;
     queue_Append(head, vp);
-    vp->vnodeHashOffset = VolumeHashOffset_r();
 }
 
 /**
@@ -8497,7 +8507,7 @@ DeleteVolumeFromHashTable(Volume * vp)
  *       hint volume object.
  */
 Volume *
-VLookupVolume_r(Error * ec, VolId volumeId, Volume * hint)
+VLookupVolume_r(Error * ec, VolumeId volumeId, Volume * hint)
 {
     int looks = 0;
     Volume * vp, *np;