DAFS: Do not clear salv state on fssync salvage
[openafs.git] / src / vol / fssync-server.c
index d5256fd..3e356cb 100644 (file)
@@ -1,12 +1,12 @@
 /*
  * 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
  *
- * Portions Copyright (c) 2006-2008 Sine Nomine Associates
+ * Portions Copyright (c) 2006-2010 Sine Nomine Associates
  */
 
 /*
        Institution:    The Information Technology Center, Carnegie-Mellon University
 
  */
-#ifdef notdef
-
-/* All this is going away in early 1989 */
-int newVLDB;                   /* Compatibility flag */
-
-#endif
-static int newVLDB = 1;
-
-
 #ifndef AFS_PTHREAD_ENV
 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
 
@@ -52,36 +43,17 @@ static int newVLDB = 1;
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
-
-#include <sys/types.h>
-#include <stdio.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#include <time.h>
-#else
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#ifdef AFS_PTHREAD_ENV
-#include <assert.h>
-#else /* AFS_PTHREAD_ENV */
-#include <afs/assert.h>
-#endif /* AFS_PTHREAD_ENV */
-#include <signal.h>
-#include <string.h>
+#include <roken.h>
 
 #include <rx/xdr.h>
 #include <afs/afsint.h>
 #include "nfs.h"
 #include <afs/errors.h>
 #include "daemon_com.h"
+#include "daemon_com_inline.h"
 #include "fssync.h"
+#include "fssync_inline.h"
+#include "salvsync.h"
 #include "lwp.h"
 #include "lock.h"
 #include <afs/afssyscalls.h>
@@ -90,6 +62,8 @@ RCSID
 #include "volume.h"
 #include "volume_inline.h"
 #include "partition.h"
+#include "vg_cache.h"
+#include "common.h"
 
 #ifdef HAVE_POLL
 #include <sys/poll.h>
@@ -102,9 +76,7 @@ RCSID
 
 #ifdef FSSYNC_BUILD_SERVER
 
-/*@printflike@*/ extern void Log(const char *format, ...);
-
-int (*V_BreakVolumeCallbacks) ();
+int (*V_BreakVolumeCallbacks) (VolumeId volume);
 
 #define MAXHANDLERS    4       /* Up to 4 clients; must be at least 2, so that
                                 * move = dump+restore can run on single server */
@@ -121,8 +93,8 @@ static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
 /**
  * fssync server socket handle.
  */
-static SYNC_server_state_t fssync_server_state = 
-    { -1,                       /* file descriptor */
+static SYNC_server_state_t fssync_server_state =
+    { OSI_NULLSOCKET,                       /* file descriptor */
       FSSYNC_ENDPOINT_DECL,     /* server endpoint */
       FSYNC_PROTO_VERSION,      /* protocol version */
       5,                        /* bind() retry limit */
@@ -130,19 +102,36 @@ static SYNC_server_state_t fssync_server_state =
       "FSSYNC",                 /* protocol name string */
     };
 
+#ifdef AFS_DEMAND_ATTACH_FS
+/**
+ * a queue of volume pointers to salvage in the background.
+ */
+struct fsync_salv_node {
+    struct rx_queue q;
+    Volume *vp;                     /**< volume to salvage */
+    unsigned char update_salv_prio; /**< whether we should update the salvage priority or not */
+};
+static struct {
+    struct rx_queue head;
+    pthread_cond_t cv;
+} fsync_salv;
+
+static void * FSYNC_salvageThread(void *);
+static void FSYNC_backgroundSalvage(Volume *vp);
+#endif /* AFS_DEMAND_ATTACH_FS */
 
 /* Forward declarations */
 static void * FSYNC_sync(void *);
-static void FSYNC_newconnection();
-static void FSYNC_com();
-static void FSYNC_Drop();
-static void AcceptOn();
-static void AcceptOff();
-static void InitHandler();
-static int AddHandler();
-static int FindHandler();
-static int FindHandler_r();
-static int RemoveHandler();
+static void FSYNC_newconnection(osi_socket afd);
+static void FSYNC_com(osi_socket fd);
+static void FSYNC_Drop(osi_socket fd);
+static void AcceptOn(void);
+static void AcceptOff(void);
+static void InitHandler(void);
+static int AddHandler(osi_socket fd, void (*aproc)(osi_socket));
+static int FindHandler(osi_socket afd);
+static int FindHandler_r(osi_socket afd);
+static int RemoveHandler(osi_socket afd);
 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
 static void CallHandler(struct pollfd *fds, int nfds, int mask);
 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
@@ -152,9 +141,11 @@ static void GetHandler(fd_set * fdsetp, int *maxfdp);
 #endif
 extern int LogLevel;
 
-static afs_int32 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
 
+#ifdef AFS_DEMAND_ATTACH_FS
 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
+#endif
 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
@@ -163,19 +154,25 @@ static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * r
 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
 #ifdef AFS_DEMAND_ATTACH_FS
+static afs_int32 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_VGQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_VGScan(FSSYNC_VolOp_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res);
 #endif /* AFS_DEMAND_ATTACH_FS */
 
-static afs_int32 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res);
 
-static afs_int32 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res);
+static afs_int32 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
 
 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
+
+#ifdef AFS_DEMAND_ATTACH_FS
 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
-
+#endif
 
 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
 
@@ -201,14 +198,20 @@ FSYNC_fsInit(void)
     Lock_Init(&FSYNC_handler_lock);
 
 #ifdef AFS_PTHREAD_ENV
-    assert(pthread_attr_init(&tattr) == 0);
-    assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
-    assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
+    osi_Assert(pthread_attr_init(&tattr) == 0);
+    osi_Assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
+    osi_Assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
 #else /* AFS_PTHREAD_ENV */
