DAFS: Put back volumes we get in FSSYNC handlers
[openafs.git] / src / vol / fssync-server.c
index 08c9175..86bd5fd 100644 (file)
@@ -6,7 +6,7 @@
  * 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 Sine Nomine Associates
+ * Portions Copyright (c) 2006-2008 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,8 +43,6 @@ static int newVLDB = 1;
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -66,6 +55,7 @@ RCSID
 #include <netinet/in.h>
 #include <netdb.h>
 #include <sys/time.h>
+#include <unistd.h>
 #endif
 #include <errno.h>
 #ifdef AFS_PTHREAD_ENV
@@ -74,15 +64,7 @@ RCSID
 #include <afs/assert.h>
 #endif /* AFS_PTHREAD_ENV */
 #include <signal.h>
-
-#ifdef HAVE_STRING_H
 #include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-
 
 #include <rx/xdr.h>
 #include <afs/afsint.h>
@@ -96,8 +78,13 @@ RCSID
 #include "ihandle.h"
 #include "vnode.h"
 #include "volume.h"
+#include "volume_inline.h"
 #include "partition.h"
 
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif /* HAVE_POLL */
+
 #ifdef USE_UNIX_SOCKETS
 #include <sys/un.h>
 #include <afs/afsutil.h>
@@ -107,12 +94,7 @@ RCSID
 
 /*@printflike@*/ extern void Log(const char *format, ...);
 
-#ifdef osi_Assert
-#undef osi_Assert
-#endif
-#define osi_Assert(e) (void)(e)
-
-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 */
@@ -122,35 +104,49 @@ int (*V_BreakVolumeCallbacks) ();
                                 * cloned read-only copies offline when salvaging
                                 * a single read-write volume */
 
-#define MAX_BIND_TRIES 5       /* Number of times to retry socket bind */
-
 
 
 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
 
-static int AcceptSd = -1;      /* Socket used by server for accepting connections */
+/**
+ * fssync server socket handle.
+ */
+static SYNC_server_state_t fssync_server_state = 
+    { -1,                       /* file descriptor */
+      FSSYNC_ENDPOINT_DECL,     /* server endpoint */
+      FSYNC_PROTO_VERSION,      /* protocol version */
+      5,                        /* bind() retry limit */
+      100,                      /* listen() queue depth */
+      "FSSYNC",                 /* protocol name string */
+    };
 
-static int getport();
 
 /* Forward declarations */
-static void FSYNC_sync();
-static void FSYNC_newconnection();
-static void FSYNC_com();
-static void FSYNC_Drop();
-static void AcceptOn();
-static void AcceptOff();
-static void InitHandler();
+static void * FSYNC_sync(void *);
+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);
+#else
 static void CallHandler(fd_set * fdsetp);
-static int AddHandler();
-static int FindHandler();
-static int FindHandler_r();
-static int RemoveHandler();
 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);
@@ -162,17 +158,23 @@ static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response
 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
 #endif /* AFS_DEMAND_ATTACH_FS */
 
-static afs_int32 FSYNC_com_StatsOp(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(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);
 
+static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
+
 
 /*
  * This lock controls access to the handler array. The overhead
@@ -203,60 +205,28 @@ FSYNC_fsInit(void)
 #endif /* AFS_PTHREAD_ENV */
 }
 
