vol: allow non-dafs volume utils to attach with V_READONLY again
[openafs.git] / src / vol / volume.c
index 791cd53..98eadba 100644 (file)
 #include <sys/file.h>
 #endif
 
-#include <rx/xdr.h>
+#ifdef AFS_PTHREAD_ENV
+# include <opr/lock.h>
+#else
+# include <opr/lockstub.h>
+#endif
+
 #include <afs/afsint.h>
 
+#include <rx/rx_queue.h>
+
 #ifndef AFS_NT40_ENV
 #if !defined(AFS_SGI_ENV)
 #ifdef AFS_OSF_ENV
@@ -374,6 +381,13 @@ static void VVByPListEndExclusive_r(struct DiskPartition64 * dp);
 static void VVByPListWait_r(struct DiskPartition64 * dp);
 
 /* online salvager */
+typedef enum {
+    VCHECK_SALVAGE_OK = 0,         /**< no pending salvage */
+    VCHECK_SALVAGE_SCHEDULED = 1,  /**< salvage has been scheduled */
+    VCHECK_SALVAGE_ASYNC = 2,      /**< salvage being scheduled */
+    VCHECK_SALVAGE_DENIED = 3,     /**< salvage not scheduled; denied */
+    VCHECK_SALVAGE_FAIL = 4        /**< salvage not scheduled; failed */
+} vsalvage_check;
 static int VCheckSalvage(Volume * vp);
 #if defined(SALVSYNC_BUILD_CLIENT) || defined(FSSYNC_BUILD_CLIENT)
 static int VScheduleSalvage_r(Volume * vp);
@@ -520,7 +534,7 @@ static void
 VSetVInit_r(int value)
 {
     VInit = value;
-    CV_BROADCAST(&vol_vinit_cond);
+    opr_cv_broadcast(&vol_vinit_cond);
 }
 
 static_inline void
@@ -569,15 +583,15 @@ VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
     } else {
        VLRU_SetOptions(VLRU_SET_ENABLED, 0);
     }
-    osi_Assert(pthread_key_create(&VThread_key, NULL) == 0);
+    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 */
@@ -586,7 +600,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
@@ -608,7 +622,7 @@ VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
 #if defined(AFS_DEMAND_ATTACH_FS) && defined(SALVSYNC_BUILD_CLIENT)
     if (VCanUseSALVSYNC()) {
        /* establish a connection to the salvager at this point */
-       osi_Assert(VConnectSALV() != 0);
+       opr_Verify(VConnectSALV() != 0);
     }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
@@ -662,13 +676,15 @@ VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
 int
 VInitAttachVolumes(ProgramType pt)
 {
-    osi_Assert(VInit==1);
+    opr_Assert(VInit==1);
     if (pt == fileServer) {
        struct DiskPartition64 *diskP;
        /* Attach all the volumes in this partition */
        for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
            int nAttached = 0, nUnattached = 0;
-           osi_Assert(VAttachVolumesByPartition(diskP, &nAttached, &nUnattached) == 0);
+           opr_Verify(VAttachVolumesByPartition(diskP,
+                                                &nAttached, &nUnattached)
+                           == 0);
        }
     }
     VOL_LOCK;