-    assert(LWP_CreateProcess
+    osi_Assert(LWP_CreateProcess
           (FSYNC_sync, USUAL_STACK_SIZE, USUAL_PRIORITY, (void *)0,
            "FSYNC_sync", &pid) == LWP_SUCCESS);
 #endif /* AFS_PTHREAD_ENV */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    queue_Init(&fsync_salv.head);
+    CV_INIT(&fsync_salv.cv, "fsync salv", CV_DEFAULT, 0);
+    osi_Assert(pthread_create(&tid, &tattr, FSYNC_salvageThread, NULL) == 0);
+#endif /* AFS_DEMAND_ATTACH_FS */
 }
 
 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
@@ -221,20 +224,27 @@ static fd_set FSYNC_readfds;
 static void *
 FSYNC_sync(void * args)
 {
-#ifdef USE_UNIX_SOCKETS
-    char tbuffer[AFSDIR_PATH_MAX];
-#endif /* USE_UNIX_SOCKETS */
-    int on = 1;
     extern int VInit;
     int code;
-    int numTries;
 #ifdef AFS_PTHREAD_ENV
     int tid;
 #endif
     SYNC_server_state_t * state = &fssync_server_state;
 #ifdef AFS_DEMAND_ATTACH_FS
     VThreadOptions_t * thread_opts;
-#endif
+    int min_vinit = 2;
+#else
+    /*
+     * For non-DAFS, only wait until we begin attaching volumes (instead
+     * of waiting until all volumes are attached), since it can take
+     * awhile until VInit == 2.
+     */
+    int min_vinit = 1;
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+    /* we must not be called before vol package initialization, since we use
+     * vol package mutexes and conds etc */
+    osi_Assert(VInit);
 
     SYNC_getAddr(&state->endpoint, &state->addr);
     SYNC_cleanupSock(state);
@@ -245,25 +255,30 @@ FSYNC_sync(void * args)
 
 #ifdef AFS_PTHREAD_ENV
     /* set our 'thread-id' so that the host hold table works */
-    MUTEX_ENTER(&rx_stats_mutex);      /* protects rxi_pthread_hinum */
-    tid = ++rxi_pthread_hinum;
-    MUTEX_EXIT(&rx_stats_mutex);
-    pthread_setspecific(rx_thread_id_key, (void *)tid);
+    tid = rx_NewThreadId();
+    pthread_setspecific(rx_thread_id_key, (void *)(intptr_t)tid);
     Log("Set thread id %d for FSYNC_sync\n", tid);
 #endif /* AFS_PTHREAD_ENV */
 
-    while (!VInit) {
-       /* Let somebody else run until level > 0.  That doesn't mean that 
-        * all volumes have been attached. */
+    VOL_LOCK;
+
+    while (VInit < min_vinit) {
+       /* Let somebody else run until all volumes have been preattached
+        * (DAFS), or we have started attaching volumes (non-DAFS). This
+        * doesn't mean that all volumes have been attached.
+        */
 #ifdef AFS_PTHREAD_ENV
-       pthread_yield();
+       VOL_CV_WAIT(&vol_vinit_cond);
 #else /* AFS_PTHREAD_ENV */
        LWP_DispatchProcess();
 #endif /* AFS_PTHREAD_ENV */
     }
+
+    VOL_UNLOCK;
+
     state->fd = SYNC_getSock(&state->endpoint);
     code = SYNC_bindSock(state);
-    assert(!code);
+    osi_Assert(!code);
 
 #ifdef AFS_DEMAND_ATTACH_FS
     /*
@@ -278,7 +293,10 @@ FSYNC_sync(void * args)
     }
     memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
     thread_opts->disallow_salvsync = 1;
-    assert(pthread_setspecific(VThread_key, thread_opts) == 0);
+    osi_Assert(pthread_setspecific(VThread_key, thread_opts) == 0);
+
+    code = VVGCache_PkgInit();
+    osi_Assert(code == 0);
 #endif
 
     InitHandler();
@@ -292,44 +310,136 @@ FSYNC_sync(void * args)
            CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
 #else
        int maxfd;
+#ifdef AFS_PTHREAD_ENV
+       struct timeval s_timeout;
+#endif
        GetHandler(&FSYNC_readfds, &maxfd);
        /* Note: check for >= 1 below is essential since IOMGR_select
         * doesn't have exactly same semantics as select.
         */
 #ifdef AFS_PTHREAD_ENV
-       if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
+       s_timeout.tv_sec = SYNC_SELECT_TIMEOUT;
+       s_timeout.tv_usec = 0;
+       if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, &s_timeout) >= 1)
 #else /* AFS_PTHREAD_ENV */
        if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
 #endif /* AFS_PTHREAD_ENV */
            CallHandler(&FSYNC_readfds);
 #endif
     }
+    return NULL; /* hush now, little gcc */
+}
+
+#ifdef AFS_DEMAND_ATTACH_FS
+/**
+ * thread for salvaging volumes in the background.
+ *
+ * Since FSSYNC handlers cannot issue SALVSYNC requests in order to avoid
+ * deadlock issues, this thread exists so code in the FSSYNC handler thread
+ * can hand off volumes to be salvaged in the background.
+ *
+ * @param[in] args  unused
+ *
+ * @note DEMAND_ATTACH_FS only
+ */
+static void *
+FSYNC_salvageThread(void * args)
+{
+    Volume *vp;
+    struct fsync_salv_node *node;
+
+    VOL_LOCK;
+
+    for (;;) {
+       while (queue_IsEmpty(&fsync_salv.head)) {
+           VOL_CV_WAIT(&fsync_salv.cv);
+       }
+
+       node = queue_First(&fsync_salv.head, fsync_salv_node);
+       queue_Remove(node);
+
+       vp = node->vp;
+       if (node->update_salv_prio) {
+           if (VUpdateSalvagePriority_r(vp)) {
+               ViceLog(0, ("FSYNC_salvageThread: unable to raise salvage priority "
+                           "for volume %lu\n", afs_printable_uint32_lu(vp->hashid)));
+           }
+       }
+
+       free(node);
+       node = NULL;
+
+       VCancelReservation_r(vp);
+    }
+
+    VOL_UNLOCK;
+
+    return NULL;
 }
 