-static fd_set FSYNC_readfds;
-
-#ifdef USE_UNIX_SOCKETS
-static int
-getport(struct sockaddr_un *addr)
-{
-    int sd;
-    char tbuffer[AFSDIR_PATH_MAX]; 
-    
-    strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
-               "fssync.sock", NULL);
-    
-    memset(addr, 0, sizeof(*addr));
-    addr->sun_family = AF_UNIX;
-    strncpy(addr->sun_path, tbuffer, (sizeof(struct sockaddr_un) - sizeof(short)));
-    assert((sd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
-    return sd;
-}
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static struct pollfd FSYNC_readfds[MAXHANDLERS];
 #else
-static int
-getport(struct sockaddr_in *addr)
-{
-    int sd;
-
-    memset(addr, 0, sizeof(*addr));
-    assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
-#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
-    addr->sin_len = sizeof(struct sockaddr_in);
-#endif
-    addr->sin_addr.s_addr = htonl(0x7f000001);
-    addr->sin_family = AF_INET;        /* was localhost->h_addrtype */
-    addr->sin_port = htons(2040);      /* XXXX htons not _really_ neccessary */
-
-    return sd;
-}
+static fd_set FSYNC_readfds;
 #endif
 
 
-static void
-FSYNC_sync()
+static void *
+FSYNC_sync(void * args)
 {
-#ifdef USE_UNIX_SOCKETS
-    struct sockaddr_un addr;
-    char tbuffer[AFSDIR_PATH_MAX];
-#else  /* USE_UNIX_SOCKETS */
-    struct sockaddr_in addr;
-#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
+
+    SYNC_getAddr(&state->endpoint, &state->addr);
+    SYNC_cleanupSock(state);
 
 #ifndef AFS_NT40_ENV
     (void)signal(SIGPIPE, SIG_IGN);
@@ -271,14 +241,6 @@ FSYNC_sync()
     Log("Set thread id %d for FSYNC_sync\n", tid);
 #endif /* AFS_PTHREAD_ENV */
 
-#ifdef USE_UNIX_SOCKETS
-    /* ignore errors */
-    strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
-              "fssync.sock", NULL);
-
-    remove(tbuffer);
-#endif /* USE_UNIX_SOCKETS */
-
     while (!VInit) {
        /* Let somebody else run until level > 0.  That doesn't mean that 
         * all volumes have been attached. */
@@ -288,27 +250,36 @@ FSYNC_sync()
        LWP_DispatchProcess();
 #endif /* AFS_PTHREAD_ENV */
     }
-    AcceptSd = getport(&addr);
-    /* Reuseaddr needed because system inexplicably leaves crud lying around */
-    code =
-       setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
-                  sizeof(on));
-    if (code)
-       Log("FSYNC_sync: setsockopt failed with (%d)\n", errno);
-
-    for (numTries = 0; numTries < MAX_BIND_TRIES; numTries++) {
-       if ((code =
-            bind(AcceptSd, (struct sockaddr *)&addr, sizeof(addr))) == 0)
-           break;
-       Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",
-           errno);
-       sleep(5);
-    }
+    state->fd = SYNC_getSock(&state->endpoint);
+    code = SYNC_bindSock(state);
     assert(!code);
-    listen(AcceptSd, 100);
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    /*
+     * make sure the volume package is incapable of recursively executing
+     * salvsync calls on this thread, since there is a possibility of
+     * deadlock.
+     */
+    thread_opts = malloc(sizeof(VThreadOptions_t));
+    if (thread_opts == NULL) {
+       Log("failed to allocate memory for thread-specific volume package options structure\n");
+       return NULL;
+    }
+    memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
+    thread_opts->disallow_salvsync = 1;
+    assert(pthread_setspecific(VThread_key, thread_opts) == 0);
+#endif
+
     InitHandler();
     AcceptOn();
