Unix CM: Make rootVolume array big enough
[openafs.git] / src / afs / afs_daemons.c
index 9e958e6..b283f77 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
@@ -10,8 +10,6 @@
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 #ifdef AFS_AIX51_ENV
 #define __FULL_PROTO
@@ -26,7 +24,9 @@ RCSID
 #include <sys/adspace.h>       /* for vm_att(), vm_det() */
 #endif
 
-
+#if defined(AFS_CACHE_BYPASS)
+#include "afs/afs_bypasscache.h"
+#endif /* AFS_CACHE_BYPASS */
 /* background request queue size */
 afs_lock_t afs_xbrs;           /* lock for brs */
 static int brsInit = 0;
@@ -36,24 +36,41 @@ struct brequest afs_brs[NBRS];      /* request structures */
 struct afs_osi_WaitHandle AFS_WaitHandler, AFS_CSWaitHandler;
 static int afs_brs_count = 0;  /* request counter, to service reqs in order */
 
-static int rxepoch_checked = 0;
-#define afs_CheckRXEpoch() {if (rxepoch_checked == 0 && rxkad_EpochWasSet) { \
-       rxepoch_checked = 1; afs_GCUserData(/* force flag */ 1);  } }
-
 /* PAG garbage collection */
 /* We induce a compile error if param.h does not define AFS_GCPAGS */
 afs_int32 afs_gcpags = AFS_GCPAGS;
 afs_int32 afs_gcpags_procsize = 0;
 
 afs_int32 afs_CheckServerDaemonStarted = 0;
-#ifdef DEFAULT_PROBE_INTERVAL
-afs_int32 PROBE_INTERVAL = DEFAULT_PROBE_INTERVAL;     /* overridding during compile */
-#else
-afs_int32 PROBE_INTERVAL = 180;        /* default to 3 min */
+#ifndef DEFAULT_PROBE_INTERVAL
+#define DEFAULT_PROBE_INTERVAL 30      /* default to 3 min */
 #endif
+afs_int32 afs_probe_interval = DEFAULT_PROBE_INTERVAL;
+afs_int32 afs_probe_all_interval = 600;
+afs_int32 afs_nat_probe_interval = 60;
+afs_int32 afs_preCache = 0;
+
+#define PROBE_WAIT() (1000 * (afs_probe_interval - ((afs_random() & 0x7fffffff) \
+                     % (afs_probe_interval/2))))
 
-#define PROBE_WAIT() (1000 * (PROBE_INTERVAL - ((afs_random() & 0x7fffffff) \
-                     % (PROBE_INTERVAL/2))))
+void
+afs_SetCheckServerNATmode(int isnat)
+{
+    static afs_int32 old_intvl, old_all_intvl;
+    static int wasnat;
+
+    if (isnat && !wasnat) {
+       old_intvl = afs_probe_interval;
+       old_all_intvl = afs_probe_all_interval;
+       afs_probe_interval = afs_nat_probe_interval;
+       afs_probe_all_interval = afs_nat_probe_interval;
+       afs_osi_CancelWait(&AFS_CSWaitHandler);
+    } else if (!isnat && wasnat) {
+       afs_probe_interval = old_intvl;
+       afs_probe_all_interval = old_all_intvl;
+    }
+    wasnat = isnat;
+}
 
 void
 afs_CheckServerDaemon(void)