+/**
+ * salvage a volume in the background.
+ *
+ * Salvages cannot be scheduled directly from the main FSYNC thread, so
+ * instead call this function to schedule a salvage asynchronously in the
+ * FSYNC_salvageThread thread.
+ *
+ * @param[in] vp  volume to pointer to salvage
+ *
+ * @pre VOL_LOCK held
+ *
+ * @note DEMAND_ATTACH_FS only
+ */
+static void
+FSYNC_backgroundSalvage(Volume *vp)
+{
+    struct fsync_salv_node *node;
+    Error ec;
+
+    VCreateReservation_r(vp);
+
+    node = malloc(sizeof(struct fsync_salv_node));
+    node->vp = vp;
+
+    /* Save this value, to know if we should VUpdateSalvagePriority_r.
+     * We need to save it here, snce VRequestSalvage_r will change it. */
+    node->update_salv_prio = vp->salvage.requested;
+
+    if (VRequestSalvage_r(&ec, vp, SALVSYNC_ERROR, 0)) {
+       ViceLog(0, ("FSYNC_backgroundSalvage: unable to request salvage for volume %lu\n",
+                   afs_printable_uint32_lu(vp->hashid)));
+    }
+
+    queue_Append(&fsync_salv.head, node);
+    CV_BROADCAST(&fsync_salv.cv);
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
 static void
-FSYNC_newconnection(int afd)
+FSYNC_newconnection(osi_socket afd)
 {
 #ifdef USE_UNIX_SOCKETS
     struct sockaddr_un other;
 #else  /* USE_UNIX_SOCKETS */
     struct sockaddr_in other;
 #endif
-    int junk, fd;
+    osi_socket fd;
+    socklen_t junk;
     junk = sizeof(other);
     fd = accept(afd, (struct sockaddr *)&other, &junk);
-    if (fd == -1) {
+    if (fd == OSI_NULLSOCKET) {
        Log("FSYNC_newconnection:  accept failed, errno==%d\n", errno);
-       assert(1 == 2);
+       osi_Assert(1 == 2);
     } else if (!AddHandler(fd, FSYNC_com)) {
        AcceptOff();
-       assert(AddHandler(fd, FSYNC_com));
+       osi_Assert(AddHandler(fd, FSYNC_com));
     }
 }
 
 /* this function processes commands from an fssync file descriptor (fd) */
 afs_int32 FS_cnt = 0;
 static void
-FSYNC_com(int fd)
+FSYNC_com(osi_socket fd)
 {
     SYNC_command com;
     SYNC_response res;
@@ -369,9 +479,22 @@ FSYNC_com(int fd)
     if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
        res.hdr.response = SYNC_OK;
        res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
-       goto respond;
+
+       /* don't respond, just drop; senders of SYNC_COM_CHANNEL_CLOSE
+        * never wait for a response. */
+       goto done;
     }
 
+    ViceLog(125, ("FSYNC_com: from fd %d got command %ld (%s) reason %ld (%s) "
+                  "pt %ld (%s) pid %ld\n", (int)fd,
+                  afs_printable_int32_ld(com.hdr.command),
+                  FSYNC_com2string(com.hdr.command),
+                  afs_printable_int32_ld(com.hdr.reason),
+                  FSYNC_reason2string(com.hdr.reason),
+                  afs_printable_int32_ld(com.hdr.programType),
+                  VPTypeToString(com.hdr.programType),
+                  afs_printable_int32_ld(com.hdr.pid)));
+
     res.hdr.com_seq = com.hdr.com_seq;
 
     VOL_LOCK;
@@ -388,7 +511,12 @@ FSYNC_com(int fd)
     case FSYNC_VOL_DONE:
     case FSYNC_VOL_QUERY:
     case FSYNC_VOL_QUERY_HDR:
+#ifdef AFS_DEMAND_ATTACH_FS
     case FSYNC_VOL_QUERY_VOP:
+    case FSYNC_VG_QUERY:
+    case FSYNC_VG_SCAN:
+    case FSYNC_VG_SCAN_ALL:
+#endif
        res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
        break;
     case FSYNC_VOL_STATS_GENERAL:
@@ -401,21 +529,36 @@ FSYNC_com(int fd)
     case FSYNC_VOL_QUERY_VNODE:
        res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
        break;
+#ifdef AFS_DEMAND_ATTACH_FS
+    case FSYNC_VG_ADD:
+    case FSYNC_VG_DEL:
+       res.hdr.response = FSYNC_com_VGUpdate(fd, &com, &res);
+       break;
+#endif
     default:
        res.hdr.response = SYNC_BAD_COMMAND;
        break;
     }
     VOL_UNLOCK;
 
+    ViceLog(125, ("FSYNC_com: fd %d responding with code %ld (%s) reason %ld "
+                  "(%s)\n", (int)fd,
+                  afs_printable_int32_ld(res.hdr.response),
+                  SYNC_res2string(res.hdr.response),
+                  afs_printable_int32_ld(res.hdr.reason),
+                  FSYNC_reason2string(res.hdr.reason)));
+
  respond:
     SYNC_putRes(&fssync_server_state, fd, &res);
+
+ done:
     if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
        FSYNC_Drop(fd);
     }
 }
 
 static afs_int32
-FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
+FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
 {
     int i;
     afs_int32 code = SYNC_OK;
@@ -441,6 +584,10 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
        }
     }
 