+
     for (;;) {
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+        int nfds;
+        GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
+        if (poll(FSYNC_readfds, nfds, -1) >=1)
+           CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
+#else
        int maxfd;
        GetHandler(&FSYNC_readfds, &maxfd);
        /* Note: check for >= 1 below is essential since IOMGR_select
@@ -320,18 +291,21 @@ FSYNC_sync()
        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 */
 }
 
 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) {
@@ -346,7 +320,7 @@ FSYNC_newconnection(int afd)
 /* 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;
@@ -358,17 +332,24 @@ FSYNC_com(int fd)
     com.payload.buf = (void *)com_buf;
     com.payload.len = SYNC_PROTO_MAX_LEN;
     res.hdr.response_len = sizeof(res.hdr);
-    res.hdr.proto_version = FSYNC_PROTO_VERSION;
     res.payload.len = SYNC_PROTO_MAX_LEN;
     res.payload.buf = (void *)res_buf;
 
     FS_cnt++;
-    if (SYNC_getCom(fd, &com)) {
+    if (SYNC_getCom(&fssync_server_state, fd, &com)) {
        Log("FSYNC_com:  read failed; dropping connection (cnt=%d)\n", FS_cnt);
        FSYNC_Drop(fd);
        return;
     }
 
+    if (com.recv_len < sizeof(com.hdr)) {
+       Log("FSSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
+       res.hdr.response = SYNC_COM_ERROR;
+       res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
     if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
        Log("FSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
        res.hdr.response = SYNC_COM_ERROR;
@@ -376,10 +357,24 @@ FSYNC_com(int fd)
        goto respond;
     }
 
+    if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       res.hdr.response = SYNC_OK;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+
+       /* don't respond, just drop; senders of SYNC_COM_CHANNEL_CLOSE
+        * never wait for a response. */
+       goto done;
+    }
+
+    res.hdr.com_seq = com.hdr.com_seq;
+
     VOL_LOCK;
     switch (com.hdr.command) {
     case FSYNC_VOL_ON:
+    case FSYNC_VOL_ATTACH:
+    case FSYNC_VOL_LEAVE_OFF:
     case FSYNC_VOL_OFF:
+    case FSYNC_VOL_FORCE_ERROR:
     case FSYNC_VOL_LISTVOLUMES:
     case FSYNC_VOL_NEEDVOLUME:
     case FSYNC_VOL_MOVE:
@@ -397,9 +392,8 @@ FSYNC_com(int fd)
     case FSYNC_VOL_STATS_VLRU:
        res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
        break;
-    case SYNC_COM_CHANNEL_CLOSE:
-       res.hdr.response = SYNC_OK;
-       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+    case FSYNC_VOL_QUERY_VNODE:
+       res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
        break;
     default:
        res.hdr.response = SYNC_BAD_COMMAND;
@@ -408,14 +402,16 @@ FSYNC_com(int fd)
     VOL_UNLOCK;
 
  respond:
-    SYNC_putRes(fd, &res);
+    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;
@@ -443,6 +439,8 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
 
     switch (com->hdr.command) {
     case FSYNC_VOL_ON:
+    case FSYNC_VOL_ATTACH:
+    case FSYNC_VOL_LEAVE_OFF:
        code = FSYNC_com_VolOn(&vcom, res);
        break;
     case FSYNC_VOL_OFF:
@@ -468,6 +466,9 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
        code = FSYNC_com_VolHdrQuery(&vcom, res);
        break;
 #ifdef AFS_DEMAND_ATTACH_FS
+    case FSYNC_VOL_FORCE_ERROR:
+       code = FSYNC_com_VolError(&vcom, res);
+       break;
     case FSYNC_VOL_QUERY_VOP:
        code = FSYNC_com_VolOpQuery(&vcom, res);
        break;
@@ -479,6 +480,30 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
     return code;
 }
 
+/**
+ * service an FSYNC request to bring a volume online.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume transitioned online
+ *   @retval SYNC_FAILED invalid command protocol message
+ *   @retval SYNC_DENIED operation could not be completed
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_ON
+ *       - FSYNC_VOL_ATTACH
+ *       - FSYNC_VOL_LEAVE_OFF
+ *
+ * @note the supplementary reason code contains additional details.
+ *       When SYNC_DENIED is returned, the specific reason is
+ *       placed in the response packet reason field.
+ *
+ * @internal
+ */
 static afs_int32
 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
@@ -493,81 +518,121 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        goto done;
     }
 
-    /*
-      This is where a detatched volume gets reattached. However in the
-      special case where the volume is merely busy, it is already
-      attatched and it is only necessary to clear the busy flag. See
-      defect #2080 for details.
-    */
-
-    /* is the volume already attatched? */
-#ifdef notdef
-    /*
-     * XXX With the following enabled we had bizarre problems where the backup id would
-     * be reset to 0; that was due to the interaction between fileserver/volserver in that they
-     * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
-     * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
-     * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
-     * be done right XXX
-     */
-    vp = VGetVolume_r(&error, vcom->vop->volume);
-    if (vp) {
-       /* yep, is the BUSY flag set? */
-       if (vp->specialStatus == VBUSY) {
+    /* so, we need to attach the volume */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    /* check DAFS permissions */
+    vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
+    if (vp &&
+       FSYNC_partMatch(vcom, vp, 1) &&
+       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 " 
+           "checked out by program type %u for command code %u.\n",
+           vcom->hdr->programType,
+           vcom->vop->volume,
+           vcom->hdr->command,
+           vp->pending_vol_op->com.programType,
+           vp->pending_vol_op->com.command);
+       code = SYNC_DENIED;
+       res->hdr.reason = FSYNC_EXCLUSIVE;
+       goto done;
+    }
+#endif
+
+    if (vcom->v)
+       vcom->v->volumeID = 0;
 
-           /* yep, clear BUSY flag */
 
-           vp->specialStatus = 0;
-           /* make sure vol is online */
-           if (vcom->v) {
-               vcom->v->volumeID = 0;
-               V_inUse(vp) = 1;        /* online */
+    if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
+       /* nothing much to do if we're leaving the volume offline */
+#ifdef AFS_DEMAND_ATTACH_FS
+       if (vp) {
+           if (FSYNC_partMatch(vcom, vp, 1)) {
+               if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
+                   (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
+                   VChangeState_r(vp, VOL_STATE_UNATTACHED);
+                   VDeregisterVolOp_r(vp);
+               } else {
+                   code = SYNC_DENIED;
+                   res->hdr.reason = FSYNC_BAD_STATE;
+               }
+           } else {
+               code = SYNC_DENIED;
+               res->hdr.reason = FSYNC_WRONG_PART;
            }
-           VPutVolume_r(vp);
-           break;
+       } else {
+           code = SYNC_DENIED;
+           res->hdr.reason = FSYNC_UNKNOWN_VOLID;
        }
-       VPutVolume_r(vp);
+#endif
+       goto done;
     }
-#endif /* notdef */
-
-    /* so, we need to attach the volume */
 
-    if (vcom->v)
-       vcom->v->volumeID = 0;
+#ifdef AFS_DEMAND_ATTACH_FS
+    /* first, check to see whether we have such a volume defined */
+    vp = VPreAttachVolumeById_r(&error,
+                               vcom->vop->partName,
+                               vcom->vop->volume);
+    if (vp) {
+       VDeregisterVolOp_r(vp);
+    }
+#else /* !AFS_DEMAND_ATTACH_FS */
     tvolName[0] = '/';
-    snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, vcom->vop->volume);
+    snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_uint32_lu(vcom->vop->volume));
     tvolName[sizeof(tvolName)-1] = '\0';
 
