vol: allow non-dafs volume utils to attach with V_READONLY again
[openafs.git] / src / vol / volume_inline.h
index acdc21d..1fc8855 100644 (file)
 #include "volume.h"
 #include "partition.h"
 
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
 # include "lock.h"
 #endif
 
+#ifdef AFS_PTHREAD_ENV
+
+#include <afs/opr_assert.h>
+
+/**
+ * @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 = opr_cv_timedwait(cv, &vol_glock_mutex, ts);
+    VOL_LOCK_DBG_CV_WAIT_END;
+    if (code == ETIMEDOUT) {
+       code = 0;
+       if (timedout) {
+           *timedout = 1;
+       }
+    }
+    opr_Assert(code == 0);
+}
+#endif /* AFS_PTHREAD_ENV */
+
 /**
  * tell caller whether the given program type represents a salvaging
  * program.
@@ -53,7 +88,7 @@ VIsSalvager(ProgramType type)
 static_inline int
 VRequiresPartLock(void)
 {
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
     return 0;
 #else
     switch (programType) {
@@ -63,7 +98,7 @@ VRequiresPartLock(void)
     default:
         return 0;
     }
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 }
 
 /**
@@ -93,8 +128,8 @@ VMustCheckoutVolume(int mode)
  * (or put it in an error state) if we detect that another program
  * claims to be using the volume when we try to attach. We don't always
  * want to do that, since sometimes we know that the volume may be in
- * use by another program, e.g. when we are attaching with V_PEEK, and
- * we don't care.
+ * use by another program, e.g. when we are attaching with V_PEEK
+ * or attaching for only reading (V_READONLY).
  *
  * @param mode  the mode of attachment for the volume
  *
@@ -112,14 +147,29 @@ VShouldCheckInUse(int mode)
        return 1;
     }
     if (VMustCheckoutVolume(mode)) {
-       /* assume we checked out the volume from the fileserver, so inUse
-        * should not be set */
-       return 1;
+       /*
+        * Before VShouldCheckInUse() was called, the caller checked out the
+        * volume from the fileserver. The volume may not be in use by the
+        * fileserver, or another program, at this point. The caller should
+        * verify by checking inUse is not set, otherwise the volume state
+        * is in error.
+        *
+        * However, an exception is made for the V_READONLY attach mode.  The
+        * volume may still be in use by the fileserver when a caller has
+        * checked out the volume from the fileserver with the V_READONLY
+        * attach mode, and so it is not an error for the inUse field to be set
+        * at this point. The caller should not check the inUse and may
+        * not change any volume state.
+        */
+       if (mode == V_READONLY) {
+           return 0; /* allowed to be inUse; do not check */
+       }
+       return 1; /* may not be inUse; check */
     }
     return 0;
 }
 
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
 /**
  * acquire a non-blocking disk lock for a particular volume id.
  *
@@ -187,7 +237,7 @@ VCanUnlockAttached(void)
  * read lock, or if we do not need to lock it at all, when attaching.
  *
  * @param[in]  mode  volume attachment mode
- * @param[in]  writeable  1 if the volume is writable, 0 if not
+ * @param[in]  writable  1 if the volume is writable, 0 if not
  *
  * @return how we need to lock the vol header
  *  @retval 0 do not lock the vol header at all
@@ -197,11 +247,11 @@ VCanUnlockAttached(void)
  * @note DAFS only (non-DAFS uses partition locks)
  */
 static_inline int
-VVolLockType(int mode, int writeable)
+VVolLockType(int mode, int writable)
 {
     switch (programType) {
     case fileServer:
-       if (writeable) {
+       if (writable) {
            return WRITE_LOCK;
        }
        return READ_LOCK;
@@ -224,7 +274,7 @@ VVolLockType(int mode, int writeable)
 
        case V_CLONE:
        case V_DUMP:
-           if (writeable) {
+           if (writable) {
                return WRITE_LOCK;
            }
            return READ_LOCK;
@@ -233,11 +283,45 @@ VVolLockType(int mode, int writeable)
            return 0;
 
        default:
-           assert(0 /* unknown checkout mode */);
+           opr_Assert(0 /* unknown checkout mode */);
            return 0;
        }
     }
 }
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+
+/**
+ * tells caller whether or not the volume is effectively salvaging.
+ *
+ * @param vp  volume pointer
+ *
+ * @return whether volume is salvaging or not
+ *  @retval 0 no, volume is not salvaging
+ *  @retval 1 yes, volume is salvaging
+ *
+ * @note The volume may not actually be getting salvaged at the moment if
+ *       this returns 1, but may have just been requested or scheduled to be
+ *       salvaged. Callers should treat these cases as pretty much the same
+ *       anyway, since we should not touch a volume that is busy salvaging or
+ *       waiting to be salvaged.
+ */
+static_inline int
+VIsSalvaging(struct Volume *vp)
+{
+    /* these tests are a bit redundant, but to be safe... */
+    switch(V_attachState(vp)) {
+    case VOL_STATE_SALVAGING:
+    case VOL_STATE_SALVAGE_REQ:
+       return 1;
+    default:
+       if (vp->salvage.requested || vp->salvage.scheduled) {
+           return 1;
+       }
+    }
+    return 0;
+}
 
 /**
  * tells caller whether or not the current state requires
@@ -268,6 +352,7 @@ VIsExclusiveState(VolState state)
     case VOL_STATE_VNODE_CLOSE:
     case VOL_STATE_VNODE_RELEASE:
     case VOL_STATE_VLRU_ADD:
+    case VOL_STATE_SCANNING_RXCALLS:
        return 1;
     default:
        return 0;
@@ -291,6 +376,7 @@ VIsErrorState(VolState state)
     switch (state) {
     case VOL_STATE_ERROR:
     case VOL_STATE_SALVAGING:
+    case VOL_STATE_SALVAGE_REQ:
        return 1;
     default:
        return 0;
@@ -382,11 +468,52 @@ VWaitStateChange_r(Volume * vp)
 {
     VolState state_save = V_attachState(vp);
 
-    assert(vp->nWaiters || vp->nUsers);
+    opr_Assert(vp->nWaiters || vp->nUsers);
     do {
        VOL_CV_WAIT(&V_attachCV(vp));
     } while (V_attachState(vp) == state_save);
+    opr_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;
+    }
 }
 
 /**
@@ -403,11 +530,11 @@ VWaitStateChange_r(Volume * vp)
 static_inline void
 VWaitExclusiveState_r(Volume * vp)
 {
-    assert(vp->nWaiters || vp->nUsers);
+    opr_Assert(vp->nWaiters || vp->nUsers);
     while (VIsExclusiveState(V_attachState(vp))) {
        VOL_CV_WAIT(&V_attachCV(vp));
     }
-    assert(V_attachState(vp) != VOL_STATE_FREED);
+    opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
 }
 
 /**
@@ -435,16 +562,14 @@ VChangeState_r(Volume * vp, VolState new_state)
     VStats.state_levels[new_state]++;
 
     V_attachState(vp) = new_state;
-    assert(pthread_cond_broadcast(&V_attachCV(vp)) == 0);
+    opr_cv_broadcast(&V_attachCV(vp));
     return old_state;
 }
 
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 #define VENUMCASE(en) \
-    case en: \
-        return #en; \
-        break
+    case en: return #en
 
 /**
  * translate a ProgramType code to a string.