DAFS: Do not transition to ERROR on trivial errors
[openafs.git] / src / vol / volume.c
index afd2bf4..1069edc 100644 (file)
@@ -22,6 +22,7 @@
 #include <afs/param.h>
 
 #include <roken.h>
+#include <afs/opr.h>
 
 #include <ctype.h>
 #include <stddef.h>
 #include "partition.h"
 #include "volume_inline.h"
 #include "common.h"
-#include "afs/afs_assert.h"
 #include "vutils.h"
 #include <afs/dir.h>
 
@@ -479,6 +479,8 @@ VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
     opts->interrupt_rxcall = NULL;
     opts->offline_timeout = -1;
     opts->offline_shutdown_timeout = -1;
+    opts->usage_threshold = 128;
+    opts->usage_rate_limit = 5;
 
 #ifdef FAST_RESTART
     opts->unsafe_attach = 1;
@@ -2781,7 +2783,7 @@ attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
         SYNC_response res;
         memset(&res, 0, sizeof(res));
 
-       if (FSYNC_VolOp(volid, VPartitionPath(partp), FSYNC_VOL_NEEDVOLUME, mode, &res)
+       if (FSYNC_VolOp(volid, partp->name, FSYNC_VOL_NEEDVOLUME, mode, &res)
            != SYNC_OK) {
 
             if (res.hdr.reason == FSYNC_SALVAGE) {
@@ -2917,7 +2919,7 @@ attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
 #if defined(AFS_DEMAND_ATTACH_FS) && defined(FSSYNC_BUILD_CLIENT)
     if (!peek && *ec == 0 && retry == 0 && VMustCheckoutVolume(mode)) {
 
-       code = FSYNC_VerifyCheckout(volid, VPartitionPath(partp), FSYNC_VOL_NEEDVOLUME, mode);
+       code = FSYNC_VerifyCheckout(volid, partp->name, FSYNC_VOL_NEEDVOLUME, mode);
 
        if (code == SYNC_DENIED) {
            /* must retry checkout; fileserver no longer thinks we have
@@ -3112,7 +3114,8 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
     if (*ec == VNOVOL) {
        /* if the volume doesn't exist, skip straight to 'error' so we don't
         * request a salvage */
-       goto unlocked_error;
+       VOL_LOCK;
+       goto error_notbroken;
     }
 
     if (!*ec) {
@@ -3200,14 +3203,14 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
        if (!VCanScheduleSalvage()) {
            Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%u\n", path, *ec);
        }
-       VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                 VOL_SALVAGE_NO_OFFLINE);
+       VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
        vp->nUsers = 0;
 
        goto locked_error;
     } else if (*ec) {
        /* volume operation in progress */
-       goto unlocked_error;
+       VOL_LOCK;
+       goto error_notbroken;
     }
 #else /* AFS_DEMAND_ATTACH_FS */
     if (*ec) {
@@ -3224,8 +3227,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
        if (!VCanScheduleSalvage()) {
            Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
        }
-       VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                  VOL_SALVAGE_NO_OFFLINE);
+       VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
        vp->nUsers = 0;
 
 #else /* AFS_DEMAND_ATTACH_FS */
@@ -3247,8 +3249,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
        if (!VCanScheduleSalvage()) {
            Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
        }
-       VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                  VOL_SALVAGE_NO_OFFLINE);
+       VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
        vp->nUsers = 0;
 
 #else /* AFS_DEMAND_ATTACH_FS */
@@ -3270,8 +3271,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
 
 #if defined(AFS_DEMAND_ATTACH_FS)
        /* schedule a salvage so the volume goes away on disk */
-       VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                 VOL_SALVAGE_NO_OFFLINE);
+       VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
        VChangeState_r(vp, VOL_STATE_ERROR);
        vp->nUsers = 0;
        forcefree = 1;
@@ -3289,8 +3289,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
            VGetBitmap_r(ec, vp, i);
            if (*ec) {
 #ifdef AFS_DEMAND_ATTACH_FS
-               VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                         VOL_SALVAGE_NO_OFFLINE);
+               VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
                vp->nUsers = 0;
 #endif /* AFS_DEMAND_ATTACH_FS */
                Log("VAttachVolume: error getting bitmap for volume (%s)\n",
@@ -3338,8 +3337,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
                "%lu; needs salvage\n", (int)*ec,
                afs_printable_uint32_lu(V_id(vp)));
 #ifdef AFS_DEMAND_ATTACH_FS
-           VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER |
-                                                     VOL_SALVAGE_NO_OFFLINE);
+           VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
            vp->nUsers = 0;
 #else /* !AFS_DEMAND_ATTACH_FS */
            *ec = VSALVAGE;