-#ifdef AFS_DEMAND_ATTACH_FS
-    vp = VPreAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
-                                 V_VOLUPD);
-    if (vp && vp->pending_vol_op) {
-       VDeregisterVolOp_r(vp, vp->pending_vol_op);
-    }
-#else /* AFS_DEMAND_ATTACH_FS */
     vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
                               V_VOLUPD);
     if (vp)
        VPutVolume_r(vp);
-#endif /* AFS_DEMAND_ATTACH_FS */
-
     if (error) {
        code = SYNC_DENIED;
        res->hdr.reason = error;
     }
+#endif /* !AFS_DEMAND_ATTACH_FS */
 
  done:
     return code;
 }
 
+/**
+ * service an FSYNC request to take a volume offline.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume transitioned offline
+ *   @retval SYNC_FAILED invalid command protocol message
+ *   @retval SYNC_DENIED operation could not be completed
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_OFF 
+ *       - FSYNC_VOL_NEEDVOLUME
+ *
+ * @note the supplementary reason code contains additional details.
+ *       When SYNC_DENIED is returned, the specific reason is
+ *       placed in the response packet reason field.
+ *
+ * @internal
+ */
 static afs_int32
 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;
+#endif
 
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
@@ -602,9 +667,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 #endif
 
     if (vp) {
-       if ((vcom->vop->partName[0] != 0) &&
-           (strncmp(vcom->vop->partName, vp->partition->name, 
-                   sizeof(vcom->vop->partName)) != 0)) {
+           if (!FSYNC_partMatch(vcom, vp, 1)) {
            /* volume on desired partition is not online, so we
             * should treat this as an offline volume.
             */
@@ -662,15 +725,24 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
         */
        switch (type) {
        case salvageServer:
+           /* 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;
+           }
        case debugUtility:
-           /* give the salvageserver lots of liberty */
            break;
+
        case volumeUtility:
-           if ((V_attachState(vp) == VOL_STATE_ERROR) ||
-               (V_attachState(vp) == VOL_STATE_SALVAGING)) {
+           if (VIsErrorState(V_attachState(vp))) {
                goto deny;
            }
+            if (vp->salvage.requested) {
+                goto deny;
+            }
            break;
+
        default:
            Log("bad program type passed to FSSYNC\n");
            goto deny;
@@ -689,6 +761,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
             * 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;
            goto done;
        default:
            break;
@@ -697,16 +770,20 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        /* convert to heavyweight ref */
        nvp = VGetVolumeByVp_r(&error, vp);
 
-       /* register the volume operation metadata with the volume */
-       VRegisterVolOp_r(vp, &info);
-
        if (!nvp) {
            Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
                vcom->vop->volume);
            res->hdr.reason = FSYNC_VOL_PKG_ERROR;
            goto deny;
+       } else if (nvp != vp) {
+           /* i don't think this should ever happen, but just in case... */
+           Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
+           vp = nvp;
        }
-       vp = nvp;
+
+       /* register the volume operation metadata with the volume */
+       VRegisterVolOp_r(vp, &info);
+
     }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
@@ -721,6 +798,9 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                    vcom->hdr->reason == V_DUMP ? "dump" : 
                    "UNKNOWN");
            }
+#ifdef AFS_DEMAND_ATTACH_FS
+            vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
+#endif
            VPutVolume_r(vp);
        } else {
            if (VVolOpSetVBusy_r(vp, &info)) {
@@ -736,7 +816,19 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
            }
 
+#ifdef AFS_DEMAND_ATTACH_FS
+            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; 
+            }
+            else {
+               VDeregisterVolOp_r(vp);
+                code = SYNC_DENIED;
+            }
+#else
            VOffline_r(vp, "A volume utility is running.");
