DAFS: Avoid unnecessary preattach on FSYNC_VOL_ON
[openafs.git] / src / vol / fssync-server.c
index ab9afc9..14d2247 100644 (file)
 #include <afsconfig.h>
 #include <afs/param.h>
 
-
-#include <sys/types.h>
-#include <stdio.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#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>
-#include <unistd.h>
-#endif
-#include <errno.h>
-#include <afs/afs_assert.h>
-#include <signal.h>
-#include <string.h>
+#include <roken.h>
 
 #include <rx/xdr.h>
 #include <afs/afsint.h>
@@ -275,9 +255,9 @@ FSYNC_sync(void * args)
 
 #ifdef AFS_PTHREAD_ENV
     /* set our 'thread-id' so that the host hold table works */
-    tid = rx_NewThreadId();
-    pthread_setspecific(rx_thread_id_key, (void *)(intptr_t)tid);
+    tid = rx_SetThreadNum();
     Log("Set thread id %d for FSYNC_sync\n", tid);
+    afs_pthread_setname_self("FSYNC_sync");
 #endif /* AFS_PTHREAD_ENV */
 
     VOL_LOCK;
@@ -330,12 +310,17 @@ 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 */
@@ -526,8 +511,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:
@@ -689,6 +674,7 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     Volume * vp;
     Error error;
 
+    /* Verify the partition name is null terminated. */
     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
        code = SYNC_FAILED;
@@ -698,6 +684,13 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
     /* so, we need to attach the volume */
 
 #ifdef AFS_DEMAND_ATTACH_FS
+    /* Verify the partition name is not empty. */
+    if (*vcom->vop->partName == 0) {
+       res->hdr.reason = FSYNC_BAD_PART;
+       code = SYNC_FAILED;
+       goto done;
+    }
+
     /* check DAFS permissions */
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
     if (vp &&
@@ -727,6 +720,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)) {
@@ -741,23 +738,47 @@ 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;
     }
 
 #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 &&
+        FSYNC_partMatch(vcom, vp, 0) &&
+        vp->pending_vol_op &&
+        vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningOnline &&
+        V_attachState(vp) == VOL_STATE_ATTACHED) {
+
+       /* noop; the volume stayed online for the volume operation and we were
+        * simply told that the vol op is done. The vp we already have is fine,
+        * so avoid confusing volume routines with trying to preattach an
+        * attached volume. */
+
+    } else {
+       /* first, check to see whether we have such a volume defined */
+       vp = VPreAttachVolumeById_r(&error,
+                                   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';
 
@@ -765,11 +786,11 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
                               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;
@@ -916,6 +937,7 @@ FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
         */
        switch (type) {
        case salvageServer:
+       case volumeSalvager:
            /* it is possible for the salvageserver to checkout a
             * volume for salvage before its scheduling request
             * has been sent to the salvageserver */
@@ -966,7 +988,6 @@ 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()
@@ -974,6 +995,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;
@@ -994,7 +1018,6 @@ 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()
@@ -1002,13 +1025,16 @@ 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;
             }
 
-           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) {
@@ -1058,15 +1084,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) {
                 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
@@ -1217,8 +1246,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. */
@@ -1226,14 +1259,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;
@@ -1310,16 +1353,21 @@ FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
     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));
+           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;
@@ -1511,18 +1559,34 @@ 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) {
-       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;
+       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;
 }
 
@@ -1931,7 +1995,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);
@@ -1942,11 +2006,7 @@ FSYNC_Drop(osi_socket fd)
     }
     VOL_UNLOCK;
     RemoveHandler(fd);
-#ifdef AFS_NT40_ENV
-    closesocket(fd);
-#else
-    close(fd);
-#endif
+    rk_closesocket(fd);
     AcceptOn();
 }