]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
vol: Add VGetVolumeTimed
authorAndrew Deason <adeason@sinenomine.net>
Wed, 27 Oct 2010 22:34:40 +0000 (17:34 -0500)
committerDerrick Brashear <shadow@dementix.org>
Wed, 14 Dec 2011 20:53:47 +0000 (12:53 -0800)
Replace the VGetVolumeNoWait interface with the more general
VGetVolumeTimed interface, which allows for waiting for offlining
volume for arbitrary amounts of time (instead of just "waiting
forever" or "not waiting at all"). Also add VOL_CV_TIMEDWAIT and
VTimedWaitStateChange_r as necessary to implement this.

Reviewed-on: http://gerrit.openafs.org/3214
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
(cherry picked from commit db6ee95864a8fc5f33b7e95c19c8ff5058d37e92)

Change-Id: I6c7b3a0b9fe174ebffeb03153dda1c4705d7dac5
Reviewed-on: http://gerrit.openafs.org/6264
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementix.org>
src/viced/afsfileprocs.c
src/vol/volume.c
src/vol/volume.h
src/vol/volume_inline.h

index 4adcd1973bbb1659b0b8a81bf517254a52f94b28..b7319b8df5f0b08ace809c0ef0b588dabac12bbc 100644 (file)
@@ -549,9 +549,15 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
                VRESTARTING
 #endif
                ;
+#ifdef AFS_PTHREAD_ENV
+           static const struct timespec timeout_ts = { 0, 0 };
+           static const struct timespec * const ts = &timeout_ts;
+#else
+           static const struct timespec * const ts = NULL;
+#endif
 
            errorCode = 0;
-           *volptr = VGetVolumeNoWait(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
+           *volptr = VGetVolumeTimed(&local_errorCode, &errorCode, (afs_int32) fid->Volume, ts);
            if (!errorCode) {
                osi_Assert(*volptr);
                break;
index c7cca3f10831e1927558a5fcbabfaf821820e862..37c2e44e5ba8c217fa57a3b604d39ccdb0cb852f 100644 (file)
@@ -199,7 +199,8 @@ static void VCloseVolumeHandles_r(Volume * vp);
 static void LoadVolumeHeader(Error * ec, Volume * vp);
 static int VCheckOffline(Volume * vp);
 static int VCheckDetach(Volume * vp);
-static Volume * GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint, int flags);
+static Volume * GetVolume(Error * ec, Error * client_ec, VolId volumeId,
+                          Volume * hint, const struct timespec *ts);
 
 int LogLevel;                  /* Vice loglevel--not defined as extern so that it will be
                                 * defined when not linked with vice, XXXX */
@@ -3504,6 +3505,46 @@ VHold_r(Volume * vp)
 }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
+/**** volume timeout-related stuff ****/
+
+#ifdef AFS_PTHREAD_ENV
+
+static_inline int
+VTimedOut(const struct timespec *ts)
+{
+    struct timeval tv;
+    int code;
+
+    if (ts->tv_sec == 0) {
+       /* short-circuit; this will have always timed out */
+       return 1;
+    }
+
+    code = gettimeofday(&tv, NULL);
+    if (code) {
+       Log("Error %d from gettimeofday, assuming we have not timed out\n", errno);
+       /* assume no timeout; failure mode is we just wait longer than normal
+        * instead of returning errors when we shouldn't */
+       return 0;
+    }
+
+    if (tv.tv_sec < ts->tv_sec ||
+        (tv.tv_sec == ts->tv_sec && tv.tv_usec*1000 < ts->tv_nsec)) {
+
+       return 0;
+    }
+
+    return 1;
+}
+
+#else /* AFS_PTHREAD_ENV */
+
+/* Waiting a certain amount of time for offlining volumes is not supported
+ * for LWP due to a lack of primitives. So, we never time out */
+# define VTimedOut(x) (0)
+
+#endif /* !AFS_PTHREAD_ENV */
+
 #if 0
 static int
 VHold(Volume * vp)
@@ -3574,14 +3615,16 @@ VGetVolume(Error * ec, Error * client_ec, VolId volumeId)
     return retVal;
 }
 