@@ -3378,7 +3376,7 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
 #ifdef AFS_DEMAND_ATTACH_FS
                error_state = VOL_STATE_ERROR;
                /* see if we can recover */
-               VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_INVALIDATE_HEADER);
+               VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, 0 /*flags*/);
 #endif
            }
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -3411,7 +3409,10 @@ attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
 
     return vp;
 
+#ifndef AFS_DEMAND_ATTACH_FS
 unlocked_error:
+#endif
+
     VOL_LOCK;
 locked_error:
 #ifdef AFS_DEMAND_ATTACH_FS
@@ -3424,6 +3425,7 @@ locked_error:
        VReleaseVolumeHandles_r(vp);
     }
 
+ error_notbroken:
 #ifdef AFS_DEMAND_ATTACH_FS
     VCheckSalvage(vp);
     if (forcefree) {
@@ -4139,7 +4141,7 @@ GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
                    vp->hashid);
 #ifdef AFS_DEMAND_ATTACH_FS
            if (VCanScheduleSalvage()) {
-               VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
+               VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0 /*flags*/);
            } else {
                FreeVolume(vp);
                vp = NULL;
@@ -4324,7 +4326,7 @@ VForceOffline_r(Volume * vp, int flags)
     }
 
 #ifdef AFS_DEMAND_ATTACH_FS
-    VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
+    VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, 0 /*flags*/);
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 #ifdef AFS_PTHREAD_ENV
@@ -5479,8 +5481,8 @@ VCheckSalvage(Volume * vp)
  * @param[in]  flags   see flags note below
  *
  * @note flags:
- *       VOL_SALVAGE_INVALIDATE_HEADER causes volume header cache entry
- *                                     to be invalidated.
+ *       VOL_SALVAGE_NO_OFFLINE do not need to wait to offline the volume; it has
+ *                              not been fully attached
  *
  * @pre VOL_LOCK is held.
  *
@@ -5569,15 +5571,6 @@ VRequestSalvage_r(Error * ec, Volume * vp, int reason, int flags)
            *ec = VSALVAGE;
            code = 1;
        }
-       if (flags & VOL_SALVAGE_INVALIDATE_HEADER) {
-           /* Instead of ReleaseVolumeHeader, we do FreeVolumeHeader()
-               so that the the next VAttachVolumeByVp_r() invocation
-               of attach2() will pull in a cached header
-               entry and fail, then load a fresh one from disk and attach
-               it to the volume.
-           */
-           FreeVolumeHeader(vp);
-       }
     }
     return code;
 }
@@ -5765,7 +5758,7 @@ VScheduleSalvage_r(Volume * vp)
         * set the volume to an exclusive state and drop the lock
         * around the SALVSYNC call
         */
-       strlcpy(partName, VPartitionPath(vp->partition), sizeof(partName));
+       strlcpy(partName, vp->partition->name, sizeof(partName));
        state_save = VChangeState_r(vp, VOL_STATE_SALVSYNC_REQ);
        VOL_UNLOCK;
 