@@ -693,7 +709,7 @@ VInitAttachVolumes(ProgramType pt)
 int
 VInitAttachVolumes(ProgramType pt)
 {
-    osi_Assert(VInit==1);
+    opr_Assert(VInit==1);
     if (pt == fileServer) {
        struct DiskPartition64 *diskP;
        struct vinitvolumepackage_thread_t params;
@@ -702,14 +718,14 @@ 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;
 
        /* create partition work queue */
        for (parts=0, diskP = DiskPartitionList; diskP; diskP = diskP->next, parts++) {
-           dpq = (diskpartition_queue_t *) malloc(sizeof(struct diskpartition_queue_t));
-           osi_Assert(dpq != NULL);
+           dpq = malloc(sizeof(struct diskpartition_queue_t));
+           opr_Assert(dpq != NULL);
            dpq->diskP = diskP;
            queue_Append(&params,dpq);
        }
@@ -718,8 +734,10 @@ VInitAttachVolumes(ProgramType pt)
 
        if (threads > 1) {
            /* spawn off a bunch of initialization threads */
-           osi_Assert(pthread_attr_init(&attrs) == 0);
-           osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
+           opr_Verify(pthread_attr_init(&attrs) == 0);
+           opr_Verify(pthread_attr_setdetachstate(&attrs,
+                                                  PTHREAD_CREATE_DETACHED)
+                           == 0);
 
            Log("VInitVolumePackage: beginning parallel fileserver startup\n");
            Log("VInitVolumePackage: using %d threads to attach volumes on %d partitions\n",
@@ -729,9 +747,9 @@ VInitAttachVolumes(ProgramType pt)
            for (i=0; i < threads; i++) {
                 AFS_SIGSET_DECL;
                 AFS_SIGSET_CLEAR();
-               osi_Assert(pthread_create
-                      (&tid, &attrs, &VInitVolumePackageThread,
-                       &params) == 0);
+               opr_Verify(pthread_create(&tid, &attrs,
+                                         &VInitVolumePackageThread,
+                                         &params) == 0);
                 AFS_SIGSET_RESTORE();
            }
 
@@ -740,7 +758,7 @@ VInitAttachVolumes(ProgramType pt)
            }
            VOL_UNLOCK;
 
-           osi_Assert(pthread_attr_destroy(&attrs) == 0);
+           opr_Verify(pthread_attr_destroy(&attrs) == 0);
        } else {
            /* if we're only going to run one init thread, don't bother creating
             * another LWP */
@@ -751,11 +769,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;
 }
@@ -786,14 +804,15 @@ VInitVolumePackageThread(void * args) {
        diskP = dpq->diskP;
        free(dpq);
 
-       osi_Assert(VAttachVolumesByPartition(diskP, &nAttached, &nUnattached) == 0);
+       opr_Verify(VAttachVolumesByPartition(diskP, &nAttached,
+                                            &nUnattached) == 0);
 
        VOL_LOCK;
     }
 
 done:
     params->n_threads_complete++;
-    CV_SIGNAL(&params->thread_done_cv);
+    opr_cv_signal(&params->thread_done_cv);
     VOL_UNLOCK;
     return NULL;
 }
@@ -813,7 +832,7 @@ done:
 int
 VInitAttachVolumes(ProgramType pt)
 {
-    osi_Assert(VInit==1);
+    opr_Assert(VInit==1);
     if (pt == fileServer) {
 
        struct DiskPartition64 *diskP;
@@ -826,12 +845,12 @@ 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 = (struct diskpartition_queue_t*)malloc(sizeof(struct diskpartition_queue_t));
-           osi_Assert(dp != NULL);
+           dp = malloc(sizeof(struct diskpartition_queue_t));
+           opr_Assert(dp != NULL);
            dp->diskP = diskP;
            queue_Append(&pq, dp);
        }
@@ -841,11 +860,12 @@ 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);
 
-        osi_Assert(pthread_attr_init(&attrs) == 0);
-        osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
+        opr_Verify(pthread_attr_init(&attrs) == 0);
+        opr_Verify(pthread_attr_setdetachstate(&attrs,
+                                              PTHREAD_CREATE_DETACHED) == 0);
 
         Log("VInitVolumePackage: beginning parallel fileserver startup\n");
         Log("VInitVolumePackage: using %d threads to pre-attach volumes on %d partitions\n",
@@ -856,30 +876,32 @@ VInitAttachVolumes(ProgramType pt)
            struct vinitvolumepackage_thread_param *params;
             AFS_SIGSET_DECL;
 
-            params = (struct vinitvolumepackage_thread_param *)malloc(sizeof(struct vinitvolumepackage_thread_param));
-            osi_Assert(params);
+            params = malloc(sizeof(struct vinitvolumepackage_thread_param));
+            opr_Assert(params);
             params->pq = &pq;
             params->vq = &vq;
             params->nthreads = threads;
             params->thread = i+1;
 
             AFS_SIGSET_CLEAR();
-           osi_Assert(pthread_create (&tid, &attrs, &VInitVolumePackageThread, (void*)params) == 0);
+           opr_Verify(pthread_create(&tid, &attrs,
+                                     &VInitVolumePackageThread,
+                                     (void*)params) == 0);
             AFS_SIGSET_RESTORE();
        }
 
         VInitPreAttachVolumes(threads, &vq);
 
-        osi_Assert(pthread_attr_destroy(&attrs) == 0);
-       CV_DESTROY(&pq.cv);
-       MUTEX_DESTROY(&pq.mutex);
-       CV_DESTROY(&vq.cv);
-       MUTEX_DESTROY(&vq.mutex);
+        opr_Verify(pthread_attr_destroy(&attrs) == 0);
+       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;
@@ -900,15 +922,15 @@ VInitVolumePackageThread(void *args)
     struct volume_init_queue *vq;
     struct volume_init_batch *vb;
 
-    osi_Assert(args);
+    opr_Assert(args);
     params = (struct vinitvolumepackage_thread_param *)args;
     pq = params->pq;
     vq = params->vq;
-    osi_Assert(pq);
-    osi_Assert(vq);
+    opr_Assert(pq);
+    opr_Assert(vq);
 
-    vb = (struct volume_init_batch*)malloc(sizeof(struct volume_init_batch));
-    osi_Assert(vb);
+    vb = malloc(sizeof(struct volume_init_batch));
+    opr_Assert(vb);
     vb->thread = params->thread;
     vb->last = 0;
     vb->size = 0;
@@ -925,25 +947,24 @@ VInitVolumePackageThread(void *args)
             continue;
         }
         while ((vid = VInitNextVolumeId(dirp))) {
-            Volume *vp = (Volume*)malloc(sizeof(Volume));
-            osi_Assert(vp);
-            memset(vp, 0, sizeof(Volume));
+            Volume *vp = calloc(1, sizeof(Volume));
+            opr_Assert(vp);
             vp->device = partition->device;
             vp->partition = partition;
             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 = (struct volume_init_batch*)malloc(sizeof(struct volume_init_batch));
-                osi_Assert(vb);
+                vb = malloc(sizeof(struct volume_init_batch));
+                opr_Assert(vb);
                 vb->thread = params->thread;
                 vb->size = 0;
                 vb->last = 0;
@@ -953,10 +974,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);
@@ -978,17 +999,17 @@ 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);
 
-    osi_Assert(dp);
-    osi_Assert(dp->diskP);
+    opr_Assert(dp);
+    opr_Assert(dp->diskP);
 
     partition = dp->diskP;
     free(dp);
@@ -1033,13 +1054,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;
@@ -1218,11 +1239,12 @@ 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);
-       osi_Assert(pthread_attr_init(&attrs) == 0);
-       osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 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);
        queue_Init(&params);
 
        /* setup the basic partition information structures for
@@ -1247,8 +1269,8 @@ VShutdown_r(void)
 
 
            /* build up the pass 0 shutdown work queue */
-           dpq = (struct diskpartition_queue_t *) malloc(sizeof(struct diskpartition_queue_t));
-           osi_Assert(dpq != NULL);
+           dpq = malloc(sizeof(struct diskpartition_queue_t));
+           opr_Assert(dpq != NULL);
            dpq->diskP = diskP;
            queue_Prepend(&params, dpq);
 
@@ -1260,11 +1282,10 @@ 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++) {
-           osi_Assert(pthread_create
-                  (&tid, &attrs, &VShutdownThread,
-                   &params) == 0);
+           opr_Verify(pthread_create(&tid, &attrs, &VShutdownThread,
+                                     &params) == 0);
        }
 
        /* wait for all the pass 0 shutdowns to complete */
@@ -1273,8 +1294,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");
@@ -1287,10 +1308,10 @@ VShutdown_r(void)
            VOL_CV_WAIT(&params.cv);
        }
 