+#endif
            vp = NULL;
        }
     }
@@ -748,12 +840,44 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     return SYNC_DENIED;
 }
 
+/**
+ * service an FSYNC request to mark a volume as moved.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume marked as moved to a remote server
+ *   @retval SYNC_FAILED invalid command protocol message
+ *   @retval SYNC_DENIED current volume state does not permit this operation
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this operation also breaks all callbacks for the given volume
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_MOVE
+ *
+ * @note the supplementary reason code contains additional details.  For
+ *       instance, SYNC_OK is still returned when the partition specified
+ *       does not match the one registered in the volume object -- reason
+ *       will be FSYNC_WRONG_PART in this case.
+ *
+ * @internal
+ */
 static afs_int32
 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
+    afs_int32 code = SYNC_DENIED;
     Error error;
     Volume * vp;
 
+    if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       code = SYNC_FAILED;
+       goto done;
+    }
+
     /* Yuch:  the "reason" for the move is the site it got moved to... */
     /* still set specialStatus so we stop sending back VBUSY.
      * also should still break callbacks.  Note that I don't know
@@ -766,13 +890,29 @@ FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     vp = VGetVolume_r(&error, vcom->vop->volume);
 #endif
     if (vp) {
-       vp->specialStatus = VMOVED;
+       if (FSYNC_partMatch(vcom, vp, 1)) {
+#ifdef AFS_DEMAND_ATTACH_FS
+           if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
+               (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
+#endif
+               code = SYNC_OK;
+               vp->specialStatus = VMOVED;
+#ifdef AFS_DEMAND_ATTACH_FS
+           } else {
+               res->hdr.reason = FSYNC_BAD_STATE;
+           }
+#endif
+       } else {
+           res->hdr.reason = FSYNC_WRONG_PART;
+       }
 #ifndef AFS_DEMAND_ATTACH_FS
        VPutVolume_r(vp);
-#endif
+#endif /* !AFS_DEMAND_ATTACH_FS */
+    } else {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
     }
 
-    if (V_BreakVolumeCallbacks) {
+    if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
        Log("fssync: volume %u moved to %x; breaking all call backs\n",
            vcom->vop->volume, vcom->hdr->reason);
        VOL_UNLOCK;
@@ -780,17 +920,48 @@ FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        VOL_LOCK;
     }
 
-    return SYNC_OK;
+
+ done:
+    return code;
 }
 
+/**
+ * service an FSYNC request to mark a volume as destroyed.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume marked as destroyed
+ *   @retval SYNC_FAILED invalid command protocol message
+ *   @retval SYNC_DENIED current volume state does not permit this operation
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_DONE
+ *
+ * @note the supplementary reason code contains additional details.  For
+ *       instance, SYNC_OK is still returned when the partition specified
+ *       does not match the one registered in the volume object -- reason
+ *       will be FSYNC_WRONG_PART in this case.
+ *
+ * @internal
+ */
 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;
+       goto done;
+    }
+
     /* don't try to put online, this call is made only after deleting
      * a volume, in which case we want to remove the vol # from the
      * OfflineVolumes array only */
@@ -799,14 +970,108 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
 #ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
-    if (vp && vp->pending_vol_op) {
-       VDeregisterVolOp_r(vp, vp->pending_vol_op);
+    if (vp) {
+       if (FSYNC_partMatch(vcom, vp, 1)) {
+           if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
+               (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
+               VChangeState_r(vp, VOL_STATE_UNATTACHED);
+               VDeregisterVolOp_r(vp);
+               code = SYNC_OK;
+           } else {
+               code = SYNC_DENIED;
+               res->hdr.reason = FSYNC_BAD_STATE;
+           }
+       } else {
+           code = SYNC_OK; /* XXX is this really a good idea? */
+           res->hdr.reason = FSYNC_WRONG_PART;
+       }
+    } else {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
     }
 #endif
 
-    return SYNC_OK;
+ done:
+    return code;
 }
 