-/* same as VGetVolume, but if a volume is waiting to go offline, we return
- * that it is actually offline, instead of waiting for it to go offline */
+/* same as VGetVolume, but if a volume is waiting to go offline, we only wait
+ * until time ts. If we have waited longer than that, we return that it is
+ * actually offline, instead of waiting for it to go offline */
 Volume *
-VGetVolumeNoWait(Error * ec, Error * client_ec, VolId volumeId)
+VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId,
+                const struct timespec *ts)
 {
     Volume *retVal;
     VOL_LOCK;
-    retVal = GetVolume(ec, client_ec, volumeId, NULL, 1);
+    retVal = GetVolume(ec, client_ec, volumeId, NULL, ts);
     VOL_UNLOCK;
     return retVal;
 }
@@ -3589,7 +3632,7 @@ VGetVolumeNoWait(Error * ec, Error * client_ec, VolId volumeId)
 Volume *
 VGetVolume_r(Error * ec, VolId volumeId)
 {
-    return GetVolume(ec, NULL, volumeId, NULL, 0);
+    return GetVolume(ec, NULL, volumeId, NULL, NULL);
 }
 
 /* try to get a volume we've previously looked up */
@@ -3597,7 +3640,7 @@ VGetVolume_r(Error * ec, VolId volumeId)
 Volume *
 VGetVolumeByVp_r(Error * ec, Volume * vp)
 {
-    return GetVolume(ec, NULL, vp->hashid, vp, 0);
+    return GetVolume(ec, NULL, vp->hashid, vp, NULL);
 }
 
 /**
@@ -3607,17 +3650,24 @@ VGetVolumeByVp_r(Error * ec, Volume * vp)
  * @param[out] client_ec  wire error code to be given to clients
  * @param[in]  volumeId   ID of the volume we want
  * @param[in]  hint       optional hint for hash lookups, or NULL
- * @param[in]  nowait     0 to wait for a 'goingOffline' volume to go offline
- *                        before returning, 1 to return immediately
+ * @param[in]  timeout    absolute deadline for waiting for the volume to go
+ *                        offline, if it is going offline. NULL to wait forever.
  *
  * @return a volume handle for the specified volume
  *  @retval NULL an error occurred, or the volume is in such a state that
  *               we cannot load a header or return any volume struct
  *
  * @note for DAFS, caller must NOT hold a ref count on 'hint'
+ *
+ * @note 'timeout' is only checked if the volume is actually going offline; so
+ *       if you pass timeout->tv_sec = 0, this will exhibit typical
+ *       nonblocking behavior.
+ *
+ * @note for LWP builds, 'timeout' must be NULL
  */
 static Volume *
-GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint, int nowait)
+GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
+          const struct timespec *timeout)
 {
     Volume *vp = hint;
     /* pull this profiling/debugging code out of regular builds */
@@ -3877,19 +3927,26 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint, int nowa
 
        if (programType == fileServer) {
            VGET_CTR_INC(V9);
-           if (vp->goingOffline && !nowait) {
-               VGET_CTR_INC(V10);
+           if (vp->goingOffline) {
+               if (timeout && VTimedOut(timeout)) {
+                   /* we've timed out; don't wait for the vol */
+               } else {
+                   VGET_CTR_INC(V10);
 #ifdef AFS_DEMAND_ATTACH_FS
-               /* wait for the volume to go offline */
-               if (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) {
-                   VWaitStateChange_r(vp);
-               }
+                   /* wait for the volume to go offline */
+                   if (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) {
+                       VTimedWaitStateChange_r(vp, timeout, NULL);
+                   }
 #elif defined(AFS_PTHREAD_ENV)
-               VOL_CV_WAIT(&vol_put_volume_cond);
+                   VOL_CV_TIMEDWAIT(&vol_put_volume_cond, timeout, NULL);
 #else /* AFS_PTHREAD_ENV */
-               LWP_WaitProcess(VPutVolume);
+                   /* LWP has no timed wait, so the caller better not be
+                    * expecting one */
+                   osi_Assert(!timeout);
+                   LWP_WaitProcess(VPutVolume);
 #endif /* AFS_PTHREAD_ENV */
-               continue;
+                   continue;
+               }
            }
            if (vp->specialStatus) {
                VGET_CTR_INC(V11);
index 89ff9eea372cd8673fd48596e40f85d1635c8675..3e0031422ae4b06600cac76a9a1392a0fdf6da83 100644 (file)
@@ -95,6 +95,37 @@ extern pthread_t vol_glock_holder;
 #define VOL_UNLOCK MUTEX_EXIT(&vol_glock_mutex)
 #define VOL_CV_WAIT(cv) CV_WAIT((cv), &vol_glock_mutex)
 #endif /* !VOL_LOCK_DEBUG */
+
+/**
+ * @param[in] cv cond var
+ * @param[in] ts deadline, or NULL to wait forever
+ * @param[out] timedout  set to 1 if we returned due to the deadline, 0 if we
+ *                       returned due to the cond var getting signalled. If
+ *                       NULL, it is ignored.
+ */
+static_inline void
+VOL_CV_TIMEDWAIT(pthread_cond_t *cv, const struct timespec *ts, int *timedout)
+{
+    int code;
+    if (timedout) {
+       *timedout = 0;
+    }
+    if (!ts) {
+       VOL_CV_WAIT(cv);
+       return;
+    }
+    VOL_LOCK_DBG_CV_WAIT_BEGIN;
+    code = CV_TIMEDWAIT(cv, &vol_glock_mutex, ts);
+    VOL_LOCK_DBG_CV_WAIT_END;
+    if (code == ETIMEDOUT) {
+       code = 0;
+       if (timedout) {
+           *timedout = 1;
+       }
+    }
+    osi_Assert(code == 0);
+}
+
 #define VSALVSYNC_LOCK MUTEX_ENTER(&vol_salvsync_mutex)
 #define VSALVSYNC_UNLOCK MUTEX_EXIT(&vol_salvsync_mutex)
 #define VTRANS_LOCK MUTEX_ENTER(&vol_trans_mutex)
@@ -767,7 +798,8 @@ struct volHeader {
 extern char *VSalvageMessage;  /* Canonical message when a volume is forced
                                 * offline */
 extern Volume *VGetVolume(Error * ec, Error * client_ec, VolId volumeId);
-extern Volume *VGetVolumeNoWait(Error * ec, Error * client_ec, VolId volumeId);
+extern Volume *VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId,
+                               const struct timespec *ts);
 extern Volume *VGetVolume_r(Error * ec, VolId volumeId);
 extern void VPutVolume(Volume *);
 extern void VPutVolume_r(Volume *);
index 5145824685a23c829cf1bf95dcb9c8e71196c1b9..445dc3bf22ed6aad8aae7930b750c28b526d7099 100644 (file)
@@ -424,6 +424,47 @@ VWaitStateChange_r(Volume * vp)
     osi_Assert(V_attachState(vp) != VOL_STATE_FREED);
 }
 
+/**
+ * wait for the volume to change states within a certain amount of time
+ *
+ * @param[in] vp  volume object pointer
+ * @param[in] ts  deadline (absolute time) or NULL to wait forever
+ *
+ * @pre VOL_LOCK held; ref held on volume
+ * @post VOL_LOCK held; volume state has changed and/or it is after the time
+ *       specified in ts
+ *
+ * @note DEMAND_ATTACH_FS only
+ * @note if ts is NULL, this is identical to VWaitStateChange_r
+ */
+static_inline void
+VTimedWaitStateChange_r(Volume * vp, const struct timespec *ts, int *atimedout)
+{
+    VolState state_save;
+    int timeout;
+
+    if (atimedout) {
+       *atimedout = 0;
+    }
+
+    if (!ts) {
+       VWaitStateChange_r(vp);
+       return;
+    }
+
+    state_save = V_attachState(vp);
+
+    assert(vp->nWaiters || vp->nUsers);
+    do {
+       VOL_CV_TIMEDWAIT(&V_attachCV(vp), ts, &timeout);
+    } while (V_attachState(vp) == state_save && !timeout);
+    assert(V_attachState(vp) != VOL_STATE_FREED);
+
+    if (atimedout && timeout) {
+       *atimedout = 1;
+    }
+}
+
 /**
  * wait for blocking ops to end.
  *