-       osi_Assert(pthread_attr_destroy(&attrs) == 0);
-       CV_DESTROY(&params.cv);
-       CV_DESTROY(&params.master_cv);
-       MUTEX_DESTROY(&params.lock);
+       opr_Verify(pthread_attr_destroy(&attrs) == 0);
+       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) {
@@ -1360,7 +1381,7 @@ VShutdown_r(void)
 void
 VShutdown(void)
 {
-    osi_Assert(VInit>0);
+    opr_Assert(VInit>0);
     VOL_LOCK;
     VShutdown_r();
     VOL_UNLOCK;
@@ -1567,14 +1588,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;
@@ -1583,24 +1604,24 @@ 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;
-    osi_Assert(pass > 0);
+    opr_Assert(pass > 0);
 
     /* now escalate through the more complicated shutdowns */
     while (pass <= 3) {
@@ -1680,7 +1701,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",
@@ -1834,7 +1855,7 @@ VShutdownVolume_r(Volume * vp)
     /* wait for other blocking ops to finish */
     VWaitExclusiveState_r(vp);
 
-    osi_Assert(VIsValidState(V_attachState(vp)));
+    opr_Assert(VIsValidState(V_attachState(vp)));
 
     switch(V_attachState(vp)) {
     case VOL_STATE_SALVAGING:
@@ -2131,7 +2152,7 @@ VPreAttachVolumeById_r(Error * ec,
 
     *ec = 0;
 
-    osi_Assert(programType == fileServer);
+    opr_Assert(programType == fileServer);
 
     if (!(partp = VGetPartition_r(partition, 0))) {
        *ec = VNOVOL;
@@ -2215,12 +2236,11 @@ VPreAttachVolumeByVp_r(Error * ec,
        VOL_UNLOCK;
 
        /* allocate the volume structure */
-       vp = nvp = (Volume *) malloc(sizeof(Volume));
-       osi_Assert(vp != NULL);
-       memset(vp, 0, sizeof(Volume));
+       vp = nvp = calloc(1, sizeof(Volume));
+       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 */
@@ -2308,7 +2328,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
     }
 
     if (VRequiresPartLock()) {
-       osi_Assert(VInit == 3);
+       opr_Assert(VInit == 3);
        VLockPartition_r(partition);
     } else if (programType == fileServer) {
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -2383,7 +2403,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
            }
        }
 
-       osi_Assert(vp != NULL);
+       opr_Assert(vp != NULL);
 
        /* handle pre-attach races
         *
@@ -2444,14 +2464,14 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
 
     if (!vp) {
       vp = (Volume *) calloc(1, sizeof(Volume));
-      osi_Assert(vp != NULL);
+      opr_Assert(vp != NULL);
       vp->hashid = volumeId;
       vp->device = partp->device;
       vp->partition = partp;
       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 */
     }
 
@@ -2581,7 +2601,7 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
     *ec = 0;
 
     /* volume utility should never call AttachByVp */
-    osi_Assert(programType == fileServer);
+    opr_Assert(programType == fileServer);
 
     volumeId = vp->hashid;
     partp = vp->partition;
@@ -2625,7 +2645,7 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
        }
     }
 
-    osi_Assert(vp != NULL);
+    opr_Assert(vp != NULL);
     VChangeState_r(vp, VOL_STATE_ATTACHING);
 
     /* restore monotonically increasing stats */
@@ -2723,8 +2743,9 @@ VLockVolumeNB(Volume *vp, int locktype)
 {
     int code;
 
-    osi_Assert(programType != fileServer || VIsExclusiveState(V_attachState(vp)));
-    osi_Assert(!(V_attachFlags(vp) & VOL_LOCKED));
+    opr_Assert(programType != fileServer
+              || VIsExclusiveState(V_attachState(vp)));
+    opr_Assert(!(V_attachFlags(vp) & VOL_LOCKED));
 
     code = VLockVolumeByIdNB(vp->hashid, vp->partition, locktype);
     if (code == 0) {
@@ -2746,8 +2767,9 @@ VLockVolumeNB(Volume *vp, int locktype)
 static void
 VUnlockVolume(Volume *vp)
 {
-    osi_Assert(programType != fileServer || VIsExclusiveState(V_attachState(vp)));
-    osi_Assert((V_attachFlags(vp) & VOL_LOCKED));
+    opr_Assert(programType != fileServer
+              || VIsExclusiveState(V_attachState(vp)));
+    opr_Assert((V_attachFlags(vp) & VOL_LOCKED));
 
     VUnlockVolumeById(vp->hashid, vp->partition);
 
@@ -3000,6 +3022,9 @@ attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
     }
 
     if (*ec) {
+       VOL_LOCK;
+       FreeVolumeHeader(vp);
+       VOL_UNLOCK;
        return;
     }
     if (retry) {
@@ -3060,12 +3085,14 @@ attach_check_vop(Error *ec, VolumeId volid, struct DiskPartition64 *partp,
        switch (vp->pending_vol_op->vol_op_state) {
        case FSSYNC_VolOpPending:
            /* this should never happen */
-           osi_Assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpPending);
+           opr_Assert(vp->pending_vol_op->vol_op_state
+                           != FSSYNC_VolOpPending);
            break;
 
        case FSSYNC_VolOpRunningUnknown:
            /* this should never happen; we resolved 'unknown' above */
-           osi_Assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpRunningUnknown);
+           opr_Assert(vp->pending_vol_op->vol_op_state
+                           != FSSYNC_VolOpRunningUnknown);
            break;
 
        case FSSYNC_VolOpRunningOffline:
@@ -3162,8 +3189,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
     if (*ec == VNOVOL) {
        /* if the volume doesn't exist, skip straight to 'error' so we don't
         * request a salvage */
-       VOL_LOCK;
-       goto error_notbroken;
+       goto unlocked_error;
     }
 
     if (!*ec) {
@@ -3256,6 +3282,9 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
     } else if (*ec) {
        /* volume operation in progress */
        VOL_LOCK;
+       /* we have already transitioned the vp away from ATTACHING state, so we
+        * can go right to the end of attach2, and we do not need to transition
+        * to ERROR. */
        goto error_notbroken;
     }
 #else /* AFS_DEMAND_ATTACH_FS */
@@ -3422,7 +3451,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
 #ifdef AFS_DEMAND_ATTACH_FS
                error_state = VOL_STATE_ERROR;
                /* see if we can recover */
-               VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, 0 /*flags*/);
+               VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
 #endif
            }
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -3432,7 +3461,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
        }
     } 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;
@@ -3455,10 +3484,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
 
     return vp;
 
-#ifndef AFS_DEMAND_ATTACH_FS
 unlocked_error:
-#endif
-
     VOL_LOCK;
 locked_error:
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -3475,9 +3501,16 @@ locked_error:
        VReleaseVolumeHandles_r(vp);
     }
 
