DAFS: Wait for exclusive ops in FSYNC_VOL_OFF
[openafs.git] / src / vol / fssync-server.c
index 7892842..c88b9f0 100644 (file)
@@ -43,8 +43,6 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -57,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
@@ -124,16 +123,16 @@ static SYNC_server_state_t fssync_server_state =
 
 /* Forward declarations */
 static void * FSYNC_sync(void *);
-static void FSYNC_newconnection(int afd);
-static void FSYNC_com(int fd);
-static void FSYNC_Drop(int fd);
+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(int fd, void (*aproc)(int));
-static int FindHandler(int afd);
-static int FindHandler_r(int afd);
-static int RemoveHandler(int afd);
+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);
@@ -143,7 +142,7 @@ 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);
@@ -159,9 +158,9 @@ 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_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);
 
@@ -224,7 +223,15 @@ FSYNC_sync(void * args)
     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 */
 
     SYNC_getAddr(&state->endpoint, &state->addr);
     SYNC_cleanupSock(state);
@@ -238,13 +245,15 @@ FSYNC_sync(void * args)
     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);
+    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. */
+    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();
 #else /* AFS_PTHREAD_ENV */
@@ -298,14 +307,14 @@ FSYNC_sync(void * args)
 }
 
 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 fd;
+    osi_socket fd;
     socklen_t junk;
     junk = sizeof(other);
     fd = accept(afd, (struct sockaddr *)&other, &junk);
@@ -321,7 +330,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;
@@ -361,7 +370,10 @@ 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;
     }
 
     res.hdr.com_seq = com.hdr.com_seq;
@@ -401,13 +413,15 @@ FSYNC_com(int fd)
 
  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;
@@ -504,7 +518,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;
 
@@ -577,7 +593,7 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     }
 #else /* !AFS_DEMAND_ATTACH_FS */
     tvolName[0] = '/';
-    snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_cast_uint32(vcom->vop->volume));
+    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,
@@ -626,8 +642,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     Volume * vp;
     Error error;
 #ifdef AFS_DEMAND_ATTACH_FS
-    int reserved = 0;
-    Volume *nvp;
+    Volume *nvp, *rvp = NULL;
 #endif
 
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
@@ -712,6 +727,12 @@ 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
@@ -765,8 +786,34 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
        /* convert to heavyweight ref */
        nvp = VGetVolumeByVp_r(&error, vp);
+       VCancelReservation_r(rvp);
+       rvp = NULL;
 
        if (!nvp) {
+            /*
+             * 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;
+                goto done;
+            default:
+                break;
+            }
+
            Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
                vcom->vop->volume);
            res->hdr.reason = FSYNC_VOL_PKG_ERROR;
@@ -828,12 +875,18 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
            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;
 }
 
 /**
@@ -901,7 +954,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;
     }
@@ -1184,17 +1239,17 @@ 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;
@@ -1203,10 +1258,12 @@ FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
     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;
@@ -1239,7 +1296,7 @@ FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 #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;
@@ -1291,7 +1348,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;
@@ -1471,7 +1528,7 @@ FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
 
 
 static void
-FSYNC_Drop(int fd)
+FSYNC_Drop(osi_socket fd)
 {
     struct offlineInfo *p;
     int i;
@@ -1486,7 +1543,7 @@ FSYNC_Drop(int fd)
            Volume *vp;
 
            tvolName[0] = '/';
-           sprintf(&tvolName[1], VFORMAT, afs_cast_uint32(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)
@@ -1526,8 +1583,8 @@ AcceptOff(void)
 
 /* The multiple FD handling code. */
 
-static int HandlerFD[MAXHANDLERS];
-static void (*HandlerProc[MAXHANDLERS]) (int);
+static osi_socket HandlerFD[MAXHANDLERS];
+static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
 
 static void
 InitHandler(void)
@@ -1576,7 +1633,7 @@ CallHandler(fd_set * fdsetp)
 #endif
 
 static int
-AddHandler(int afd, void (*aproc) (int))
+AddHandler(osi_socket afd, void (*aproc) (osi_socket))
 {
     register int i;
     ObtainWriteLock(&FSYNC_handler_lock);
@@ -1594,7 +1651,7 @@ AddHandler(int afd, void (*aproc) (int))
 }
 
 static int
-FindHandler(register int afd)
+FindHandler(register osi_socket afd)
 {
     register int i;
     ObtainReadLock(&FSYNC_handler_lock);
@@ -1609,7 +1666,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++)
@@ -1621,7 +1678,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;
@@ -1658,8 +1715,11 @@ 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 */