Remove DUX/OSF code
[openafs.git] / src / vol / volume.c
index 7df0705..a3b0662 100644 (file)
 #include <sys/file.h>
 #endif
 
-#include <afs/opr.h>
+#ifdef AFS_PTHREAD_ENV
+# include <opr/lock.h>
+#else
+# include <opr/lockstub.h>
+#endif
+#include <opr/ffs.h>
+#include <opr/jhash.h>
+
 #include <afs/afsint.h>
 
 #include <rx/rx_queue.h>
 
 #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
@@ -58,7 +62,6 @@
 #include <sys/fs.h>
 #endif
 #endif /* AFS_VFSINCL_ENV */
-#endif /* AFS_OSF_ENV */
 #endif /* AFS_SGI_ENV */
 #endif /* !AFS_NT40_ENV */
 
@@ -135,12 +138,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);
@@ -154,7 +153,7 @@ 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);
@@ -166,11 +165,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;
 
@@ -190,9 +187,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.
@@ -213,6 +212,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"
 
 
@@ -226,24 +231,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
@@ -306,7 +293,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 */
@@ -334,7 +321,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 */
 };
@@ -529,7 +516,7 @@ static void
 VSetVInit_r(int value)
 {
     VInit = value;
-    CV_BROADCAST(&vol_vinit_cond);
+    opr_cv_broadcast(&vol_vinit_cond);
 }
 
 static_inline void
@@ -581,12 +568,12 @@ VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
     opr_Verify(pthread_key_create(&VThread_key, NULL) == 0);
 #endif
 
-    MUTEX_INIT(&vol_glock_mutex, "vol glock", MUTEX_DEFAULT, 0);
-    MUTEX_INIT(&vol_trans_mutex, "vol trans", MUTEX_DEFAULT, 0);
-    CV_INIT(&vol_put_volume_cond, "vol put", CV_DEFAULT, 0);
-    CV_INIT(&vol_sleep_cond, "vol sleep", CV_DEFAULT, 0);
-    CV_INIT(&vol_init_attach_cond, "vol init attach", CV_DEFAULT, 0);
-    CV_INIT(&vol_vinit_cond, "vol init", CV_DEFAULT, 0);
+    opr_mutex_init(&vol_glock_mutex);
+    opr_mutex_init(&vol_trans_mutex);
+    opr_cv_init(&vol_put_volume_cond);
+    opr_cv_init(&vol_sleep_cond);
+    opr_cv_init(&vol_init_attach_cond);
+    opr_cv_init(&vol_vinit_cond);
 #ifndef AFS_PTHREAD_ENV
     IOMGR_Initialize();
 #endif /* AFS_PTHREAD_ENV */
@@ -595,7 +582,7 @@ VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
     srandom(time(0));          /* For VGetVolumeInfo */
 
 #ifdef AFS_DEMAND_ATTACH_FS
-    MUTEX_INIT(&vol_salvsync_mutex, "salvsync", MUTEX_DEFAULT, 0);
+    opr_mutex_init(&vol_salvsync_mutex);
 #endif /* AFS_DEMAND_ATTACH_FS */
 
     /* Ok, we have done enough initialization that fileserver can
@@ -713,7 +700,7 @@ VInitAttachVolumes(ProgramType pt)
        pthread_t tid;
        pthread_attr_t attrs;
 
-       CV_INIT(&params.thread_done_cv, "thread done", CV_DEFAULT, 0);
+       opr_cv_init(&params.thread_done_cv);
        queue_Init(&params);
        params.n_threads_complete = 0;
 
@@ -764,11 +751,11 @@ VInitAttachVolumes(ProgramType pt)
            VInitVolumePackageThread(&params);
        }
 
-       CV_DESTROY(&params.thread_done_cv);
+       opr_cv_destroy(&params.thread_done_cv);
     }
     VOL_LOCK;
     VSetVInit_r(2);                    /* Initialized, and all volumes have been attached */
-    CV_BROADCAST(&vol_init_attach_cond);
+    opr_cv_broadcast(&vol_init_attach_cond);
     VOL_UNLOCK;
     return 0;
 }