@@ -6225,7 +6218,7 @@ VAllocBitmapEntry_r(Error * ec, Volume * vp,
                VGetBitmap_r(ec, vp, i);
                if (*ec) {
 #ifdef AFS_DEMAND_ATTACH_FS
-                   VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
+                   VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0 /*flags*/);
 #else /* AFS_DEMAND_ATTACH_FS */
                    DeleteVolumeFromHashTable(vp);
                    vp->shuttingDown = 1;       /* Let who has it free it. */
@@ -6689,10 +6682,16 @@ VBumpVolumeUsage_r(Volume * vp)
     if (now - V_dayUseDate(vp) > OneDay)
        VAdjustVolumeStatistics_r(vp);
     /*
-     * Save the volume header image to disk after every 128 bumps to dayUse.
+     * Save the volume header image to disk after a threshold of bumps to dayUse,
+     * at most every usage_rate_limit seconds.
      */
-    if ((V_dayUse(vp)++ & 127) == 0) {
+    V_dayUse(vp)++;
+    vp->usage_bumps_outstanding++;
+    if (vp->usage_bumps_outstanding >= vol_opts.usage_threshold
+       && vp->usage_bumps_next_write <= now) {
        Error error;
+       vp->usage_bumps_outstanding = 0;
+       vp->usage_bumps_next_write = now + vol_opts.usage_rate_limit;
        VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT);
     }
 }
@@ -7920,6 +7919,51 @@ VInitVolumeHeaderCache(afs_uint32 howMany)
        ReleaseVolumeHeader(hp++);
 }
 
+/* get a volume header off of the volume header LRU.
+ *
+ * @return volume header
+ *  @retval NULL no usable volume header is available on the LRU
+ *
+ * @pre VOL_LOCK held
+ *
+ * @post for DAFS, if the returned header is associated with a volume, that
+ *       volume is NOT in an exclusive state
+ *
+ * @internal volume package internal use only.
+ */
+#ifdef AFS_DEMAND_ATTACH_FS
+static struct volHeader*
+GetVolHeaderFromLRU(void)
+{
+    struct volHeader *hd = NULL, *qh, *nqh;
+    /* Usually, a volume in an exclusive state will not have its header on
+     * the LRU. However, it is possible for this to occur when a salvage
+     * request is received over FSSYNC, and possibly in other corner cases.
+     * So just skip over headers whose volumes are in an exclusive state. We
+     * could VWaitExclusiveState_r instead, but not waiting is faster and
+     * easier to do */
+    for (queue_Scan(&volume_hdr_LRU, qh, nqh, volHeader)) {
+       if (!qh->back || !VIsExclusiveState(V_attachState(qh->back))) {
+           queue_Remove(qh);
+           hd = qh;
+           break;
+       }
+    }
+    return hd;
+}
+#else /* AFS_DEMAND_ATTACH_FS */
+static struct volHeader*
+GetVolHeaderFromLRU(void)
+{
+    struct volHeader *hd = NULL;
+    if (queue_IsNotEmpty(&volume_hdr_LRU)) {
+       hd = queue_First(&volume_hdr_LRU, volHeader);
+       queue_Remove(hd);
+    }
+    return hd;
+}
+#endif /* !AFS_DEMAND_ATTACH_FS */
+
 /**
  * get a volume header and attach it to the volume object.
  *
@@ -7988,12 +8032,8 @@ GetVolumeHeader(Volume * vp)
             V_attachFlags(vp) &= ~(VOL_HDR_IN_LRU);
 #endif
        } else {
-           /* we need to grab a new element off the LRU */
-           if (queue_IsNotEmpty(&volume_hdr_LRU)) {
-               /* grab an element and pull off of LRU */
-               hd = queue_First(&volume_hdr_LRU, volHeader);
-               queue_Remove(hd);
-           } else {
+           hd = GetVolHeaderFromLRU();
+           if (!hd) {
                /* LRU is empty, so allocate a new volHeader
                 * this is probably indicative of a leak, so let the user know */
                hd = (struct volHeader *)calloc(1, sizeof(struct volHeader));
@@ -8010,8 +8050,8 @@ GetVolumeHeader(Volume * vp)
                 * be sync'd out to disk */
 
 #ifdef AFS_DEMAND_ATTACH_FS
-               /* if hd->back were in an exclusive state, then
-                * its volHeader would not be on the LRU... */
+               /* GetVolHeaderFromLRU had better not give us back a header
+                * with a volume in exclusive state... */
                osi_Assert(!VIsExclusiveState(V_attachState(hd->back)));
 #endif