vlserver: remove an unused global
[openafs.git] / src / vlserver / vlutils.c
index 2b6a3e1..cabe98d 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
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
-
-#include <sys/types.h>
-#include <string.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#else
-#include <netinet/in.h>
-#endif
+#include <roken.h>
 
 #include <lock.h>
 #include <rx/xdr.h>
 #include <ubik.h>
+
 #include "vlserver.h"
+#include "vlserver_internal.h"
 
-extern struct vlheader cheader;
 struct vlheader xheader;
-extern afs_uint32 HostAddress[];
 extern int maxnservers;
-struct extentaddr extentaddr;
-extern struct extentaddr *ex_addr[];
+extern afs_uint32 rd_HostAddress[MAXSERVERID + 1];
+extern afs_uint32 wr_HostAddress[MAXSERVERID + 1];
+struct extentaddr *rd_ex_addr[VL_MAX_ADDREXTBLKS] = { 0, 0, 0, 0 };
+struct extentaddr *wr_ex_addr[VL_MAX_ADDREXTBLKS] = { 0, 0, 0, 0 };
+struct vlheader rd_cheader;    /* kept in network byte order */
+struct vlheader wr_cheader;
 int vldbversion = 0;
 
-static int index_OK();
+static int index_OK(struct vl_ctx *ctx, afs_int32 blockindex);
 
-#define ERROR_EXIT(code) {error=(code); goto error_exit;}
+#define ERROR_EXIT(code) do { \
+    error = (code); \
+    goto error_exit; \
+} while (0)
 
 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
 afs_int32
-IDHash(volumeid)
-     afs_int32 volumeid;
+IDHash(afs_int32 volumeid)
 {
     return ((abs(volumeid)) % HASHSIZE);
 }
@@ -49,11 +46,10 @@ IDHash(volumeid)
 
 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
 afs_int32
-NameHash(volumename)
-     register char *volumename;
+NameHash(char *volumename)
 {
-    register unsigned int hash;
-    register int i;
+    unsigned int hash;
+    int i;
 
     hash = 0;
     for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
@@ -64,15 +60,12 @@ NameHash(volumename)
 
 /* package up seek and write into one procedure for ease of use */
 afs_int32
-vlwrite(trans, offset, buffer, length)
-     struct ubik_trans *trans;
-     afs_int32 offset;
-     char *buffer;
-     afs_int32 length;
+vlwrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
+       afs_int32 length)
 {
     afs_int32 errorcode;
 
-    if (errorcode = ubik_Seek(trans, 0, offset))
+    if ((errorcode = ubik_Seek(trans, 0, offset)))
        return errorcode;
     return (ubik_Write(trans, buffer, length));
 }
@@ -80,15 +73,12 @@ vlwrite(trans, offset, buffer, length)
 
 /* Package up seek and read into one procedure for ease of use */
 afs_int32
-vlread(trans, offset, buffer, length)
-     struct ubik_trans *trans;
-     afs_int32 offset;
-     char *buffer;
-     afs_int32 length;
+vlread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
+       afs_int32 length)
 {
     afs_int32 errorcode;
 
-    if (errorcode = ubik_Seek(trans, 0, offset))
+    if ((errorcode = ubik_Seek(trans, 0, offset)))
        return errorcode;
     return (ubik_Read(trans, buffer, length));
 }
@@ -96,16 +86,13 @@ vlread(trans, offset, buffer, length)
 
 /* take entry and convert to network order and write to disk */
 afs_int32