@@ -807,7 +794,7 @@ VInitVolumePackageThread(void * args) {
 
 done:
     params->n_threads_complete++;
-    CV_SIGNAL(&params->thread_done_cv);
+    opr_cv_signal(&params->thread_done_cv);
     VOL_UNLOCK;
     return NULL;
 }
@@ -840,8 +827,8 @@ VInitAttachVolumes(ProgramType pt)
 
        /* create partition work queue */
         queue_Init(&pq);
-       CV_INIT(&(pq.cv), "partq", CV_DEFAULT, 0);
-       MUTEX_INIT(&(pq.mutex), "partq", MUTEX_DEFAULT, 0);
+       opr_cv_init(&pq.cv);
+       opr_mutex_init(&pq.mutex);
        for (parts = 0, diskP = DiskPartitionList; diskP; diskP = diskP->next, parts++) {
            struct diskpartition_queue_t *dp;
            dp = malloc(sizeof(struct diskpartition_queue_t));
@@ -855,8 +842,8 @@ VInitAttachVolumes(ProgramType pt)
 
         /* create volume work queue */
         queue_Init(&vq);
-       CV_INIT(&(vq.cv), "volq", CV_DEFAULT, 0);
-       MUTEX_INIT(&(vq.mutex), "volq", MUTEX_DEFAULT, 0);
+       opr_cv_init(&vq.cv);
+       opr_mutex_init(&vq.mutex);
 
         opr_Verify(pthread_attr_init(&attrs) == 0);
         opr_Verify(pthread_attr_setdetachstate(&attrs,
@@ -888,15 +875,15 @@ VInitAttachVolumes(ProgramType pt)
         VInitPreAttachVolumes(threads, &vq);
 
         opr_Verify(pthread_attr_destroy(&attrs) == 0);
-       CV_DESTROY(&pq.cv);
-       MUTEX_DESTROY(&pq.mutex);
-       CV_DESTROY(&vq.cv);
-       MUTEX_DESTROY(&vq.mutex);
+       opr_cv_destroy(&pq.cv);
+       opr_mutex_destroy(&pq.mutex);
+       opr_cv_destroy(&vq.cv);
+       opr_mutex_destroy(&vq.mutex);
     }
 
     VOL_LOCK;
     VSetVInit_r(2);                    /* Initialized, and all volumes have been attached */
-    CV_BROADCAST(&vol_init_attach_cond);
+    opr_cv_broadcast(&vol_init_attach_cond);
     VOL_UNLOCK;
 
     return 0;
@@ -933,7 +920,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));
@@ -949,14 +936,14 @@ VInitVolumePackageThread(void *args)
             vp->hashid = vid;
             queue_Init(&vp->vnode_list);
             queue_Init(&vp->rx_call_list);
-           CV_INIT(&V_attachCV(vp), "partattach", CV_DEFAULT, 0);
+           opr_cv_init(&V_attachCV(vp));
 
             vb->batch[vb->size++] = vp;
             if (vb->size == VINIT_BATCH_MAX_SIZE) {
-               MUTEX_ENTER(&vq->mutex);
+               opr_mutex_enter(&vq->mutex);
                 queue_Append(vq, vb);
-               CV_BROADCAST(&vq->cv);
-               MUTEX_EXIT(&vq->mutex);
+               opr_cv_broadcast(&vq->cv);
+               opr_mutex_exit(&vq->mutex);
 
                 vb = malloc(sizeof(struct volume_init_batch));
                 opr_Assert(vb);
@@ -969,10 +956,10 @@ VInitVolumePackageThread(void *args)
     }
 
     vb->last = 1;
-    MUTEX_ENTER(&vq->mutex);
+    opr_mutex_enter(&vq->mutex);
     queue_Append(vq, vb);
-    CV_BROADCAST(&vq->cv);
-    MUTEX_EXIT(&vq->mutex);
+    opr_cv_broadcast(&vq->cv);
+    opr_mutex_exit(&vq->mutex);
 
     Log("Partition scan thread %d of %d ended\n", params->thread, params->nthreads);
     free(params);
@@ -994,14 +981,14 @@ VInitNextPartition(struct partition_queue *pq)
     }
 
     /* get next partition to scan */