+    ViceLog(125, ("FSYNC_com_VolOp: fd %d got command for vol %lu part %.16s\n",
+                  (int)fd, afs_printable_uint32_lu(vcom.vop->volume),
+                  vcom.vop->partName));
+
     switch (com->hdr.command) {
     case FSYNC_VOL_ON:
     case FSYNC_VOL_ATTACH:
@@ -476,6 +623,15 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
     case FSYNC_VOL_QUERY_VOP:
        code = FSYNC_com_VolOpQuery(&vcom, res);
        break;
+    case FSYNC_VG_QUERY:
+       code = FSYNC_com_VGQuery(&vcom, res);
+       break;
+    case FSYNC_VG_SCAN:
+       code = FSYNC_com_VGScan(&vcom, res);
+       break;
+    case FSYNC_VG_SCAN_ALL:
+       code = FSYNC_com_VGScanAll(&vcom, res);
+       break;
 #endif /* AFS_DEMAND_ATTACH_FS */
     default:
        code = SYNC_BAD_COMMAND;
@@ -512,7 +668,9 @@ static afs_int32
 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
+#ifndef AFS_DEMAND_ATTACH_FS
     char tvolName[VMAXPATHLEN];
+#endif
     Volume * vp;
     Error error;
 
@@ -529,11 +687,11 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
     if (vp &&
        FSYNC_partMatch(vcom, vp, 1) &&
-       vp->pending_vol_op && 
+       vp->pending_vol_op &&
        (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
        /* a different program has this volume checked out. deny. */
        Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
-           "state for volume %u using command code %u while the volume is " 
+           "state for volume %u using command code %u while the volume is "
            "checked out by program type %u for command code %u.\n",
            vcom->hdr->programType,
            vcom->vop->volume,
@@ -554,6 +712,10 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        /* nothing much to do if we're leaving the volume offline */
 #ifdef AFS_DEMAND_ATTACH_FS
        if (vp) {
+           VCreateReservation_r(vp);
+           VWaitExclusiveState_r(vp);
+       }
+       if (vp && V_attachState(vp) != VOL_STATE_DELETED) {
            if (FSYNC_partMatch(vcom, vp, 1)) {
                if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
                    (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
@@ -568,9 +730,14 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                res->hdr.reason = FSYNC_WRONG_PART;
            }
        } else {
-           code = SYNC_DENIED;
+           code = SYNC_FAILED;
            res->hdr.reason = FSYNC_UNKNOWN_VOLID;
        }
+
+       if (vp) {
+           VCancelReservation_r(vp);
+           vp = NULL;
+       }
 #endif
        goto done;
     }
@@ -581,11 +748,15 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                                vcom->vop->partName,
                                vcom->vop->volume);
     if (vp) {
+       VCreateReservation_r(vp);
+       VWaitExclusiveState_r(vp);
        VDeregisterVolOp_r(vp);
+       VCancelReservation_r(vp);
+       vp = NULL;
     }
 #else /* !AFS_DEMAND_ATTACH_FS */
-    tvolName[0] = '/';
-    snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, vcom->vop->volume);
+    tvolName[0] = OS_DIRSEPC;
+    snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_uint32_lu(vcom->vop->volume));
     tvolName[sizeof(tvolName)-1] = '\0';
 
     vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
@@ -616,7 +787,7 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  * @note this is an FSYNC RPC server stub
  *
  * @note this procedure handles the following FSSYNC command codes:
- *       - FSYNC_VOL_OFF 
+ *       - FSYNC_VOL_OFF
  *       - FSYNC_VOL_NEEDVOLUME
  *
  * @note the supplementary reason code contains additional details.
@@ -631,10 +802,10 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     FSSYNC_VolOp_info info;
     afs_int32 code = SYNC_OK;
     int i;
-    Volume * vp, * nvp;
+    Volume * vp;
     Error error;
 #ifdef AFS_DEMAND_ATTACH_FS
-    int reserved = 0;
+    Volume *nvp, *rvp = NULL;
 #endif
 
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
@@ -691,10 +862,19 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        /* enforce mutual exclusion for volume ops */
        if (vp->pending_vol_op) {
            if (vp->pending_vol_op->com.programType != type) {
+                if (vp->pending_vol_op->com.command == FSYNC_VOL_OFF &&
+                    vp->pending_vol_op->com.reason == FSYNC_SALVAGE) {
+
+                    Log("denying offline request for volume %lu; volume is salvaging\n",
+                       afs_printable_uint32_lu(vp->hashid));
+
+                    res->hdr.reason = FSYNC_SALVAGE;
+                    goto deny;
+                }
                Log("volume %u already checked out\n", vp->hashid);
                /* XXX debug */
                Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%u, part='%s' } }\n",
-                   vp->pending_vol_op->com.proto_version, 
+                   vp->pending_vol_op->com.proto_version,
                    vp->pending_vol_op->com.programType,
                    vp->pending_vol_op->com.command,
                    vp->pending_vol_op->com.reason,
@@ -719,31 +899,58 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
            }
        }
 