- error_notbroken:
 #ifdef AFS_DEMAND_ATTACH_FS
-    VCheckSalvage(vp);
+ error_notbroken:
+    if (VCheckSalvage(vp) == VCHECK_SALVAGE_FAIL) {
+       /* The salvage could not be scheduled with the salvage server
+        * due to a hard error. Reset the error code to prevent retry loops by
+        * callers. */
+       if (*ec == VSALVAGING) {
+           *ec = VSALVAGE;
+       }
+    }
     if (forcefree) {
        FreeVolume(vp);
     } else {
@@ -3514,7 +3547,7 @@ VAttachVolume_r(Error * ec, VolumeId volumeId, int mode)
        Error error;
        vp = VGetVolume_r(&error, volumeId);
        if (vp) {
-           osi_Assert(V_inUse(vp) == 0);
+           opr_Assert(V_inUse(vp) == 0);
            VDetachVolume_r(ec, vp);
        }
        return NULL;
@@ -3673,7 +3706,8 @@ static const struct timespec *
 VOfflineTimeout(struct timespec *ats)
 {
     if (vol_shutting_down) {
-       osi_Assert(pthread_once(&shutdown_timeout_once, VShutdownTimeoutInit) == 0);
+       opr_Verify(pthread_once(&shutdown_timeout_once,
+                               VShutdownTimeoutInit) == 0);
        return shutdown_timeout;
     } else {
        return VCalcTimeout(ats, vol_opts.offline_timeout);
@@ -3829,7 +3863,7 @@ VDeregisterCall_r(Volume *vp, struct VCallByVol *cbv)
 void
 VPutVolume_r(Volume * vp)
 {
-    osi_Assert(--vp->nUsers >= 0);
+    opr_Verify(--vp->nUsers >= 0);
     if (vp->nUsers == 0) {
        VCheckOffline(vp);
        ReleaseVolumeHeader(vp->header);
@@ -4105,12 +4139,18 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
                case VSALVAGING:
                    break;
                case VOFFLINE:
-                   if (!vp->pending_vol_op) {
-                       endloop = 1;
+                   endloop = 1;
+                   if (vp->specialStatus) {
+                       *ec = vp->specialStatus;
                    }
                    break;
+
                default:
-                   *ec = VNOVOL;
+                   if (vp->specialStatus) {
+                       *ec = vp->specialStatus;
+                   } else {
+                       *ec = VNOVOL;
+                   }
                    endloop = 1;
                }
                if (endloop) {
@@ -4147,46 +4187,12 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
        }
 
        /*
-        * this test MUST happen after VAttachVolymeByVp, so vol_op_state is
-        * not VolOpRunningUnknown (attach2 would have converted it to Online
-        * or Offline)
+        * this test MUST happen after VAttachVolymeByVp, so we have no
+        * conflicting vol op. (attach2 would have errored out if we had one;
+        * specifically attach_check_vop must have detected a conflicting vop)
         */
+         opr_Assert(!vp->pending_vol_op || vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningOnline);
 
-         /* only valid before/during demand attachment */
-         osi_Assert(!vp->pending_vol_op || vp->pending_vol_op->vol_op_state != FSSYNC_VolOpRunningUnknown);
-
-         /* deny getvolume due to running mutually exclusive vol op */
-         if (vp->pending_vol_op && vp->pending_vol_op->vol_op_state==FSSYNC_VolOpRunningOffline) {
-          /*
-           * volume cannot remain online during this volume operation.
-           * notify client.
-           */
-          if (vp->specialStatus) {
-              /*
-               * special status codes outrank normal VOFFLINE code
-               */
-              *ec = vp->specialStatus;
-              if (client_ec) {
-                  *client_ec = vp->specialStatus;
-              }
-          } else {
-              if (client_ec) {
-                  /* see CheckVnode() in afsfileprocs.c for an explanation
-                   * of this error code logic */
-                  afs_uint32 now = FT_ApproxTime();
-                  if ((vp->stats.last_vol_op + (10 * 60)) >= now) {
-                      *client_ec = VBUSY;
-                  } else {
-                      *client_ec = VRESTARTING;
-                  }
-              }
-              *ec = VOFFLINE;
-          }
-          VChangeState_r(vp, VOL_STATE_UNATTACHED);
-          FreeVolumeHeader(vp);
-          vp = NULL;
-          break;
-       }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
        LoadVolumeHeader(ec, vp);
@@ -4236,7 +4242,7 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
 #else /* AFS_PTHREAD_ENV */
                    /* LWP has no timed wait, so the caller better not be
                     * expecting one */
-                   osi_Assert(!timeout);
+                   opr_Assert(!timeout);
                    LWP_WaitProcess(VPutVolume);
 #endif /* AFS_PTHREAD_ENV */
                    continue;
@@ -4283,7 +4289,7 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
 #endif /* AFS_DEMAND_ATTACH_FS */
 
  not_inited:
-    osi_Assert(vp || *ec);
+    opr_Assert(vp || *ec);
     return vp;
 }
 
@@ -4299,8 +4305,8 @@ VTakeOffline_r(Volume * vp)
 {
     Error error;
 
-    osi_Assert(vp->nUsers > 0);
-    osi_Assert(programType == fileServer);
+    opr_Assert(vp->nUsers > 0);
+    opr_Assert(programType == fileServer);
 
     VCreateReservation_r(vp);
     VWaitExclusiveState_r(vp);
@@ -4315,8 +4321,8 @@ VTakeOffline_r(Volume * vp)
 void
 VTakeOffline_r(Volume * vp)
 {
-    osi_Assert(vp->nUsers > 0);
-    osi_Assert(programType == fileServer);
+    opr_Assert(vp->nUsers > 0);
+    opr_Assert(programType == fileServer);
 
     vp->goingOffline = 1;
     V_needsSalvaged(vp) = 1;
@@ -4388,7 +4394,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 */
@@ -4577,7 +4583,7 @@ VOffline_r(Volume * vp, char *message)
     VolumeId vid = V_id(vp);
 #endif
 
-    osi_Assert(programType != volumeUtility && programType != volumeServer);
+    opr_Assert(programType != volumeUtility && programType != volumeServer);
     if (!V_inUse(vp)) {
        VPutVolume_r(vp);
        return;
@@ -4631,7 +4637,7 @@ void
 VOfflineForVolOp_r(Error *ec, Volume *vp, char *message)
 {
     int salvok = 1;
-    osi_Assert(vp->pending_vol_op);
+    opr_Assert(vp->pending_vol_op);
     if (!V_inUse(vp)) {
        VPutVolume_r(vp);
         *ec = 1;
@@ -4946,9 +4952,9 @@ VSyncVolume_r(Error * ec, Volume * vp, int flags)
        VOL_UNLOCK;
 #endif
        fdP = IH_OPEN(V_diskDataHandle(vp));
-       osi_Assert(fdP != NULL);
+       opr_Assert(fdP != NULL);
        code = FDH_SYNC(fdP);
-       osi_Assert(code == 0);
+       opr_Assert(code == 0);
        FDH_CLOSE(fdP);
 #ifdef AFS_DEMAND_ATTACH_FS
        VOL_LOCK;
@@ -5040,7 +5046,7 @@ VCheckDetach(Volume * vp)
        VCheckSalvage(vp);
        ReallyFreeVolume(vp);
        if (programType == fileServer) {
-           CV_BROADCAST(&vol_put_volume_cond);
+           opr_cv_broadcast(&vol_put_volume_cond);
        }
     }
     return ret;
@@ -5074,7 +5080,7 @@ VCheckDetach(Volume * 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 */
@@ -5094,8 +5100,8 @@ VCheckOffline(Volume * vp)
 
     if (vp->goingOffline && !vp->nUsers) {
        Error error;
-       osi_Assert(programType == fileServer);
-       osi_Assert((V_attachState(vp) != VOL_STATE_ATTACHED) &&
+       opr_Assert(programType == fileServer);
+       opr_Assert((V_attachState(vp) != VOL_STATE_ATTACHED) &&
               (V_attachState(vp) != VOL_STATE_FREED) &&
               (V_attachState(vp) != VOL_STATE_PREATTACHED) &&
               (V_attachState(vp) != VOL_STATE_UNATTACHED) &&
@@ -5155,7 +5161,7 @@ VCheckOffline(Volume * vp)
 
     if (vp->goingOffline && !vp->nUsers) {
        Error error;
-       osi_Assert(programType == fileServer);
+       opr_Assert(programType == fileServer);
 
        ret = 1;
        vp->goingOffline = 0;
@@ -5174,7 +5180,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 */
@@ -5225,7 +5231,7 @@ VCheckOffline(Volume * vp)
 void
 VCancelReservation_r(Volume * vp)
 {
-    osi_Assert(--vp->nWaiters >= 0);
+    opr_Verify(--vp->nWaiters >= 0);
     if (vp->nWaiters == 0) {
        VCheckOffline(vp);
        if (!VCheckDetach(vp)) {
@@ -5281,8 +5287,8 @@ VRegisterVolOp_r(Volume * vp, FSSYNC_VolOp_info * vopinfo)
     FSSYNC_VolOp_info * info;
 
     /* attach a vol op info node to the volume struct */
-    info = (FSSYNC_VolOp_info *) malloc(sizeof(FSSYNC_VolOp_info));
-    osi_Assert(info != NULL);
+    info = malloc(sizeof(FSSYNC_VolOp_info));
+    opr_Assert(info != NULL);
     memcpy(info, vopinfo, sizeof(FSSYNC_VolOp_info));
     vp->pending_vol_op = info;
 
@@ -5478,8 +5484,11 @@ VOfflineForSalvage_r(struct Volume *vp)
  * @param[in] vp   pointer to volume object
  *
  * @return status code
- *    @retval 0 no salvage scheduled
- *    @retval 1 a salvage has been scheduled with the salvageserver
+ *    @retval VCHECK_SALVAGE_OK (0)         no pending salvage
+ *    @retval VCHECK_SALVAGE_SCHEDULED (1)  salvage has been scheduled
+ *    @retval VCHECK_SALVAGE_ASYNC (2)      salvage being scheduled
+ *    @retval VCHECK_SALVAGE_DENIED (3)     salvage not scheduled; denied
+ *    @retval VCHECK_SALVAGE_FAIL (4)       salvage not scheduled; failed
  *
  * @pre VOL_LOCK is held
  *
@@ -5499,31 +5508,32 @@ VOfflineForSalvage_r(struct Volume *vp)
 static int
 VCheckSalvage(Volume * vp)
 {
-    int ret = 0;
+    int ret = VCHECK_SALVAGE_OK;
+
 #if defined(SALVSYNC_BUILD_CLIENT) || defined(FSSYNC_BUILD_CLIENT)
-    if (vp->nUsers)
-       return ret;
     if (!vp->salvage.requested) {
-       return ret;
+       return VCHECK_SALVAGE_OK;
+    }
+    if (vp->nUsers) {
+       return VCHECK_SALVAGE_ASYNC;
     }
 
     /* prevent recursion; some of the code below creates and removes
      * lightweight refs, which can call VCheckSalvage */
     if (vp->salvage.scheduling) {
-       return ret;
+       return VCHECK_SALVAGE_ASYNC;
     }
     vp->salvage.scheduling = 1;
 
     if (V_attachState(vp) == VOL_STATE_SALVAGE_REQ) {
        if (!VOfflineForSalvage_r(vp)) {
            vp->salvage.scheduling = 0;
-           return ret;
+           return VCHECK_SALVAGE_FAIL;
        }
     }
 
     if (vp->salvage.requested) {
-       VScheduleSalvage_r(vp);
-       ret = 1;
+       ret = VScheduleSalvage_r(vp);
     }
     vp->salvage.scheduling = 0;
 #endif /* SALVSYNC_BUILD_CLIENT || FSSYNC_BUILD_CLIENT */
@@ -5748,8 +5758,11 @@ try_FSSYNC(Volume *vp, char *partName, int *code) {
  * @param[in] vp  pointer to volume object
  *
  * @return operation status
- *    @retval 0 salvage scheduled successfully
- *    @retval 1 salvage not scheduled, or SALVSYNC/FSSYNC com error
+ *    @retval VCHECK_SALVAGE_OK (0)         no pending salvage
+ *    @retval VCHECK_SALVAGE_SCHEDULED (1)  salvage has been scheduled
+ *    @retval VCHECK_SALVAGE_ASYNC (2)      salvage being scheduled
+ *    @retval VCHECK_SALVAGE_DENIED (3)     salvage not scheduled; denied
+ *    @retval VCHECK_SALVAGE_FAIL (4)       salvage not scheduled; failed
  *
  * @pre
  *    @arg VOL_LOCK is held.
@@ -5772,21 +5785,22 @@ try_FSSYNC(Volume *vp, char *partName, int *code) {
 static int
 VScheduleSalvage_r(Volume * vp)
 {
-    int ret=0;
+    int ret = VCHECK_SALVAGE_SCHEDULED;
     int code = 0;
     VolState state_save;
     VThreadOptions_t * thread_opts;
     char partName[16];
 
-    osi_Assert(VCanUseSALVSYNC() || VCanUseFSSYNC());
+    opr_Verify(VCanUseSALVSYNC() || VCanUseFSSYNC());
 
     if (vp->nWaiters || vp->nUsers) {
-       return 1;
+       return VCHECK_SALVAGE_ASYNC;
     }
 
     /* prevent endless salvage,attach,salvage,attach,... loops */
-    if (vp->stats.salvages >= SALVAGE_COUNT_MAX)
-       return 1;
+    if (vp->stats.salvages >= SALVAGE_COUNT_MAX) {
+       return VCHECK_SALVAGE_FAIL;
+    }
 
     /*
      * don't perform salvsync ops on certain threads
@@ -5796,11 +5810,11 @@ VScheduleSalvage_r(Volume * vp)
        thread_opts = &VThread_defaults;
     }
     if (thread_opts->disallow_salvsync || vol_disallow_salvsync) {
-       return 1;
+       return VCHECK_SALVAGE_ASYNC;
     }
 
     if (vp->salvage.scheduled) {
-       return ret;
+       return VCHECK_SALVAGE_SCHEDULED;
     }
 
     VCreateReservation_r(vp);
@@ -5810,7 +5824,9 @@ VScheduleSalvage_r(Volume * vp)
      * XXX the scheduling process should really be done asynchronously
      *     to avoid fssync deadlocks
      */
-    if (!vp->salvage.scheduled) {
+    if (vp->salvage.scheduled) {
+       ret = VCHECK_SALVAGE_SCHEDULED;
+    } else {
        /* if we haven't previously scheduled a salvage, do so now
         *
         * set the volume to an exclusive state and drop the lock
@@ -5820,13 +5836,14 @@ VScheduleSalvage_r(Volume * vp)
        state_save = VChangeState_r(vp, VOL_STATE_SALVSYNC_REQ);
        VOL_UNLOCK;
 
-       osi_Assert(try_SALVSYNC(vp, partName, &code) ||
-              try_FSSYNC(vp, partName, &code));
+       opr_Verify(try_SALVSYNC(vp, partName, &code)
+                  || try_FSSYNC(vp, partName, &code));
 
        VOL_LOCK;
        VChangeState_r(vp, state_save);
 
        if (code == SYNC_OK) {
+           ret = VCHECK_SALVAGE_SCHEDULED;
            vp->salvage.scheduled = 1;
            vp->stats.last_salvage_req = FT_ApproxTime();
            if (VCanUseSALVSYNC()) {
@@ -5836,20 +5853,23 @@ VScheduleSalvage_r(Volume * vp)
                IncUInt64(&VStats.salvages);
            }
        } else {
-           ret = 1;
            switch(code) {
            case SYNC_BAD_COMMAND:
            case SYNC_COM_ERROR:
+               ret = VCHECK_SALVAGE_FAIL;
                break;
            case SYNC_DENIED:
+               ret = VCHECK_SALVAGE_DENIED;
                Log("VScheduleSalvage_r: Salvage request for volume %lu "
                    "denied\n", afs_printable_uint32_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));
                break;
            default:
+               ret = VCHECK_SALVAGE_FAIL;
                Log("VScheduleSalvage_r: Salvage request for volume %lu "
                    "received unknown protocol error %d\n",
                    afs_printable_uint32_lu(vp->hashid), code);
@@ -5868,7 +5888,7 @@ VScheduleSalvage_r(Volume * vp)
      * this, as the caller may reference vp without any refs. Instead, it
      * is the duty of the caller to inspect 'vp' after we return to see if
      * needs to be freed. */
-    osi_Assert(--vp->nWaiters >= 0);
+    opr_Verify(--vp->nWaiters >= 0);
     return ret;
 }
 #endif /* SALVSYNC_BUILD_CLIENT || FSSYNC_BUILD_CLIENT */
@@ -6084,7 +6104,7 @@ int
 VConnectFS_r(void)
 {
     int rc;
-    osi_Assert((VInit == 2) &&
+    opr_Assert((VInit == 2) &&
           (programType != fileServer) &&
           (programType != salvager));
     rc = FSYNC_clientInit();
@@ -6113,7 +6133,7 @@ VConnectFS_r(void)
 void
 VDisconnectFS_r(void)
 {
-    osi_Assert((programType != fileServer) &&
+    opr_Assert((programType != fileServer) &&
           (programType != salvager));
     FSYNC_clientFinis();
     VSetVInit_r(2);
@@ -6339,7 +6359,7 @@ VAllocBitmapEntry_r(Error * ec, Volume * vp,
     }
     /* No bit map entry--must grow bitmap */
     VGrowBitmap(index);
-    bp = index->bitmap;
+    bp = index->bitmap + index->bitmapOffset;
     *bp = 1;
     ret = index->bitmapOffset * 8;
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -6444,13 +6464,13 @@ VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class)
     VOL_UNLOCK;
 
     fdP = IH_OPEN(vip->handle);
-    osi_Assert(fdP != NULL);
+    opr_Assert(fdP != NULL);
     file = FDH_FDOPEN(fdP, "r");
-    osi_Assert(file != NULL);
-    vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
-    osi_Assert(vnode != NULL);
+    opr_Assert(file != NULL);
+    vnode = malloc(vcp->diskSize);
+    opr_Assert(vnode != NULL);
     size = OS_SIZE(fdP->fd_fd);
-    osi_Assert(size != -1);
+    opr_Assert(size != -1);
     nVnodes = (size <= vcp->diskSize ? 0 : size - vcp->diskSize)
        >> vcp->logSize;
     vip->bitmapSize = ((nVnodes / 8) + 10) / 4 * 4;    /* The 10 is a little extra so
@@ -6460,10 +6480,10 @@ VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class)
                                                         * it that way */
 #ifdef BITMAP_LATER
     BitMap = (byte *) calloc(1, vip->bitmapSize);
-    osi_Assert(BitMap != NULL);
+    opr_Assert(BitMap != NULL);
 #else /* BITMAP_LATER */
     vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
-    osi_Assert(vip->bitmap != NULL);
+    opr_Assert(vip->bitmap != NULL);
     vip->bitmapOffset = 0;
 #endif /* BITMAP_LATER */
     if (STREAM_ASEEK(file, vcp->diskSize) != -1) {
@@ -6514,7 +6534,7 @@ VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class)
        vip->bitmap = BitMap;
        vip->bitmapOffset = 0;
     } else
-       free((byte *) BitMap);
+       free(BitMap);
 #endif /* BITMAP_LATER */
 #ifdef AFS_DEMAND_ATTACH_FS
     VChangeState_r(vp, state_save);
@@ -6848,7 +6868,7 @@ VAddToVolumeUpdateList_r(Error * ec, Volume * vp)
        return;
     if (UpdateList == NULL) {
        updateSize = UPDATE_LIST_SIZE;
-       UpdateList = (VolumeId *) malloc(sizeof(VolumeId) * updateSize);
+       UpdateList = malloc(sizeof(VolumeId) * updateSize);
     } else {
        if (nUpdatedVolumes == updateSize) {
            updateSize <<= 1;
@@ -6856,12 +6876,11 @@ VAddToVolumeUpdateList_r(Error * ec, Volume * vp)
                Log("warning: there is likely a bug in the volume update scanner\n");
                return;
            }
-           UpdateList =
-               (VolumeId *) realloc(UpdateList,
-                                    sizeof(VolumeId) * updateSize);
+           UpdateList = realloc(UpdateList,
+                                sizeof(VolumeId) * updateSize);
        }
     }
-    osi_Assert(UpdateList != NULL);
+    opr_Assert(UpdateList != NULL);
     UpdateList[nUpdatedVolumes++] = V_id(vp);
 #endif /* !AFS_DEMAND_ATTACH_FS */
 }
@@ -7117,7 +7136,7 @@ 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 */
@@ -7135,10 +7154,12 @@ 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);
-       osi_Assert(pthread_attr_init(&attrs) == 0);
-       osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
-       osi_Assert(pthread_create(&tid, &attrs, &VLRU_ScannerThread, NULL) == 0);
+       opr_cv_init(&volume_LRU.cv);
+       opr_Verify(pthread_attr_init(&attrs) == 0);
+       opr_Verify(pthread_attr_setdetachstate(&attrs,
+                                              PTHREAD_CREATE_DETACHED) == 0);
+       opr_Verify(pthread_create(&tid, &attrs,
+                                 &VLRU_ScannerThread, NULL) == 0);
     }
 }
 
@@ -7164,7 +7185,7 @@ VLRU_Init_Node_r(Volume * vp)
     if (!VLRU_enabled)
        return;
 
-    osi_Assert(queue_IsNotOnQueue(&vp->vlru));
+    opr_Assert(queue_IsNotOnQueue(&vp->vlru));
     vp->vlru.idx = VLRU_QUEUE_INVALID;
 }
 
@@ -7308,7 +7329,7 @@ VLRU_UpdateAccess_r(Volume * vp)
     if (queue_IsNotOnQueue(&vp->vlru))
        return;
 
-    osi_Assert(V_attachFlags(vp) & VOL_ON_VLRU);
+    opr_Assert(V_attachFlags(vp) & VOL_ON_VLRU);
 
     /* update the access timestamp */
     vp->stats.last_get = FT_ApproxTime();
@@ -7441,7 +7462,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);
@@ -7517,7 +7538,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;
 }
@@ -7620,7 +7641,7 @@ VLRU_Demote_r(int idx)
     Volume ** salv_flag_vec = NULL;
     int salv_vec_offset = 0;
 
-    osi_Assert(idx == VLRU_QUEUE_MID || idx == VLRU_QUEUE_OLD);
+    opr_Assert(idx == VLRU_QUEUE_MID || idx == VLRU_QUEUE_OLD);
 
     /* get exclusive access to two chains, and drop the glock */
     VLRU_Wait_r(&volume_LRU.q[idx-1]);
@@ -7631,7 +7652,7 @@ VLRU_Demote_r(int idx)
 
     /* no big deal if this allocation fails */
     if (volume_LRU.q[idx].len) {
-       salv_flag_vec = (Volume **) malloc(volume_LRU.q[idx].len * sizeof(Volume *));
+       salv_flag_vec = malloc(volume_LRU.q[idx].len * sizeof(Volume *));
     }
 
     now = FT_ApproxTime();
@@ -7719,7 +7740,7 @@ VLRU_Scan_r(int idx)
     Volume * vp;
     int i, locked = 1;
 
-    osi_Assert(idx == VLRU_QUEUE_NEW || idx == VLRU_QUEUE_CANDIDATE);
+    opr_Assert(idx == VLRU_QUEUE_NEW || idx == VLRU_QUEUE_CANDIDATE);
 
     /* gain exclusive access to the idx VLRU */
     VLRU_Wait_r(&volume_LRU.q[idx]);
@@ -7810,7 +7831,7 @@ VCheckSoftDetachCandidate(Volume * vp, afs_uint32 thresh)
 
     idx = vp->vlru.idx;
 
-    osi_Assert(idx == VLRU_QUEUE_NEW);
+    opr_Assert(idx == VLRU_QUEUE_NEW);
 
     if (vp->stats.last_get <= thresh) {
        /* move to candidate pool */
@@ -7830,7 +7851,7 @@ VCheckSoftDetachCandidate(Volume * vp, afs_uint32 thresh)
 static void
 VLRU_BeginExclusive_r(struct VLRU_q * q)
 {
-    osi_Assert(q->busy == 0);
+    opr_Assert(q->busy == 0);
     q->busy = 1;
 }
 
@@ -7838,9 +7859,9 @@ VLRU_BeginExclusive_r(struct VLRU_q * q)
 static void
 VLRU_EndExclusive_r(struct VLRU_q * q)
 {
-    osi_Assert(q->busy);
+    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 */
@@ -7862,7 +7883,7 @@ VSoftDetachVolume_r(Volume * vp, afs_uint32 thresh)
     afs_uint32 ts_save;
     int ret = 0;
 
-    osi_Assert(vp->vlru.idx == VLRU_QUEUE_CANDIDATE);
+    opr_Assert(vp->vlru.idx == VLRU_QUEUE_CANDIDATE);
 
     ts_save = vp->stats.last_get;
     if (ts_save > thresh)
@@ -7917,7 +7938,7 @@ VSoftDetachVolume_r(Volume * vp, afs_uint32 thresh)
            vp = NULL;
        } else {
            /* pull it off the VLRU */
-           osi_Assert(vp->vlru.idx == VLRU_QUEUE_CANDIDATE);
+           opr_Assert(vp->vlru.idx == VLRU_QUEUE_CANDIDATE);
            volume_LRU.q[VLRU_QUEUE_CANDIDATE].len--;
            queue_Remove(&vp->vlru);
            vp->vlru.idx = VLRU_QUEUE_INVALID;
@@ -7979,7 +8000,7 @@ VInitVolumeHeaderCache(afs_uint32 howMany)
     volume_hdr_LRU.stats.used = howMany;
     volume_hdr_LRU.stats.attached = 0;
     hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
-    osi_Assert(hp != NULL);
+    opr_Assert(hp != NULL);
 
     while (howMany--)
        /* We are using ReleaseVolumeHeader to initialize the values on the header list
@@ -8081,8 +8102,8 @@ GetVolumeHeader(Volume * vp)
     if (programType != fileServer) {
        /* for volume utilities, we allocate volHeaders as needed */
        if (!vp->header) {
-           hd = (struct volHeader *)calloc(1, sizeof(*vp->header));
-           osi_Assert(hd != NULL);
+           hd = calloc(1, sizeof(*vp->header));
+           opr_Assert(hd != NULL);
            vp->header = hd;
            hd->back = vp;
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -8096,7 +8117,7 @@ GetVolumeHeader(Volume * vp)
             * still available. pull it off the lru and return */
            hd = vp->header;
            queue_Remove(hd);
-           osi_Assert(hd->back == vp);
+           opr_Assert(hd->back == vp);
 #ifdef AFS_DEMAND_ATTACH_FS
             V_attachFlags(vp) &= ~(VOL_HDR_IN_LRU);
 #endif
@@ -8105,8 +8126,8 @@ GetVolumeHeader(Volume * vp)
            if (!hd) {
                /* LRU is empty, so allocate a new volHeader
                 * this is probably indicative of a leak, so let the user know */
-               hd = (struct volHeader *)calloc(1, sizeof(struct volHeader));
-               osi_Assert(hd != NULL);
+               hd = calloc(1, sizeof(struct volHeader));
+               opr_Assert(hd != NULL);
                if (!everLogged) {
                    Log("****Allocated more volume headers, probably leak****\n");
                    everLogged = 1;
@@ -8121,7 +8142,7 @@ GetVolumeHeader(Volume * vp)
 #ifdef AFS_DEMAND_ATTACH_FS
                /* GetVolHeaderFromLRU had better not give us back a header
                 * with a volume in exclusive state... */
-               osi_Assert(!VIsExclusiveState(V_attachState(hd->back)));
+               opr_Assert(!VIsExclusiveState(V_attachState(hd->back)));
 #endif
 
                if (hd->diskstuff.inUse) {
@@ -8351,12 +8372,12 @@ VInitVolumeHash(void)
 
     VolumeHashTable.Table = (VolumeHashChainHead *) calloc(VolumeHashTable.Size,
                                                           sizeof(VolumeHashChainHead));
-    osi_Assert(VolumeHashTable.Table != NULL);
+    opr_Assert(VolumeHashTable.Table != NULL);
 
     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 */
     }
 }
@@ -8625,7 +8646,7 @@ VReorderHash_r(VolumeHashChainHead * head, Volume * pp, Volume * vp)
 static void
 VHashBeginExclusive_r(VolumeHashChainHead * head)
 {
-    osi_Assert(head->busy == 0);
+    opr_Assert(head->busy == 0);
     head->busy = 1;
 }
 
@@ -8649,9 +8670,9 @@ VHashBeginExclusive_r(VolumeHashChainHead * head)
 static void
 VHashEndExclusive_r(VolumeHashChainHead * head)
 {
-    osi_Assert(head->busy);
+    opr_Assert(head->busy);
     head->busy = 0;
-    CV_BROADCAST(&head->chain_busy_cv);
+    opr_cv_broadcast(&head->chain_busy_cv);
 }
 
 /**
@@ -8789,7 +8810,7 @@ DeleteVolumeFromVByPList_r(Volume * vp)
 static void
 VVByPListBeginExclusive_r(struct DiskPartition64 * dp)
 {
-    osi_Assert(dp->vol_list.busy == 0);
+    opr_Assert(dp->vol_list.busy == 0);
     dp->vol_list.busy = 1;
 }
 
@@ -8813,9 +8834,9 @@ VVByPListBeginExclusive_r(struct DiskPartition64 * dp)
 static void
 VVByPListEndExclusive_r(struct DiskPartition64 * dp)
 {
-    osi_Assert(dp->vol_list.busy);
+    opr_Assert(dp->vol_list.busy);
     dp->vol_list.busy = 0;
-    CV_BROADCAST(&dp->vol_list.cv);
+    opr_cv_broadcast(&dp->vol_list.cv);
 }
 
 /**