+#ifdef AFS_DEMAND_ATTACH_FS
+/**
+ * service an FSYNC request to transition a volume to the hard error state.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume transitioned to hard error state
+ *   @retval SYNC_FAILED invalid command protocol message
+ *   @retval SYNC_DENIED (see note)
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_FORCE_ERROR
+ *
+ * @note SYNC_DENIED is returned in the following cases:
+ *        - no partition name is specified (reason field set to
+ *          FSYNC_WRONG_PART).
+ *        - volume id not known to fileserver (reason field set
+ *          to FSYNC_UNKNOWN_VOLID).
+ *
+ * @note demand attach fileserver only
+ *
+ * @internal
+ */
+static afs_int32
+FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
+{
+    Error error;
+    Volume * vp;
+    afs_int32 code = SYNC_FAILED;
+
+    if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       goto done;
+    }
+
+    vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
+    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);
+           code = SYNC_OK;
+       } else {
+           res->hdr.reason = FSYNC_WRONG_PART;
+       }
+    } else {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+    }
+
+ done:
+    return code;
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+/**
+ * service an FSYNC request to break all callbacks for this volume.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK callback breaks scheduled for volume
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_BREAKCBKS
+ *
+ * @note demand attach fileserver only
+ *
+ * @todo should do partition matching
+ *
+ * @internal
+ */
 static afs_int32
 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
@@ -821,13 +1086,35 @@ FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     return SYNC_OK;
 }
 
+/**
+ * service an FSYNC request to return the Volume object.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK      volume object returned to caller
+ *   @retval SYNC_FAILED  bad command packet, or failed to locate volume object
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_QUERY
+ *
+ * @internal
+ */
 static afs_int32
 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
-    afs_int32 code = SYNC_OK;
+    afs_int32 code = SYNC_FAILED;
     Error error;
     Volume * vp;
 
+    if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       goto done;
+    }
+
 #ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
 #else /* !AFS_DEMAND_ATTACH_FS */
@@ -835,58 +1122,101 @@ FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 #endif /* !AFS_DEMAND_ATTACH_FS */
 
     if (vp) {
-       assert(sizeof(Volume) <= res->payload.len);
-       memcpy(res->payload.buf, vp, sizeof(Volume));
-       res->hdr.response_len += sizeof(Volume);
+       if (FSYNC_partMatch(vcom, vp, 1)) {
+           if (res->payload.len >= sizeof(Volume)) {
+               memcpy(res->payload.buf, vp, sizeof(Volume));
+               res->hdr.response_len += sizeof(Volume);
+               code = SYNC_OK;
+           } else {
+               res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
+           }
+       } else {
+           res->hdr.reason = FSYNC_WRONG_PART;
+       }
 #ifndef AFS_DEMAND_ATTACH_FS
        VPutVolume_r(vp);
 #endif
     } else {
        res->hdr.reason = FSYNC_UNKNOWN_VOLID;
-       code = SYNC_FAILED;
     }
+
+ done:
     return code;
 }
 
+/**
+ * service an FSYNC request to return the Volume header.
+ *
+ * @param[in]   vcom  pointer command object
+ * @param[out]  res   object in which to store response packet
+ *
+ * @return operation status
+ *   @retval SYNC_OK volume header returned to caller
+ *   @retval SYNC_FAILED  bad command packet, or failed to locate volume header
+ *
+ * @note this is an FSYNC RPC server stub
+ *
+ * @note this procedure handles the following FSSYNC command codes:
+ *       - FSYNC_VOL_QUERY_HDR
+ *
+ * @internal
+ */
 static afs_int32
 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
-    afs_int32 code = SYNC_OK;
+    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;
+       goto done;
+    }
+    if (res->payload.len < sizeof(VolumeDiskData)) {
+       res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
+       goto done;
+    }
 
 #ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
-    if (vp &&
-       (vp->header != NULL) &&
-       (V_attachFlags(vp) & VOL_HDR_ATTACHED) &&
-       (V_attachFlags(vp) & VOL_HDR_LOADED)) {
-       hdr_ok = 1;
-    }
 #else /* !AFS_DEMAND_ATTACH_FS */
     vp = VGetVolume_r(&error, vcom->vop->volume);