+       /* wait for exclusive ops, so we have an accurate picture of the
+        * vol attach state */
+       VCreateReservation_r(vp);
+       VWaitExclusiveState_r(vp);
+       rvp = vp;
+
        /* filter based upon requestor
         *
-        * volume utilities are not allowed to check out volumes
-        * which are in an error state
+        * volume utilities / volserver are not allowed to check out
+        * volumes which are in an error state
         *
         * unknown utility programs will be denied on principal
         */
        switch (type) {
        case salvageServer:
-           /* it is possible for the salvageserver to checkout a 
+       case volumeSalvager:
+           /* it is possible for the salvageserver to checkout a
             * volume for salvage before its scheduling request
             * has been sent to the salvageserver */
            if (vp->salvage.requested && !vp->salvage.scheduled) {
                vp->salvage.scheduled = 1;
            }
+
+           /* If the volume is in VOL_STATE_SALVAGE_REQ, we need to wait
+            * for the vol to go offline before we can give it away. Also
+            * make sure we don't come out with vp in an excl state. */
+           while (V_attachState(vp) == VOL_STATE_SALVAGE_REQ ||
+                  VIsExclusiveState(V_attachState(vp))) {
+
+               VOL_CV_WAIT(&V_attachCV(vp));
+           }
+
        case debugUtility:
            break;
 
        case volumeUtility:
+       case volumeServer:
+            if (VIsSalvaging(vp)) {
+                Log("denying offline request for volume %lu; volume is in salvaging state\n",
+                   afs_printable_uint32_lu(vp->hashid));
+                res->hdr.reason = FSYNC_SALVAGE;
+
+               /* the volume hasn't been checked out yet by the salvager,
+                * but we think the volume is salvaging; schedule a
+                * a salvage to update the salvage priority */
+               FSYNC_backgroundSalvage(vp);
+
+               goto deny;
+            }
            if (VIsErrorState(V_attachState(vp))) {
                goto deny;
            }
-            if (vp->salvage.requested) {
-                goto deny;
-            }
            break;
 
        default:
@@ -765,6 +972,9 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
             * attaching the volume would be safe */
            VRegisterVolOp_r(vp, &info);
            vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
+           /* fall through */
+
+       case VOL_STATE_DELETED:
            goto done;
        default:
            break;
@@ -772,10 +982,36 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
        /* convert to heavyweight ref */
        nvp = VGetVolumeByVp_r(&error, vp);
-
        if (!nvp) {
-           Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
-               vcom->vop->volume);
+            /*
+             * It's possible for VGetVolumeByVp_r to have dropped and
+             * re-acquired VOL_LOCK, so volume state may have changed
+             * back to one of the states we tested for above. Since
+             * GetVolume can return NULL in some of those states, just
+             * test for the states again here.
+             */
+            switch (V_attachState(vp)) {
+            case VOL_STATE_UNATTACHED:
+            case VOL_STATE_PREATTACHED:
+            case VOL_STATE_SALVAGING:
+            case VOL_STATE_ERROR:
+                /* register the volume operation metadata with the volume
+                 *
+                 * if the volume is currently pre-attached, attach2()
+                 * will evaluate the vol op metadata to determine whether
+                 * attaching the volume would be safe */
+                VRegisterVolOp_r(vp, &info);
+                vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
+               /* fall through */
+
+            case VOL_STATE_DELETED:
+                goto done;
+            default:
+                break;
+            }
+
+           Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u (state=%u, flags=0x%x)\n",
+               vcom->vop->volume, V_attachState(vp), V_attachFlags(vp));
            res->hdr.reason = FSYNC_VOL_PKG_ERROR;
            goto deny;
        } else if (nvp != vp) {
@@ -784,6 +1020,10 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
            vp = nvp;
        }
 
+       /* kill off lightweight ref to ensure we can't deadlock against ourselves later... */
+       VCancelReservation_r(rvp);
+       rvp = NULL;
+
        /* register the volume operation metadata with the volume */
        VRegisterVolOp_r(vp, &info);
 
@@ -794,11 +1034,12 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        if (VVolOpLeaveOnline_r(vp, &info)) {
            VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT);       /* At least get volume stats right */
            if (LogLevel) {
-               Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n", 
-                   V_id(vp), V_name(vp), 
-                   vcom->hdr->reason == V_CLONE ? "clone" : 
-                   vcom->hdr->reason == V_READONLY ? "readonly" : 
-                   vcom->hdr->reason == V_DUMP ? "dump" : 
+               Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
+                   V_id(vp), V_name(vp),
+                   vcom->hdr->reason == V_CLONE ? "clone" :
+                   vcom->hdr->reason == V_READONLY ? "readonly" :
+                   vcom->hdr->reason == V_DUMP ? "dump" :
+                   vcom->hdr->reason == FSYNC_SALVAGE ? "salvage" :
                    "UNKNOWN");
            }
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -820,27 +1061,36 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
            }
 
 #ifdef AFS_DEMAND_ATTACH_FS
+           VCreateReservation_r(vp);
             VOfflineForVolOp_r(&error, vp, "A volume utility is running.");
             if (error==0) {
-                assert(vp->nUsers==0);
-                vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline; 
+                osi_Assert(vp->nUsers==0);
+                vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
             }
             else {
+               VWaitExclusiveState_r(vp);
                VDeregisterVolOp_r(vp);
                 code = SYNC_DENIED;
             }
+           VCancelReservation_r(vp);
 #else
            VOffline_r(vp, "A volume utility is running.");
 #endif
            vp = NULL;
        }
     }
+    goto done;
+
+ deny:
+    code = SYNC_DENIED;
 
  done:
+#ifdef AFS_DEMAND_ATTACH_FS
+    if (rvp) {
+        VCancelReservation_r(rvp);
+    }
+#endif
     return code;
-
- deny:
-    return SYNC_DENIED;
 }
 
 /**
@@ -908,7 +1158,9 @@ FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        } else {
            res->hdr.reason = FSYNC_WRONG_PART;
        }
+#ifndef AFS_DEMAND_ATTACH_FS
        VPutVolume_r(vp);
+#endif /* !AFS_DEMAND_ATTACH_FS */
     } else {
        res->hdr.reason = FSYNC_UNKNOWN_VOLID;
     }
@@ -953,10 +1205,8 @@ static afs_int32
 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
     afs_int32 code = SYNC_FAILED;
-#ifdef AFS_DEMAND_ATTACH_FS
     Error error;
     Volume * vp;
-#endif
 
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
@@ -969,19 +1219,47 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     if (vcom->v)
        vcom->v->volumeID = 0;
 