-vlentrywrite(trans, offset, buffer, length)
-     struct ubik_trans *trans;
-     afs_int32 offset;
-     char *buffer;
-     afs_int32 length;
+vlentrywrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
+            afs_int32 length)
 {
     struct vlentry oentry;
     struct nvlentry nentry, *nep;
     char *bufp;
-    register afs_int32 i;
+    afs_int32 i;
 
     if (length != sizeof(oentry))
        return -1;
@@ -148,16 +135,13 @@ vlentrywrite(trans, offset, buffer, length)
 
 /* read entry and convert to host order and write to disk */
 afs_int32
-vlentryread(trans, offset, buffer, length)
-     struct ubik_trans *trans;
-     afs_int32 offset;
-     char *buffer;
-     afs_int32 length;
+vlentryread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
+           afs_int32 length)
 {
     struct vlentry *oep, tentry;
     struct nvlentry *nep, *nbufp;
     char *bufp = (char *)&tentry;
-    register afs_int32 i;
+    afs_int32 i;
 
     if (length != sizeof(vlentry))
        return -1;
@@ -203,11 +187,10 @@ vlentryread(trans, offset, buffer, length)
 
 /* Convenient write of small critical vldb header info to the database. */
 int
-write_vital_vlheader(trans)
-     register struct ubik_trans *trans;
+write_vital_vlheader(struct vl_ctx *ctx)
 {
     if (vlwrite
-       (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
+       (ctx->trans, 0, (char *)&ctx->cheader->vital_header, sizeof(vital_vlheader)))
        return VL_IO;
     return 0;
 }
@@ -224,28 +207,27 @@ int extent_mod = 0;
  * (extent_mod tells us the on-disk copy is bad).
  */
 afs_int32
-readExtents(trans)
-     struct ubik_trans *trans;
+readExtents(struct ubik_trans *trans)
 {
     afs_uint32 extentAddr;
     afs_int32 error = 0, code;
     int i;
 
     extent_mod = 0;
-    extentAddr = ntohl(cheader.SIT);
+    extentAddr = ntohl(rd_cheader.SIT);
     if (!extentAddr)
        return 0;
 
     /* Read the first extension block */
-    if (!ex_addr[0]) {
-       ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
-       if (!ex_addr[0])
+    if (!rd_ex_addr[0]) {
+       rd_ex_addr[0] = malloc(VL_ADDREXTBLK_SIZE);
+       if (!rd_ex_addr[0])
            ERROR_EXIT(VL_NOMEM);
     }
-    code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
+    code = vlread(trans, extentAddr, (char *)rd_ex_addr[0], VL_ADDREXTBLK_SIZE);
     if (code) {
-       free(ex_addr[0]);       /* Not the place to create it */
-       ex_addr[0] = 0;
+       free(rd_ex_addr[0]);    /* Not the place to create it */
+       rd_ex_addr[0] = 0;
        ERROR_EXIT(VL_IO);
     }
 
@@ -253,47 +235,47 @@ readExtents(trans)
      * continuation blocks
      */
     for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
-       if (!ex_addr[0]->ex_contaddrs[i])
+       if (!rd_ex_addr[0]->ex_contaddrs[i])
            continue;
 
        /* Before reading it in, check to see if the address is good */
-       if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
-            ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
-           || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
-               ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
+       if ((ntohl(rd_ex_addr[0]->ex_contaddrs[i]) <
+            ntohl(rd_ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
+           || (ntohl(rd_ex_addr[0]->ex_contaddrs[i]) >
+               ntohl(rd_cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
            extent_mod = 1;
-           ex_addr[0]->ex_contaddrs[i] = 0;
+           rd_ex_addr[0]->ex_contaddrs[i] = 0;
            continue;
        }
 
 
        /* Read the continuation block */
-       if (!ex_addr[i]) {
-           ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
-           if (!ex_addr[i])
+       if (!rd_ex_addr[i]) {
+           rd_ex_addr[i] = malloc(VL_ADDREXTBLK_SIZE);
+           if (!rd_ex_addr[i])
                ERROR_EXIT(VL_NOMEM);
        }
        code =
-           vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
-                  (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
+           vlread(trans, ntohl(rd_ex_addr[0]->ex_contaddrs[i]),
+                  (char *)rd_ex_addr[i], VL_ADDREXTBLK_SIZE);
        if (code) {
-           free(ex_addr[i]);   /* Not the place to create it */
-           ex_addr[i] = 0;
+           free(rd_ex_addr[i]);        /* Not the place to create it */
+           rd_ex_addr[i] = 0;
            ERROR_EXIT(VL_IO);
        }
 
        /* After reading it in, check to see if its a real continuation block */
-       if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
+       if (ntohl(rd_ex_addr[i]->ex_hdrflags) != VLCONTBLOCK) {
            extent_mod = 1;
-           ex_addr[0]->ex_contaddrs[i] = 0;
-           free(ex_addr[i]);   /* Not the place to create it */
-           ex_addr[i] = 0;
+           rd_ex_addr[0]->ex_contaddrs[i] = 0;
+           free(rd_ex_addr[i]);        /* Not the place to create it */
+           rd_ex_addr[i] = 0;
            continue;
        }
     }
 
     if (extent_mod) {
-       code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
+       code = vlwrite(trans, extentAddr, rd_ex_addr[0], VL_ADDREXTBLK_SIZE);
        if (!code) {
            VLog(0, ("Multihome server support modification\n"));
        }
@@ -307,39 +289,38 @@ readExtents(trans)
 
 /* Check that the database has been initialized.  Be careful to fail in a safe
    manner, to avoid bogusly reinitializing the db.  */
-afs_int32
-CheckInit(trans, builddb)
-     struct ubik_trans *trans;
-     int builddb;
+/**
+ * reads in db cache from ubik.
+ *
+ * @param[in] ut ubik transaction
+ * @param[in] rock  opaque pointer to an int*; if 1, we should rebuild the db
+ *                  if it appears empty, if 0 we should return an error if the
+ *                  db appears empty
+ *
+ * @return operation status
+ *   @retval 0 success
+ */
+static afs_int32
+UpdateCache(struct ubik_trans *trans, void *rock)
 {
-    afs_int32 error = 0, i, code, ubcode = 0;
-
-    /* ubik_CacheUpdate must be called on every transaction.  It returns 0 if the
-     * previous transaction would have left the cache fine, and non-zero otherwise.
-     * Thus, a local abort or a remote commit will cause this to return non-zero
-     * and force a header re-read.  Necessary for a local abort because we may
-     * have damaged cheader during the operation.  Necessary for a remote commit
-     * since it may have changed cheader. 
-     */
-    if (ubik_CacheUpdate(trans) != 0) {
-       /* if version changed (or first call), read the header */
-       ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
-       vldbversion = ntohl(cheader.vital_header.vldbversion);
-
-       if (!ubcode && (vldbversion != 0)) {
-           memcpy(HostAddress, cheader.IpMappedAddr,
-                  sizeof(cheader.IpMappedAddr));
-           for (i = 0; i < MAXSERVERID + 1; i++) {     /* cvt HostAddress to host order */
-               HostAddress[i] = ntohl(HostAddress[i]);
-           }
-
-           code = readExtents(trans);
-           if (code)
-               ERROR_EXIT(code);
+    int *builddb_rock = rock;
+    int builddb = *builddb_rock;
+    afs_int32 error = 0, i, code, ubcode;
+
+    /* if version changed (or first call), read the header */
+    ubcode = vlread(trans, 0, (char *)&rd_cheader, sizeof(rd_cheader));
+    vldbversion = ntohl(rd_cheader.vital_header.vldbversion);
+
+    if (!ubcode && (vldbversion != 0)) {
+       memcpy(rd_HostAddress, rd_cheader.IpMappedAddr, sizeof(rd_cheader.IpMappedAddr));
+       for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
+           rd_HostAddress[i] = ntohl(rd_HostAddress[i]);
        }
-    }
 
-    vldbversion = ntohl(cheader.vital_header.vldbversion);
+       code = readExtents(trans);
+       if (code)
+           ERROR_EXIT(code);
+    }
 
     /* now, if can't read, or header is wrong, write a new header */
     if (ubcode || vldbversion == 0) {
@@ -347,29 +328,33 @@ CheckInit(trans, builddb)
            printf("Can't read VLDB header, re-initialising...\n");
 
            /* try to write a good header */
-           memset(&cheader, 0, sizeof(cheader));
-           cheader.vital_header.vldbversion = htonl(VLDBVERSION);
-           cheader.vital_header.headersize = htonl(sizeof(cheader));
+           memset(&rd_cheader, 0, sizeof(rd_cheader));
+           rd_cheader.vital_header.vldbversion = htonl(VLDBVERSION);
+           rd_cheader.vital_header.headersize = htonl(sizeof(rd_cheader));
            /* DANGER: Must get this from a master place!! */
-           cheader.vital_header.MaxVolumeId = htonl(0x20000000);
-           cheader.vital_header.eofPtr = htonl(sizeof(cheader));
+           rd_cheader.vital_header.MaxVolumeId = htonl(0x20000000);
+           rd_cheader.vital_header.eofPtr = htonl(sizeof(rd_cheader));
            for (i = 0; i < MAXSERVERID + 1; i++) {
-               cheader.IpMappedAddr[i] = 0;
-               HostAddress[i] = 0;
+               rd_cheader.IpMappedAddr[i] = 0;
+               rd_HostAddress[i] = 0;
            }
-           code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
+           code = vlwrite(trans, 0, (char *)&rd_cheader, sizeof(rd_cheader));
            if (code) {
                printf("Can't write VLDB header (error = %d)\n", code);
                ERROR_EXIT(VL_IO);
            }
-       } else
+           vldbversion = ntohl(rd_cheader.vital_header.vldbversion);
+       } else {
            ERROR_EXIT(VL_EMPTY);
-    } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
-              && (vldbversion != VLDBVERSION_4)) {
+       }
+    }
+
+    if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
+        && (vldbversion != VLDBVERSION_4)) {
        printf
            ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
             vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
-       ERROR_EXIT(VL_BADVERSION);
+       return VL_BADVERSION;
     }
 
     maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
@@ -379,57 +364,79 @@ CheckInit(trans, builddb)
     return error;
 }
 
+afs_int32
+CheckInit(struct ubik_trans *trans, int builddb)
+{
+    afs_int32 code;
+
+    code = ubik_CheckCache(trans, UpdateCache, &builddb);
+    if (code) {
+       return code;
+    }
+
+    /* these next two cases shouldn't happen (UpdateCache should either
+     * rebuild the db or return an error if these cases occur), but just to
+     * be on the safe side... */
+    if (vldbversion == 0) {
+       return VL_EMPTY;
+    }
+    if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
+        && (vldbversion != VLDBVERSION_4)) {
+       return VL_BADVERSION;
+    }
+
+    return 0;
+}
+
 
 afs_int32
-GetExtentBlock(trans, base)
-     register struct ubik_trans *trans;
-     register afs_int32 base;
+GetExtentBlock(struct vl_ctx *ctx, register afs_int32 base)
 {
     afs_int32 blockindex, code, error = 0;
 
     /* Base 0 must exist before any other can be created */
-    if ((base != 0) && !ex_addr[0])
+    if ((base != 0) && !ctx->ex_addr[0])
        ERROR_EXIT(VL_CREATEFAIL);      /* internal error */
 
-    if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
+    if (!ctx->ex_addr[0] || !ctx->ex_addr[0]->ex_contaddrs[base]) {
        /* Create a new extension block */
-       if (!ex_addr[base]) {
-           ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
-           if (!ex_addr[base])
+       if (!ctx->ex_addr[base]) {
+           ctx->ex_addr[base] = malloc(VL_ADDREXTBLK_SIZE);
+           if (!ctx->ex_addr[base])
                ERROR_EXIT(VL_NOMEM);
        }
-       memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
+       memset(ctx->ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
 
        /* Write the full extension block at end of vldb */
-       ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
-       blockindex = ntohl(cheader.vital_header.eofPtr);
+       ctx->ex_addr[base]->ex_hdrflags = htonl(VLCONTBLOCK);
+       blockindex = ntohl(ctx->cheader->vital_header.eofPtr);
        code =
-           vlwrite(trans, blockindex, (char *)ex_addr[base],
+           vlwrite(ctx->trans, blockindex, (char *)ctx->ex_addr[base],
                    VL_ADDREXTBLK_SIZE);
        if (code)
            ERROR_EXIT(VL_IO);
 
        /* Update the cheader.vitalheader structure on disk */
-       cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
-       cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
-       code = write_vital_vlheader(trans);
+       ctx->cheader->vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
+       ctx->cheader->vital_header.eofPtr = htonl(ctx->cheader->vital_header.eofPtr);
+       code = write_vital_vlheader(ctx);
        if (code)
            ERROR_EXIT(VL_IO);
 
        /* Write the address of the base extension block in the vldb header */
        if (base == 0) {
-           cheader.SIT = htonl(blockindex);
+           ctx->cheader->SIT = htonl(blockindex);
            code =
-               vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
-                       (char *)&cheader.SIT, sizeof(cheader.SIT));
+               vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->SIT),
+                       (char *)&ctx->cheader->SIT, sizeof(ctx->cheader->SIT));
            if (code)
                ERROR_EXIT(VL_IO);
        }
 
        /* Write the address of this extension block into the base extension block */
-       ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
+       ctx->ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
        code =
-           vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
+           vlwrite(ctx->trans, ntohl(ctx->cheader->SIT), ctx->ex_addr[0],
                    sizeof(struct extentaddr));
        if (code)
            ERROR_EXIT(VL_IO);
@@ -441,35 +448,33 @@ GetExtentBlock(trans, base)
 
 
 afs_int32
-FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
-     register struct ubik_trans *trans;
-     afsUUID *uuidp;
-     afs_int32 createit, hostslot, *basep;
-     struct extentaddr **expp;
+FindExtentBlock(struct vl_ctx *ctx, afsUUID *uuidp,
+               afs_int32 createit, afs_int32 hostslot,
+               struct extentaddr **expp, afs_int32 *basep)
 {
     afsUUID tuuid;
     struct extentaddr *exp;
-    register afs_int32 i, j, code, base, index, error = 0;
+    afs_int32 i, j, code, base, index, error = 0;
 
     *expp = NULL;
     *basep = 0;
 
     /* Create the first extension block if it does not exist */
-    if (!cheader.SIT) {
-       code = GetExtentBlock(trans, 0);
+    if (!ctx->cheader->SIT) {
+       code = GetExtentBlock(ctx, 0);
        if (code)
            ERROR_EXIT(code);
     }
 
     for (i = 0; i < MAXSERVERID + 1; i++) {
-       if ((HostAddress[i] & 0xff000000) == 0xff000000) {
-           if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
+       if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
+           if ((base = (ctx->hostaddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
                ERROR_EXIT(VL_INDEXERANGE);
            }
-           if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
+           if ((index = ctx->hostaddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
                ERROR_EXIT(VL_INDEXERANGE);
            }
-           exp = &ex_addr[base][index];
+           exp = &ctx->ex_addr[base][index];
            tuuid = exp->ex_hostuuid;
            afs_ntohuuid(&tuuid);
            if (afs_uuid_equal(uuidp, &tuuid)) {
@@ -483,7 +488,7 @@ FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
     if (createit) {
        if (hostslot == -1) {
            for (i = 0; i < MAXSERVERID + 1; i++) {
-               if (!HostAddress[i])
+               if (!ctx->hostaddress[i])
                    break;
            }
            if (i > MAXSERVERID)
@@ -493,13 +498,13 @@ FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
        }
 
        for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
-           if (!ex_addr[0]->ex_contaddrs[base]) {
-               code = GetExtentBlock(trans, base);
+           if (!ctx->ex_addr[0]->ex_contaddrs[base]) {
+               code = GetExtentBlock(ctx, base);
                if (code)
                    ERROR_EXIT(code);
            }
            for (j = 1; j < VL_MHSRV_PERBLK; j++) {
-               exp = &ex_addr[base][j];
+               exp = &ctx->ex_addr[base][j];
                tuuid = exp->ex_hostuuid;
                afs_ntohuuid(&tuuid);
                if (afs_uuid_is_nil(&tuuid)) {
@@ -507,29 +512,29 @@ FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
                    afs_htonuuid(&tuuid);
                    exp->ex_hostuuid = tuuid;
                    code =
-                       vlwrite(trans,
-                               DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
-                                       (char *)ex_addr[base], (char *)exp),
+                       vlwrite(ctx->trans,
+                               DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
+                                       (char *)ctx->ex_addr[base], (char *)exp),
                                (char *)&tuuid, sizeof(tuuid));
                    if (code)
                        ERROR_EXIT(VL_IO);
-                   HostAddress[i] =
+                   ctx->hostaddress[i] =
                        0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
                    *expp = exp;
                    *basep = base;
                    if (vldbversion != VLDBVERSION_4) {
-                       cheader.vital_header.vldbversion =
+                       ctx->cheader->vital_header.vldbversion =
                            htonl(VLDBVERSION_4);
-                       code = write_vital_vlheader(trans);
+                       code = write_vital_vlheader(ctx);
                        if (code)
                            ERROR_EXIT(VL_IO);
                    }
-                   cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
+                   ctx->cheader->IpMappedAddr[i] = htonl(ctx->hostaddress[i]);
                    code =
-                       vlwrite(trans,
-                               DOFFSET(0, &cheader,
-                                       &cheader.IpMappedAddr[i]),
-                               (char *)&cheader.IpMappedAddr[i],
+                       vlwrite(ctx->trans,
+                               DOFFSET(0, ctx->cheader,
+                                       &ctx->cheader->IpMappedAddr[i]),
+                               (char *)&ctx->cheader->IpMappedAddr[i],
                                sizeof(afs_int32));
                    if (code)
                        ERROR_EXIT(VL_IO);
@@ -547,25 +552,23 @@ FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
 /* Allocate a free block of storage for entry, returning address of a new
    zeroed entry (or zero if something is wrong).  */
 afs_int32
-AllocBlock(trans, tentry)
-     register struct ubik_trans *trans;
-     struct nvlentry *tentry;
+AllocBlock(struct vl_ctx *ctx, struct nvlentry *tentry)
 {
-    register afs_int32 blockindex;
+    afs_int32 blockindex;
 
-    if (cheader.vital_header.freePtr) {
+    if (ctx->cheader->vital_header.freePtr) {
        /* allocate this dude */
-       blockindex = ntohl(cheader.vital_header.freePtr);
-       if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
+       blockindex = ntohl(ctx->cheader->vital_header.freePtr);
+       if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(vlentry)))
            return 0;
-       cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
+       ctx->cheader->vital_header.freePtr = htonl(tentry->nextIdHash[0]);
     } else {
        /* hosed, nothing on free list, grow file */
-       blockindex = ntohl(cheader.vital_header.eofPtr);        /* remember this guy */
-       cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
+       blockindex = ntohl(ctx->cheader->vital_header.eofPtr);  /* remember this guy */
+       ctx->cheader->vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
     }
-    cheader.vital_header.allocs++;
-    if (write_vital_vlheader(trans))
+    ctx->cheader->vital_header.allocs++;
+    if (write_vital_vlheader(ctx))
        return 0;
     memset(tentry, 0, sizeof(nvlentry));       /* zero new entry */
     return blockindex;
@@ -574,49 +577,47 @@ AllocBlock(trans, tentry)
 
 /* Free a block given its index.  It must already have been unthreaded. Returns zero for success or an error code on failure. */
 int
-FreeBlock(trans, blockindex)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
+FreeBlock(struct vl_ctx *ctx, afs_int32 blockindex)
 {
     struct nvlentry tentry;
 
     /* check validity of blockindex just to be on the safe side */
-    if (!index_OK(trans, blockindex))
+    if (!index_OK(ctx, blockindex))
        return VL_BADINDEX;
     memset(&tentry, 0, sizeof(nvlentry));
-    tentry.nextIdHash[0] = cheader.vital_header.freePtr;       /* already in network order */
+    tentry.nextIdHash[0] = ctx->cheader->vital_header.freePtr; /* already in network order */
     tentry.flags = htonl(VLFREE);
-    cheader.vital_header.freePtr = htonl(blockindex);
-    if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
+    ctx->cheader->vital_header.freePtr = htonl(blockindex);
+    if (vlwrite(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
        return VL_IO;
-    cheader.vital_header.frees++;
-    if (write_vital_vlheader(trans))
+    ctx->cheader->vital_header.frees++;
+    if (write_vital_vlheader(ctx))
        return VL_IO;
     return 0;
 }
 
 
-/* Look for a block by volid and voltype (if not known use -1 which searches all 3 volid hash lists. Note that the linked lists are read in first from the database header.  If found read the block's contents into the area pointed to by tentry and return the block's index.  If not found return 0. */
+/* Look for a block by volid and voltype (if not known use -1 which searches
+ * all 3 volid hash lists. Note that the linked lists are read in first from
+ * the database header.  If found read the block's contents into the area
+ * pointed to by tentry and return the block's index.  If not found return 0.
+ */
 afs_int32
-FindByID(trans, volid, voltype, tentry, error)
-     struct ubik_trans *trans;
-     afs_uint32 volid;
-     afs_int32 voltype;
-     struct nvlentry *tentry;
-     afs_int32 *error;
+FindByID(struct vl_ctx *ctx, afs_uint32 volid, afs_int32 voltype,
+        struct nvlentry *tentry, afs_int32 *error)
 {
-    register afs_int32 typeindex, hashindex, blockindex;
+    afs_int32 typeindex, hashindex, blockindex;
 
     *error = 0;
     hashindex = IDHash(volid);
     if (voltype == -1) {
 /* Should we have one big hash table for volids as opposed to the three ones? */
        for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
-           for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
+           for (blockindex = ntohl(ctx->cheader->VolidHash[typeindex][hashindex]);
                 blockindex != NULLO;
                 blockindex = tentry->nextIdHash[typeindex]) {
                if (vlentryread
-                   (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
+                   (ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
                    *error = VL_IO;
                    return 0;
                }
@@ -625,10 +626,10 @@ FindByID(trans, volid, voltype, tentry, error)
            }
        }
     } else {
-       for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
+       for (blockindex = ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
             blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
            if (vlentryread
-               (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
+               (ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
                *error = VL_IO;
                return 0;
            }
@@ -640,19 +641,21 @@ FindByID(trans, volid, voltype, tentry, error)
 }
 
 
-/* Look for a block by volume name. If found read the block's contents into the area pointed to by tentry and return the block's index.  If not found return 0. */
+/* Look for a block by volume name. If found read the block's contents into
+ * the area pointed to by tentry and return the block's index.  If not
+ * found return 0.
+ */
 afs_int32
-FindByName(trans, volname, tentry, error)
-     struct ubik_trans *trans;
-     char *volname;
-     struct nvlentry *tentry;
-     afs_int32 *error;
+FindByName(struct vl_ctx *ctx, char *volname, struct nvlentry *tentry,
+          afs_int32 *error)
 {
-    register afs_int32 hashindex;
-    register afs_int32 blockindex;
+    afs_int32 hashindex;
+    afs_int32 blockindex;
     char tname[VL_MAXNAMELEN];
 
-    /* remove .backup or .readonly extensions for stupid backwards compatibility */
+    /* remove .backup or .readonly extensions for stupid backwards
+     * compatibility
+     */
     hashindex = strlen(volname);       /* really string length */
     if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
        /* this is a backup volume */
@@ -668,9 +671,9 @@ FindByName(trans, volname, tentry, error)
 
     *error = 0;
     hashindex = NameHash(tname);
-    for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
+    for (blockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
         blockindex != NULLO; blockindex = tentry->nextNameHash) {
-       if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
+       if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
            *error = VL_IO;
            return 0;
        }
@@ -680,19 +683,93 @@ FindByName(trans, volname, tentry, error)
     return 0;                  /* no such entry */
 }
 
+/**
+ * Returns whether or not any of the supplied volume IDs already exist
+ * in the vldb.
+ *
+ * @param ctx      transaction context
+ * @param ids      an array of volume IDs
+ * @param ids_len  the number of elements in the 'ids' array
+ * @param error    filled in with an error code in case of error
+ *
+ * @return whether any of the volume IDs are already used
+ *  @retval 1  at least one of the volume IDs is already used
+ *  @retval 0  none of the volume IDs are used, or an error occurred
+ */
 int
-HashNDump(trans, hashindex)
-     struct ubik_trans *trans;
-     int hashindex;
+EntryIDExists(struct vl_ctx *ctx, const afs_uint32 *ids,
+             afs_int32 ids_len, afs_int32 *error)
+{
+    afs_int32 typeindex;
+    struct nvlentry tentry;
+
+    *error = 0;
+
+    for (typeindex = 0; typeindex < ids_len; typeindex++) {
+       if (ids[typeindex]
+           && FindByID(ctx, ids[typeindex], -1, &tentry, error)) {
 
+           return 1;
+       } else if (*error) {
+           return 0;
+       }
+    }
+
+    return 0;
+}
+
+/**
+ * Finds the next range of unused volume IDs in the vldb.
+ *
+ * @param ctx       transaction context
+ * @param maxvolid  the current max vol ID, and where to start looking
+ *                  for an unused volume ID range
+ * @param bump      how many volume IDs we need to be unused
+ * @param error     filled in with an error code in case of error
+ *
+ * @return the next volume ID 'volid' such that the range
+ *         [volid, volid+bump) of volume IDs is unused, or 0 if there's
+ *         an error
+ */
+afs_uint32
+NextUnusedID(struct vl_ctx *ctx, afs_uint32 maxvolid, afs_uint32 bump,
+            afs_int32 *error)
+{
+    struct nvlentry tentry;
+    afs_uint32 id;
+    afs_uint32 nfree;
+
+    *error = 0;
+
+     /* we simply start at the given maxvolid, keep a running tally of
+      * how many free volume IDs we've seen in a row, and return when
+      * we've seen 'bump' unused IDs in a row */
+    for (id = maxvolid, nfree = 0; nfree < bump; ++id) {
+       if (FindByID(ctx, id, -1, &tentry, error)) {
+           nfree = 0;
+       } else if (*error) {
+           return 0;
+       } else {
+           ++nfree;
+       }
+    }
+
+    /* 'id' is now at the end of the [maxvolid,maxvolid+bump) range,
+     * but we need to return the first unused id, so subtract the
+     * number of current running free IDs to get the beginning */
+    return id - nfree;
+}
+
+int
+HashNDump(struct vl_ctx *ctx, int hashindex)
 {
-    register int i = 0;
-    register int blockindex;
+    int i = 0;
+    int blockindex;
     struct nvlentry tentry;
 
-    for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
+    for (blockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
         blockindex != NULLO; blockindex = tentry.nextNameHash) {
-       if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
+       if (vlentryread(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
            return 0;
        i++;
        VLog(0,
@@ -704,18 +781,15 @@ HashNDump(trans, hashindex)
 
 
 int
-HashIdDump(trans, hashindex)
-     struct ubik_trans *trans;
-     int hashindex;
-
+HashIdDump(struct vl_ctx *ctx, int hashindex)
 {
-    register int i = 0;
-    register int blockindex;
+    int i = 0;
+    int blockindex;
     struct nvlentry tentry;
 
-    for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
+    for (blockindex = ntohl(ctx->cheader->VolidHash[0][hashindex]);
         blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
-       if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
+       if (vlentryread(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
            return 0;
        i++;
        VLog(0,
@@ -726,98 +800,97 @@ HashIdDump(trans, hashindex)
 }
 
 
-/* Add a block to the hash table given a pointer to the block and its index. The block is threaded onto both hash tables and written to disk.  The routine returns zero if there were no errors. */
+/* Add a block to the hash table given a pointer to the block and its index.
+ * The block is threaded onto both hash tables and written to disk.  The
+ * routine returns zero if there were no errors.
+ */
 int
-ThreadVLentry(trans, blockindex, tentry)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
-     struct nvlentry *tentry;
+ThreadVLentry(struct vl_ctx *ctx, afs_int32 blockindex,
+             struct nvlentry *tentry)
 {
     int errorcode;
 
-    if (!index_OK(trans, blockindex))
+    if (!index_OK(ctx, blockindex))
        return VL_BADINDEX;
     /* Insert into volid's hash linked list */
-    if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
+    if ((errorcode = HashVolid(ctx, RWVOL, blockindex, tentry)))
        return errorcode;
 
-    /* For rw entries we also enter the RO and BACK volume ids (if they exist) in the hash tables; note all there volids (RW, RO, BACK) should not be hashed yet! */
+    /* For rw entries we also enter the RO and BACK volume ids (if they
+     * exist) in the hash tables; note all there volids (RW, RO, BACK)
+     * should not be hashed yet! */
     if (tentry->volumeId[ROVOL]) {
-       if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
+       if ((errorcode = HashVolid(ctx, ROVOL, blockindex, tentry)))
            return errorcode;
     }
     if (tentry->volumeId[BACKVOL]) {
-       if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
+       if ((errorcode = HashVolid(ctx, BACKVOL, blockindex, tentry)))
            return errorcode;
     }
 
     /* Insert into volname's hash linked list */
-    HashVolname(trans, blockindex, tentry);
+    HashVolname(ctx, blockindex, tentry);
 
     /* Update cheader entry */
-    if (write_vital_vlheader(trans))
+    if (write_vital_vlheader(ctx))
        return VL_IO;
 
     /* Update hash list pointers in the entry itself */
-    if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
+    if (vlentrywrite(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry)))
        return VL_IO;
     return 0;
 }
 
 
-/* Remove a block from both the hash tables.  If success return 0, else return an error code. */
+/* Remove a block from both the hash tables.  If success return 0, else
+ * return an error code. */
 int
-UnthreadVLentry(trans, blockindex, aentry)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
-     struct nvlentry *aentry;
+UnthreadVLentry(struct vl_ctx *ctx, afs_int32 blockindex,
+               struct nvlentry *aentry)
 {
-    register afs_int32 errorcode, typeindex;
+    afs_int32 errorcode, typeindex;
 
-    if (!index_OK(trans, blockindex))
+    if (!index_OK(ctx, blockindex))
        return VL_BADINDEX;
-    if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
+    if ((errorcode = UnhashVolid(ctx, RWVOL, blockindex, aentry)))
        return errorcode;
 
     /* Take the RO/RW entries of their respective hash linked lists. */
     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
-       if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
+       if ((errorcode = UnhashVolid(ctx, typeindex, blockindex, aentry)))
            return errorcode;
     }
 
     /* Take it out of the Volname hash list */
-    if (errorcode = UnhashVolname(trans, blockindex, aentry))
+    if ((errorcode = UnhashVolname(ctx, blockindex, aentry)))
        return errorcode;
 
     /* Update cheader entry */
-    write_vital_vlheader(trans);
+    write_vital_vlheader(ctx);
 
     return 0;
 }
 
 /* cheader must have be read before this routine is called. */
 int
-HashVolid(trans, voltype, blockindex, tentry)
-     struct ubik_trans *trans;
-     afs_int32 voltype;
-     afs_int32 blockindex;
-     struct nvlentry *tentry;
+HashVolid(struct vl_ctx *ctx, afs_int32 voltype, afs_int32 blockindex,
+          struct nvlentry *tentry)
 {
     afs_int32 hashindex, errorcode;
-    struct vlentry ventry;
+    struct nvlentry ventry;
 
     if (FindByID
-       (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
+       (ctx, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
        return VL_IDALREADYHASHED;
     else if (errorcode)
        return errorcode;
     hashindex = IDHash(tentry->volumeId[voltype]);
     tentry->nextIdHash[voltype] =
-       ntohl(cheader.VolidHash[voltype][hashindex]);
-    cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
+       ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
+    ctx->cheader->VolidHash[voltype][hashindex] = htonl(blockindex);
     if (vlwrite
-       (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
-        (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
+       (ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolidHash[voltype][hashindex]),
+        (char *)&ctx->cheader->VolidHash[voltype][hashindex], sizeof(afs_int32)))
        return VL_IO;
     return 0;
 }
@@ -825,11 +898,8 @@ HashVolid(trans, voltype, blockindex, tentry)
 
 /* cheader must have be read before this routine is called. */
 int
-UnhashVolid(trans, voltype, blockindex, aentry)
-     struct ubik_trans *trans;
-     afs_int32 voltype;
-     afs_int32 blockindex;
-     struct nvlentry *aentry;
+UnhashVolid(struct vl_ctx *ctx, afs_int32 voltype, afs_int32 blockindex,
+           struct nvlentry *aentry)
 {
     int hashindex, nextblockindex, prevblockindex;
     struct nvlentry tentry;
@@ -840,16 +910,16 @@ UnhashVolid(trans, voltype, blockindex, aentry)
        return 0;
     /* Take it out of the VolId[voltype] hash list */
     hashindex = IDHash(aentry->volumeId[voltype]);
-    nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
+    nextblockindex = ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
     if (nextblockindex == blockindex) {
        /* First on the hash list; just adjust pointers */
-       cheader.VolidHash[voltype][hashindex] =
+       ctx->cheader->VolidHash[voltype][hashindex] =
            htonl(aentry->nextIdHash[voltype]);
        code =
-           vlwrite(trans,
-                   DOFFSET(0, &cheader,
-                           &cheader.VolidHash[voltype][hashindex]),
-                   (char *)&cheader.VolidHash[voltype][hashindex],
+           vlwrite(ctx->trans,
+                   DOFFSET(0, ctx->cheader,
+                           &ctx->cheader->VolidHash[voltype][hashindex]),
+                   (char *)&ctx->cheader->VolidHash[voltype][hashindex],
                    sizeof(afs_int32));
        if (code)
            return VL_IO;
@@ -857,7 +927,7 @@ UnhashVolid(trans, voltype, blockindex, aentry)
        while (nextblockindex != blockindex) {
            prevblockindex = nextblockindex;    /* always done once */
            if (vlentryread
-               (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
+               (ctx->trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
                return VL_IO;
            if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
                return VL_NOENT;
@@ -865,7 +935,7 @@ UnhashVolid(trans, voltype, blockindex, aentry)
        temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
        temp = htonl(temp);     /* convert to network byte order before writing */
        if (vlwrite
-           (trans,
+           (ctx->trans,
             DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
             (char *)&temp, sizeof(afs_int32)))
            return VL_IO;
@@ -876,21 +946,19 @@ UnhashVolid(trans, voltype, blockindex, aentry)
 
 
 int
-HashVolname(trans, blockindex, aentry)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
-     struct nvlentry *aentry;
+HashVolname(struct vl_ctx *ctx, afs_int32 blockindex,
+           struct nvlentry *aentry)
 {
-    register afs_int32 hashindex;
-    register afs_int32 code;
+    afs_int32 hashindex;
+    afs_int32 code;
 
     /* Insert into volname's hash linked list */
     hashindex = NameHash(aentry->name);
-    aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
-    cheader.VolnameHash[hashindex] = htonl(blockindex);
+    aentry->nextNameHash = ntohl(ctx->cheader->VolnameHash[hashindex]);
+    ctx->cheader->VolnameHash[hashindex] = htonl(blockindex);
     code =
-       vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
-               (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
+       vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolnameHash[hashindex]),
+               (char *)&ctx->cheader->VolnameHash[hashindex], sizeof(afs_int32));
     if (code)
        return VL_IO;
     return 0;
@@ -898,30 +966,28 @@ HashVolname(trans, blockindex, aentry)
 
 
 int
-UnhashVolname(trans, blockindex, aentry)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
-     struct nvlentry *aentry;
+UnhashVolname(struct vl_ctx *ctx, afs_int32 blockindex,
+             struct nvlentry *aentry)
 {
-    register afs_int32 hashindex, nextblockindex, prevblockindex;
+    afs_int32 hashindex, nextblockindex, prevblockindex;
     struct nvlentry tentry;
     afs_int32 temp;
 
     /* Take it out of the Volname hash list */
     hashindex = NameHash(aentry->name);
-    nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
+    nextblockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
     if (nextblockindex == blockindex) {
        /* First on the hash list; just adjust pointers */
-       cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
+       ctx->cheader->VolnameHash[hashindex] = htonl(aentry->nextNameHash);
        if (vlwrite
-           (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
-            (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
+           (ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolnameHash[hashindex]),
+            (char *)&ctx->cheader->VolnameHash[hashindex], sizeof(afs_int32)))
            return VL_IO;
     } else {
        while (nextblockindex != blockindex) {
            prevblockindex = nextblockindex;    /* always done at least once */
            if (vlentryread
-               (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
+               (ctx->trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
                return VL_IO;
            if ((nextblockindex = tentry.nextNameHash) == NULLO)
                return VL_NOENT;
@@ -929,7 +995,7 @@ UnhashVolname(trans, blockindex, aentry)
        tentry.nextNameHash = aentry->nextNameHash;
        temp = htonl(tentry.nextNameHash);
        if (vlwrite
-           (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
+           (ctx->trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
             (char *)&temp, sizeof(afs_int32)))
            return VL_IO;
     }
@@ -938,30 +1004,30 @@ UnhashVolname(trans, blockindex, aentry)
 }
 
 
-/* Returns the vldb entry tentry at offset index; remaining is the number of entries left; the routine also returns the index of the next sequential entry in the vldb */
+/* Returns the vldb entry tentry at offset index; remaining is the number of
+ * entries left; the routine also returns the index of the next sequential
+ * entry in the vldb
+ */
 
 afs_int32
-NextEntry(trans, blockindex, tentry, remaining)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
-     struct nvlentry *tentry;
-     afs_int32 *remaining;
+NextEntry(struct vl_ctx *ctx, afs_int32 blockindex,
+         struct nvlentry *tentry, afs_int32 *remaining)
 {
-    register afs_int32 lastblockindex;
+    afs_int32 lastblockindex;
 
     if (blockindex == 0)       /* get first one */
-       blockindex = sizeof(cheader);
+       blockindex = sizeof(*ctx->cheader);
     else {
-       if (!index_OK(trans, blockindex)) {
+       if (!index_OK(ctx, blockindex)) {
            *remaining = -1;    /* error */
            return 0;
        }
        blockindex += sizeof(nvlentry);
     }
     /* now search for the first entry that isn't free */
-    for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
+    for (lastblockindex = ntohl(ctx->cheader->vital_header.eofPtr);
         blockindex < lastblockindex;) {
-       if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
+       if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
            *remaining = -1;
            return 0;
        }
@@ -985,14 +1051,67 @@ NextEntry(trans, blockindex, tentry, remaining)
 }
 
 
-/* Routine to verify that index is a legal offset to a vldb entry in the table */
+/* Routine to verify that index is a legal offset to a vldb entry in the
+ * table
+ */
 static int
-index_OK(trans, blockindex)
-     struct ubik_trans *trans;
-     afs_int32 blockindex;
+index_OK(struct vl_ctx *ctx, afs_int32 blockindex)
 {
-    if ((blockindex < sizeof(cheader))
-       || (blockindex >= ntohl(cheader.vital_header.eofPtr)))
+    if ((blockindex < sizeof(*ctx->cheader))
+       || (blockindex >= ntohl(ctx->cheader->vital_header.eofPtr)))
        return 0;
     return 1;
 }
+
+/* makes a deep copy of src_ex into dst_ex */
+static int
+vlexcpy(struct extentaddr **dst_ex, struct extentaddr **src_ex)
+{
+    int i;
+    for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
+       if (src_ex[i]) {
+           if (!dst_ex[i]) {
+               dst_ex[i] = malloc(VL_ADDREXTBLK_SIZE);
+           }
+           if (!dst_ex[i]) {
+               return VL_NOMEM;
+           }
+           memcpy(dst_ex[i], src_ex[i], VL_ADDREXTBLK_SIZE);
+
+       } else if (dst_ex[i]) {
+           /* we have no src, but we have a dst... meaning, this block
+            * has gone away */
+           free(dst_ex[i]);
+           dst_ex[i] = NULL;
+       }
+    }
+    return 0;
+}
+
+int
+vlsetcache(struct vl_ctx *ctx, int locktype)
+{
+    if (locktype == LOCKREAD) {
+       ctx->hostaddress = rd_HostAddress;
+       ctx->ex_addr = rd_ex_addr;
+       ctx->cheader = &rd_cheader;
+       return 0;
+    } else {
+       memcpy(wr_HostAddress, rd_HostAddress, sizeof(wr_HostAddress));
+       memcpy(&wr_cheader, &rd_cheader, sizeof(wr_cheader));
+
+       ctx->hostaddress = wr_HostAddress;
+       ctx->ex_addr = wr_ex_addr;
+       ctx->cheader = &wr_cheader;
+
+       return vlexcpy(wr_ex_addr, rd_ex_addr);
+    }
+}
+
+int
+vlsynccache(void)
+{
+    memcpy(rd_HostAddress, wr_HostAddress, sizeof(rd_HostAddress));
+    memcpy(&rd_cheader, &wr_cheader, sizeof(rd_cheader));
+    return vlexcpy(rd_ex_addr, wr_ex_addr);
+}