@@ -69,33 +86,33 @@ afs_CheckServerDaemon(void)
     last10MinCheck = lastCheck = osi_Time();
     while (1) {
        if (afs_termState == AFSOP_STOP_CS) {
-           afs_termState = AFSOP_STOP_BKG;
+           afs_termState = AFSOP_STOP_TRUNCDAEMON;
            afs_osi_Wakeup(&afs_termState);
            break;
        }
 
        now = osi_Time();
-       if (PROBE_INTERVAL + lastCheck <= now) {
+       if (afs_probe_interval + lastCheck <= now) {
            afs_CheckServers(1, NULL);  /* check down servers */
            lastCheck = now = osi_Time();
        }
 
-       if (600 + last10MinCheck <= now) {
-           afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, 600);
+       if (afs_probe_all_interval + last10MinCheck <= now) {
+           afs_Trace1(afs_iclSetp, CM_TRACE_PROBEUP, ICL_TYPE_INT32, afs_probe_all_interval);
            afs_CheckServers(0, NULL);
            last10MinCheck = now = osi_Time();
        }
        /* shutdown check. */
        if (afs_termState == AFSOP_STOP_CS) {
-           afs_termState = AFSOP_STOP_BKG;
+           afs_termState = AFSOP_STOP_TRUNCDAEMON;
            afs_osi_Wakeup(&afs_termState);
            break;
        }
 
        /* Compute time to next probe. */
-       delay = PROBE_INTERVAL + lastCheck;
-       if (delay > 600 + last10MinCheck)
-           delay = 600 + last10MinCheck;
+       delay = afs_probe_interval + lastCheck;
+       if (delay > afs_probe_all_interval + last10MinCheck)
+           delay = afs_probe_all_interval + last10MinCheck;
        delay -= now;
        if (delay < 1)
            delay = 1;
@@ -104,6 +121,12 @@ afs_CheckServerDaemon(void)
     afs_CheckServerDaemonStarted = 0;
 }
 
+extern int vfs_context_ref;
+
+/* This function always holds the GLOCK whilst it is running. The caller
+ * gets the GLOCK before invoking it, and afs_osi_Sleep drops the GLOCK
+ * whilst we are sleeping, and regains it when we're woken up.
+ */
 void
 afs_Daemon(void)
 {
@@ -111,18 +134,25 @@ afs_Daemon(void)
     struct afs_exporter *exporter;
     afs_int32 now;
     afs_int32 last3MinCheck, last10MinCheck, last60MinCheck, lastNMinCheck;
-    afs_int32 last1MinCheck;
+    afs_int32 last1MinCheck, last5MinCheck;
     afs_uint32 lastCBSlotBump;
-    char cs_warned = 0;
 
     AFS_STATCNT(afs_Daemon);
-    last1MinCheck = last3MinCheck = last60MinCheck = last10MinCheck =
-       lastNMinCheck = 0;
 
     afs_rootFid.Fid.Volume = 0;
     while (afs_initState < 101)
        afs_osi_Sleep(&afs_initState);
 
+#ifdef AFS_DARWIN80_ENV
+    if (afs_osi_ctxtp_initialized)
+        osi_Panic("vfs context already initialized");
+    while (afs_osi_ctxtp && vfs_context_ref)
+        afs_osi_Sleep(&afs_osi_ctxtp);
+    if (afs_osi_ctxtp && !vfs_context_ref)
+       vfs_context_rele(afs_osi_ctxtp);
+    afs_osi_ctxtp = vfs_context_create(NULL);
+    afs_osi_ctxtp_initialized = 1;
+#endif
     now = osi_Time();
     lastCBSlotBump = now;
 
@@ -133,6 +163,7 @@ afs_Daemon(void)
     last3MinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
     last60MinCheck = now - 1800 + ((afs_random() & 0x7fffffff) % 3600);
     last10MinCheck = now - 300 + ((afs_random() & 0x7fffffff) % 600);
+    last5MinCheck = now - 150 + ((afs_random() & 0x7fffffff) % 300);
     lastNMinCheck = now - 90 + ((afs_random() & 0x7fffffff) % 180);
 
     /* start off with afs_initState >= 101 (basic init done) */
@@ -143,24 +174,9 @@ afs_Daemon(void)
        if (afs_nfsexporter)
            afs_FlushActiveVcaches(0);  /* flush NFS writes */
        afs_FlushVCBs(1);       /* flush queued callbacks */
+
        afs_MaybeWakeupTruncateDaemon();        /* free cache space if have too */
        rx_CheckPackets();      /* Does RX need more packets? */
-#if    defined(AFS_AIX32_ENV) || defined(AFS_HPUX_ENV)
-       /* 
-        * Hack: We always want to make sure there are plenty free
-        * entries in the small free pool so that we don't have to
-        * worry about rx (with disabled interrupts) to have to call
-        * malloc). So we do the dummy call below...
-        */
-       if (((afs_stats_cmperf.SmallBlocksAlloced -
-             afs_stats_cmperf.SmallBlocksActive)
-            <= AFS_SALLOC_LOW_WATER))
-           osi_FreeSmallSpace(osi_AllocSmallSpace(AFS_SMALLOCSIZ));
-       if (((afs_stats_cmperf.MediumBlocksAlloced -
-             afs_stats_cmperf.MediumBlocksActive)
-            <= AFS_MALLOC_LOW_WATER + 50))
-           osi_AllocMoreMSpace(AFS_MALLOC_LOW_WATER * 2);
-#endif
 
        now = osi_Time();
        if (lastCBSlotBump + CBHTSLOTLEN < now) {       /* pretty time-dependant */
@@ -174,11 +190,13 @@ afs_Daemon(void)
            /* things to do every minute */
            DFlush();           /* write out dir buffers */
            afs_WriteThroughDSlots();   /* write through cacheinfo entries */
+           ObtainWriteLock(&afs_xvcache, 736);
+           afs_FlushReclaimedVcaches();
+           ReleaseWriteLock(&afs_xvcache);
            afs_FlushActiveVcaches(1);  /* keep flocks held & flush nfs writes */
-#ifdef AFS_DISCON_ENV
+#if 0
            afs_StoreDirtyVcaches();
 #endif
-           afs_CheckRXEpoch();
            last1MinCheck = now;
        }
 
@@ -187,13 +205,21 @@ afs_Daemon(void)
                                         * tickets */
            last3MinCheck = now;
        }
-       if (!afs_CheckServerDaemonStarted) {
-           /* Do the check here if the correct afsd is not installed. */
-           if (!cs_warned) {
-               cs_warned = 1;
-               printf("Please install afsd with check server daemon.\n");
+
+        if (afsd_dynamic_vcaches && (last5MinCheck + 300 < now)) {
+            /* start with trying to drop us back to our base usage */
+            int anumber = VCACHE_FREE + (afs_vcount - afs_cacheStats);
+
+           if (anumber > 0) {
+               ObtainWriteLock(&afs_xvcache, 734);
+               afs_ShakeLooseVCaches(anumber);
+               ReleaseWriteLock(&afs_xvcache);
            }
-           if (lastNMinCheck + PROBE_INTERVAL < now) {
+            last5MinCheck = now;
+        }
+
+       if (!afs_CheckServerDaemonStarted) {
+           if (lastNMinCheck + afs_probe_interval < now) {
                /* only check down servers */
                afs_CheckServers(1, NULL);
                lastNMinCheck = now;
@@ -215,7 +241,7 @@ afs_Daemon(void)
 #endif /* else AFS_USERSPACE_IP_ADDR */
            if (!afs_CheckServerDaemonStarted)
                afs_CheckServers(0, NULL);
-           afs_GCUserData(0);  /* gc old conns */
+           afs_GCUserData();   /* gc old conns */
            /* This is probably the wrong way of doing GC for the various exporters but it will suffice for a while */
            for (exporter = root_exported; exporter;
                 exporter = exporter->exp_next) {
@@ -258,7 +284,7 @@ afs_Daemon(void)
 
        /* 18285 is because we're trying to divide evenly into 128, that is,
         * CBSlotLen, while staying just under 20 seconds.  If CBSlotLen
-        * changes, should probably change this interval, too. 
+        * changes, should probably change this interval, too.
         * Some of the preceding actions may take quite some time, so we
         * might not want to wait the entire interval */
        now = 18285 - (osi_Time() - now);
@@ -270,7 +296,7 @@ afs_Daemon(void)
            if (afs_CheckServerDaemonStarted)
                afs_termState = AFSOP_STOP_CS;
            else
-               afs_termState = AFSOP_STOP_BKG;
+               afs_termState = AFSOP_STOP_TRUNCDAEMON;
            afs_osi_Wakeup(&afs_termState);
            return;
        }
@@ -280,7 +306,7 @@ afs_Daemon(void)
 int
 afs_CheckRootVolume(void)
 {
-    char rootVolName[32];
+    char rootVolName[MAXROOTVOLNAMELEN];
     struct volume *tvp = NULL;
     int usingDynroot = afs_GetDynrootEnable();
     int localcell;
@@ -325,8 +351,16 @@ afs_CheckRootVolume(void)
                 * count to zero and fs checkv is executed when the current
                 * directory is /afs.
                 */
+#ifdef AFS_LINUX22_ENV
+               osi_ResetRootVCache(volid);
+#else
+# ifdef AFS_DARWIN80_ENV
+               afs_PutVCache(afs_globalVp);
+# else
                AFS_FAST_RELE(afs_globalVp);
+# endif
                afs_globalVp = 0;
+#endif
            }
            afs_rootFid.Fid.Volume = volid;
            afs_rootFid.Fid.Vnode = 1;
@@ -338,29 +372,6 @@ afs_CheckRootVolume(void)
        afs_osi_Wakeup(&afs_initState);
        afs_PutVolume(tvp, READ_LOCK);
     }
-#ifdef AFS_DEC_ENV
-/* This is to make sure that we update the root gnode */
-/* every time root volume gets released */
-    {
-       struct gnode *rootgp;
-       struct mount *mp;
-       int code;
-
-       /* Only do this if afs_globalVFS is properly set due to race conditions
-        * this routine could be called before the gfs_mount is performed!
-        * Furthermore, afs_root (called below) *waits* until
-        * initState >= 200, so we don't try this until we've gotten
-        * at least that far */
-       if (afs_globalVFS && afs_initState >= 200) {
-           if (code = afs_root(afs_globalVFS, &rootgp))
-               return code;
-           mp = (struct mount *)afs_globalVFS->vfs_data;
-           mp->m_rootgp = gget(mp, 0, 0, (char *)rootgp);
-           afs_unlock(mp->m_rootgp);   /* unlock basic gnode */
-           afs_vrele(VTOAFS(rootgp));  /* zap afs_root's vnode hold */
-       }
-    }
-#endif
     if (afs_rootFid.Fid.Volume)
        return 0;
     else
@@ -369,68 +380,61 @@ afs_CheckRootVolume(void)
 
 /* ptr_parm 0 is the pathname, size_parm 0 to the fetch is the chunk number */
 static void
-BPath(register struct brequest *ab)
+BPath(struct brequest *ab)
 {
-    register struct dcache *tdc = NULL;
+    struct dcache *tdc = NULL;
     struct vcache *tvc = NULL;
     struct vnode *tvn = NULL;
 #ifdef AFS_LINUX22_ENV
     struct dentry *dp = NULL;
 #endif
     afs_size_t offset, len;
-    struct vrequest treq;
+    struct vrequest *treq = NULL;
     afs_int32 code;
 
     AFS_STATCNT(BPath);
-    if ((code = afs_InitReq(&treq, ab->cred)))
+    if ((code = afs_CreateReq(&treq, ab->cred))) {
        return;
+    }
     AFS_GUNLOCK();
 #ifdef AFS_LINUX22_ENV
-    code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, NULL, &dp);
+    code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, &dp);
     if (dp)
        tvn = (struct vnode *)dp->d_inode;
 #else
-    code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, NULL, &tvn);
+    code = gop_lookupname((char *)ab->ptr_parm[0], AFS_UIOSYS, 1, &tvn);
 #endif
     AFS_GLOCK();
     osi_FreeLargeSpace((char *)ab->ptr_parm[0]);       /* free path name buffer here */
-    if (code)
+    if (code) {
+       afs_DestroyReq(treq);
        return;
+    }
     /* now path may not have been in afs, so check that before calling our cache manager */
     if (!tvn || !IsAfsVnode(tvn)) {
        /* release it and give up */
        if (tvn) {
-#ifdef AFS_DEC_ENV
-           grele(tvn);
-#else
 #ifdef AFS_LINUX22_ENV
            dput(dp);
 #else
            AFS_RELE(tvn);
 #endif
-#endif
        }
+       afs_DestroyReq(treq);
        return;
     }
-#ifdef AFS_DEC_ENV
-    tvc = VTOAFS(afs_gntovn(tvn));
-#else
     tvc = VTOAFS(tvn);
-#endif
     /* here we know its an afs vnode, so we can get the data for the chunk */
-    tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
+    tdc = afs_GetDCache(tvc, ab->size_parm[0], treq, &offset, &len, 1);
     if (tdc) {
        afs_PutDCache(tdc);
     }
-#ifdef AFS_DEC_ENV
-    grele(tvn);
-#else
 #ifdef AFS_LINUX22_ENV
     dput(dp);
 #else
     AFS_RELE(tvn);
 #endif
-#endif
+    afs_DestroyReq(treq);
 }
 
 /* size_parm 0 to the fetch is the chunk number,
@@ -438,21 +442,27 @@ BPath(register struct brequest *ab)
  * size_parm 1 is true iff we should release the dcache entry here.
  */
 static void
-BPrefetch(register struct brequest *ab)
+BPrefetch(struct brequest *ab)
 {
-    register struct dcache *tdc;
-    register struct vcache *tvc;
-    afs_size_t offset, len;
-    struct vrequest treq;
+    struct dcache *tdc;
+    struct vcache *tvc;
+    afs_size_t offset, len, abyte, totallen = 0;
+    struct vrequest *treq = NULL;
+    int code;
 
     AFS_STATCNT(BPrefetch);
-    if ((len = afs_InitReq(&treq, ab->cred)))
+    if ((code = afs_CreateReq(&treq, ab->cred)))
        return;
+    abyte = ab->size_parm[0];
     tvc = ab->vc;
-    tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
-    if (tdc) {
-       afs_PutDCache(tdc);
-    }
+    do {
+       tdc = afs_GetDCache(tvc, abyte, treq, &offset, &len, 1);
+       if (tdc) {
+           afs_PutDCache(tdc);
+       }
+       abyte+=len;
+       totallen += len;
+    } while ((totallen < afs_preCache) && tdc && (len > 0));
     /* now, dude may be waiting for us to clear DFFetchReq bit; do so.  Can't
      * use tdc from GetDCache since afs_GetDCache may fail, but someone may
      * be waiting for our wakeup anyway.
@@ -470,23 +480,40 @@ BPrefetch(register struct brequest *ab)
     if (ab->size_parm[1]) {
        afs_PutDCache(tdc);     /* put this one back, too */
     }
+    afs_DestroyReq(treq);
 }
 
+#if defined(AFS_CACHE_BYPASS)
+static void
+BPrefetchNoCache(struct brequest *ab)
+{
+    struct vrequest *treq = NULL;
+    int code;
+
+    if ((code = afs_CreateReq(&treq, ab->cred)))
+       return;
+
+#ifndef UKERNEL
+    /* OS-specific prefetch routine */
+    afs_PrefetchNoCache(ab->vc, ab->cred, (struct nocache_read_request *) ab->ptr_parm[0]);
+#endif
+    afs_DestroyReq(treq);
+}
+#endif
 
 static void
-BStore(register struct brequest *ab)
+BStore(struct brequest *ab)
 {
-    register struct vcache *tvc;
-    register afs_int32 code;
-    struct vrequest treq;
+    struct vcache *tvc;
+    afs_int32 code;
+    struct vrequest *treq = NULL;
 #if defined(AFS_SGI_ENV)
     struct cred *tmpcred;
 #endif
 
     AFS_STATCNT(BStore);
-    if ((code = afs_InitReq(&treq, ab->cred)))
+    if ((code = afs_CreateReq(&treq, ab->cred)))
        return;
-    code = 0;
     tvc = ab->vc;
 #if defined(AFS_SGI_ENV)
     /*
@@ -505,7 +532,7 @@ BStore(register struct brequest *ab)
     AFS_RWLOCK((vnode_t *) tvc, 1);
 #endif
     ObtainWriteLock(&tvc->lock, 209);
-    code = afs_StoreOnLastReference(tvc, &treq);
+    code = afs_StoreOnLastReference(tvc, treq);
     ReleaseWriteLock(&tvc->lock);
 #if defined(AFS_SGI_ENV)
     OSI_SET_CURRENT_CRED(tmpcred);
@@ -513,28 +540,77 @@ BStore(register struct brequest *ab)
 #endif
     /* now set final return code, and wakeup anyone waiting */
     if ((ab->flags & BUVALID) == 0) {
-       ab->code = afs_CheckCode(code, &treq, 43);      /* set final code, since treq doesn't go across processes */
+
+       /* To explain code_raw/code_checkcode:
+        * Anyone that's waiting won't have our treq, so they won't be able to
+        * call afs_CheckCode themselves on the return code we provide here.
+        * But if we give back only the afs_CheckCode value, they won't know
+        * what the "raw" value was. So give back both values, so the waiter
+        * can know the "raw" value for interpreting the value internally, as
+        * well as the afs_CheckCode value to give to the OS. */
+       ab->code_raw = code;
+       ab->code_checkcode = afs_CheckCode(code, treq, 430);
+
        ab->flags |= BUVALID;
        if (ab->flags & BUWAIT) {
            ab->flags &= ~BUWAIT;
            afs_osi_Wakeup(ab);
        }
     }
+    afs_DestroyReq(treq);
+}
+
+static void
+BPartialStore(struct brequest *ab)
+{
+    struct vcache *tvc;
+    afs_int32 code;
+    struct vrequest *treq = NULL;
+    int locked, shared_locked = 0;
+
+    AFS_STATCNT(BStore);
+    if ((code = afs_CreateReq(&treq, ab->cred)))
+       return;
+    tvc = ab->vc;
+    locked = tvc->lock.excl_locked? 1:0;
+    if (!locked)
+        ObtainWriteLock(&tvc->lock, 1209);
+    else if (!(tvc->lock.excl_locked & WRITE_LOCK)) {
+       shared_locked = 1;
+       ConvertSToRLock(&tvc->lock);
+    }
+    code = afs_StoreAllSegments(tvc, treq, AFS_ASYNC);
+    if (!locked)
+       ReleaseWriteLock(&tvc->lock);
+    else if (shared_locked)
+       ConvertSToRLock(&tvc->lock);
+    /* now set final return code, and wakeup anyone waiting */
+    if ((ab->flags & BUVALID) == 0) {
+       /* set final code, since treq doesn't go across processes */
+       ab->code_raw = code;
+       ab->code_checkcode = afs_CheckCode(code, treq, 43);
+       ab->flags |= BUVALID;
+       if (ab->flags & BUWAIT) {
+           ab->flags &= ~BUWAIT;
+           afs_osi_Wakeup(ab);
+       }
+    }
+    afs_DestroyReq(treq);
 }
 
 /* release a held request buffer */
 void
-afs_BRelease(register struct brequest *ab)
+afs_BRelease(struct brequest *ab)
 {
 
     AFS_STATCNT(afs_BRelease);
-    MObtainWriteLock(&afs_xbrs, 294);
+    ObtainWriteLock(&afs_xbrs, 294);
     if (--ab->refCount <= 0) {
        ab->flags = 0;
     }
     if (afs_brsWaiters)
        afs_osi_Wakeup(&afs_brsWaiters);
-    MReleaseWriteLock(&afs_xbrs);
+    ReleaseWriteLock(&afs_xbrs);
 }
 
 /* return true if bkg fetch daemons are all busy */
@@ -548,15 +624,16 @@ afs_BBusy(void)
 }
 
 struct brequest *