-#ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
     if (vp) {
        if (FSYNC_partMatch(vcom, vp, 1)) {
+#ifdef AFS_DEMAND_ATTACH_FS
+           VCreateReservation_r(vp);
+           VWaitExclusiveState_r(vp);
+
            if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
-               (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
-               VChangeState_r(vp, VOL_STATE_UNATTACHED);
+               (V_attachState(vp) == VOL_STATE_PREATTACHED) ||
+               VIsErrorState(V_attachState(vp))) {
+
+               /* Change state to DELETED, not UNATTACHED, so clients get
+                * a VNOVOL error when they try to access from now on. */
+
+               VChangeState_r(vp, VOL_STATE_DELETED);
                VDeregisterVolOp_r(vp);
+
+               /* Volume is gone; clear out old salvage stats */
+               memset(&vp->salvage, 0, sizeof(vp->salvage));
+
+               /* Someday we should free the vp, too, after about 2 hours,
+                * possibly by putting the vp back on the VLRU. */
+
                code = SYNC_OK;
+           } else if (V_attachState(vp) == VOL_STATE_DELETED) {
+               VDeregisterVolOp_r(vp);
+               res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+
            } else {
                code = SYNC_DENIED;
                res->hdr.reason = FSYNC_BAD_STATE;
            }
+
+           VCancelReservation_r(vp);
+           vp = NULL;
+#else /* AFS_DEMAND_ATTACH_FS */
+           if (!vp->specialStatus) {
+               vp->specialStatus = VNOVOL;
+           }
+           code = SYNC_OK;
+#endif /* !AFS_DEMAND_ATTACH_FS */
        } else {
            code = SYNC_OK; /* XXX is this really a good idea? */
            res->hdr.reason = FSYNC_WRONG_PART;
@@ -989,7 +1267,6 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     } else {
        res->hdr.reason = FSYNC_UNKNOWN_VOLID;
     }
-#endif
 
  done:
     return code;
@@ -1035,11 +1312,39 @@ FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     }
 
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
+
+    if (!vp && vcom->hdr->reason == FSYNC_SALVAGE) {
+       /* The requested volume doesn't seem to exist. However, it is possible
+        * that this is triggered by trying to create or clone a volume that
+        * was prevented from succeeding by a half-created volume in the way.
+        * (e.g. we tried to create volume X, but volume X exists except that
+        * its .vol header was deleted for some reason) So, still try to
+        * a salvage for that volume ID. */
+
+       Log("FSYNC_com_VolError: attempting to schedule salvage for unknown "
+           "volume %lu part %s\n", afs_printable_uint32_lu(vcom->vop->volume),
+           vcom->vop->partName);
+       vp = VPreAttachVolumeById_r(&error, vcom->vop->partName,
+                                   vcom->vop->volume);
+    }
+
     if (vp) {
        if (FSYNC_partMatch(vcom, vp, 0)) {
-           /* null out salvsync control state, as it's no longer relevant */
-           memset(&vp->salvage, 0, sizeof(vp->salvage));
-           VChangeState_r(vp, VOL_STATE_ERROR);
+           VCreateReservation_r(vp);
+           VWaitExclusiveState_r(vp);
+            VDeregisterVolOp_r(vp);
+
+            if (vcom->hdr->reason == FSYNC_SALVAGE) {
+               FSYNC_backgroundSalvage(vp);
+            } else {
+               /* null out salvsync control state, as it's no longer relevant */
+               memset(&vp->salvage, 0, sizeof(vp->salvage));
+               VChangeState_r(vp, VOL_STATE_ERROR);
+            }
+
+           VCancelReservation_r(vp);
+           vp = NULL;
+
            code = SYNC_OK;
        } else {
            res->hdr.reason = FSYNC_WRONG_PART;
@@ -1168,7 +1473,6 @@ FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     afs_int32 code = SYNC_FAILED;
     Error error;
     Volume * vp;
-    int hdr_ok = 0;
 
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
@@ -1192,30 +1496,31 @@ FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
                !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
                res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
-               goto done;
+               goto cleanup;
            }
 #else /* !AFS_DEMAND_ATTACH_FS */
            if (!vp || !vp->header) {
                res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
-               goto done;
+               goto cleanup;
            }
 #endif /* !AFS_DEMAND_ATTACH_FS */
        } else {
            res->hdr.reason = FSYNC_WRONG_PART;
-           goto done;
+           goto cleanup;
        }
     } else {
        res->hdr.reason = FSYNC_UNKNOWN_VOLID;
        goto done;
     }
 
- load_done:
     memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
     res->hdr.response_len += sizeof(VolumeDiskData);
+    code = SYNC_OK;
+
+ cleanup:
 #ifndef AFS_DEMAND_ATTACH_FS
     VPutVolume_r(vp);
 #endif
-    code = SYNC_OK;
 
  done:
     return code;
@@ -1231,24 +1536,182 @@ FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
 