-    MUTEX_ENTER(&pq->mutex);
+    opr_mutex_enter(&pq->mutex);
     if (queue_IsEmpty(pq)) {
-       MUTEX_EXIT(&pq->mutex);
+       opr_mutex_exit(&pq->mutex);
         return NULL;
     }
     dp = queue_First(pq, diskpartition_queue_t);
     queue_Remove(dp);
-    MUTEX_EXIT(&pq->mutex);
+    opr_mutex_exit(&pq->mutex);
 
     opr_Assert(dp);
     opr_Assert(dp->diskP);
@@ -1014,11 +1001,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))) {
@@ -1049,13 +1036,13 @@ VInitPreAttachVolumes(int nthreads, struct volume_init_queue *vq)
 
     while (nthreads) {
         /* dequeue next volume */
-       MUTEX_ENTER(&vq->mutex);
+       opr_mutex_enter(&vq->mutex);
         if (queue_IsEmpty(vq)) {
-           CV_WAIT(&vq->cv, &vq->mutex);
+           opr_cv_wait(&vq->cv, &vq->mutex);
         }
         vb = queue_First(vq, volume_init_batch);
         queue_Remove(vb);
-       MUTEX_EXIT(&vq->mutex);
+       opr_mutex_exit(&vq->mutex);
 
         if (vb->size) {
             VOL_LOCK;
@@ -1070,7 +1057,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
@@ -1128,7 +1115,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);
@@ -1234,9 +1221,9 @@ VShutdown_r(void)
     if (vol_attach_threads > 1) {
        /* prepare for parallel shutdown */
        params.n_threads = vol_attach_threads;
-       MUTEX_INIT(&params.lock, "params", MUTEX_DEFAULT, 0);
-       CV_INIT(&params.cv, "params", CV_DEFAULT, 0);
-       CV_INIT(&params.master_cv, "params master", CV_DEFAULT, 0);
+       opr_mutex_init(&params.lock);
+       opr_cv_init(&params.cv);
+       opr_cv_init(&params.master_cv);
        opr_Verify(pthread_attr_init(&attrs) == 0);
        opr_Verify(pthread_attr_setdetachstate(&attrs,
                                               PTHREAD_CREATE_DETACHED) == 0);
@@ -1277,7 +1264,7 @@ VShutdown_r(void)
            vol_attach_threads, params.n_parts, params.n_parts > 1 ? "s" : "" );
 
        /* do pass 0 shutdown */
-       MUTEX_ENTER(&params.lock);
+       opr_mutex_enter(&params.lock);
        for (i=0; i < params.n_threads; i++) {
            opr_Verify(pthread_create(&tid, &attrs, &VShutdownThread,
                                      &params) == 0);
@@ -1289,8 +1276,8 @@ VShutdown_r(void)
        }
        params.n_threads_complete = 0;
        params.pass = 1;
-       CV_BROADCAST(&params.cv);
-       MUTEX_EXIT(&params.lock);
+       opr_cv_broadcast(&params.cv);
+       opr_mutex_exit(&params.lock);
 
        Log("VShutdown:  pass 0 completed using the 1 thread per partition algorithm\n");
        Log("VShutdown:  starting passes 1 through 3 using finely-granular mp-fast algorithm\n");
@@ -1304,9 +1291,9 @@ VShutdown_r(void)
        }
 
        opr_Verify(pthread_attr_destroy(&attrs) == 0);
-       CV_DESTROY(&params.cv);
-       CV_DESTROY(&params.master_cv);
-       MUTEX_DESTROY(&params.lock);
+       opr_cv_destroy(&params.cv);
+       opr_cv_destroy(&params.master_cv);
+       opr_mutex_destroy(&params.lock);
 
        /* drop the VByPList exclusive reservations */
        for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
@@ -1359,9 +1346,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");
@@ -1583,14 +1570,14 @@ VShutdownThread(void * args)
     params = (vshutdown_thread_t *) args;
 
     /* acquire the shutdown pass 0 lock */
-    MUTEX_ENTER(&params->lock);
+    opr_mutex_enter(&params->lock);
 
     /* if there's still pass 0 work to be done,
      * get a work entry, and do a pass 0 shutdown */
     if (queue_IsNotEmpty(params)) {
        dpq = queue_First(params, diskpartition_queue_t);
        queue_Remove(dpq);
-       MUTEX_EXIT(&params->lock);
+       opr_mutex_exit(&params->lock);
        diskP = dpq->diskP;
        free(dpq);
        id = diskP->index;
@@ -1599,20 +1586,20 @@ VShutdownThread(void * args)
        while (ShutdownVolumeWalk_r(diskP, 0, &params->part_pass_head[id]))
            count++;
        params->stats[0][diskP->index] = count;
-       MUTEX_ENTER(&params->lock);
+       opr_mutex_enter(&params->lock);
     }
 
     params->n_threads_complete++;
     if (params->n_threads_complete == params->n_threads) {
        /* notify control thread that all workers have completed pass 0 */
-       CV_SIGNAL(&params->master_cv);
+       opr_cv_signal(&params->master_cv);
     }
     while (params->pass == 0) {
-       CV_WAIT(&params->cv, &params->lock);
+       opr_cv_wait(&params->cv, &params->lock);
     }
 
     /* switch locks */
-    MUTEX_EXIT(&params->lock);
+    opr_mutex_exit(&params->lock);
     VOL_LOCK;
 
     pass = params->pass;
@@ -1696,7 +1683,7 @@ VShutdownThread(void * args)
                    ShutdownCreateSchedule(params);
 
                    /* wake up all the workers */
-                   CV_BROADCAST(&params->cv);
+                   opr_cv_broadcast(&params->cv);
 
                    VOL_UNLOCK;
                    Log("VShutdown:  pass %d completed using %d threads on %d partitions\n",
@@ -1780,9 +1767,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;
 }
@@ -1842,9 +1834,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 */
@@ -1869,9 +1862,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");
@@ -1933,7 +1926,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;
@@ -1943,7 +1936,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);
@@ -1951,18 +1944,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;
@@ -1973,8 +1966,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;
     }