-afs_BQueue(register short aopcode, register struct vcache *avc,
-          afs_int32 dontwait, afs_int32 ause, struct AFS_UCRED *acred,
-          afs_size_t asparm0, afs_size_t asparm1, void *apparm0)
+afs_BQueue(short aopcode, struct vcache *avc,
+          afs_int32 dontwait, afs_int32 ause, afs_ucred_t *acred,
+          afs_size_t asparm0, afs_size_t asparm1, void *apparm0,
+          void *apparm1, void *apparm2)
 {
-    register int i;
-    register struct brequest *tb;
+    int i;
+    struct brequest *tb;
 
     AFS_STATCNT(afs_BQueue);
-    MObtainWriteLock(&afs_xbrs, 296);
+    ObtainWriteLock(&afs_xbrs, 296);
     while (1) {
        tb = afs_brs;
        for (i = 0; i < NBRS; i++, tb++) {
@@ -568,44 +645,43 @@ afs_BQueue(register short aopcode, register struct vcache *avc,
            tb->opcode = aopcode;
            tb->vc = avc;
            tb->cred = acred;
-           crhold(tb->cred);
+           if (tb->cred) {
+               crhold(tb->cred);
+           }
            if (avc) {
-#ifdef AFS_DEC_ENV
-               avc->vrefCount++;
-#else
-               VN_HOLD(AFSTOV(avc));
-#endif
+               AFS_FAST_HOLD(avc);
            }
            tb->refCount = ause + 1;
            tb->size_parm[0] = asparm0;
            tb->size_parm[1] = asparm1;
            tb->ptr_parm[0] = apparm0;
+           tb->ptr_parm[1] = apparm1;
+           tb->ptr_parm[2] = apparm2;
            tb->flags = 0;
-           tb->code = 0;
+           tb->code_raw = tb->code_checkcode = 0;
            tb->ts = afs_brs_count++;
            /* if daemons are waiting for work, wake them up */
            if (afs_brsDaemons > 0) {
                afs_osi_Wakeup(&afs_brsDaemons);
            }
-           MReleaseWriteLock(&afs_xbrs);
+           ReleaseWriteLock(&afs_xbrs);
            return tb;
        }
        if (dontwait) {
-           MReleaseWriteLock(&afs_xbrs);
+           ReleaseWriteLock(&afs_xbrs);
            return NULL;
        }
        /* no free buffers, sleep a while */
        afs_brsWaiters++;
-       MReleaseWriteLock(&afs_xbrs);
+       ReleaseWriteLock(&afs_xbrs);
        afs_osi_Sleep(&afs_brsWaiters);
-       MObtainWriteLock(&afs_xbrs, 301);
+       ObtainWriteLock(&afs_xbrs, 301);
        afs_brsWaiters--;
     }
 }
 
-#ifdef AFS_AIX32_ENV
 #ifdef AFS_AIX41_ENV
-/* AIX 4.1 has a much different sleep/wakeup mechanism available for use. 
+/* AIX 4.1 has a much different sleep/wakeup mechanism available for use.
  * The modifications here will work for either a UP or MP machine.
  */
 struct buf *afs_asyncbuf = (struct buf *)0;
@@ -613,7 +689,7 @@ tid_t afs_asyncbuf_cv = EVENT_NULL;
 afs_int32 afs_biodcnt = 0;
 
 /* in implementing this, I assumed that all external linked lists were
- * null-terminated.  
+ * null-terminated.
  *
  * Several places in this code traverse a linked list.  The algorithm
  * used here is probably unfamiliar to most people.  Careful examination
@@ -626,20 +702,20 @@ afs_int32 afs_biodcnt = 0;
  *
  * This function obtains, and returns, a pointer to a buffer for
  * processing by a daemon.  It sleeps until such a buffer is available.
- * The source of buffers for it is the list afs_asyncbuf (see also 
- * naix_vm_strategy).  This function may be invoked concurrently by
+ * The source of buffers for it is the list afs_asyncbuf (see also
+ * afs_gn_strategy).  This function may be invoked concurrently by
  * several processes, that is, several instances of the same daemon.
- * naix_vm_strategy, which adds buffers to the list, runs at interrupt
+ * afs_gn_strategy, which adds buffers to the list, runs at interrupt
  * level, while get_bioreq runs at process level.
  *
  * Since AIX 4.1 can wake just one process at a time, the separate sleep
  * addresses have been removed.
- * Note that the kernel_lock is held until the e_sleep_thread() occurs. 
+ * Note that the kernel_lock is held until the e_sleep_thread() occurs.
  * The afs_asyncbuf_lock is primarily used to serialize access between
  * process and interrupts.
  */
 Simple_lock afs_asyncbuf_lock;
-/*static*/ struct buf *
+struct buf *
 afs_get_bioreq()
 {
     struct buf *bp = NULL;
@@ -654,7 +730,7 @@ afs_get_bioreq()
     /* ??? Does the forward pointer of the returned buffer need to be NULL?
      */
 
-    /* Disable interrupts from the strategy function, and save the 
+    /* Disable interrupts from the strategy function, and save the
      * prior priority level and lock access to the afs_asyncbuf.
      */
     AFS_GUNLOCK();
@@ -707,7 +783,7 @@ afs_get_bioreq()
 
     /* For the convenience of other code, replace the gnodes in
      * the b_vp field of bp and the other buffers on the b_work
-     * chain with the corresponding vnodes.   
+     * chain with the corresponding vnodes.
      *
      * ??? what happens to the gnodes?  They're not just cut loose,
      * are they?
@@ -781,9 +857,9 @@ afs_BioDaemon(afs_int32 nbiods)
        limit_sigs(&sigbits, &osigbits);        /*   and already masked */
     }
     /* Main body starts here -- this is an intentional infinite loop, and
-     * should NEVER exit 
+     * should NEVER exit
      *
-     * Now, the loop will exit if get_bioreq() returns NULL, indicating 
+     * Now, the loop will exit if get_bioreq() returns NULL, indicating
      * that we've been interrupted.
      */
     while (1) {
@@ -812,19 +888,19 @@ afs_BioDaemon(afs_int32 nbiods)
            if (vcp->v.v_gnode->gn_mwrcnt) {
                afs_offs_t newlength =
                    (afs_offs_t) dbtob(bp->b_blkno) + bp->b_bcount;
-               if (vcp->m.Length < newlength) {
+               if (vcp->f.m.Length < newlength) {
                    afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
                               ICL_TYPE_STRING, __FILE__, ICL_TYPE_LONG,
                               __LINE__, ICL_TYPE_OFFSET,
-                              ICL_HANDLE_OFFSET(vcp->m.Length),
+                              ICL_HANDLE_OFFSET(vcp->f.m.Length),
                               ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(newlength));
-                   vcp->m.Length = newlength;
+                   vcp->f.m.Length = newlength;
                }
            }
            ReleaseWriteLock(&vcp->lock);
        }
        /* If the buffer represents a protection violation, rather than
-        * an actual request for I/O, no special action need be taken.  
+        * an actual request for I/O, no special action need be taken.
         */
        if (bp->b_flags & B_PFPROT) {
            iodone(bp);         /* Notify all users of the buffer that we're done */
@@ -855,9 +931,9 @@ afs_BioDaemon(afs_int32 nbiods)
 
        /*
         * buffer may be linked with other buffers via the b_work field.
-        * See also naix_vm_strategy.  For each buffer in the chain (including
+        * See also afs_gn_strategy.  For each buffer in the chain (including
         * bp) notify all users of the buffer that the daemon is finished
-        * using it by calling iodone.  
+        * using it by calling iodone.
         * assumes iodone can modify the b_work field.
         */
        for (tbp1 = bp;;) {
@@ -877,393 +953,101 @@ afs_BioDaemon(afs_int32 nbiods)
     }                          /* infinite loop (unless we're interrupted) */
 }                              /* end of afs_BioDaemon() */
 
-#else /* AFS_AIX41_ENV */
-
-
-#define        squeue afs_q
-struct afs_bioqueue {
-    struct squeue lruq;
-    int sleeper;
-    int cnt;
-};
-struct afs_bioqueue afs_bioqueue;
-struct buf *afs_busyq = NULL;
-struct buf *afs_asyncbuf;
-afs_int32 afs_biodcnt = 0;
-
-/* in implementing this, I assumed that all external linked lists were
- * null-terminated.  
- *
- * Several places in this code traverse a linked list.  The algorithm
- * used here is probably unfamiliar to most people.  Careful examination
- * will show that it eliminates an assignment inside the loop, as compared
- * to the standard algorithm, at the cost of occasionally using an extra
- * variable.
- */
+#endif /* AFS_AIX41_ENV */
 
-/* get_bioreq()
- *
- * This function obtains, and returns, a pointer to a buffer for
- * processing by a daemon.  It sleeps until such a buffer is available.
- * The source of buffers for it is the list afs_asyncbuf (see also 
- * naix_vm_strategy).  This function may be invoked concurrently by
- * several processes, that is, several instances of the same daemon.
- * naix_vm_strategy, which adds buffers to the list, runs at interrupt
- * level, while get_bioreq runs at process level.
- *
- * The common kernel paradigm of sleeping and waking up, in which all the
- * competing processes sleep waiting for wakeups on one address, is not
- * followed here.  Instead, the following paradigm is used:  when a daemon
- * goes to sleep, it checks for other sleeping daemons.  If there aren't any,
- * it sleeps on the address of variable afs_asyncbuf.  But if there is
- * already a daemon sleeping on that address, it threads its own unique
- * address onto a list, and sleeps on that address.  This way, every 
- * sleeper is sleeping on a different address, and every wakeup wakes up
- * exactly one daemon.  This prevents a whole bunch of daemons from waking
- * up and then immediately having to go back to sleep.  This provides a
- * performance gain and makes the I/O scheduling a bit more deterministic.
- * The list of sleepers is variable afs_bioqueue.  The unique address
- * on which to sleep is passed to get_bioreq as its parameter.
- */
-/*static*/ struct buf *
-afs_get_bioreq(self)
-     struct afs_bioqueue *self;        /* address on which to sleep */
 
+int afs_nbrs = 0;
+static_inline void
+afs_BackgroundDaemon_once(void)
 {
-    struct buf *bp = NULL;
-    struct buf *bestbp;
-    struct buf **bestlbpP, **lbpP;
-    int bestage, stop;
-    struct buf *t1P, *t2P;     /* temp pointers for list manipulation */
-    int oldPriority;
-    afs_uint32 wait_ret;
-    struct afs_bioqueue *s;
-
-    /* ??? Does the forward pointer of the returned buffer need to be NULL?
-     */
-
-    /* Disable interrupts from the strategy function, and save the 
-     * prior priority level
-     */
-    oldPriority = i_disable(INTMAX);
-
-    /* Each iteration of following loop either pulls
-     * a buffer off afs_asyncbuf, or sleeps.  
+    LOCK_INIT(&afs_xbrs, "afs_xbrs");
+    memset(afs_brs, 0, sizeof(afs_brs));
+    brsInit = 1;
+#if defined (AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
+    /*
+     * steal the first daemon for doing delayed DSlot flushing
+     * (see afs_GetDownDSlot)
      */
-    while (1) {                        /* inner loop */
-       if (afs_asyncbuf) {
-           /* look for oldest buffer */
-           bp = bestbp = afs_asyncbuf;
-           bestage = (int)bestbp->av_back;
-           bestlbpP = &afs_asyncbuf;
-           while (1) {
-               lbpP = &bp->av_forw;
-               bp = *lbpP;
-               if (!bp)
-                   break;
-               if ((int)bp->av_back - bestage < 0) {
-                   bestbp = bp;
-                   bestlbpP = lbpP;
-                   bestage = (int)bp->av_back;
-               }
-           }
-           bp = bestbp;
-           *bestlbpP = bp->av_forw;
-           break;
-       } else {
-           int interrupted;
-
-           /* If afs_asyncbuf is null, it is necessary to go to sleep.
-            * There are two possibilities:  either there is already a
-            * daemon that is sleeping on the address of afs_asyncbuf,
-            * or there isn't. 
-            */
-           if (afs_bioqueue.sleeper) {
-               /* enqueue */
-               QAdd(&(afs_bioqueue.lruq), &(self->lruq));
-               interrupted = sleep((caddr_t) self, PCATCH | (PZERO + 1));
-               if (self->lruq.next != &self->lruq) {   /* XXX ##3 XXX */
-                   QRemove(&(self->lruq));     /* dequeue */
-               }
-               self->cnt++;
-               afs_bioqueue.sleeper = FALSE;
-               if (interrupted) {
-                   /* re-enable interrupts from strategy */
-                   i_enable(oldPriority);
-                   return (NULL);
-               }
-               continue;
-           } else {
-               afs_bioqueue.sleeper = TRUE;
-               interrupted =
-                   sleep((caddr_t) & afs_asyncbuf, PCATCH | (PZERO + 1));
-               afs_bioqueue.sleeper = FALSE;
-               if (interrupted) {
-                   /*
-                    * We need to wakeup another daemon if present
-                    * since we were waiting on afs_asyncbuf.
-                    */
-#ifdef notdef                  /* The following doesn't work as advertised */
-                   if (afs_bioqueue.lruq.next != &afs_bioqueue.lruq) {
-                       struct squeue *bq = afs_bioqueue.lruq.next;
-                       QRemove(bq);
-                       wakeup(bq);
-                   }
+    AFS_GUNLOCK();
+    afs_sgidaemon();
+    exit(CLD_EXITED, 0);
 #endif
-                   /* re-enable interrupts from strategy */
-                   i_enable(oldPriority);
-                   return (NULL);
-               }
-               continue;
-           }
-
-       }                       /* end of "else asyncbuf is empty" */
-    }                          /* end of "inner loop" */
-
-    /*assert (bp); */
-
-    i_enable(oldPriority);     /* re-enable interrupts from strategy */
-
-    /* For the convenience of other code, replace the gnodes in
-     * the b_vp field of bp and the other buffers on the b_work
-     * chain with the corresponding vnodes.   
-     *
-     * ??? what happens to the gnodes?  They're not just cut loose,
-     * are they?
-     */
-    for (t1P = bp;;) {
-       t2P = (struct buf *)t1P->b_work;
-       t1P->b_vp = ((struct gnode *)t1P->b_vp)->gn_vnode;
-       if (!t2P)
-           break;
-
-       t1P = (struct buf *)t2P->b_work;
-       t2P->b_vp = ((struct gnode *)t2P->b_vp)->gn_vnode;
-       if (!t1P)
-           break;
-    }
-
-    /* If the buffer does not specify I/O, it may immediately
-     * be returned to the caller.  This condition is detected
-     * by examining the buffer's flags (the b_flags field).  If
-     * the B_PFPROT bit is set, the buffer represents a protection
-     * violation, rather than a request for I/O.  The remainder
-     * of the outer loop handles the case where the B_PFPROT bit is clear.
-     */
-    if (bp->b_flags & B_PFPROT) {
-       return (bp);
-    }
-
-    /* wake up another process to handle the next buffer, and return
-     * bp to the caller.
-     */
-    oldPriority = i_disable(INTMAX);
-
-    /* determine where to find the sleeping process. 
-     * There are two cases: either it is sleeping on
-     * afs_asyncbuf, or it is sleeping on its own unique
-     * address.  These cases are distinguished by examining
-     * the sleeper field of afs_bioqueue.
-     */
-    if (afs_bioqueue.sleeper) {
-       wakeup(&afs_asyncbuf);
-    } else {
-       if (afs_bioqueue.lruq.next == &afs_bioqueue.lruq) {
-           /* queue is empty, what now? ??? */
-           /* Should this be impossible, or does    */
-           /* it just mean that nobody is sleeping? */ ;
-       } else {
-           struct squeue *bq = afs_bioqueue.lruq.next;
-           QRemove(bq);
-           QInit(bq);
-           wakeup(bq);
-           afs_bioqueue.sleeper = TRUE;
-       }
-    }
-    i_enable(oldPriority);     /* re-enable interrupts from strategy */
-    return (bp);
-
-}                              /* end of function get_bioreq() */
-
+}
 