+    if (vp) {
+       VCreateReservation_r(vp);
+       VWaitExclusiveState_r(vp);
+    }
+
     if (vp && vp->pending_vol_op) {
-       assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
-       memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
-       res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
-    } else {
-       if (vp) {
-           res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
+       if (!FSYNC_partMatch(vcom, vp, 1)) {
+           res->hdr.reason = FSYNC_WRONG_PART;
+           code = SYNC_FAILED;
        } else {
+           osi_Assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
+           memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
+           res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
+       }
+    } else {
+       if (!vp || V_attachState(vp) == VOL_STATE_DELETED) {
            res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+       } else if (!FSYNC_partMatch(vcom, vp, 1)) {
+           res->hdr.reason = FSYNC_WRONG_PART;
+       } else {
+           res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
        }
        code = SYNC_FAILED;
     }
+
+    if (vp) {
+       VCancelReservation_r(vp);
+    }
+    return code;
+}
+
+static afs_int32
+FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
+{
+    afs_int32 code = SYNC_FAILED;
+    int rc;
+    struct DiskPartition64 * dp;
+
+    if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       goto done;
+    }
+
+    dp = VGetPartition_r(vcom->vop->partName, 0);
+    if (dp == NULL) {
+       res->hdr.reason = FSYNC_BAD_PART;
+       goto done;
+    }
+
+    osi_Assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
+
+    rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
+    switch (rc) {
+    case 0:
+       res->hdr.response_len += sizeof(FSSYNC_VGQry_response_t);
+       code = SYNC_OK;
+       break;
+    case EAGAIN:
+       res->hdr.reason = FSYNC_PART_SCANNING;
+       break;
+    case ENOENT:
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+       break;
+    default:
+       break;
+    }
+
+ done:
+    return code;
+}
+
+static afs_int32
+FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res)
+{
+    afs_int32 code = SYNC_FAILED;
+    struct DiskPartition64 * dp;
+    FSSYNC_VGUpdate_command_t * vgucom;
+    int rc;
+
+    if (com->recv_len != (sizeof(com->hdr) + sizeof(*vgucom))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       code = SYNC_COM_ERROR;
+       goto done;
+    }
+
+    vgucom = com->payload.buf;
+
+    ViceLog(125, ("FSYNC_com_VGUpdate: fd %d got command for parent %lu child "
+                  "%lu partName %.16s\n", (int)fd,
+                  afs_printable_uint32_lu(vgucom->parent),
+                  afs_printable_uint32_lu(vgucom->child),
+                  vgucom->partName));
+
+    if (SYNC_verifyProtocolString(vgucom->partName, sizeof(vgucom->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       goto done;
+    }
+
+    dp = VGetPartition_r(vgucom->partName, 0);
+    if (dp == NULL) {
+       res->hdr.reason = FSYNC_BAD_PART;
+       goto done;
+    }
+
+    switch(com->hdr.command) {
+    case FSYNC_VG_ADD:
+       rc = VVGCache_entry_add_r(dp, vgucom->parent, vgucom->child, NULL);
+       break;
+
+    case FSYNC_VG_DEL:
+       rc = VVGCache_entry_del_r(dp, vgucom->parent, vgucom->child);
+       break;
+
+    default:
+       Log("FSYNC_com_VGUpdate called improperly\n");
+       rc = -1;
+       break;
+    }
+
+    /* EINVAL means the partition VGC doesn't exist at all; not really
+     * an error */
+    if (rc == 0 || rc == EINVAL) {
+       code = SYNC_OK;
+    }
+
+    if (rc == ENOENT) {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+    } else {
+       res->hdr.reason = FSYNC_WHATEVER;
+    }
+
+ done:
+    return code;
+}
+
+static afs_int32
+FSYNC_com_VGScan(FSSYNC_VolOp_command * vcom, SYNC_response * res)
+{
+    afs_int32 code = SYNC_FAILED;
+    struct DiskPartition64 * dp;
+
+    if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       goto done;
+    }
+
+    dp = VGetPartition_r(vcom->vop->partName, 0);
+    if (dp == NULL) {
+       res->hdr.reason = FSYNC_BAD_PART;
+       goto done;
+    }
+
+    if (VVGCache_scanStart_r(dp) == 0) {
+       code = SYNC_OK;
+    }
+
+ done:
+    return code;
+}
+
+static afs_int32
+FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res)
+{
+    afs_int32 code = SYNC_FAILED;
+
+    if (VVGCache_scanStart_r(NULL) == 0) {
+       code = SYNC_OK;
+    }
+
     return code;
 }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 static afs_int32
-FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
+FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
     FSSYNC_VnQry_hdr * qry = com->payload.buf;
@@ -1262,6 +1725,14 @@ FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
        return SYNC_COM_ERROR;
     }
 
+    ViceLog(125, ("FSYNC_com_VnQry: fd %d got command for vol %lu vnode %lu "
+                  "uniq %lu spare %lu partName %.16s\n", (int)fd,
+                  afs_printable_uint32_lu(qry->volume),
+                  afs_printable_uint32_lu(qry->vnode),
+                  afs_printable_uint32_lu(qry->unique),
+                  afs_printable_uint32_lu(qry->spare),
+                  qry->partName));
+
 #ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, qry->volume, NULL);
 #else /* !AFS_DEMAND_ATTACH_FS */
@@ -1300,7 +1771,7 @@ FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
 }
 
 static afs_int32
-FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
+FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
     FSSYNC_StatsOp_command scom;
@@ -1315,6 +1786,13 @@ FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
     scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
     scom.com = com;
 
+    ViceLog(125, ("FSYNC_com_StatsOp: fd %d got command for stats: "
+                  "{vlru_generation = %lu, hash_bucket = %lu, partName = "
+                  "%.16s}\n", (int)fd,
+                  afs_printable_uint32_lu(scom.sop->args.vlru_generation),
+                  afs_printable_uint32_lu(scom.sop->args.hash_bucket),
+                  scom.sop->args.partName));
+
     switch (com->hdr.command) {
     case FSYNC_VOL_STATS_GENERAL:
        code = FSYNC_com_StatsOpGeneral(&scom, res);
@@ -1377,7 +1855,7 @@ FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
        stats->minFree = dp->minFree;
        stats->f_files = dp->f_files;
        stats->vol_list_len = dp->vol_list.len;
-       
+
        res->hdr.response_len += sizeof(struct DiskPartitionStats64);
     }
 
@@ -1407,7 +1885,7 @@ FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
     AssignInt64(head->reorders, &stats->chain_reorders);
 
     res->hdr.response_len += sizeof(struct VolumeHashChainStats);
-    
+
     return code;
 }
 
@@ -1453,7 +1931,7 @@ FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
 }
 
 /**
- * check whether command packet partition name matches volume 
+ * check whether command packet partition name matches volume
  * object's partition name.
  *
  * @param[in] vcom        pointer to command packet
@@ -1470,17 +1948,17 @@ FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
  *
  * @internal
  */
