salvager: Do not AskOnline nonexistent volumes
[openafs.git] / src / vol / fssync-server.c
index 98f30c7..d163442 100644 (file)
@@ -43,6 +43,7 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
+#include <roken.h>
 
 #include <sys/types.h>
 #include <stdio.h>
 #include <unistd.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 <afs/afs_assert.h>
 #include <signal.h>
 #include <string.h>
 
@@ -118,7 +115,7 @@ static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
  * fssync server socket handle.
  */
 static SYNC_server_state_t fssync_server_state =
-    { -1,                       /* file descriptor */
+    { OSI_NULLSOCKET,                       /* file descriptor */
       FSSYNC_ENDPOINT_DECL,     /* server endpoint */
       FSYNC_PROTO_VERSION,      /* protocol version */
       5,                        /* bind() retry limit */
@@ -222,19 +219,19 @@ 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);
-    assert(pthread_cond_init(&fsync_salv.cv, NULL) == 0);
-    assert(pthread_create(&tid, &tattr, FSYNC_salvageThread, NULL) == 0);
+    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 */
 }
 
@@ -268,7 +265,7 @@ FSYNC_sync(void * args)
 
     /* we must not be called before vol package initialization, since we use
      * vol package mutexes and conds etc */
-    assert(VInit);
+    osi_Assert(VInit);
 
     SYNC_getAddr(&state->endpoint, &state->addr);
     SYNC_cleanupSock(state);
@@ -302,7 +299,7 @@ FSYNC_sync(void * args)
 
     state->fd = SYNC_getSock(&state->endpoint);
     code = SYNC_bindSock(state);
-    assert(!code);
+    osi_Assert(!code);
 
 #ifdef AFS_DEMAND_ATTACH_FS
     /*
@@ -317,10 +314,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();
-    assert(code == 0);
+    osi_Assert(code == 0);
 #endif
 
     InitHandler();
@@ -430,7 +427,7 @@ FSYNC_backgroundSalvage(Volume *vp)
     }
 
     queue_Append(&fsync_salv.head, node);
-    assert(pthread_cond_broadcast(&fsync_salv.cv) == 0);
+    CV_BROADCAST(&fsync_salv.cv);
 }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
@@ -446,12 +443,12 @@ FSYNC_newconnection(osi_socket afd)
     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));
     }
 }
 
@@ -530,8 +527,8 @@ FSYNC_com(osi_socket fd)
     case FSYNC_VOL_DONE:
     case FSYNC_VOL_QUERY:
     case FSYNC_VOL_QUERY_HDR:
-    case FSYNC_VOL_QUERY_VOP:
 #ifdef AFS_DEMAND_ATTACH_FS
+    case FSYNC_VOL_QUERY_VOP:
     case FSYNC_VG_QUERY:
     case FSYNC_VG_SCAN:
     case FSYNC_VG_SCAN_ALL:
@@ -731,6 +728,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)) {
@@ -745,9 +746,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;
     }
@@ -758,10 +764,14 @@ 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] = '/';
+    tvolName[0] = OS_DIRSEPC;
     snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_uint32_lu(vcom->vop->volume));
     tvolName[sizeof(tvolName)-1] = '\0';
 
@@ -926,14 +936,22 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
            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 (V_attachState(vp) == VOL_STATE_SALVAGING ||
-               vp->salvage.requested) {
-
+            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;
@@ -962,6 +980,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        case VOL_STATE_PREATTACHED:
        case VOL_STATE_SALVAGING:
        case VOL_STATE_ERROR:
+       case VOL_STATE_DELETED:
            /* register the volume operation metadata with the volume
             *
             * if the volume is currently pre-attached, attach2()
@@ -976,9 +995,6 @@ 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
@@ -992,6 +1008,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
             case VOL_STATE_PREATTACHED:
             case VOL_STATE_SALVAGING:
             case VOL_STATE_ERROR:
+            case VOL_STATE_DELETED:
                 /* register the volume operation metadata with the volume
                  *
                  * if the volume is currently pre-attached, attach2()
@@ -1004,8 +1021,8 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                 break;
             }
 
-           Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
-               vcom->vop->volume);
+           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) {
@@ -1014,6 +1031,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);
 
@@ -1051,15 +1072,18 @@ 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);
+                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
@@ -1210,8 +1234,12 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     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)) {
+               (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. */
@@ -1219,14 +1247,24 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                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;
@@ -1305,6 +1343,9 @@ FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        if (FSYNC_partMatch(vcom, vp, 0)) {
            /* null out salvsync control state, as it's no longer relevant */
            memset(&vp->salvage, 0, sizeof(vp->salvage));
+
+           VCreateReservation_r(vp);
+           VWaitExclusiveState_r(vp);
             VDeregisterVolOp_r(vp);
 
             if (vcom->hdr->reason == FSYNC_SALVAGE) {
@@ -1313,6 +1354,9 @@ FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                VChangeState_r(vp, VOL_STATE_ERROR);
             }
 
+           VCancelReservation_r(vp);
+           vp = NULL;
+
            code = SYNC_OK;
        } else {
            res->hdr.reason = FSYNC_WRONG_PART;
@@ -1505,14 +1549,16 @@ FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
 
     if (vp && vp->pending_vol_op) {
-       assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
+       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) {
-           res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
-       } 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;
     }
@@ -1537,7 +1583,7 @@ FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
        goto done;
     }
 
-    assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
+    osi_Assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
 
     rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
     switch (rc) {
@@ -1924,7 +1970,7 @@ FSYNC_Drop(osi_socket fd)
 
            Volume *vp;
 
-           tvolName[0] = '/';
+           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);
@@ -1949,7 +1995,7 @@ static void
 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);
     }
 }
@@ -1958,7 +2004,7 @@ static void
 AcceptOff(void)
 {
     if (AcceptHandler != -1) {
-       assert(RemoveHandler(fssync_server_state.fd));
+       osi_Assert(RemoveHandler(fssync_server_state.fd));
        AcceptHandler = -1;
     }
 }
@@ -1974,7 +2020,7 @@ InitHandler(void)
     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);
@@ -2020,7 +2066,7 @@ AddHandler(osi_socket afd, void (*aproc) (osi_socket))
     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);
@@ -2043,7 +2089,7 @@ FindHandler(osi_socket afd)
            return i;
        }
     ReleaseReadLock(&FSYNC_handler_lock);      /* just in case */
-    assert(1 == 2);
+    osi_Assert(1 == 2);
     return -1;                 /* satisfy compiler */
 }
 
@@ -2055,7 +2101,7 @@ FindHandler_r(osi_socket afd)
        if (HandlerFD[i] == afd) {
            return i;
        }
-    assert(1 == 2);
+    osi_Assert(1 == 2);
     return -1;                 /* satisfy compiler */
 }
 
@@ -2063,7 +2109,7 @@ static int
 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;
 }
@@ -2076,8 +2122,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;
@@ -2095,7 +2141,7 @@ GetHandler(fd_set * fdsetp, int *maxfdp)
     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);
 #ifndef AFS_NT40_ENV
             /* On Windows the nfds parameter to select() is ignored */