@@ -2140,7 +2133,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;
@@ -2155,11 +2148,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);
 }
 
@@ -2175,6 +2183,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
@@ -2193,12 +2203,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) &&
@@ -2212,8 +2227,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 */
@@ -2235,7 +2251,7 @@ VPreAttachVolumeByVp_r(Error * ec,
        opr_Assert(vp != NULL);
        queue_Init(&vp->vnode_list);
        queue_Init(&vp->rx_call_list);
-       CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0);
+       opr_cv_init(&V_attachCV(vp));
     }
 
     /* link the volume with its associated vice partition */
@@ -2273,8 +2289,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)
@@ -2305,7 +2321,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;
@@ -2466,7 +2482,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
       queue_Init(&vp->vnode_list);
       queue_Init(&vp->rx_call_list);
 #ifdef AFS_DEMAND_ATTACH_FS
-      CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0);
+      opr_cv_init(&V_attachCV(vp));
 #endif /* AFS_DEMAND_ATTACH_FS */
     }
 
@@ -2552,8 +2568,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));
     }
 
@@ -2589,7 +2605,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;
@@ -2676,7 +2692,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;
     }
@@ -2694,15 +2711,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);
@@ -2935,7 +2953,7 @@ attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
     if (VCanUseFSSYNC() && (mode == V_PEEK || peek)) {
        SYNC_response res;
        res.payload.len = sizeof(VolumeDiskData);
-       res.payload.buf = &vp->header->diskstuff;
+       res.payload.buf = &(V_disk(vp));
 
        if (FSYNC_VolOp(vp->hashid,
                        partp->name,
@@ -3147,7 +3165,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? */
@@ -3423,15 +3441,21 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
            V_inUse(vp) = fileServer;
            V_offlineMessage(vp)[0] = '\0';
        }
+#ifdef AFS_DEMAND_ATTACH_FS
+       /* check if the volume is actually usable. only do this for DAFS; for
+        * non-DAFS, volumes that are not inService/blessed can still be
+        * attached, even if clients cannot access them. this is relevant
+        * because for non-DAFS, we try to attach the volume when e.g.
+        * volserver gives us back then vol when its done with it, but
+        * volserver may give us back a volume that is not inService/blessed. */
+
        if (!V_inUse(vp)) {
            *ec = VNOVOL;
-#ifdef AFS_DEMAND_ATTACH_FS
            /* Put the vol into PREATTACHED state, so if someone tries to
             * access it again, we try to attach, see that we're not blessed,
             * and give a VNOVOL error again. Putting it into UNATTACHED state
             * would result in a VOFFLINE error instead. */
            error_state = VOL_STATE_PREATTACHED;
-#endif /* AFS_DEMAND_ATTACH_FS */
 
            /* mimic e.g. GetVolume errors */
            if (!V_blessed(vp)) {
@@ -3439,30 +3463,30 @@ 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)));
                *ec = VSALVAGE;
-#ifdef AFS_DEMAND_ATTACH_FS
                error_state = VOL_STATE_ERROR;
                /* see if we can recover */
                VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
-#endif
            }