-static int 
+static int
 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
 {
     return ((match_anon && vcom->vop->partName[0] == 0) ||
-           (strncmp(vcom->vop->partName, V_partition(vp)->name, 
+           (strncmp(vcom->vop->partName, V_partition(vp)->name,
                     sizeof(vcom->vop->partName)) == 0));
 }
 
 
 static void
-FSYNC_Drop(int fd)
+FSYNC_Drop(osi_socket fd)
 {
     struct offlineInfo *p;
     int i;
@@ -1494,8 +1972,8 @@ FSYNC_Drop(int fd)
 
            Volume *vp;
 
-           tvolName[0] = '/';
-           sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
+           tvolName[0] = OS_DIRSEPC;
+           sprintf(&tvolName[1], VFORMAT, afs_printable_uint32_lu(p[i].volumeID));
            vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
                                       V_VOLUPD);
            if (vp)
@@ -1505,46 +1983,42 @@ FSYNC_Drop(int fd)
     }
     VOL_UNLOCK;
     RemoveHandler(fd);
-#ifdef AFS_NT40_ENV
-    closesocket(fd);
-#else
-    close(fd);
-#endif
+    rk_closesocket(fd);
     AcceptOn();
 }
 
 static int AcceptHandler = -1; /* handler id for accept, if turned on */
 
 static void
-AcceptOn()
+AcceptOn(void)
 {
     if (AcceptHandler == -1) {
-       assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
+       osi_Assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
        AcceptHandler = FindHandler(fssync_server_state.fd);
     }
 }
 
 static void
-AcceptOff()
+AcceptOff(void)
 {
     if (AcceptHandler != -1) {
-       assert(RemoveHandler(fssync_server_state.fd));
+       osi_Assert(RemoveHandler(fssync_server_state.fd));
        AcceptHandler = -1;
     }
 }
 
 /* The multiple FD handling code. */
 
-static int HandlerFD[MAXHANDLERS];
-static int (*HandlerProc[MAXHANDLERS]) ();
+static osi_socket HandlerFD[MAXHANDLERS];
+static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
 
 static void
-InitHandler()
+InitHandler(void)
 {
-    register int i;
+    int i;
     ObtainWriteLock(&FSYNC_handler_lock);
     for (i = 0; i < MAXHANDLERS; i++) {
-       HandlerFD[i] = -1;
+       HandlerFD[i] = OSI_NULLSOCKET;
        HandlerProc[i] = 0;
     }
     ReleaseWriteLock(&FSYNC_handler_lock);
@@ -1571,7 +2045,7 @@ CallHandler(struct pollfd *fds, int nfds, int mask)
 static void
 CallHandler(fd_set * fdsetp)
 {
-    register int i;
+    int i;
     ObtainReadLock(&FSYNC_handler_lock);
     for (i = 0; i < MAXHANDLERS; i++) {
        if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
@@ -1585,12 +2059,12 @@ CallHandler(fd_set * fdsetp)
 #endif
 
 static int
-AddHandler(int afd, int (*aproc) ())
+AddHandler(osi_socket afd, void (*aproc) (osi_socket))
 {
-    register int i;
+    int i;
     ObtainWriteLock(&FSYNC_handler_lock);
     for (i = 0; i < MAXHANDLERS; i++)
-       if (HandlerFD[i] == -1)
+       if (HandlerFD[i] == OSI_NULLSOCKET)
            break;
     if (i >= MAXHANDLERS) {
        ReleaseWriteLock(&FSYNC_handler_lock);
@@ -1603,9 +2077,9 @@ AddHandler(int afd, int (*aproc) ())
 }
 
 static int
-FindHandler(register int afd)
+FindHandler(osi_socket afd)
 {
-    register int i;
+    int i;
     ObtainReadLock(&FSYNC_handler_lock);
     for (i = 0; i < MAXHANDLERS; i++)
        if (HandlerFD[i] == afd) {
@@ -1613,27 +2087,27 @@ FindHandler(register int afd)
            return i;
        }
     ReleaseReadLock(&FSYNC_handler_lock);      /* just in case */
-    assert(1 == 2);
+    osi_Assert(1 == 2);
     return -1;                 /* satisfy compiler */
 }
 
 static int
-FindHandler_r(register int afd)
+FindHandler_r(osi_socket afd)
 {
-    register int i;
+    int i;
     for (i = 0; i < MAXHANDLERS; i++)
        if (HandlerFD[i] == afd) {
            return i;
        }
-    assert(1 == 2);
+    osi_Assert(1 == 2);
     return -1;                 /* satisfy compiler */
 }
 
 static int
-RemoveHandler(register int afd)
+RemoveHandler(osi_socket afd)
 {
     ObtainWriteLock(&FSYNC_handler_lock);
-    HandlerFD[FindHandler_r(afd)] = -1;
+    HandlerFD[FindHandler_r(afd)] = OSI_NULLSOCKET;
     ReleaseWriteLock(&FSYNC_handler_lock);
     return 1;
 }
@@ -1646,8 +2120,8 @@ GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
     int fdi = 0;
     ObtainReadLock(&FSYNC_handler_lock);
     for (i = 0; i < MAXHANDLERS; i++)
-       if (HandlerFD[i] != -1) {
-           assert(fdi<maxfds);
+       if (HandlerFD[i] != OSI_NULLSOCKET) {
+           osi_Assert(fdi<maxfds);
            fds[fdi].fd = HandlerFD[i];
            fds[fdi].events = events;
            fds[fdi].revents = 0;
@@ -1660,15 +2134,18 @@ GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
 static void
 GetHandler(fd_set * fdsetp, int *maxfdp)
 {
-    register int i;
-    register int maxfd = -1;
+    int i;
+    int maxfd = -1;
     FD_ZERO(fdsetp);
     ObtainReadLock(&FSYNC_handler_lock);       /* just in case */
     for (i = 0; i < MAXHANDLERS; i++)
-       if (HandlerFD[i] != -1) {
+       if (HandlerFD[i] != OSI_NULLSOCKET) {
            FD_SET(HandlerFD[i], fdsetp);
-           if (maxfd < HandlerFD[i])
+#ifndef AFS_NT40_ENV
+            /* On Windows the nfds parameter to select() is ignored */
+           if (maxfd < HandlerFD[i] || maxfd == (int)-1)
                maxfd = HandlerFD[i];
+#endif /* AFS_NT40_ENV */
        }
     *maxfdp = maxfd;
     ReleaseReadLock(&FSYNC_handler_lock);      /* just in case */