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;
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);
}
}
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.
*
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));
* 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