-    if (vp && vp->header) {
-       hdr_ok = 1;
-    }
-#endif /* !AFS_DEMAND_ATTACH_FS */
-
- load_done:
-    if (hdr_ok) {
-       assert(sizeof(VolumeDiskData) <= res->payload.len);
-       memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
-       res->hdr.response_len += sizeof(VolumeDiskData);
-#ifndef AFS_DEMAND_ATTACH_FS
-       VPutVolume_r(vp);
 #endif
-    } else {
-       if (vp) {
-           res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
+
+    if (vp) {
+       if (FSYNC_partMatch(vcom, vp, 1)) {
+#ifdef AFS_DEMAND_ATTACH_FS
+           if ((vp->header == NULL) ||
+               !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
+               !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
+               res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
+               goto cleanup;
+           }
+#else /* !AFS_DEMAND_ATTACH_FS */
+           if (!vp || !vp->header) {
+               res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
+               goto cleanup;
+           }
+#endif /* !AFS_DEMAND_ATTACH_FS */
        } else {
-           res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+           res->hdr.reason = FSYNC_WRONG_PART;
+           goto cleanup;
        }
-       code = SYNC_FAILED;
+    } else {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+       goto 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
+
+ done:
     return code;
 }
 
@@ -917,9 +1247,60 @@ FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 static afs_int32
-FSYNC_com_StatsOp(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;
+    Volume * vp;
+    Vnode * vnp;
+    Error error;
+
+    if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       return SYNC_COM_ERROR;
+    }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    vp = VLookupVolume_r(&error, qry->volume, NULL);
+#else /* !AFS_DEMAND_ATTACH_FS */
+    vp = VGetVolume_r(&error, qry->volume);
+#endif /* !AFS_DEMAND_ATTACH_FS */
+
+    if (!vp) {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+       code = SYNC_FAILED;
+       goto done;
+    }
+
+    vnp = VLookupVnode(vp, qry->vnode);
+    if (!vnp) {
+       res->hdr.reason = FSYNC_UNKNOWN_VNID;
+       code = SYNC_FAILED;
+       goto cleanup;
+    }
+
+    if (Vn_class(vnp)->residentSize > res->payload.len) {
+       res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
+       code = SYNC_FAILED;
+       goto cleanup;
+    }
+
+    memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
+    res->hdr.response_len += Vn_class(vnp)->residentSize;
+
+ cleanup:
+#ifndef AFS_DEMAND_ATTACH_FS
+    VPutVolume_r(vp);
+#endif
+
+ done:
+    return code;
+}
+
+static afs_int32
+FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
 {
-    int i;
     afs_int32 code = SYNC_OK;
     FSSYNC_StatsOp_command scom;
 
@@ -976,8 +1357,8 @@ static afs_int32
 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
-    struct DiskPartition * dp;
-    struct DiskPartitionStats * stats;
+    struct DiskPartition64 * dp;
+    struct DiskPartitionStats64 * stats;
 
     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
@@ -989,14 +1370,14 @@ FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
     if (!dp) {
        code = SYNC_FAILED;
     } else {
-       stats = (struct DiskPartitionStats *) res->payload.buf;
+       stats = (struct DiskPartitionStats64 *) res->payload.buf;
        stats->free = dp->free;
        stats->totalUsable = dp->totalUsable;
        stats->minFree = dp->minFree;
        stats->f_files = dp->f_files;
        stats->vol_list_len = dp->vol_list.len;
        
-       res->hdr.response_len += sizeof(struct DiskPartitionStats);
+       res->hdr.response_len += sizeof(struct DiskPartitionStats64);
     }
 
  done:
@@ -1051,15 +1432,54 @@ FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
 }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
+/**
+ * populate an FSSYNC_VolOp_info object from a command packet object.
+ *
+ * @param[in]   vcom  pointer to command packet
+ * @param[out]  info  pointer to info object which will be populated
+ *
+ * @note FSSYNC_VolOp_info objects are attached to Volume objects when
+ *       a volume operation is commenced.
+ *
+ * @internal
+ */
 static void
 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
 {
     memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
     memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
+    info->vol_op_state = FSSYNC_VolOpPending;
 }
 
+/**
+ * check whether command packet partition name matches volume 
+ * object's partition name.
+ *
+ * @param[in] vcom        pointer to command packet
+ * @param[in] vp          pointer to volume object
+ * @param[in] match_anon  anon matching control flag (see note below)
+ *
+ * @return whether partitions match
+ *   @retval 0  partitions do NOT match
+ *   @retval 1  partitions match
+ *
+ * @note if match_anon is non-zero, then this function will return a
+ *       positive match for a zero-length partition string in the
+ *       command packet.
+ *
+ * @internal
+ */
+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, 
+                    sizeof(vcom->vop->partName)) == 0));
+}
+
+
 static void