-#ifdef AFS_DEMAND_ATTACH_FS
            vp->nUsers = 0;
-#endif
            goto locked_error;
        }
+#endif /* AFS_DEMAND_ATTACH_FS */
     } else {
 #ifdef AFS_DEMAND_ATTACH_FS
-       if ((mode != V_PEEK) && (mode != V_SECRETLY))
+       if ((mode != V_PEEK) && (mode != V_SECRETLY) && (mode != V_READONLY))
            V_inUse(vp) = programType;
 #endif /* AFS_DEMAND_ATTACH_FS */
        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);
@@ -3484,9 +3508,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);
     }
@@ -3902,7 +3933,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;
@@ -3933,7 +3964,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;
@@ -3945,7 +3976,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);
 }
@@ -3981,7 +4012,7 @@ 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;
@@ -4195,9 +4226,9 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
            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*/);
@@ -4375,7 +4406,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;
@@ -4389,7 +4420,7 @@ VForceOffline_r(Volume * vp, int flags)
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 #ifdef AFS_PTHREAD_ENV
-    CV_BROADCAST(&vol_put_volume_cond);
+    opr_cv_broadcast(&vol_put_volume_cond);
 #else /* AFS_PTHREAD_ENV */
     LWP_NoYieldSignal(VPutVolume);
 #endif /* AFS_PTHREAD_ENV */
@@ -4443,14 +4474,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);
@@ -4797,9 +4828,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);
@@ -4850,9 +4881,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);
@@ -4888,10 +4919,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);
@@ -4909,8 +4950,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)) {
@@ -5033,15 +5074,15 @@ 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);
        VCheckSalvage(vp);
        ReallyFreeVolume(vp);
        if (programType == fileServer) {
-           CV_BROADCAST(&vol_put_volume_cond);
+           opr_cv_broadcast(&vol_put_volume_cond);
        }
     }
     return ret;
@@ -5067,15 +5108,15 @@ 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);
        ReallyFreeVolume(vp);
        if (programType == fileServer) {
 #if defined(AFS_PTHREAD_ENV)
-           CV_BROADCAST(&vol_put_volume_cond);
+           opr_cv_broadcast(&vol_put_volume_cond);
 #else /* AFS_PTHREAD_ENV */
            LWP_NoYieldSignal(VPutVolume);
 #endif /* AFS_PTHREAD_ENV */
@@ -5124,7 +5165,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),
@@ -5163,7 +5204,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),
@@ -5175,7 +5216,7 @@ VCheckOffline(Volume * vp)
        }
        FreeVolumeHeader(vp);
 #ifdef AFS_PTHREAD_ENV
-       CV_BROADCAST(&vol_put_volume_cond);
+       opr_cv_broadcast(&vol_put_volume_cond);
 #else /* AFS_PTHREAD_ENV */
        LWP_NoYieldSignal(VPutVolume);
 #endif /* AFS_PTHREAD_ENV */
@@ -5624,7 +5665,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 */
@@ -5634,6 +5675,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;
 }
@@ -5708,8 +5780,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 */
@@ -5729,8 +5801,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
@@ -5855,19 +5927,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;
            }
 
@@ -6342,7 +6414,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
@@ -6415,7 +6487,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 */
 }
@@ -6561,7 +6635,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];
@@ -6571,7 +6645,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));
@@ -6634,7 +6708,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;
 }
 
@@ -6655,7 +6729,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));
 }
 
 
@@ -7131,13 +7205,13 @@ VInitVLRU(void)
        queue_Init(&volume_LRU.q[i]);
        volume_LRU.q[i].len = 0;
        volume_LRU.q[i].busy = 0;