-/* afs_BioDaemon
- *
- * This function is the daemon.  It is called from the syscall
- * interface.  Ordinarily, a script or an administrator will run a
- * daemon startup utility, specifying the number of I/O daemons to
- * run.  The utility will fork off that number of processes,
- * each making the appropriate syscall, which will cause this
- * function to be invoked.
- */
-static int afs_initbiod = 0;   /* this is self-initializing code */
-int DOvmlock = 0;
-afs_BioDaemon(nbiods)
-     afs_int32 nbiods;
+static_inline void
+brequest_release(struct brequest *tb)
 {
-    struct afs_bioqueue *self;
-    afs_int32 code, s, pflg = 0;
-    label_t jmpbuf;
-    struct buf *bp, *bp1, *tbp1, *tbp2;        /* temp pointers only */
-    caddr_t tmpaddr;
-    struct vnode *vp;
-    struct vcache *vcp;
-    char tmperr;
-    if (!afs_initbiod) {
-       /* XXX ###1 XXX */
-       afs_initbiod = 1;
-       /* Initialize the queue of waiting processes, afs_bioqueue.  */
-       QInit(&(afs_bioqueue.lruq));
+    if (tb->vc) {
+       AFS_RELE(AFSTOV(tb->vc));       /* MUST call vnode layer or could lose vnodes */
+       tb->vc = NULL;
     }
+    if (tb->cred) {
+       crfree(tb->cred);
+       tb->cred = (afs_ucred_t *)0;
+    }
+    afs_BRelease(tb);  /* this grabs and releases afs_xbrs lock */
+}
 
-    /* establish ourself as a kernel process so shutdown won't kill us */
-/*    u.u_procp->p_flag |= SKPROC;*/
-
-    /* Initialize a token (self) to use in the queue of sleeping processes.   */
-    self = (struct afs_bioqueue *)afs_osi_Alloc(sizeof(struct afs_bioqueue));
-    pin(self, sizeof(struct afs_bioqueue));    /* fix in memory */
-    memset(self, 0, sizeof(*self));
-    QInit(&(self->lruq));      /* initialize queue entry pointers */
-
-
-    /* Ignore HUP signals... */
-    SIGDELSET(u.u_procp->p_sig, SIGHUP);
-    SIGADDSET(u.u_procp->p_sigignore, SIGHUP);
-    SIGDELSET(u.u_procp->p_sigcatch, SIGHUP);
-    /* Main body starts here -- this is an intentional infinite loop, and
-     * should NEVER exit 
-     *
-     * Now, the loop will exit if get_bioreq() returns NULL, indicating 
-     * that we've been interrupted.
-     */
-    while (1) {
-       bp = afs_get_bioreq(self);
-       if (!bp)
-           break;              /* we were interrupted */
-       if (code = setjmpx(&jmpbuf)) {
-           /* This should not have happend, maybe a lack of resources  */
-           s = splimp();
-           for (bp1 = bp; bp; bp = bp1) {
-               if (bp1)
-                   bp1 = bp1->b_work;
-               bp->b_actf = 0;
-               bp->b_error = code;
-               bp->b_flags |= B_ERROR;
-               iodone(bp);
-           }
-           splx(s);
-           continue;
-       }
-       vcp = VTOAFS(bp->b_vp);
-       if (bp->b_flags & B_PFSTORE) {
-           ObtainWriteLock(&vcp->lock, 210);
-           if (vcp->v.v_gnode->gn_mwrcnt) {
-               afs_offs_t newlength =
-                   (afs_offs_t) dbtob(bp->b_blkno) + bp->b_bcount;
-               if (vcp->m.Length < newlength) {
-                   afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
-                              ICL_TYPE_STRING, __FILE__, ICL_TYPE_LONG,
-                              __LINE__, ICL_TYPE_OFFSET,
-                              ICL_HANDLE_OFFSET(vcp->m.Length),
-                              ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(newlength));
-                   vcp->m.Length = newlength;
-               }
-           }
-           ReleaseWriteLock(&vcp->lock);
-       }
-       /* If the buffer represents a protection violation, rather than
-        * an actual request for I/O, no special action need be taken.  
-        */
-       if (bp->b_flags & B_PFPROT) {
-           iodone(bp);         /* Notify all users of the buffer that we're done */
-           continue;
-       }
-       if (DOvmlock)
-           ObtainWriteLock(&vcp->pvmlock, 558);
-       /*
-        * First map its data area to a region in the current address space
-        * by calling vm_att with the subspace identifier, and a pointer to
-        * the data area.  vm_att returns  a new data area pointer, but we
-        * also want to hang onto the old one.
-        */
-       tmpaddr = bp->b_baddr;
-       bp->b_baddr = vm_att(bp->b_xmemd.subspace_id, tmpaddr);
-       tmperr = afs_ustrategy(bp);     /* temp variable saves offset calculation */
-       if (tmperr) {           /* in non-error case */
-           bp->b_flags |= B_ERROR;     /* should other flags remain set ??? */
-           bp->b_error = tmperr;
-       }
-
-       /* Unmap the buffer's data area by calling vm_det.  Reset data area
-        * to the value that we saved above.
-        */
-       vm_det(bp->b_un.b_addr);
-       bp->b_baddr = tmpaddr;
-
-       /*
-        * buffer may be linked with other buffers via the b_work field.
-        * See also naix_vm_strategy.  For each buffer in the chain (including
-        * bp) notify all users of the buffer that the daemon is finished
-        * using it by calling iodone.  
-        * assumes iodone can modify the b_work field.
-        */
-       for (tbp1 = bp;;) {
-           tbp2 = (struct buf *)tbp1->b_work;
-           iodone(tbp1);
-           if (!tbp2)
-               break;
-
-           tbp1 = (struct buf *)tbp2->b_work;
-           iodone(tbp2);
-           if (!tbp1)
-               break;
-       }
-       if (DOvmlock)
-           ReleaseWriteLock(&vcp->pvmlock);    /* Unlock the vnode.  */
-       clrjmpx(&jmpbuf);
-    }                          /* infinite loop (unless we're interrupted) */
-    unpin(self, sizeof(struct afs_bioqueue));
-    afs_osi_Free(self, sizeof(struct afs_bioqueue));
-}                              /* end of afs_BioDaemon() */
-#endif /* AFS_AIX41_ENV */
-#endif /* AFS_AIX32_ENV */
-
-
-int afs_nbrs = 0;
+#ifdef AFS_NEW_BKG
+int
+afs_BackgroundDaemon(struct afs_uspc_param *uspc, void *param1, void *param2)
+#else
 void
 afs_BackgroundDaemon(void)