-FSYNC_Drop(int fd)
+FSYNC_Drop(osi_socket fd)
 {
     struct offlineInfo *p;
     int i;
@@ -1074,7 +1494,7 @@ FSYNC_Drop(int fd)
            Volume *vp;
 
            tvolName[0] = '/';
-           sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
+           sprintf(&tvolName[1], VFORMAT, afs_printable_uint32_lu(p[i].volumeID));
            vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
                                       V_VOLUPD);
            if (vp)
@@ -1095,30 +1515,30 @@ FSYNC_Drop(int fd)
 static int AcceptHandler = -1; /* handler id for accept, if turned on */
 
 static void
-AcceptOn()
+AcceptOn(void)
 {
     if (AcceptHandler == -1) {
-       assert(AddHandler(AcceptSd, FSYNC_newconnection));
-       AcceptHandler = FindHandler(AcceptSd);
+       assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
+       AcceptHandler = FindHandler(fssync_server_state.fd);
     }
 }
 
 static void
-AcceptOff()
+AcceptOff(void)
 {
     if (AcceptHandler != -1) {
-       assert(RemoveHandler(AcceptSd));
+       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;
     ObtainWriteLock(&FSYNC_handler_lock);
@@ -1129,6 +1549,24 @@ InitHandler()
     ReleaseWriteLock(&FSYNC_handler_lock);
 }
 
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static void
+CallHandler(struct pollfd *fds, int nfds, int mask)
+{
+    int i;
+    int handler;
+    ObtainReadLock(&FSYNC_handler_lock);
+    for (i = 0; i < nfds; i++) {
+        if (fds[i].revents & mask) {
+           handler = FindHandler_r(fds[i].fd);
+            ReleaseReadLock(&FSYNC_handler_lock);
+            (*HandlerProc[handler]) (fds[i].fd);
+           ObtainReadLock(&FSYNC_handler_lock);
+        }
+    }
+    ReleaseReadLock(&FSYNC_handler_lock);
+}
+#else
 static void
 CallHandler(fd_set * fdsetp)
 {
@@ -1143,9 +1581,10 @@ CallHandler(fd_set * fdsetp)
     }
     ReleaseReadLock(&FSYNC_handler_lock);
 }
+#endif
 
 static int
-AddHandler(int afd, int (*aproc) ())
+AddHandler(osi_socket afd, void (*aproc) (osi_socket))
 {
     register int i;
     ObtainWriteLock(&FSYNC_handler_lock);
@@ -1163,7 +1602,7 @@ AddHandler(int afd, int (*aproc) ())
 }
 
 static int
-FindHandler(register int afd)
+FindHandler(register osi_socket afd)
 {
     register int i;
     ObtainReadLock(&FSYNC_handler_lock);
@@ -1178,7 +1617,7 @@ FindHandler(register int afd)
 }
 
 static int
-FindHandler_r(register int afd)
+FindHandler_r(register osi_socket afd)
 {
     register int i;
     for (i = 0; i < MAXHANDLERS; i++)
@@ -1190,7 +1629,7 @@ FindHandler_r(register int afd)
 }
 
 static int
-RemoveHandler(register int afd)
+RemoveHandler(register osi_socket afd)
 {
     ObtainWriteLock(&FSYNC_handler_lock);
     HandlerFD[FindHandler_r(afd)] = -1;
@@ -1198,6 +1637,25 @@ RemoveHandler(register int afd)
     return 1;
 }
 
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static void
+GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
+{
+    int i;
+    int fdi = 0;
+    ObtainReadLock(&FSYNC_handler_lock);
+    for (i = 0; i < MAXHANDLERS; i++)
+       if (HandlerFD[i] != -1) {
+           assert(fdi<maxfds);
+           fds[fdi].fd = HandlerFD[i];
+           fds[fdi].events = events;
+           fds[fdi].revents = 0;
+           fdi++;
+       }
+    *nfds = fdi;
+    ReleaseReadLock(&FSYNC_handler_lock);
+}
+#else
 static void
 GetHandler(fd_set * fdsetp, int *maxfdp)
 {
@@ -1208,11 +1666,15 @@ GetHandler(fd_set * fdsetp, int *maxfdp)
     for (i = 0; i < MAXHANDLERS; i++)
        if (HandlerFD[i] != -1) {
            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 */
 }
+#endif /* HAVE_POLL && AFS_PTHREAD_ENV */
 
 #endif /* FSSYNC_BUILD_SERVER */