-       CV_INIT(&volume_LRU.q[i].cv, "vol lru", CV_DEFAULT, 0);
+       opr_cv_init(&volume_LRU.q[i].cv);
     }
 
     /* 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);
@@ -7149,7 +7223,7 @@ VInitVLRU(void)
     /* start up the VLRU scanner */
     volume_LRU.scanner_state = VLRU_SCANNER_STATE_OFFLINE;
     if (programType == fileServer) {
-       CV_INIT(&volume_LRU.cv, "vol lru", CV_DEFAULT, 0);
+       opr_cv_init(&volume_LRU.cv);
        opr_Verify(pthread_attr_init(&attrs) == 0);
        opr_Verify(pthread_attr_setdetachstate(&attrs,
                                               PTHREAD_CREATE_DETACHED) == 0);
@@ -7457,7 +7531,7 @@ VLRU_ScannerThread(void * args)
        /* check to see if we've been asked to pause */
        if (volume_LRU.scanner_state == VLRU_SCANNER_STATE_PAUSING) {
            volume_LRU.scanner_state = VLRU_SCANNER_STATE_PAUSED;
-           CV_BROADCAST(&volume_LRU.cv);
+           opr_cv_broadcast(&volume_LRU.cv);
            do {
                VOL_CV_WAIT(&volume_LRU.cv);
            } while (volume_LRU.scanner_state == VLRU_SCANNER_STATE_PAUSED);
@@ -7533,7 +7607,7 @@ VLRU_ScannerThread(void * args)
 
     /* signal that scanner is down */
     volume_LRU.scanner_state = VLRU_SCANNER_STATE_OFFLINE;
-    CV_BROADCAST(&volume_LRU.cv);
+    opr_cv_broadcast(&volume_LRU.cv);
     VOL_UNLOCK;
     return NULL;
 }
@@ -7856,7 +7930,7 @@ VLRU_EndExclusive_r(struct VLRU_q * q)
 {
     opr_Assert(q->busy);
     q->busy = 0;
-    CV_BROADCAST(&q->cv);
+    opr_cv_broadcast(&q->cv);
 }
 
 /* wait for another thread to end exclusive access on VLRU */
@@ -8342,8 +8416,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
@@ -8372,7 +8446,7 @@ VInitVolumeHash(void)
     for (i=0; i < VolumeHashTable.Size; i++) {
        queue_Init(&VolumeHashTable.Table[i]);
 #ifdef AFS_DEMAND_ATTACH_FS
-       CV_INIT(&VolumeHashTable.Table[i].chain_busy_cv, "vhash busy", CV_DEFAULT, 0);
+       opr_cv_init(&VolumeHashTable.Table[i].chain_busy_cv);
 #endif /* AFS_DEMAND_ATTACH_FS */
     }
 }
@@ -8394,7 +8468,7 @@ VInitVolumeHash(void)
  *       asynchronous hash chain reordering to finish.
  */
 static void
-AddVolumeToHashTable(Volume * vp, int hashid)
+AddVolumeToHashTable(Volume * vp, VolumeId hashid)
 {
     VolumeHashChainHead * head;
 
@@ -8414,7 +8488,6 @@ AddVolumeToHashTable(Volume * vp, int hashid)
     head->len++;
     vp->hashid = hashid;
     queue_Append(head, vp);
-    vp->vnodeHashOffset = VolumeHashOffset_r();
 }
 
 /**
@@ -8489,7 +8562,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;
@@ -8667,7 +8740,7 @@ VHashEndExclusive_r(VolumeHashChainHead * head)
 {
     opr_Assert(head->busy);
     head->busy = 0;
-    CV_BROADCAST(&head->chain_busy_cv);
+    opr_cv_broadcast(&head->chain_busy_cv);
 }
 
 /**
@@ -8831,7 +8904,7 @@ VVByPListEndExclusive_r(struct DiskPartition64 * dp)
 {
     opr_Assert(dp->vol_list.busy);
     dp->vol_list.busy = 0;
-    CV_BROADCAST(&dp->vol_list.cv);
+    opr_cv_broadcast(&dp->vol_list.cv);
 }
 
 /**