+#endif
 {
     struct brequest *tb;
     int i, foundAny;
 
     AFS_STATCNT(afs_BackgroundDaemon);
     /* initialize subsystem */
-    if (brsInit == 0) {
-       LOCK_INIT(&afs_xbrs, "afs_xbrs");
-       memset((char *)afs_brs, 0, sizeof(afs_brs));
-       brsInit = 1;
-#if defined (AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
-       /*
-        * steal the first daemon for doing delayed DSlot flushing
-        * (see afs_GetDownDSlot)
-        */
-       AFS_GUNLOCK();
-       afs_sgidaemon();
-       return;
+    if (brsInit == 0)
+       /* Irix with "short stack" exits */
+       afs_BackgroundDaemon_once();
+
+#ifdef AFS_NEW_BKG
+    /* If it's a re-entering syscall, complete the request and release */
+    if (uspc->ts > -1) {
+        tb = afs_brs;
+        for (i = 0; i < NBRS; i++, tb++) {
+            if (tb->ts == uspc->ts) {
+                /* copy the userspace status back in */
+                ((struct afs_uspc_param *) tb->ptr_parm[0])->retval =
+                    uspc->retval;
+                /* mark it valid and notify our caller */
+                tb->flags |= BUVALID;
+                if (tb->flags & BUWAIT) {
+                    tb->flags &= ~BUWAIT;
+                    afs_osi_Wakeup(tb);
+                }
+                brequest_release(tb);
+                break;
+            }
+        }
+    } else {
+        afs_osi_MaskUserLoop();
 #endif
+        /* Otherwise it's a new one */
+       afs_nbrs++;
+#ifdef AFS_NEW_BKG
     }
-    afs_nbrs++;
+#endif
 
-    MObtainWriteLock(&afs_xbrs, 302);
+    ObtainWriteLock(&afs_xbrs, 302);
     while (1) {
        int min_ts = 0;
        struct brequest *min_tb = NULL;
 
        if (afs_termState == AFSOP_STOP_BKG) {
            if (--afs_nbrs <= 0)
-               afs_termState = AFSOP_STOP_TRUNCDAEMON;
-           MReleaseWriteLock(&afs_xbrs);
+               afs_termState = AFSOP_STOP_RXCALLBACK;
+           ReleaseWriteLock(&afs_xbrs);
            afs_osi_Wakeup(&afs_termState);
+#ifdef AFS_NEW_BKG
+           return -2;
+#else
            return;
+#endif
        }
 
        /* find a request */
@@ -1282,42 +1066,52 @@ afs_BackgroundDaemon(void)
        if ((tb = min_tb)) {
            /* claim and process this request */
            tb->flags |= BSTARTED;
-           MReleaseWriteLock(&afs_xbrs);
+           ReleaseWriteLock(&afs_xbrs);
            foundAny = 1;
            afs_Trace1(afs_iclSetp, CM_TRACE_BKG1, ICL_TYPE_INT32,
                       tb->opcode);
            if (tb->opcode == BOP_FETCH)
                BPrefetch(tb);
+#if defined(AFS_CACHE_BYPASS)
+           else if (tb->opcode == BOP_FETCH_NOCACHE)
+               BPrefetchNoCache(tb);
+#endif
            else if (tb->opcode == BOP_STORE)
                BStore(tb);
            else if (tb->opcode == BOP_PATH)
                BPath(tb);
+#ifdef AFS_DARWIN80_ENV
+            else if (tb->opcode == BOP_MOVE) {
+                memcpy(uspc, (struct afs_uspc_param *) tb->ptr_parm[0],
+                       sizeof(struct afs_uspc_param));
+                uspc->ts = tb->ts;
+                /* string lengths capped in move vop; copy NUL tho */
+                memcpy(param1, (char *)tb->ptr_parm[1],
+                       strlen(tb->ptr_parm[1])+1);
+                memcpy(param2, (char *)tb->ptr_parm[2],
+                       strlen(tb->ptr_parm[2])+1);
+                return 0;
+            }
+#endif
+           else if (tb->opcode == BOP_PARTIAL_STORE)
+               BPartialStore(tb);
            else
                panic("background bop");
-           if (tb->vc) {
-#ifdef AFS_DEC_ENV
-               tb->vc->vrefCount--;    /* fix up reference count */
-#else
-               AFS_RELE(AFSTOV(tb->vc));       /* MUST call vnode layer or could lose vnodes */
-#endif
-               tb->vc = NULL;
-           }
-           if (tb->cred) {
-               crfree(tb->cred);
-               tb->cred = (struct AFS_UCRED *)0;
-           }
-           afs_BRelease(tb);   /* this grabs and releases afs_xbrs lock */
-           MObtainWriteLock(&afs_xbrs, 305);
+           brequest_release(tb);
+           ObtainWriteLock(&afs_xbrs, 305);
        }
        if (!foundAny) {
            /* wait for new request */
            afs_brsDaemons++;
-           MReleaseWriteLock(&afs_xbrs);
+           ReleaseWriteLock(&afs_xbrs);
            afs_osi_Sleep(&afs_brsDaemons);
-           MObtainWriteLock(&afs_xbrs, 307);
+           ObtainWriteLock(&afs_xbrs, 307);
            afs_brsDaemons--;
        }
     }
+#ifdef AFS_NEW_BKG
+    return -2;
+#endif
 }
 
 
@@ -1327,20 +1121,14 @@ shutdown_daemons(void)
     AFS_STATCNT(shutdown_daemons);
     if (afs_cold_shutdown) {
        afs_brsDaemons = brsInit = 0;
-       rxepoch_checked = afs_nbrs = 0;
-       memset((char *)afs_brs, 0, sizeof(afs_brs));
-       memset((char *)&afs_xbrs, 0, sizeof(afs_lock_t));
+       afs_nbrs = 0;
+       memset(afs_brs, 0, sizeof(afs_brs));
+       memset(&afs_xbrs, 0, sizeof(afs_lock_t));
        afs_brsWaiters = 0;
-#ifdef AFS_AIX32_ENV
 #ifdef AFS_AIX41_ENV
        lock_free(&afs_asyncbuf_lock);
        unpin(&afs_asyncbuf, sizeof(struct buf *));
        unpin(&afs_asyncbuf_cv, sizeof(afs_int32));
-#else /* AFS_AIX41_ENV */
-       afs_busyq = NULL;
-       afs_biodcnt = 0;
-       memset((char *)&afs_bioqueue, 0, sizeof(struct afs_bioqueue));
-#endif
        afs_initbiod = 0;
 #endif
     }
@@ -1385,7 +1173,7 @@ afs_sgidaemon(void)
            SPUNLOCK(afs_sgibklock, s);
            AFS_GLOCK();
            tdc->dflags &= ~DFEntryMod;
-           afs_WriteDCache(tdc, 1);
+           osi_Assert(afs_WriteDCache(tdc, 1) == 0);
            AFS_GUNLOCK();
            s = SPLOCK(afs_sgibklock);
        }